diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..93771ecc --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Check out text files with LF on every platform, overriding core.autocrlf. +# The build writes LF, so CRLF checkouts make every dist/ file look modified. +* text=auto eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eaa89887..88d9f2a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,10 +38,9 @@ jobs: with: node-version: ${{ matrix.node }} # No `cache: npm`: that needs a lockfile, and this repo gitignores one. - # Measured, caching ~/.npm would buy nothing anyway - install time is - # node-gyp compiling better-sqlite3, not downloads (see the PR body). - # Installing cold every run also keeps the native-install path that - # issues #100/#102/#105/#125/#135/#162 are about under real test. + # Installing cold every run keeps the native dependency path that + # issues #100/#102/#105/#125/#135/#162 are about under real test, + # including the bundled better-sqlite3 N-API platform binary. # No lockfile is committed, so `npm ci` cannot be used. Dependency ranges # resolve fresh on every run; see the PR body for the caveat this implies. diff --git a/.mcp.json b/.mcp.json index 46558f39..426fa096 100644 --- a/.mcp.json +++ b/.mcp.json @@ -11,6 +11,8 @@ "PERSONAL_SUPERPOWERS_DIR", "XDG_CONFIG_HOME", "EPISODIC_MEMORY_DB_PATH", + "EPISODIC_MEMORY_MODEL_CACHE_DIR", + "EPISODIC_MEMORY_OFFLINE", "CONVERSATION_SEARCH_EXCLUDE_PROJECTS" ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 511074ff..5347f567 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Fixed + +- Native database installs now use the N-API-based `better-sqlite3` 13.x line, so switching Node versions no longer leaves an ABI-specific binding behind. This also avoids a Node 24.19-24.21 cleanup-hook crash caused by rebuilding the old 12.x addon from source. Install verification now performs a real sqlite-vec write and nearest-neighbor query, and the MCP integration test covers text search, vector search, and reading the returned archive. + ## [1.6.0] - 2026-09-08 Adds a fifth conversation source, an off switch for automatic syncing, and two fixes for real-world resource problems. diff --git a/README.md b/README.md index ee952317..c27d7aac 100644 --- a/README.md +++ b/README.md @@ -301,12 +301,26 @@ Codex summarization requires `codex-cli 0.130.0` or newer. If Codex app-server s | Component | Uses custom config? | |-----------|---------------------| | Summarization | Yes (up to 10 calls/sync) | -| Embeddings | No (local Transformers.js) | +| Embeddings | Optional cache and offline settings (local Transformers.js) | | Search | No (local SQLite) | | MCP tools | No | Summaries are display-only: they decorate search results and are never embedded or searched, so `EPISODIC_MEMORY_SKIP_SUMMARIES=1` costs you that line of context and nothing else. +### Embedding model cache and offline mode + +Embedding computation is local, but a fresh installation may download its model +on first use. Model files are cached under the durable Episodic Memory +configuration directory in `models/`, outside npm-owned `node_modules`, so an +upgrade or dependency reinstall does not discard them. Set +`EPISODIC_MEMORY_MODEL_CACHE_DIR` to an absolute path to use a different or +pre-seeded cache. + +Set `EPISODIC_MEMORY_OFFLINE=1` to forbid remote model downloads. In that mode, +seed the model cache before indexing or semantic search; a missing model fails +with an explicit cache/offline error rather than silently fetching it. Other +values retain the normal first-install download behavior. + ## Commands ### `episodic-memory sync` @@ -411,7 +425,7 @@ open output.html 1. **Sync** - Copies conversation files from Claude Code and Codex transcript directories to archive; exports opencode sessions from SQLite into generated JSONL transcripts 2. **Parse** - Extracts user-agent exchanges from Claude Code JSONL, Codex rollout JSONL, or opencode transcript JSONL -3. **Embed** - Generates vector embeddings using Transformers.js (local, offline) +3. **Embed** - Generates vectors locally with Transformers.js after the model is available 4. **Index** - Stores in SQLite with sqlite-vec for fast similarity search 5. **Search** - Semantic search using vector similarity or exact text matching @@ -519,6 +533,12 @@ npm test npm run build ``` +`npm test` prepares the embedding model once in the ignored +`tmp/test-model-cache` directory, then runs test workers without remote model +downloads. A fresh test run may download the public model; setting +`EPISODIC_MEMORY_OFFLINE=1` requires a pre-seeded test cache instead. This does +not change the production model cache or summarization routes. + ## License MIT diff --git a/dist/embeddings.js b/dist/embeddings.js index efc41dc4..80fd0b77 100644 --- a/dist/embeddings.js +++ b/dist/embeddings.js @@ -1,3 +1,4 @@ +import { getModelCacheDir } from './paths.js'; /** * Embedding model configuration. * @@ -65,6 +66,8 @@ export class EmbeddingsUnavailableError extends Error { export async function initEmbeddings() { if (embeddingPipeline) return; + const modelCacheDir = getModelCacheDir(); + const offline = process.env.EPISODIC_MEMORY_OFFLINE === '1'; // Load @huggingface/transformers lazily. Its module graph eagerly requires // `sharp`, so a static top-level import would crash *every* consumer of this // file at import time on hosts where sharp's native binding can't load — @@ -73,9 +76,11 @@ export async function initEmbeddings() { let pipeline; try { const transformers = await import('@huggingface/transformers'); - // Disable progress callbacks / remote cache to prevent stdout pollution in - // MCP context, where stdout is reserved for JSON-RPC communication. + // Keep model files in durable operator-owned state. Offline mode is an + // explicit choice; a fresh default install can still fetch its model. + transformers.env.cacheDir = modelCacheDir; transformers.env.allowLocalModels = true; + transformers.env.allowRemoteModels = !offline; transformers.env.useBrowserCache = false; pipeline = transformers.pipeline; } @@ -97,7 +102,15 @@ export async function initEmbeddings() { interOpNumThreads: 1, }; } - embeddingPipeline = await pipeline('feature-extraction', MODEL_ID, options); + try { + embeddingPipeline = await pipeline('feature-extraction', MODEL_ID, options); + } + catch (error) { + const message = offline + ? 'Embedding model unavailable in the local cache while EPISODIC_MEMORY_OFFLINE=1; pre-seed the model cache or disable offline mode.' + : 'Embedding model unavailable; check the model cache and remote model access.'; + throw new EmbeddingsUnavailableError(message, { cause: error }); + } console.error('Embedding model loaded'); } export async function generateEmbedding(text) { diff --git a/dist/mcp-server.js b/dist/mcp-server.js index e3a9adac..c8ca7b19 100644 --- a/dist/mcp-server.js +++ b/dist/mcp-server.js @@ -469,9 +469,9 @@ var require_codegen = __commonJS({ } }; var Throw = class extends Node { - constructor(error61) { + constructor(error62) { super(); - this.error = error61; + this.error = error62; } render({ _n }) { return `throw ${this.error};` + _n; @@ -708,9 +708,9 @@ var require_codegen = __commonJS({ } }; var Catch = class extends BlockNode { - constructor(error61) { + constructor(error62) { super(); - this.error = error61; + this.error = error62; } render(opts) { return `catch(${this.error})` + super.render(opts); @@ -901,9 +901,9 @@ var require_codegen = __commonJS({ this._blockNode(node2); this.code(tryBody); if (catchCode) { - const error61 = this.name("e"); - this._currNode = node2.catch = new Catch(error61); - catchCode(error61); + const error62 = this.name("e"); + this._currNode = node2.catch = new Catch(error62); + catchCode(error62); } if (finallyCode) { this._currNode = node2.finally = new Finally(); @@ -912,8 +912,8 @@ var require_codegen = __commonJS({ return this._endBlockNode(Catch, Finally); } // `throw` statement - throw(error61) { - return this._leafNode(new Throw(error61)); + throw(error62) { + return this._leafNode(new Throw(error62)); } // start self-balancing block block(body, nodeCount) { @@ -1269,10 +1269,10 @@ var require_errors = __commonJS({ exports.keyword$DataError = { message: ({ keyword, schemaType }) => schemaType ? (0, codegen_1.str)`"${keyword}" keyword must be ${schemaType} ($data)` : (0, codegen_1.str)`"${keyword}" keyword is invalid ($data)` }; - function reportError(cxt, error61 = exports.keywordError, errorPaths, overrideAllErrors) { + function reportError(cxt, error62 = exports.keywordError, errorPaths, overrideAllErrors) { const { it } = cxt; const { gen, compositeRule, allErrors } = it; - const errObj = errorObjectCode(cxt, error61, errorPaths); + const errObj = errorObjectCode(cxt, error62, errorPaths); if (overrideAllErrors !== null && overrideAllErrors !== void 0 ? overrideAllErrors : compositeRule || allErrors) { addError(gen, errObj); } else { @@ -1280,10 +1280,10 @@ var require_errors = __commonJS({ } } exports.reportError = reportError; - function reportExtraError(cxt, error61 = exports.keywordError, errorPaths) { + function reportExtraError(cxt, error62 = exports.keywordError, errorPaths) { const { it } = cxt; const { gen, compositeRule, allErrors } = it; - const errObj = errorObjectCode(cxt, error61, errorPaths); + const errObj = errorObjectCode(cxt, error62, errorPaths); addError(gen, errObj); if (!(compositeRule || allErrors)) { returnErrors(it, names_1.default.vErrors); @@ -1334,19 +1334,19 @@ var require_errors = __commonJS({ schema: new codegen_1.Name("schema"), parentSchema: new codegen_1.Name("parentSchema") }; - function errorObjectCode(cxt, error61, errorPaths) { + function errorObjectCode(cxt, error62, errorPaths) { const { createErrors } = cxt.it; if (createErrors === false) return (0, codegen_1._)`{}`; - return errorObject(cxt, error61, errorPaths); + return errorObject(cxt, error62, errorPaths); } - function errorObject(cxt, error61, errorPaths = {}) { + function errorObject(cxt, error62, errorPaths = {}) { const { gen, it } = cxt; const keyValues = [ errorInstancePath(it, errorPaths), errorSchemaPath(cxt, errorPaths) ]; - extraErrorProps(cxt, error61, keyValues); + extraErrorProps(cxt, error62, keyValues); return gen.object(...keyValues); } function errorInstancePath({ errorPath }, { instancePath }) { @@ -1775,13 +1775,13 @@ var require_code2 = __commonJS({ exports.callValidateCode = callValidateCode; var newRegExp = (0, codegen_1._)`new RegExp`; function usePattern({ gen, it: { opts } }, pattern) { - const u3 = opts.unicodeRegExp ? "u" : ""; + const u = opts.unicodeRegExp ? "u" : ""; const { regExp } = opts.code; - const rx = regExp(pattern, u3); + const rx = regExp(pattern, u); return gen.scopeValue("pattern", { key: rx.toString(), ref: rx, - code: (0, codegen_1._)`${regExp.code === "new RegExp" ? newRegExp : (0, util_2.useFunc)(gen, regExp)}(${pattern}, ${u3})` + code: (0, codegen_1._)`${regExp.code === "new RegExp" ? newRegExp : (0, util_2.useFunc)(gen, regExp)}(${pattern}, ${u})` }); } exports.usePattern = usePattern; @@ -1878,13 +1878,13 @@ var require_keyword = __commonJS({ modifyData(cxt); reportErrs(() => cxt.error()); } else { - const ruleErrs = def.async ? validateAsync2() : validateSync(); + const ruleErrs = def.async ? validateAsync3() : validateSync(); if (def.modifying) modifyData(cxt); reportErrs(() => addErrs(cxt, ruleErrs)); } } - function validateAsync2() { + function validateAsync3() { const ruleErrs = gen.let("ruleErrs", null); gen.try(() => assignValid((0, codegen_1._)`await `), (e) => gen.assign(valid, false).if((0, codegen_1._)`${e} instanceof ${it.ValidationError}`, () => gen.assign(ruleErrs, (0, codegen_1._)`${e}.errors`), () => gen.throw(e))); return ruleErrs; @@ -4144,13 +4144,14 @@ var require_fast_uri = __commonJS({ if (!malformedIPLiteral) { malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP); } - if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) { - if (uri.indexOf("%") !== -1) { - if (parsed.host !== void 0 && !malformedIPLiteral) { - const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true); - parsed.host = reescapeHostDelimiters(host, isIP); - } + if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) { + let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true); + if (!isIP) { + host = normalizePercentEncoding(host.toLowerCase()); } + parsed.host = reescapeHostDelimiters(host, isIP); + } + if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) { if (parsed.path) { parsed.path = normalizePathEncoding(parsed.path); } @@ -5010,7 +5011,7 @@ var require_limitNumber = __commonJS({ exclusiveMaximum: { okStr: "<", ok: ops.LT, fail: ops.GTE }, exclusiveMinimum: { okStr: ">", ok: ops.GT, fail: ops.LTE } }; - var error61 = { + var error62 = { message: ({ keyword, schemaCode }) => (0, codegen_1.str)`must be ${KWDs[keyword].okStr} ${schemaCode}`, params: ({ keyword, schemaCode }) => (0, codegen_1._)`{comparison: ${KWDs[keyword].okStr}, limit: ${schemaCode}}` }; @@ -5019,7 +5020,7 @@ var require_limitNumber = __commonJS({ type: "number", schemaType: "number", $data: true, - error: error61, + error: error62, code(cxt) { const { keyword, data, schemaCode } = cxt; cxt.fail$data((0, codegen_1._)`${data} ${KWDs[keyword].fail} ${schemaCode} || isNaN(${data})`); @@ -5035,7 +5036,7 @@ var require_multipleOf = __commonJS({ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var codegen_1 = require_codegen(); - var error61 = { + var error62 = { message: ({ schemaCode }) => (0, codegen_1.str)`must be multiple of ${schemaCode}`, params: ({ schemaCode }) => (0, codegen_1._)`{multipleOf: ${schemaCode}}` }; @@ -5044,7 +5045,7 @@ var require_multipleOf = __commonJS({ type: "number", schemaType: "number", $data: true, - error: error61, + error: error62, code(cxt) { const { gen, data, schemaCode, it } = cxt; const prec = it.opts.multipleOfPrecision; @@ -5091,7 +5092,7 @@ var require_limitLength = __commonJS({ var codegen_1 = require_codegen(); var util_1 = require_util(); var ucs2length_1 = require_ucs2length(); - var error61 = { + var error62 = { message({ keyword, schemaCode }) { const comp = keyword === "maxLength" ? "more" : "fewer"; return (0, codegen_1.str)`must NOT have ${comp} than ${schemaCode} characters`; @@ -5103,7 +5104,7 @@ var require_limitLength = __commonJS({ type: "string", schemaType: "number", $data: true, - error: error61, + error: error62, code(cxt) { const { keyword, data, schemaCode, it } = cxt; const op = keyword === "maxLength" ? codegen_1.operators.GT : codegen_1.operators.LT; @@ -5123,7 +5124,7 @@ var require_pattern = __commonJS({ var code_1 = require_code2(); var util_1 = require_util(); var codegen_1 = require_codegen(); - var error61 = { + var error62 = { message: ({ schemaCode }) => (0, codegen_1.str)`must match pattern "${schemaCode}"`, params: ({ schemaCode }) => (0, codegen_1._)`{pattern: ${schemaCode}}` }; @@ -5132,15 +5133,15 @@ var require_pattern = __commonJS({ type: "string", schemaType: "string", $data: true, - error: error61, + error: error62, code(cxt) { const { gen, data, $data, schema, schemaCode, it } = cxt; - const u3 = it.opts.unicodeRegExp ? "u" : ""; + const u = it.opts.unicodeRegExp ? "u" : ""; if ($data) { const { regExp } = it.opts.code; const regExpCode = regExp.code === "new RegExp" ? (0, codegen_1._)`new RegExp` : (0, util_1.useFunc)(gen, regExp); const valid = gen.let("valid"); - gen.try(() => gen.assign(valid, (0, codegen_1._)`${regExpCode}(${schemaCode}, ${u3}).test(${data})`), () => gen.assign(valid, false)); + gen.try(() => gen.assign(valid, (0, codegen_1._)`${regExpCode}(${schemaCode}, ${u}).test(${data})`), () => gen.assign(valid, false)); cxt.fail$data((0, codegen_1._)`!${valid}`); } else { const regExp = (0, code_1.usePattern)(cxt, schema); @@ -5158,7 +5159,7 @@ var require_limitProperties = __commonJS({ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var codegen_1 = require_codegen(); - var error61 = { + var error62 = { message({ keyword, schemaCode }) { const comp = keyword === "maxProperties" ? "more" : "fewer"; return (0, codegen_1.str)`must NOT have ${comp} than ${schemaCode} properties`; @@ -5170,7 +5171,7 @@ var require_limitProperties = __commonJS({ type: "object", schemaType: "number", $data: true, - error: error61, + error: error62, code(cxt) { const { keyword, data, schemaCode } = cxt; const op = keyword === "maxProperties" ? codegen_1.operators.GT : codegen_1.operators.LT; @@ -5189,7 +5190,7 @@ var require_required = __commonJS({ var code_1 = require_code2(); var codegen_1 = require_codegen(); var util_1 = require_util(); - var error61 = { + var error62 = { message: ({ params: { missingProperty } }) => (0, codegen_1.str)`must have required property '${missingProperty}'`, params: ({ params: { missingProperty } }) => (0, codegen_1._)`{missingProperty: ${missingProperty}}` }; @@ -5198,7 +5199,7 @@ var require_required = __commonJS({ type: "object", schemaType: "array", $data: true, - error: error61, + error: error62, code(cxt) { const { gen, schema, schemaCode, data, $data, it } = cxt; const { opts } = it; @@ -5269,7 +5270,7 @@ var require_limitItems = __commonJS({ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var codegen_1 = require_codegen(); - var error61 = { + var error62 = { message({ keyword, schemaCode }) { const comp = keyword === "maxItems" ? "more" : "fewer"; return (0, codegen_1.str)`must NOT have ${comp} than ${schemaCode} items`; @@ -5281,7 +5282,7 @@ var require_limitItems = __commonJS({ type: "array", schemaType: "number", $data: true, - error: error61, + error: error62, code(cxt) { const { keyword, data, schemaCode } = cxt; const op = keyword === "maxItems" ? codegen_1.operators.GT : codegen_1.operators.LT; @@ -5312,7 +5313,7 @@ var require_uniqueItems = __commonJS({ var codegen_1 = require_codegen(); var util_1 = require_util(); var equal_1 = require_equal(); - var error61 = { + var error62 = { message: ({ params: { i, j: j2 } }) => (0, codegen_1.str)`must NOT have duplicate items (items ## ${j2} and ${i} are identical)`, params: ({ params: { i, j: j2 } }) => (0, codegen_1._)`{i: ${i}, j: ${j2}}` }; @@ -5321,7 +5322,7 @@ var require_uniqueItems = __commonJS({ type: "array", schemaType: "boolean", $data: true, - error: error61, + error: error62, code(cxt) { const { gen, data, $data, schema, parentSchema, schemaCode, it } = cxt; if (!$data && !schema) @@ -5378,14 +5379,14 @@ var require_const = __commonJS({ var codegen_1 = require_codegen(); var util_1 = require_util(); var equal_1 = require_equal(); - var error61 = { + var error62 = { message: "must be equal to constant", params: ({ schemaCode }) => (0, codegen_1._)`{allowedValue: ${schemaCode}}` }; var def = { keyword: "const", $data: true, - error: error61, + error: error62, code(cxt) { const { gen, data, $data, schemaCode, schema } = cxt; if ($data || schema && typeof schema == "object") { @@ -5407,7 +5408,7 @@ var require_enum = __commonJS({ var codegen_1 = require_codegen(); var util_1 = require_util(); var equal_1 = require_equal(); - var error61 = { + var error62 = { message: "must be equal to one of the allowed values", params: ({ schemaCode }) => (0, codegen_1._)`{allowedValues: ${schemaCode}}` }; @@ -5415,7 +5416,7 @@ var require_enum = __commonJS({ keyword: "enum", schemaType: "array", $data: true, - error: error61, + error: error62, code(cxt) { const { gen, data, $data, schema, schemaCode, it } = cxt; if (!$data && schema.length === 0) @@ -5494,7 +5495,7 @@ var require_additionalItems = __commonJS({ exports.validateAdditionalItems = void 0; var codegen_1 = require_codegen(); var util_1 = require_util(); - var error61 = { + var error62 = { message: ({ params: { len } }) => (0, codegen_1.str)`must NOT have more than ${len} items`, params: ({ params: { len } }) => (0, codegen_1._)`{limit: ${len}}` }; @@ -5503,7 +5504,7 @@ var require_additionalItems = __commonJS({ type: "array", schemaType: ["boolean", "object"], before: "uniqueItems", - error: error61, + error: error62, code(cxt) { const { parentSchema, it } = cxt; const { items } = parentSchema; @@ -5583,10 +5584,10 @@ var require_items = __commonJS({ }); function checkStrictTuple(sch) { const { opts, errSchemaPath } = it; - const l = schArr.length; - const fullTuple = l === sch.minItems && (l === sch.maxItems || sch[extraItems] === false); + const l3 = schArr.length; + const fullTuple = l3 === sch.minItems && (l3 === sch.maxItems || sch[extraItems] === false); if (opts.strictTuples && !fullTuple) { - const msg = `"${keyword}" is ${l}-tuple, but minItems or maxItems/${extraItems} are not specified or different at path "${errSchemaPath}"`; + const msg = `"${keyword}" is ${l3}-tuple, but minItems or maxItems/${extraItems} are not specified or different at path "${errSchemaPath}"`; (0, util_1.checkStrictMode)(it, msg, opts.strictTuples); } } @@ -5622,7 +5623,7 @@ var require_items2020 = __commonJS({ var util_1 = require_util(); var code_1 = require_code2(); var additionalItems_1 = require_additionalItems(); - var error61 = { + var error62 = { message: ({ params: { len } }) => (0, codegen_1.str)`must NOT have more than ${len} items`, params: ({ params: { len } }) => (0, codegen_1._)`{limit: ${len}}` }; @@ -5631,7 +5632,7 @@ var require_items2020 = __commonJS({ type: "array", schemaType: ["object", "boolean"], before: "uniqueItems", - error: error61, + error: error62, code(cxt) { const { schema, parentSchema, it } = cxt; const { prefixItems } = parentSchema; @@ -5655,7 +5656,7 @@ var require_contains = __commonJS({ Object.defineProperty(exports, "__esModule", { value: true }); var codegen_1 = require_codegen(); var util_1 = require_util(); - var error61 = { + var error62 = { message: ({ params: { min, max } }) => max === void 0 ? (0, codegen_1.str)`must contain at least ${min} valid item(s)` : (0, codegen_1.str)`must contain at least ${min} and no more than ${max} valid item(s)`, params: ({ params: { min, max } }) => max === void 0 ? (0, codegen_1._)`{minContains: ${min}}` : (0, codegen_1._)`{minContains: ${min}, maxContains: ${max}}` }; @@ -5665,7 +5666,7 @@ var require_contains = __commonJS({ schemaType: ["object", "boolean"], before: "uniqueItems", trackErrors: true, - error: error61, + error: error62, code(cxt) { const { gen, schema, parentSchema, data, it } = cxt; let min; @@ -5843,7 +5844,7 @@ var require_propertyNames = __commonJS({ Object.defineProperty(exports, "__esModule", { value: true }); var codegen_1 = require_codegen(); var util_1 = require_util(); - var error61 = { + var error62 = { message: "property name must be valid", params: ({ params }) => (0, codegen_1._)`{propertyName: ${params.propertyName}}` }; @@ -5851,7 +5852,7 @@ var require_propertyNames = __commonJS({ keyword: "propertyNames", type: "object", schemaType: ["object", "boolean"], - error: error61, + error: error62, code(cxt) { const { gen, schema, data, it } = cxt; if ((0, util_1.alwaysValidSchema)(it, schema)) @@ -5888,7 +5889,7 @@ var require_additionalProperties = __commonJS({ var codegen_1 = require_codegen(); var names_1 = require_names(); var util_1 = require_util(); - var error61 = { + var error62 = { message: "must NOT have additional properties", params: ({ params }) => (0, codegen_1._)`{additionalProperty: ${params.additionalProperty}}` }; @@ -5898,7 +5899,7 @@ var require_additionalProperties = __commonJS({ schemaType: ["boolean", "object"], allowUndefined: true, trackErrors: true, - error: error61, + error: error62, code(cxt) { const { gen, schema, parentSchema, data, errsCount, it } = cxt; if (!errsCount) @@ -6172,7 +6173,7 @@ var require_oneOf = __commonJS({ Object.defineProperty(exports, "__esModule", { value: true }); var codegen_1 = require_codegen(); var util_1 = require_util(); - var error61 = { + var error62 = { message: "must match exactly one schema in oneOf", params: ({ params }) => (0, codegen_1._)`{passingSchemas: ${params.passing}}` }; @@ -6180,7 +6181,7 @@ var require_oneOf = __commonJS({ keyword: "oneOf", schemaType: "array", trackErrors: true, - error: error61, + error: error62, code(cxt) { const { gen, schema, parentSchema, it } = cxt; if (!Array.isArray(schema)) @@ -6257,7 +6258,7 @@ var require_if = __commonJS({ Object.defineProperty(exports, "__esModule", { value: true }); var codegen_1 = require_codegen(); var util_1 = require_util(); - var error61 = { + var error62 = { message: ({ params }) => (0, codegen_1.str)`must match "${params.ifClause}" schema`, params: ({ params }) => (0, codegen_1._)`{failingKeyword: ${params.ifClause}}` }; @@ -6265,7 +6266,7 @@ var require_if = __commonJS({ keyword: "if", schemaType: ["object", "boolean"], trackErrors: true, - error: error61, + error: error62, code(cxt) { const { gen, parentSchema, it } = cxt; if (parentSchema.then === void 0 && parentSchema.else === void 0) { @@ -6391,7 +6392,7 @@ var require_format = __commonJS({ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var codegen_1 = require_codegen(); - var error61 = { + var error62 = { message: ({ schemaCode }) => (0, codegen_1.str)`must match format "${schemaCode}"`, params: ({ schemaCode }) => (0, codegen_1._)`{format: ${schemaCode}}` }; @@ -6400,7 +6401,7 @@ var require_format = __commonJS({ type: ["number", "string"], schemaType: "string", $data: true, - error: error61, + error: error62, code(cxt, ruleType) { const { gen, data, $data, schema, schemaCode, it } = cxt; const { opts, errSchemaPath, schemaEnv, self } = it; @@ -6555,7 +6556,7 @@ var require_discriminator = __commonJS({ var compile_1 = require_compile(); var ref_error_1 = require_ref_error(); var util_1 = require_util(); - var error61 = { + var error62 = { message: ({ params: { discrError, tagName } }) => discrError === types_1.DiscrError.Tag ? `tag "${tagName}" must be string` : `value of tag "${tagName}" must be in oneOf`, params: ({ params: { discrError, tag, tagName } }) => (0, codegen_1._)`{error: ${discrError}, tag: ${tagName}, tagValue: ${tag}}` }; @@ -6563,7 +6564,7 @@ var require_discriminator = __commonJS({ keyword: "discriminator", type: "object", schemaType: "object", - error: error61, + error: error62, code(cxt) { const { gen, data, schema, parentSchema, it } = cxt; const { oneOf } = parentSchema; @@ -7095,7 +7096,7 @@ var require_limit = __commonJS({ formatExclusiveMaximum: { okStr: "<", ok: ops.LT, fail: ops.GTE }, formatExclusiveMinimum: { okStr: ">", ok: ops.GT, fail: ops.LTE } }; - var error61 = { + var error62 = { message: ({ keyword, schemaCode }) => (0, codegen_1.str)`should be ${KWDs[keyword].okStr} ${schemaCode}`, params: ({ keyword, schemaCode }) => (0, codegen_1._)`{comparison: ${KWDs[keyword].okStr}, limit: ${schemaCode}}` }; @@ -7104,7 +7105,7 @@ var require_limit = __commonJS({ type: "string", schemaType: "string", $data: true, - error: error61, + error: error62, code(cxt) { const { gen, data, schemaCode, keyword, it } = cxt; const { opts, self } = it; @@ -7226,6 +7227,7 @@ __export(core_exports2, { $ZodCheckMultipleOf: () => $ZodCheckMultipleOf, $ZodCheckNumberFormat: () => $ZodCheckNumberFormat, $ZodCheckOverwrite: () => $ZodCheckOverwrite, + $ZodCheckProperties: () => $ZodCheckProperties, $ZodCheckProperty: () => $ZodCheckProperty, $ZodCheckRegex: () => $ZodCheckRegex, $ZodCheckSizeEquals: () => $ZodCheckSizeEquals, @@ -7250,6 +7252,7 @@ __export(core_exports2, { $ZodFile: () => $ZodFile, $ZodFunction: () => $ZodFunction, $ZodGUID: () => $ZodGUID, + $ZodIBAN: () => $ZodIBAN, $ZodIPv4: () => $ZodIPv4, $ZodIPv6: () => $ZodIPv6, $ZodISODate: () => $ZodISODate, @@ -7351,6 +7354,7 @@ __export(core_exports2, { _gt: () => _gt, _gte: () => _gte, _guid: () => _guid, + _iban: () => _iban, _includes: () => _includes, _int: () => _int, _int32: () => _int32, @@ -7442,6 +7446,9 @@ __export(core_exports2, { _void: () => _void, _xid: () => _xid, _xor: () => _xor, + base64Charset: () => base64Charset, + base64urlCharset: () => base64urlCharset, + canParseURL: () => canParseURL, clone: () => clone, compile: () => compile, compileFn: () => compileFn, @@ -7468,6 +7475,7 @@ __export(core_exports2, { isValidBase64URL: () => isValidBase64URL, isValidCIDRv6: () => isValidCIDRv6, isValidCreditCard: () => isValidCreditCard, + isValidIBAN: () => isValidIBAN, isValidIPv6: () => isValidIPv6, isValidJWT: () => isValidJWT, locales: () => locales_exports, @@ -7478,7 +7486,8 @@ __export(core_exports2, { parseAsync: () => parseAsync, parseURLObject: () => parseURLObject, prettifyError: () => prettifyError, - process: () => process2, + process: () => processSchema, + processSchema: () => processSchema, regexes: () => regexes_exports, registry: () => registry, safeDecode: () => safeDecode, @@ -7498,7 +7507,9 @@ __export(core_exports2, { util: () => util_exports, validate: () => validate, validateAsync: () => validateAsync, - version: () => version + validateURL: () => validateURL, + version: () => version, + withParser: () => withParser }); // node_modules/zod/v4/core/util.js @@ -7530,6 +7541,7 @@ __export(util_exports, { createTransparentProxy: () => createTransparentProxy, defineLazy: () => defineLazy, defineLazyInternal: () => defineLazyInternal, + derived: () => derived, esc: () => esc, escapeRegex: () => escapeRegex, explicitlyAborted: () => explicitlyAborted, @@ -7567,6 +7579,7 @@ __export(util_exports, { promiseAllObject: () => promiseAllObject, propertyKeyTypes: () => propertyKeyTypes, randomString: () => randomString, + rawShape: () => rawShape, required: () => required, safeExtend: () => safeExtend, shallowClone: () => shallowClone, @@ -7607,18 +7620,22 @@ function jsonStringifyReplacer(_2, value) { return value.toString(); return value; } -function cached(getter) { - const set2 = false; - return { - get value() { - if (!set2) { - const value = getter(); - Object.defineProperty(this, "value", { value }); - return value; - } - throw new Error("cached value already set"); +var Cached = class { + constructor(getter) { + this._getter = getter; + this._value = void 0; + } + get value() { + const getter = this._getter; + if (getter !== void 0) { + this._value = getter(); + this._getter = void 0; } - }; + return this._value; + } +}; +function cached(getter) { + return new Cached(getter); } function nullish(input2) { return input2 === null || input2 === void 0; @@ -7670,6 +7687,56 @@ function assignProp(target, prop, value) { configurable: true }); } +function rawShape(def) { + const desc = Object.getOwnPropertyDescriptor(def, "shape"); + return desc?.get ? desc.get.raw : desc?.value; +} +function sourceShape(schema) { + return rawShape(schema._zod.def) ?? schema._zod.def.shape; +} +function deferProp(target, key, getter) { + Object.defineProperty(target, key, { + get() { + const value = getter(); + assignProp(this, key, value); + return value; + }, + enumerable: true, + configurable: true + }); +} +function putProp(target, key, value) { + if (key in target) + assignProp(target, key, value); + else + target[key] = value; +} +function mirrorShape(target, source, keys, wrap) { + const raw = sourceShape(source); + for (const key of keys) { + const desc = Object.getOwnPropertyDescriptor(raw, key); + if (!desc.enumerable) + continue; + if (desc.get) { + deferProp(target, key, () => { + const value = source._zod.def.shape[key]; + return wrap ? wrap(value, key) : value; + }); + } else + putProp(target, key, wrap ? wrap(desc.value, key) : desc.value); + } +} +function mirrorProps(target, source) { + for (const key of Reflect.ownKeys(source)) { + const desc = Object.getOwnPropertyDescriptor(source, key); + if (!desc.enumerable) + continue; + if (desc.get) + deferProp(target, key, () => source[key]); + else + putProp(target, key, desc.value); + } +} function mergeDefs(...defs) { const mergedDescriptors = {}; for (const def of defs) { @@ -7908,23 +7975,21 @@ function pick(schema, mask) { if (hasChecks) { throw new Error(".pick() cannot be used on object schemas containing refinements"); } - const def = mergeDefs(schema._zod.def, { - get shape() { - const newShape = {}; - for (const key of Reflect.ownKeys(mask)) { - if (!Object.prototype.hasOwnProperty.call(currDef.shape, key)) { - throw new Error(`Unrecognized key: "${String(key)}"`); - } - if (!mask[key]) - continue; - assignProp(newShape, key, currDef.shape[key]); - } - assignProp(this, "shape", newShape); - return newShape; - }, - checks: [] - }); - return clone(schema, def); + const newShape = {}; + mirrorShape(newShape, schema, maskedKeys(schema, mask)); + return clone(schema, mergeDefs(currDef, { shape: newShape, checks: [] })); +} +function maskedKeys(schema, mask) { + const raw = sourceShape(schema); + const keys = []; + for (const key of Reflect.ownKeys(mask)) { + if (!Object.getOwnPropertyDescriptor(raw, key)?.enumerable) { + throw new Error(`Unrecognized key: "${String(key)}"`); + } + if (mask[key]) + keys.push(key); + } + return keys; } function omit(schema, mask) { const currDef = schema._zod.def; @@ -7933,23 +7998,10 @@ function omit(schema, mask) { if (hasChecks) { throw new Error(".omit() cannot be used on object schemas containing refinements"); } - const def = mergeDefs(schema._zod.def, { - get shape() { - const newShape = { ...schema._zod.def.shape }; - for (const key of Reflect.ownKeys(mask)) { - if (!Object.prototype.hasOwnProperty.call(currDef.shape, key)) { - throw new Error(`Unrecognized key: "${String(key)}"`); - } - if (!mask[key]) - continue; - delete newShape[key]; - } - assignProp(this, "shape", newShape); - return newShape; - }, - checks: [] - }); - return clone(schema, def); + const omitted = new Set(maskedKeys(schema, mask)); + const newShape = {}; + mirrorShape(newShape, schema, Reflect.ownKeys(sourceShape(schema)).filter((key) => !omitted.has(key))); + return clone(schema, mergeDefs(currDef, { shape: newShape, checks: [] })); } function extend(schema, shape) { if (!isPlainObject(shape)) { @@ -7958,34 +8010,26 @@ function extend(schema, shape) { const checks = schema._zod.def.checks; const hasChecks = checks && checks.length > 0; if (hasChecks) { - const existingShape = schema._zod.def.shape; + const existingShape = sourceShape(schema); for (const key of Reflect.ownKeys(shape)) { if (Object.getOwnPropertyDescriptor(existingShape, key) !== void 0) { throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead."); } } } - const def = mergeDefs(schema._zod.def, { - get shape() { - const _shape = { ...schema._zod.def.shape, ...shape }; - assignProp(this, "shape", _shape); - return _shape; - } - }); - return clone(schema, def); + return clone(schema, mergeDefs(schema._zod.def, { shape: extended(schema, shape) })); +} +function extended(schema, shape) { + const newShape = {}; + mirrorShape(newShape, schema, Reflect.ownKeys(sourceShape(schema))); + mirrorProps(newShape, shape); + return newShape; } function safeExtend(schema, shape) { if (!isPlainObject(shape)) { throw new Error("Invalid input to safeExtend: expected a plain object"); } - const def = mergeDefs(schema._zod.def, { - get shape() { - const _shape = { ...schema._zod.def.shape, ...shape }; - assignProp(this, "shape", _shape); - return _shape; - } - }); - return clone(schema, def); + return clone(schema, mergeDefs(schema._zod.def, { shape: extended(schema, shape) })); } function merge(a, b2) { if (!b2?._zod?.def) { @@ -7994,12 +8038,11 @@ function merge(a, b2) { if (a._zod.def.checks?.length) { throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead."); } + const newShape = {}; + mirrorShape(newShape, a, Reflect.ownKeys(sourceShape(a))); + mirrorShape(newShape, b2, Reflect.ownKeys(sourceShape(b2))); const def = mergeDefs(a._zod.def, { - get shape() { - const _shape = { ...a._zod.def.shape, ...b2._zod.def.shape }; - assignProp(this, "shape", _shape); - return _shape; - }, + shape: newShape, get catchall() { return b2._zod.def.catchall; }, @@ -8014,67 +8057,19 @@ function partial(Class2, schema, mask, name = "partial") { if (hasChecks) { throw new Error(`.${name}() cannot be used on object schemas containing refinements`); } - const def = mergeDefs(schema._zod.def, { - get shape() { - const oldShape = schema._zod.def.shape; - const shape = { ...oldShape }; - if (mask) { - for (const key of Reflect.ownKeys(mask)) { - if (!Object.prototype.hasOwnProperty.call(oldShape, key)) { - throw new Error(`Unrecognized key: "${String(key)}"`); - } - if (!mask[key]) - continue; - shape[key] = Class2 ? new Class2({ - type: "optional", - innerType: oldShape[key] - }) : oldShape[key]; - } - } else { - for (const key of Reflect.ownKeys(oldShape)) { - shape[key] = Class2 ? new Class2({ - type: "optional", - innerType: oldShape[key] - }) : oldShape[key]; - } - } - assignProp(this, "shape", shape); - return shape; - }, - checks: [] - }); - return clone(schema, def); + const selected = mask ? new Set(maskedKeys(schema, mask)) : void 0; + const newShape = {}; + mirrorShape(newShape, schema, Reflect.ownKeys(sourceShape(schema)), Class2 && ((value, key) => selected && !selected.has(key) ? value : new Class2({ type: "optional", innerType: value }))); + return clone(schema, mergeDefs(schema._zod.def, { shape: newShape, checks: [] })); } function required(Class2, schema, mask) { - const def = mergeDefs(schema._zod.def, { - get shape() { - const oldShape = schema._zod.def.shape; - const shape = { ...oldShape }; - if (mask) { - for (const key of Reflect.ownKeys(mask)) { - if (!Object.prototype.hasOwnProperty.call(shape, key)) { - throw new Error(`Unrecognized key: "${String(key)}"`); - } - if (!mask[key]) - continue; - shape[key] = new Class2({ - type: "nonoptional", - innerType: oldShape[key] - }); - } - } else { - for (const key of Reflect.ownKeys(oldShape)) { - shape[key] = new Class2({ - type: "nonoptional", - innerType: oldShape[key] - }); - } - } - assignProp(this, "shape", shape); - return shape; - } - }); - return clone(schema, def); + const selected = mask ? new Set(maskedKeys(schema, mask)) : void 0; + const newShape = {}; + mirrorShape(newShape, schema, Reflect.ownKeys(sourceShape(schema)), (value, key) => ( + // overwrite with non-optional + selected && !selected.has(key) ? value : new Class2({ type: "nonoptional", innerType: value }) + )); + return clone(schema, mergeDefs(schema._zod.def, { shape: newShape })); } function aborted(x2, startIndex = 0) { if (x2.aborted === true) @@ -8124,13 +8119,18 @@ function finalizeIssue(iss, ctx, config2) { } const schemaError = iss.schema !== iss.inst ? iss.schema?._zod.def?.error : void 0; const message = iss.message ? iss.message : unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(schemaError?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config2.customError?.(iss)) ?? unwrapMessage(config2.localeError?.(iss)) ?? "Invalid input"; - const { inst: _inst, schema: _schema, continue: _continue, input: _input, ...rest } = iss; - rest.path ?? (rest.path = []); - rest.message = message; + const full = {}; + for (const k2 of Object.keys(iss)) { + if (k2 === "inst" || k2 === "schema" || k2 === "continue" || k2 === "input" || k2 === "__proto__") + continue; + full[k2] = iss[k2]; + } + full.path ?? (full.path = []); + full.message = message; if (ctx?.reportInput) { - rest.input = _input; + full.input = iss.input; } - return rest; + return full; } function getSizableOrigin(input2) { if (input2 instanceof Set) @@ -8257,6 +8257,23 @@ function own(inst, key, value, enumerable = true) { function hide(inst, key, value) { return own(inst, key, value, false); } +// @__NO_SIDE_EFFECTS__ +function derived(computes, table) { + for (const key in computes) { + const compute = computes[key]; + Object.defineProperty(table, key, { + configurable: true, + enumerable: true, + get() { + return own(this, key, compute(this)); + }, + set(value) { + own(this, key, value); + } + }); + } + return table; +} function defineBound(proto, key, fn) { Object.defineProperty(proto, key, { configurable: true, @@ -8384,8 +8401,7 @@ function $constructor(name, initializer3, proto, params) { } finally { _zodDesc.value = void 0; } - } - if (inst._zod.traits.has(name)) { + } else if (inst._zod.traits.has(name)) { return; } inst._zod.traits.add(name); @@ -8476,16 +8492,12 @@ var _messageDesc = { enumerable: true, configurable: true }; -var _zodDesc2 = { value: void 0, enumerable: false }; var _issuesDesc = { value: void 0, enumerable: false }; var _installedToString = /* @__PURE__ */ new WeakSet([Object.prototype, Error.prototype]); var initializer = (inst, def) => { inst.name = "$ZodError"; - _zodDesc2.value = inst._zod; - Object.defineProperty(inst, "_zod", _zodDesc2); _issuesDesc.value = def; Object.defineProperty(inst, "issues", _issuesDesc); - _zodDesc2.value = void 0; _issuesDesc.value = void 0; Object.defineProperty(inst, "message", _messageDesc); const proto = Object.getPrototypeOf(inst); @@ -8519,10 +8531,10 @@ function node(obj, key, make) { } return obj[key]; } -function flattenError(error61, mapper = (issue2) => issue2.message) { +function flattenError(error62, mapper = (issue2) => issue2.message) { const fieldErrors = {}; const formErrors = []; - for (const sub of error61.issues) { + for (const sub of error62.issues) { if (sub.path.length > 0) { node(fieldErrors, sub.path[0], () => []).push(mapper(sub)); } else { @@ -8531,10 +8543,10 @@ function flattenError(error61, mapper = (issue2) => issue2.message) { } return { formErrors, fieldErrors }; } -function formatError(error61, mapper = (issue2) => issue2.message) { +function formatError(error62, mapper = (issue2) => issue2.message) { const fieldErrors = { _errors: [] }; - const processError = (error62, path3 = []) => { - for (const issue2 of error62.issues) { + const processError = (error63, path3 = []) => { + for (const issue2 of error63.issues) { if (issue2.code === "invalid_union" && issue2.errors.length) { issue2.errors.map((issues) => processError({ issues }, [...path3, ...issue2.path])); } else if (issue2.code === "invalid_key") { @@ -8576,14 +8588,14 @@ function formatError(error61, mapper = (issue2) => issue2.message) { } } }; - processError(error61); + processError(error62); return fieldErrors; } -function treeifyError(error61, mapper = (issue2) => issue2.message) { +function treeifyError(error62, mapper = (issue2) => issue2.message) { const result = { errors: [] }; - const processError = (error62, path3 = []) => { + const processError = (error63, path3 = []) => { var _a3; - for (const issue2 of error62.issues) { + for (const issue2 of error63.issues) { if (issue2.code === "invalid_union" && issue2.errors.length) { issue2.errors.map((issues) => processError({ issues }, [...path3, ...issue2.path])); } else if (issue2.code === "invalid_key") { @@ -8625,7 +8637,7 @@ function treeifyError(error61, mapper = (issue2) => issue2.message) { } } }; - processError(error61); + processError(error62); return result; } function toDotPath(_path) { @@ -8646,9 +8658,9 @@ function toDotPath(_path) { } return segs.join(""); } -function prettifyError(error61) { +function prettifyError(error62) { const lines = []; - const issues = [...error61.issues].sort((a, b2) => (a.path ?? []).length - (b2.path ?? []).length); + const issues = [...error62.issues].sort((a, b2) => (a.path ?? []).length - (b2.path ?? []).length); for (const issue2 of issues) { lines.push(`\u2716 ${issue2.message}`); if (issue2.path?.length) @@ -8700,33 +8712,50 @@ var _safeParse = (_Err) => (schema, value, _ctx) => { if (result instanceof Promise) { throw new $ZodAsyncError(); } - return result.issues.length ? { - success: false, - error: new (_Err ?? $ZodError)(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) - } : { success: true, data: result.value }; + return result.issues.length ? failure(_Err, result.issues, ctx) : { success: true, data: result.value }; }; var safeParse = /* @__PURE__ */ _safeParse($ZodRealError); +function failure(Err, issues, ctx) { + let error62; + return { + success: false, + get error() { + if (!error62) { + error62 = new Err(issues.map((iss) => finalizeIssue(iss, ctx, config()))); + issues = void 0; + ctx = void 0; + } + return error62; + }, + set error(e) { + error62 = e; + issues = void 0; + ctx = void 0; + } + }; +} var _safeParseAsync = (_Err) => async (schema, value, _ctx) => { const ctx = _ctx ? { ..._ctx, async: true } : { async: true }; let result = schema._zod.run({ value, issues: [] }, ctx); if (result instanceof Promise) result = await result; - return result.issues.length ? { - success: false, - error: new _Err(result.issues.map((iss) => finalizeIssue(iss, ctx, config()))) - } : { success: true, data: result.value }; + return result.issues.length ? failure(_Err, result.issues, ctx) : { success: true, data: result.value }; }; var safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError); var COMPILE_INVALID = /* @__PURE__ */ Symbol.for("zod.compile.invalid"); var COMPILE_FALLBACK = /* @__PURE__ */ Symbol.for("zod.compile.fallback"); var validate = ((schema, value, _ctx) => { const validator = schema._zod.bag.validator; - if (validator !== void 0 && validator(value) !== COMPILE_INVALID) - return true; + if (validator !== void 0) { + if (validator(value) !== COMPILE_INVALID) + return true; + if (validator.definite === true && _ctx === void 0) + return false; + } return validateFallback(schema, value, _ctx); }); function validateFallback(schema, value, _ctx) { - const ctx = _ctx ? { ..._ctx, async: false } : { async: false }; + const ctx = _ctx ? { ..._ctx, async: false, abortEarly: true } : { async: false, abortEarly: true }; const fallbackRun = schema._zod.bag.fallbackRun; let result; if (fallbackRun) { @@ -8741,7 +8770,7 @@ function validateFallback(schema, value, _ctx) { return result.issues.length === 0; } var validateAsync = async (schema, value, _ctx) => { - const ctx = _ctx ? { ..._ctx, async: true } : { async: true }; + const ctx = _ctx ? { ..._ctx, async: true, abortEarly: true } : { async: true, abortEarly: true }; let result = schema._zod.run({ value, issues: [] }, ctx); if (result instanceof Promise) result = await result; @@ -8803,6 +8832,7 @@ var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync($ZodRealError); // node_modules/zod/v4/core/regexes.js var regexes_exports = {}; __export(regexes_exports, { + anyString: () => anyString, base64: () => base64, base64url: () => base64url, bigint: () => bigint, @@ -8813,6 +8843,7 @@ __export(regexes_exports, { creditCard: () => creditCard, cuid: () => cuid, cuid2: () => cuid2, + currencyCode: () => currencyCode, date: () => date, datetime: () => datetime, domain: () => domain, @@ -8826,6 +8857,7 @@ __export(regexes_exports, { hostname: () => hostname, html5Email: () => html5Email, httpProtocol: () => httpProtocol, + iban: () => iban, idnEmail: () => idnEmail, integer: () => integer, ipv4: () => ipv4, @@ -8885,13 +8917,13 @@ var uuid = (version2) => { var uuid4 = /* @__PURE__ */ uuid(4); var uuid6 = /* @__PURE__ */ uuid(6); var uuid7 = /* @__PURE__ */ uuid(7); -var email = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/; +var email = /^(?:[A-Za-z0-9_'+\-]+\.)*[A-Za-z0-9_'+\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/; var html5Email = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; var rfc5322Email = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; var unicodeEmail = /^[^\s@"]{1,64}@[^\s@]{1,255}$/u; var idnEmail = unicodeEmail; var browserEmail = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; -var _emoji = `^[\\p{Extended_Pictographic}\\p{Emoji_Component}]+$`; +var _emoji = `^(?=[\\s\\S]*[\\p{Extended_Pictographic}\\p{Regional_Indicator}\\u20E3])[\\p{Extended_Pictographic}\\p{Emoji_Component}]+$`; function emoji() { return new RegExp(_emoji, "u"); } @@ -8904,12 +8936,14 @@ var mac = (delimiter) => { var cidrv4 = /^((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])\/([0-9]|[1-2][0-9]|3[0-2])$/; var cidrv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/; var base64 = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/; -var base64url = /^[A-Za-z0-9_-]*$/; +var base64url = /^(?:[A-Za-z0-9_-]{4})*(?:[A-Za-z0-9_-]{2,3})?$/; var hostname = /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/; var domain = /^(?=.{1,253}$)([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}$/; var httpProtocol = /^https?$/; var e164 = /^\+[1-9]\d{6,14}$/; var creditCard = /^\d(?:[ -]?\d){11,18}$/; +var currencyCode = /^(?:AED|AFN|ALL|AMD|AOA|ARS|AUD|AWG|AZN|BAM|BBD|BDT|BHD|BIF|BMD|BND|BOB|BOV|BRL|BSD|BTN|BWP|BYN|BZD|CAD|CDF|CHE|CHF|CHW|CLF|CLP|CNY|COP|COU|CRC|CUP|CVE|CZK|DJF|DKK|DOP|DZD|EGP|ERN|ETB|EUR|FJD|FKP|GBP|GEL|GHS|GIP|GMD|GNF|GTQ|GYD|HKD|HNL|HTG|HUF|IDR|ILS|INR|IQD|IRR|ISK|JMD|JOD|JPY|KES|KGS|KHR|KMF|KPW|KRW|KWD|KYD|KZT|LAK|LBP|LKR|LRD|LSL|LYD|MAD|MDL|MGA|MKD|MMK|MNT|MOP|MRU|MUR|MVR|MWK|MXN|MXV|MYR|MZN|NAD|NGN|NIO|NOK|NPR|NZD|OMR|PAB|PEN|PGK|PHP|PKR|PLN|PYG|QAR|RON|RSD|RUB|RWF|SAR|SBD|SCR|SDG|SEK|SGD|SHP|SLE|SOS|SRD|SSP|STN|SVC|SYP|SZL|THB|TJS|TMT|TND|TOP|TRY|TTD|TWD|TZS|UAH|UGX|USD|USN|UYI|UYU|UYW|UZS|VED|VES|VND|VUV|WST|XAD|XAF|XAG|XAU|XBA|XBB|XBC|XBD|XCD|XCG|XDR|XOF|XPD|XPF|XPT|XSU|XTS|XUA|XXX|YER|ZAR|ZMW|ZWG)$/; +var iban = /^[A-Z]{2}(?!00|01|99)\d{2}[A-Z0-9]{11,30}$/; var dateSource = `(?:(?:\\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])))`; function anchor(source) { return new RegExp(`^${source}$`); @@ -8931,6 +8965,7 @@ function datetime(args) { const timeRegex = args.local ? `${qualified}|${timeSource({ precision: args.precision })}` : qualified; return new RegExp(`^${dateSource}T(?:${timeRegex})$`); } +var anyString = /^[\s\S]{0,}$/; var string = (params) => { const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`; return new RegExp(`^${regex}$`); @@ -8989,16 +9024,6 @@ var numericOriginMap = { var $ZodCheckLessThan = /* @__PURE__ */ $constructor("$ZodCheckLessThan", (inst, def) => { $ZodCheck.init(inst, def); const origin = numericOriginMap[typeof def.value]; - inst._zod.onattach.push((inst2) => { - const bag = inst2._zod.bag; - const curr = (def.inclusive ? bag.maximum : bag.exclusiveMaximum) ?? Number.POSITIVE_INFINITY; - if (def.value < curr) { - if (def.inclusive) - bag.maximum = def.value; - else - bag.exclusiveMaximum = def.value; - } - }); inst._zod.check = (payload) => { if (def.inclusive ? payload.value <= def.value : payload.value < def.value) { return; @@ -9017,16 +9042,6 @@ var $ZodCheckLessThan = /* @__PURE__ */ $constructor("$ZodCheckLessThan", (inst, var $ZodCheckGreaterThan = /* @__PURE__ */ $constructor("$ZodCheckGreaterThan", (inst, def) => { $ZodCheck.init(inst, def); const origin = numericOriginMap[typeof def.value]; - inst._zod.onattach.push((inst2) => { - const bag = inst2._zod.bag; - const curr = (def.inclusive ? bag.minimum : bag.exclusiveMinimum) ?? Number.NEGATIVE_INFINITY; - if (def.value > curr) { - if (def.inclusive) - bag.minimum = def.value; - else - bag.exclusiveMinimum = def.value; - } - }); inst._zod.check = (payload) => { if (def.inclusive ? payload.value >= def.value : payload.value > def.value) { return; @@ -9044,10 +9059,6 @@ var $ZodCheckGreaterThan = /* @__PURE__ */ $constructor("$ZodCheckGreaterThan", }); var $ZodCheckMultipleOf = /* @__PURE__ */ $constructor("$ZodCheckMultipleOf", (inst, def) => { $ZodCheck.init(inst, def); - inst._zod.onattach.push((inst2) => { - var _a3; - (_a3 = inst2._zod.bag).multipleOf ?? (_a3.multipleOf = def.value); - }); inst._zod.check = (payload) => { if (typeof payload.value !== typeof def.value) throw new Error("Cannot mix number and bigint in multiple_of check."); @@ -9073,14 +9084,6 @@ var $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberFormat" const isInt = def.format?.includes("int"); const origin = isInt ? "int" : "number"; const [minimum, maximum] = NUMBER_FORMAT_RANGES[def.format]; - inst._zod.onattach.push((inst2) => { - const bag = inst2._zod.bag; - bag.format = def.format; - bag.minimum = minimum; - bag.maximum = maximum; - if (isInt) - bag.pattern = integer; - }); inst._zod.check = (payload) => { const input2 = payload.value; if (isInt) { @@ -9149,12 +9152,6 @@ var $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberFormat" var $ZodCheckBigIntFormat = /* @__PURE__ */ $constructor("$ZodCheckBigIntFormat", (inst, def) => { $ZodCheck.init(inst, def); const [minimum, maximum] = BIGINT_FORMAT_RANGES[def.format]; - inst._zod.onattach.push((inst2) => { - const bag = inst2._zod.bag; - bag.format = def.format; - bag.minimum = minimum; - bag.maximum = maximum; - }); inst._zod.check = (payload) => { const input2 = payload.value; if (input2 < minimum) { @@ -9185,11 +9182,6 @@ var $ZodCheckMaxSize = /* @__PURE__ */ $constructor("$ZodCheckMaxSize", (inst, d var _a3; $ZodCheck.init(inst, def); (_a3 = inst._zod.def).when ?? (_a3.when = _whenHasSize); - inst._zod.onattach.push((inst2) => { - const curr = inst2._zod.bag.maximum ?? Number.POSITIVE_INFINITY; - if (def.maximum < curr) - inst2._zod.bag.maximum = def.maximum; - }); inst._zod.check = (payload) => { const input2 = payload.value; const size = input2.size; @@ -9210,11 +9202,6 @@ var $ZodCheckMinSize = /* @__PURE__ */ $constructor("$ZodCheckMinSize", (inst, d var _a3; $ZodCheck.init(inst, def); (_a3 = inst._zod.def).when ?? (_a3.when = _whenHasSize); - inst._zod.onattach.push((inst2) => { - const curr = inst2._zod.bag.minimum ?? Number.NEGATIVE_INFINITY; - if (def.minimum > curr) - inst2._zod.bag.minimum = def.minimum; - }); inst._zod.check = (payload) => { const input2 = payload.value; const size = input2.size; @@ -9235,12 +9222,6 @@ var $ZodCheckSizeEquals = /* @__PURE__ */ $constructor("$ZodCheckSizeEquals", (i var _a3; $ZodCheck.init(inst, def); (_a3 = inst._zod.def).when ?? (_a3.when = _whenHasSize); - inst._zod.onattach.push((inst2) => { - const bag = inst2._zod.bag; - bag.minimum = def.size; - bag.maximum = def.size; - bag.size = def.size; - }); inst._zod.check = (payload) => { const input2 = payload.value; const size = input2.size; @@ -9262,11 +9243,6 @@ var $ZodCheckMaxLength = /* @__PURE__ */ $constructor("$ZodCheckMaxLength", (ins var _a3; $ZodCheck.init(inst, def); (_a3 = inst._zod.def).when ?? (_a3.when = _whenHasLength); - inst._zod.onattach.push((inst2) => { - const curr = inst2._zod.bag.maximum ?? Number.POSITIVE_INFINITY; - if (def.maximum < curr) - inst2._zod.bag.maximum = def.maximum; - }); inst._zod.check = (payload) => { const input2 = payload.value; const units = input2.length; @@ -9289,11 +9265,6 @@ var $ZodCheckMinLength = /* @__PURE__ */ $constructor("$ZodCheckMinLength", (ins var _a3; $ZodCheck.init(inst, def); (_a3 = inst._zod.def).when ?? (_a3.when = _whenHasLength); - inst._zod.onattach.push((inst2) => { - const curr = inst2._zod.bag.minimum ?? Number.NEGATIVE_INFINITY; - if (def.minimum > curr) - inst2._zod.bag.minimum = def.minimum; - }); inst._zod.check = (payload) => { const input2 = payload.value; const units = input2.length; @@ -9316,12 +9287,6 @@ var $ZodCheckLengthEquals = /* @__PURE__ */ $constructor("$ZodCheckLengthEquals" var _a3; $ZodCheck.init(inst, def); (_a3 = inst._zod.def).when ?? (_a3.when = _whenHasLength); - inst._zod.onattach.push((inst2) => { - const bag = inst2._zod.bag; - bag.minimum = def.length; - bag.maximum = def.length; - bag.length = def.length; - }); inst._zod.check = (payload) => { const input2 = payload.value; const units = input2.length; @@ -9344,14 +9309,6 @@ var $ZodCheckLengthEquals = /* @__PURE__ */ $constructor("$ZodCheckLengthEquals" var $ZodCheckStringFormat = /* @__PURE__ */ $constructor("$ZodCheckStringFormat", (inst, def) => { var _a3, _b; $ZodCheck.init(inst, def); - inst._zod.onattach.push((inst2) => { - const bag = inst2._zod.bag; - bag.format = def.format; - if (def.pattern) { - bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); - bag.patterns.add(def.pattern); - } - }); if (def.pattern) (_a3 = inst._zod).check ?? (_a3.check = (payload) => { def.pattern.lastIndex = 0; @@ -9401,11 +9358,6 @@ var $ZodCheckIncludes = /* @__PURE__ */ $constructor("$ZodCheckIncludes", (inst, const escapedRegex = escapeRegex(def.includes); const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position},}${escapedRegex}` : escapedRegex); def.pattern = pattern; - inst._zod.onattach.push((inst2) => { - const bag = inst2._zod.bag; - bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); - bag.patterns.add(pattern); - }); inst._zod.check = (payload) => { if (payload.value.includes(def.includes, def.position)) return; @@ -9424,11 +9376,6 @@ var $ZodCheckStartsWith = /* @__PURE__ */ $constructor("$ZodCheckStartsWith", (i $ZodCheck.init(inst, def); const pattern = new RegExp(`^${escapeRegex(def.prefix)}.*`); def.pattern ?? (def.pattern = pattern); - inst._zod.onattach.push((inst2) => { - const bag = inst2._zod.bag; - bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); - bag.patterns.add(pattern); - }); inst._zod.check = (payload) => { if (payload.value.startsWith(def.prefix)) return; @@ -9447,11 +9394,6 @@ var $ZodCheckEndsWith = /* @__PURE__ */ $constructor("$ZodCheckEndsWith", (inst, $ZodCheck.init(inst, def); const pattern = new RegExp(`.*${escapeRegex(def.suffix)}$`); def.pattern ?? (def.pattern = pattern); - inst._zod.onattach.push((inst2) => { - const bag = inst2._zod.bag; - bag.patterns ?? (bag.patterns = /* @__PURE__ */ new Set()); - bag.patterns.add(pattern); - }); inst._zod.check = (payload) => { if (payload.value.endsWith(def.suffix)) return; @@ -9485,12 +9427,37 @@ var $ZodCheckProperty = /* @__PURE__ */ $constructor("$ZodCheckProperty", (inst, return; }; }); +var $ZodCheckProperties = /* @__PURE__ */ $constructor("$ZodCheckProperties", (inst, def) => { + $ZodCheck.init(inst, def); + hide(inst, Symbol.iterator, function* () { + yield inst; + }); + let entries; + inst._zod.check = (payload) => { + if (payload.value == null) { + payload.issues.push({ expected: "object", code: "invalid_type", input: payload.value, inst }); + return void 0; + } + entries ?? (entries = Reflect.ownKeys(def.shape).map((key) => [key, def.shape[key]])); + const input2 = payload.value; + let proms; + for (const [key, schema] of entries) { + const result = schema._zod.run({ value: input2[key], issues: [] }, {}); + if (result instanceof Promise) { + proms ?? (proms = []); + proms.push(result.then((result2) => handleCheckPropertyResult(result2, payload, key))); + } else { + handleCheckPropertyResult(result, payload, key); + } + } + if (proms) + return Promise.all(proms).then(() => void 0); + return void 0; + }; +}); var $ZodCheckMimeType = /* @__PURE__ */ $constructor("$ZodCheckMimeType", (inst, def) => { $ZodCheck.init(inst, def); const mimeSet = new Set(def.mime); - inst._zod.onattach.push((inst2) => { - inst2._zod.bag.mime = def.mime; - }); inst._zod.check = (payload) => { if (mimeSet.has(payload.value.type)) return; @@ -9518,10 +9485,14 @@ var Doc = class { this.args = args; this.closed = closed; } + // the compiler catches a child's throw and keeps writing into this doc, so the indent has to unwind with it indented(fn) { this.indent += 1; - fn(this); - this.indent -= 1; + try { + fn(this); + } finally { + this.indent -= 1; + } } write(arg) { if (typeof arg === "function") { @@ -9550,8 +9521,8 @@ ${content.join("\n")} // node_modules/zod/v4/core/versions.js var version = { major: 4, - minor: 5, - patch: 4 + minor: 6, + patch: 5 }; // node_modules/zod/v4/core/schemas.js @@ -9664,15 +9635,22 @@ var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => { own(this, "~standard", value); } }); -var toStandardResult = (r) => r.success ? { value: r.data } : { issues: r.error?.issues }; +var toStandardResult = (r, ctx) => r.issues.length ? { issues: r.issues.map((iss) => finalizeIssue(iss, ctx, config())) } : { value: r.value }; +async function validateAsync2(inst, value) { + const ctx = { async: true }; + return toStandardResult(await inst._zod.run({ value, issues: [] }, ctx), ctx); +} function standardProps(inst) { return { validate: (value) => { + const ctx = { async: false }; try { - return toStandardResult(safeParse(inst, value)); + const r = inst._zod.run({ value, issues: [] }, ctx); + if (!(r instanceof Promise)) + return toStandardResult(r, ctx); } catch (_2) { - return safeParseAsync(inst, value).then(toStandardResult); } + return validateAsync2(inst, value); }, vendor: "zod", version: 1 @@ -9680,7 +9658,7 @@ function standardProps(inst) { } var $ZodString = /* @__PURE__ */ $constructor("$ZodString", (inst, def) => { $ZodType.init(inst, def); - inst._zod.pattern = [...inst?._zod.bag?.patterns ?? []].pop() ?? string(inst._zod.bag); + inst._zod.pattern = def.pattern ?? anyString; inst._zod.parse = (payload, _2) => { if (def.coerce) try { @@ -9732,11 +9710,32 @@ var $ZodEmail = /* @__PURE__ */ $constructor("$ZodEmail", (inst, def) => { }); var URL_BAD_FORMAT = 1; var URL_UNPARSEABLE = 2; +function canParseURL(input2) { + try { + if (typeof URL !== "undefined" && typeof URL.canParse === "function") + return URL.canParse(input2); + new URL(input2); + return true; + } catch { + return false; + } +} +function validateURL(trimmed, def) { + if (!("normalize" in def) && !("hostname" in def) && !("protocol" in def)) { + return canParseURL(trimmed) || URL_UNPARSEABLE; + } + return parseURLObject(trimmed, def); +} function parseURLObject(trimmed, def) { if (!def.normalize && def.protocol?.source === httpProtocol.source && !/^https?:\/\//i.test(trimmed)) { return URL_BAD_FORMAT; } try { + if (typeof URL !== "undefined") { + const URLStatic = URL; + if (typeof URLStatic.parse === "function") + return URLStatic.parse(trimmed) ?? URL_UNPARSEABLE; + } return new URL(trimmed); } catch { return URL_UNPARSEABLE; @@ -9759,7 +9758,7 @@ var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => { inst._zod.check = (payload) => { try { const trimmed = payload.value.trim(); - const url2 = parseURLObject(trimmed, def); + const url2 = validateURL(trimmed, def); if (url2 === URL_BAD_FORMAT) { payload.issues.push({ code: "invalid_format", @@ -9781,6 +9780,10 @@ var $ZodURL = /* @__PURE__ */ $constructor("$ZodURL", (inst, def) => { }); return; } + if (url2 === true) { + payload.value = stripTabAndNewline(trimmed); + return; + } if (def.hostname && !urlHostnameOk(url2, def.hostname)) { payload.issues.push({ code: "invalid_format", @@ -9849,12 +9852,6 @@ var $ZodKSUID = /* @__PURE__ */ $constructor("$ZodKSUID", (inst, def) => { var $ZodISODateTime = /* @__PURE__ */ $constructor("$ZodISODateTime", (inst, def) => { def.pattern ?? (def.pattern = datetime(def)); $ZodStringFormat.init(inst, def); - if (def.local || def.precision === -1) { - inst._zod.bag.laxFormat = true; - inst._zod.onattach.push((s) => { - s._zod.bag.laxFormat = true; - }); - } }); var $ZodISODate = /* @__PURE__ */ $constructor("$ZodISODate", (inst, def) => { def.pattern ?? (def.pattern = date); @@ -9871,23 +9868,16 @@ var $ZodISODuration = /* @__PURE__ */ $constructor("$ZodISODuration", (inst, def var $ZodIPv4 = /* @__PURE__ */ $constructor("$ZodIPv4", (inst, def) => { def.pattern ?? (def.pattern = ipv4); $ZodStringFormat.init(inst, def); - inst._zod.bag.format = `ipv4`; }); var ipv6Alphabet = /^[0-9a-fA-F:.]+$/; function isValidIPv6(value) { if (!ipv6Alphabet.test(value)) return false; - try { - new URL(`http://[${value}]`); - return true; - } catch { - return false; - } + return canParseURL(`http://[${value}]`); } var $ZodIPv6 = /* @__PURE__ */ $constructor("$ZodIPv6", (inst, def) => { def.pattern ?? (def.pattern = ipv6); $ZodStringFormat.init(inst, def); - inst._zod.bag.format = `ipv6`; inst._zod.check = (payload) => { if (!isValidIPv6(payload.value)) { payload.issues.push({ @@ -9903,7 +9893,6 @@ var $ZodIPv6 = /* @__PURE__ */ $constructor("$ZodIPv6", (inst, def) => { var $ZodMAC = /* @__PURE__ */ $constructor("$ZodMAC", (inst, def) => { def.pattern ?? (def.pattern = mac(def.delimiter)); $ZodStringFormat.init(inst, def); - inst._zod.bag.format = `mac`; }); var $ZodCIDRv4 = /* @__PURE__ */ $constructor("$ZodCIDRv4", (inst, def) => { def.pattern ?? (def.pattern = cidrv4); @@ -9952,10 +9941,10 @@ function isValidBase64(data) { return false; } } +var base64Charset = /^[0-9a-zA-Z+/]*={0,2}$/; var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => { - def.pattern ?? (def.pattern = base64); + def.pattern ?? (def.pattern = base64Charset); $ZodStringFormat.init(inst, def); - inst._zod.bag.contentEncoding = "base64"; inst._zod.check = (payload) => { if (isValidBase64(payload.value)) return; @@ -9968,17 +9957,17 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => { }); }; }); +var base64urlCharset = /^[A-Za-z0-9_-]*$/; function isValidBase64URL(data) { - if (!base64url.test(data)) + if (!base64urlCharset.test(data)) return false; const base643 = data.replace(/[-_]/g, (c) => c === "-" ? "+" : "/"); const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "="); return isValidBase64(padded); } var $ZodBase64URL = /* @__PURE__ */ $constructor("$ZodBase64URL", (inst, def) => { - def.pattern ?? (def.pattern = base64url); + def.pattern ?? (def.pattern = base64urlCharset); $ZodStringFormat.init(inst, def); - inst._zod.bag.contentEncoding = "base64url"; inst._zod.check = (payload) => { if (isValidBase64URL(payload.value)) return; @@ -10001,7 +9990,7 @@ function isLuhnAlgo(digits) { let bit = 1; let sum = 0; while (length) { - const value = +digits[--length]; + const value = digits.charCodeAt(--length) - 48; bit ^= 1; sum += bit ? [0, 2, 4, 6, 8, 1, 3, 5, 7, 9][value] : value; } @@ -10027,6 +10016,39 @@ var $ZodCreditCard = /* @__PURE__ */ $constructor("$ZodCreditCard", (inst, def) }); }; }); +function isIso7064Mod97(iban3) { + let remainder = 0; + const len = iban3.length; + for (let i = 4; i < len; i++) { + const code = iban3.charCodeAt(i); + remainder = (code >= 65 ? remainder * 100 + (code - 55) : remainder * 10 + (code - 48)) % 97; + } + for (let i = 0; i < 4; i++) { + const code = iban3.charCodeAt(i); + remainder = (code >= 65 ? remainder * 100 + (code - 55) : remainder * 10 + (code - 48)) % 97; + } + return remainder === 1; +} +function isValidIBAN(input2) { + if (!iban.test(input2)) + return false; + return isIso7064Mod97(input2); +} +var $ZodIBAN = /* @__PURE__ */ $constructor("$ZodIBAN", (inst, def) => { + def.pattern ?? (def.pattern = iban); + $ZodStringFormat.init(inst, def); + inst._zod.check = (payload) => { + if (isValidIBAN(payload.value)) + return; + payload.issues.push({ + code: "invalid_format", + format: "iban", + input: payload.value, + inst, + continue: !def.abort + }); + }; +}); function isValidJWT(token, algorithm = null) { try { const tokensParts = token.split("."); @@ -10077,7 +10099,7 @@ var $ZodCustomStringFormat = /* @__PURE__ */ $constructor("$ZodCustomStringForma }); var $ZodNumber = /* @__PURE__ */ $constructor("$ZodNumber", (inst, def) => { $ZodType.init(inst, def); - inst._zod.pattern = inst._zod.bag.pattern ?? number; + inst._zod.pattern = number; inst._zod.parse = (payload, _ctx) => { if (def.coerce) try { @@ -10279,6 +10301,7 @@ var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => { } payload.value = memo2 ? memo2.alloc(inst, payload, Array(input2.length), ctx) : Array(input2.length); const proms = []; + const abortEarly = ctx?.abortEarly; for (let i = 0; i < input2.length; i++) { const item = input2[i]; const result = def.element._zod.run({ @@ -10289,6 +10312,8 @@ var $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => { proms.push(result.then((result2) => handleArrayResult(result2, payload, i))); } else { handleArrayResult(result, payload, i); + if (abortEarly && result.issues.length !== 0 && aborted(result)) + break; } } if (proms.length) { @@ -10321,7 +10346,7 @@ function handlePropertyResult(result, final, key, input2, optin, optout) { return; } if (result.value === void 0) { - if (isPresent) { + if (isPresent || optin === "defaulted" && !isOptionalOut) { final.value[key] = void 0; } } else { @@ -10350,14 +10375,20 @@ function normalizeDef(def) { optionalKeys: new Set(okeys) }; } -function handleCatchall(proms, input2, payload, ctx, def, inst) { +function handleCatchall(proms, input2, payload, ctx, def, inst, abortEarly) { const unrecognized = []; const keySet = def.keySet; const _catchall = def.catchall._zod; const t = _catchall.def.type; const optin = _catchall.optin; const optout = _catchall.optout; + let seen = 0; for (const key in input2) { + if (abortEarly && payload.issues.length !== seen) { + if (aborted(payload, seen)) + break; + seen = payload.issues.length; + } if (keySet.has(key)) continue; if (key === "__proto__") { @@ -10392,23 +10423,19 @@ function handleCatchall(proms, input2, payload, ctx, def, inst) { return payload; }); } -var propShapes = /* @__PURE__ */ new WeakMap(); var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => { $ZodType.init(inst, def); const desc = Object.getOwnPropertyDescriptor(def, "shape"); - if (!desc?.get) { - const sh = def.shape; - propShapes.set(def, sh); - Object.defineProperty(def, "shape", { - get: () => { - const newSh = { ...sh }; - Object.defineProperty(def, "shape", { - value: newSh - }); - propShapes.set(def, newSh); - return newSh; - } - }); + const sh = desc?.get ? desc.get.raw : def.shape ?? {}; + if (sh) { + const get = () => { + const newSh = { ...sh }; + Object.defineProperty(def, "shape", { value: newSh }); + get.raw = newSh; + return newSh; + }; + get.raw = sh; + Object.defineProperty(def, "shape", { get }); } const _normalized = cached(() => normalizeDef(def)); defineLazyInternal(inst, "propValues", (zod) => { @@ -10448,7 +10475,14 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => { payload.value = memo2 ? memo2.alloc(inst, payload, {}, ctx) : {}; const proms = []; const shape = value.shape; + const abortEarly = ctx?.abortEarly; + let seen = payload.issues.length; for (const key of value.allKeys) { + if (abortEarly && payload.issues.length !== seen) { + if (aborted(payload, seen)) + break; + seen = payload.issues.length; + } if (key === "__proto__") continue; const el = shape[key]; @@ -10464,7 +10498,7 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => { if (!catchall) { return proms.length ? Promise.all(proms).then(() => payload) : payload; } - return handleCatchall(proms, input2, payload, ctx, _normalized.value, inst); + return handleCatchall(proms, input2, payload, ctx, _normalized.value, inst, abortEarly === true); }; }); var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) => { @@ -10478,10 +10512,16 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) => const doc = new Doc(["payload", "ctx"], { shape, inst, memo: memo2, syms }); const parseStr = (k2) => `shape[${k2}]._zod.run({ value: input[${k2}], issues: [] }, ctx)`; const prefixStr = (id, k2) => ` + let ${id}_ab = false; for (let i = 0; i < ${id}.issues.length; i++) { const iss = ${id}.issues[i]; iss.path = iss.path ? [${k2}, ...iss.path] : [${k2}]; payload.issues.push(iss); + if (iss.continue !== true) ${id}_ab = true; + } + if (${id}_ab && ctx && ctx.abortEarly) { + payload.value = newResult; + return payload; }`; doc.write(`const input = payload.value;`); const ids = /* @__PURE__ */ Object.create(null); @@ -10527,6 +10567,10 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) => input: undefined, path: [${k2}] }); + if (ctx && ctx.abortEarly) { + payload.value = newResult; + return payload; + } } if (${id}_present) { @@ -10538,16 +10582,16 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) => doc.write(` if (${id}.issues.length) {${prefixStr(id, k2)} } - - if (${id}.value === undefined) { - if (${isPresent}) { - newResult[${k2}] = undefined; - } + `); + if (optin === "defaulted") { + doc.write(`newResult[${k2}] = ${id}.value;`); } else { + doc.write(` + if (${id}.value !== undefined || ${isPresent}) { newResult[${k2}] = ${id}.value; } - `); + } } } doc.write(`payload.value = newResult;`); @@ -10579,7 +10623,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) => payload = fastpass(payload, ctx); if (!catchall) return payload; - return handleCatchall([], input2, payload, ctx, value, inst); + return handleCatchall([], input2, payload, ctx, value, inst, ctx?.abortEarly === true); } return superParse(payload, ctx); }; @@ -10711,16 +10755,31 @@ function getDiscriminatedOption(union2, value) { const internals = union2._zod; let map2 = internals.bag.optionsMap; if (!map2) { - map2 = /* @__PURE__ */ new Map(); - const { options, discriminator } = internals.def; - for (const option of options) { - for (const v2 of option._zod.propValues?.[discriminator] ?? []) - if (!map2.has(v2)) - map2.set(v2, option); - } + map2 = discriminatorMap(internals.def); internals.bag.optionsMap = map2; } - return map2.get(value); + const option = map2.get(value); + if (option === null) + throw new Error(`Ambiguous discriminator value "${String(value)}"`); + return option; +} +function discriminatorMap(def) { + const map2 = /* @__PURE__ */ new Map(); + for (const option of def.options) { + const values = option._zod.propValues?.[def.discriminator]; + if (!values || values.size === 0) + throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(option)}"`); + for (const value of values) { + if (map2.has(value)) { + if (value !== void 0) + throw new Error(`Duplicate discriminator value "${String(value)}"`); + map2.set(value, null); + } else { + map2.set(value, option); + } + } + } + return map2; } var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnion", (inst, def) => { def.inclusive = false; @@ -10728,10 +10787,13 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio const _super = inst._zod.parse; defineLazyInternal(inst, "propValues", (zod) => { const propValues = {}; + let undefinedCount = 0; for (const option of zod.def.options) { const pv = option._zod.propValues; if (!pv || Object.keys(pv).length === 0) throw new Error(`Invalid discriminated union option at index "${zod.def.options.indexOf(option)}"`); + if (pv[zod.def.discriminator]?.has(void 0)) + undefinedCount++; for (const [k2, v2] of Object.entries(pv)) { if (!Object.prototype.hasOwnProperty.call(propValues, k2)) { assignProp(propValues, k2, /* @__PURE__ */ new Set()); @@ -10741,30 +10803,17 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio } } } + if (!zod.def.unionFallback && undefinedCount > 1) + propValues[zod.def.discriminator]?.delete(void 0); return propValues; }); def.options.forEach((option, i) => { - const propShape = propShapes.get(option._zod.def); + const propShape = rawShape(option._zod.def); if (propShape && !Object.prototype.hasOwnProperty.call(propShape, def.discriminator)) { throw new Error(`Invalid discriminated union option at index "${i}"`); } }); - const disc = cached(() => { - const opts = def.options; - const map2 = /* @__PURE__ */ new Map(); - for (const o of opts) { - const values = o._zod.propValues?.[def.discriminator]; - if (!values || values.size === 0) - throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(o)}"`); - for (const v2 of values) { - if (map2.has(v2)) { - throw new Error(`Duplicate discriminator value "${String(v2)}"`); - } - map2.set(v2, o); - } - } - return map2; - }); + const disc = cached(() => discriminatorMap(def)); inst._zod.parse = (payload, ctx) => { const input2 = payload.value; if (!isObject(input2)) { @@ -10776,8 +10825,9 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio }); return payload; } - const opt = disc.value.get(input2?.[def.discriminator]); - if (opt) { + const value = input2?.[def.discriminator]; + const opt = disc.value.get(value); + if (opt && (value !== void 0 || ctx.direction !== "backward")) { return opt._zod.run(payload, ctx); } if (def.unionFallback || ctx.direction === "backward") { @@ -10788,7 +10838,7 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio errors: [], note: "No matching discriminator", discriminator: def.discriminator, - options: Array.from(disc.value.keys()), + options: Array.from(disc.value.keys()).filter((value2) => disc.value.get(value2) !== null), input: input2, path: [def.discriminator], inst @@ -10954,6 +11004,8 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => { } } const itemResults = new Array(items.length); + const abortEarly = def.rest ? ctx?.abortEarly : void 0; + let itemAborted = false; for (let i = 0; i < items.length; i++) { const r = items[i]._zod.run({ value: input2[i], issues: [] }, ctx); if (r instanceof Promise) { @@ -10962,12 +11014,20 @@ var $ZodTuple = /* @__PURE__ */ $constructor("$ZodTuple", (inst, def) => { })); } else { itemResults[i] = r; + if (abortEarly && !itemAborted && r.issues.length) + itemAborted = aborted(r); } } - if (def.rest) { + if (def.rest && !itemAborted) { let i = items.length - 1; const rest = input2.slice(items.length); + let seen = payload.issues.length; for (const el of rest) { + if (abortEarly && payload.issues.length !== seen) { + if (aborted(payload, seen)) + break; + seen = payload.issues.length; + } i++; const result = def.rest._zod.run({ value: el, issues: [] }, ctx); if (result instanceof Promise) { @@ -11195,7 +11255,14 @@ var $ZodMap = /* @__PURE__ */ $constructor("$ZodMap", (inst, def) => { } const proms = []; payload.value = memo2 ? memo2.alloc(inst, payload, /* @__PURE__ */ new Map(), ctx) : /* @__PURE__ */ new Map(); + const abortEarly = ctx?.abortEarly; + let seen = payload.issues.length; for (const [key, value] of input2) { + if (abortEarly && payload.issues.length !== seen) { + if (aborted(payload, seen)) + break; + seen = payload.issues.length; + } const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx); const valueResult = def.valueType._zod.run({ value, issues: [] }, ctx); if (keyResult instanceof Promise || valueResult instanceof Promise) { @@ -11258,7 +11325,14 @@ var $ZodSet = /* @__PURE__ */ $constructor("$ZodSet", (inst, def) => { } const proms = []; payload.value = memo2 ? memo2.alloc(inst, payload, /* @__PURE__ */ new Set(), ctx) : /* @__PURE__ */ new Set(); + const abortEarly = ctx?.abortEarly; + let seen = payload.issues.length; for (const item of input2) { + if (abortEarly && payload.issues.length !== seen) { + if (aborted(payload, seen)) + break; + seen = payload.issues.length; + } const result = def.valueType._zod.run({ value: item, issues: [] }, ctx); if (result instanceof Promise) { proms.push(result.then((result2) => handleSetResult(result2, payload))); @@ -11281,8 +11355,10 @@ var $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => { const values = getEnumValues(def.entries); const valuesSet = new Set(values); inst._zod.values = valuesSet; - const patternValues = values.filter((k2) => propertyKeyTypes.has(typeof k2)); - inst._zod.pattern = new RegExp(patternValues.length ? `^(${patternValues.map((o) => escapeRegex(o.toString())).join("|")})$` : "^[^\\s\\S]$"); + defineLazyInternal(inst, "pattern", (zod) => { + const patternValues = getEnumValues(zod.def.entries).filter((k2) => propertyKeyTypes.has(typeof k2)); + return new RegExp(patternValues.length ? `^(${patternValues.map((o) => escapeRegex(o.toString())).join("|")})$` : "^[^\\s\\S]$"); + }); inst._zod.parse = (payload, _ctx) => { const input2 = payload.value; if (valuesSet.has(input2)) { @@ -11301,7 +11377,10 @@ var $ZodLiteral = /* @__PURE__ */ $constructor("$ZodLiteral", (inst, def) => { $ZodType.init(inst, def); const values = new Set(def.values); inst._zod.values = values; - inst._zod.pattern = new RegExp(def.values.length ? `^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$` : "^[^\\s\\S]$"); + defineLazyInternal(inst, "pattern", (zod) => { + const vals = zod.def.values; + return new RegExp(vals.length ? `^(${vals.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$` : "^[^\\s\\S]$"); + }); inst._zod.parse = (payload, _ctx) => { const input2 = payload.value; if (values.has(input2)) { @@ -11639,20 +11718,62 @@ function handleReadonlyResult(payload) { payload.value = Object.freeze(payload.value); return payload; } +function leafPattern(schema) { + const def = schema._zod.def; + let pattern = def.pattern; + let isInt = !!def.format?.includes("int"); + let minimum; + let maximum; + for (const ch of def.checks ?? []) { + const d2 = ch._zod.def; + if (d2.pattern) + pattern = d2.pattern; + isInt || (isInt = !!d2.format?.includes("int")); + const lo = d2.minimum ?? d2.length; + const hi = d2.maximum ?? d2.length; + if (lo !== void 0 && (minimum === void 0 || lo > minimum)) + minimum = lo; + if (hi !== void 0 && (maximum === void 0 || hi < maximum)) + maximum = hi; + } + if (pattern) + return pattern.source; + if (minimum !== void 0 && maximum !== void 0 && minimum > maximum) + return "(?!)"; + if (minimum !== void 0 || maximum !== void 0) + return string({ minimum, maximum }).source; + const own2 = schema._zod.pattern; + return (isInt && own2 === number ? integer : own2)?.source; +} +function partPattern(schema) { + const def = schema._zod.def; + const own2 = schema._zod.pattern?.source; + const inner = def.innerType ?? schema._zod.innerType; + if (inner) { + const before = inner._zod.pattern?.source; + const after = partPattern(inner); + if (own2 && before && after && after !== before) { + return own2.replace(cleanRegex(before), () => cleanRegex(after)); + } + return own2; + } + if (def.options) { + const sources = def.options.map(partPattern); + if (sources.every(Boolean)) + return `^(${sources.map((s) => cleanRegex(s)).join("|")})$`; + } + return leafPattern(schema); +} var $ZodTemplateLiteral = /* @__PURE__ */ $constructor("$ZodTemplateLiteral", (inst, def) => { $ZodType.init(inst, def); const regexParts = []; for (const part of def.parts) { if (typeof part === "object" && part !== null) { - if (!part._zod.pattern) { + const source = partPattern(part); + if (!source) { throw new Error(`Invalid template literal part, no pattern found: ${[...part._zod.traits].shift()}`); } - const source = part._zod.pattern instanceof RegExp ? part._zod.pattern.source : part._zod.pattern; - if (!source) - throw new Error(`Invalid template literal part: ${part._zod.traits}`); - const start = source.startsWith("^") ? 1 : 0; - const end = source.endsWith("$") ? source.length - 1 : source.length; - regexParts.push(source.slice(start, end)); + regexParts.push(cleanRegex(source)); } else if (part === null || primitiveTypes.has(typeof part)) { regexParts.push(escapeRegex(`${part}`)); } else { @@ -11827,28 +11948,53 @@ var $ZodCyclicError = class extends Error { }; var STATE = "~memo"; var NO_ISSUES = []; +function isRef(value) { + return value !== null && typeof value === "object"; +} function cloneIssues(issues) { return issues.map((iss) => iss.path ? { ...iss, path: iss.path.slice() } : { ...iss }); } var recursive = /* @__PURE__ */ new WeakMap(); -function isRecursive(inst, stack) { +var NONE = 0; +var ASSUMED = 1; +var PROVEN = 2; +function isRecursive(inst, stack, resolve) { const cached2 = recursive.get(inst); if (cached2 !== void 0) - return cached2; + return cached2 ? PROVEN : NONE; if (stack.has(inst)) - return true; + return PROVEN; stack.add(inst); - let result = false; + let result = NONE; const check2 = (child) => { - if (!result && child?._zod && isRecursive(child, stack)) - result = true; + if (result !== PROVEN && child?._zod) { + const answer = isRecursive(child, stack, resolve); + if (answer > result) + result = answer; + } + }; + const shape = (sh, spread) => { + let answer = NONE; + for (const key of Reflect.ownKeys(sh)) { + const desc = Object.getOwnPropertyDescriptor(sh, key); + if (spread && !desc.enumerable) + continue; + const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve) : NONE; + if (child > answer) + answer = child; + } + return answer; + }; + const merge2 = (answer) => { + if (answer > result) + result = answer; }; const def = inst._zod.def; const kind = def.type; switch (kind) { case "object": { - for (const key of Reflect.ownKeys(def.shape)) - check2(def.shape[key]); + const raw = rawShape(def); + merge2(raw ? shape(raw, true) : ASSUMED); check2(def.catchall); break; } @@ -11895,10 +12041,12 @@ function isRecursive(inst, stack) { check2(def.input); check2(def.output); break; - // reading `_zod.innerType` resolves the getter once and caches it - case "lazy": - check2(inst._zod.innerType); + // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly + case "lazy": { + const inner = def._cachedInner ?? (resolve ? inst._zod.innerType : void 0); + merge2(inner ? isRecursive(inner, stack, false) : ASSUMED); break; + } // a leaf by choice: `parts` are regex fragments, not data positions case "template_literal": // leaves @@ -11940,16 +12088,20 @@ function isRecursive(inst, stack) { } } stack.delete(inst); - recursive.set(inst, result); - return result; + return settle(inst, result); +} +function settle(inst, answer) { + if (answer !== ASSUMED) + recursive.set(inst, answer === PROVEN); + return answer; } function isRecursiveSchema(inst) { - return isRecursive(inst, /* @__PURE__ */ new Set()); + return isRecursive(inst, /* @__PURE__ */ new Set(), true) !== NONE; } function bucketFor(state, inst) { let bucket = state.buckets.get(inst); if (!bucket) { - bucket = /* @__PURE__ */ new Map(); + bucket = /* @__PURE__ */ new WeakMap(); state.buckets.set(inst, bucket); } return bucket; @@ -11985,6 +12137,7 @@ var memo = { attach(inst) { var _a3; let isRecursiveInst; + let rechecked = false; let lastCtx; let lastBucket; (_a3 = inst._zod).deferred ?? (_a3.deferred = []); @@ -11992,20 +12145,24 @@ var memo = { const base = inst._zod.parse; const wrapped = (payload, ctx) => { if (isRecursiveInst === void 0) { - isRecursiveInst = isRecursive(inst, /* @__PURE__ */ new Set()); - if (!isRecursiveInst) { + const walked = isRecursive(inst, /* @__PURE__ */ new Set(), false); + if (walked === NONE) { inst._zod.parse = base; if (inst._zod.run === wrapped) inst._zod.run = base; return base(payload, ctx); } + if (walked === PROVEN || rechecked) + isRecursiveInst = true; + else + rechecked = true; } const input2 = payload.value; - if (input2 === null || typeof input2 !== "object") + if (!isRef(input2)) return base(payload, ctx); let state = ctx[STATE]; if (!state) { - state = { buckets: /* @__PURE__ */ new Map(), backEdges: void 0 }; + state = { buckets: /* @__PURE__ */ new WeakMap(), backEdges: void 0 }; ctx[STATE] = state; } let bucket; @@ -12024,7 +12181,7 @@ var memo = { payload.issues.push(...cloneIssues(hit.issues)); } else { payload.memo = true; - state.backEdges ?? (state.backEdges = /* @__PURE__ */ new Set()); + state.backEdges ?? (state.backEdges = /* @__PURE__ */ new WeakSet()); state.backEdges.add(hit.value); } return payload; @@ -12056,7 +12213,7 @@ function memoizer() { } function isBackEdge(ctx, value) { const backEdges = ctx[STATE]?.backEdges; - return backEdges !== void 0 && value !== null && typeof value === "object" && backEdges.has(value); + return backEdges !== void 0 && isRef(value) && backEdges.has(value); } // node_modules/zod/v4/locales/index.js @@ -12113,6 +12270,7 @@ __export(locales_exports, { sl: () => sl_default, sv: () => sv_default, ta: () => ta_default, + tg: () => tg_default, th: () => th_default, tk: () => tk_default, tr: () => tr_default, @@ -12167,6 +12325,8 @@ var error = () => { json_string: "\u0646\u064E\u0635 \u0639\u0644\u0649 \u0647\u064A\u0626\u0629 JSON", e164: "\u0631\u0642\u0645 \u0647\u0627\u062A\u0641 \u0628\u0645\u0639\u064A\u0627\u0631 E.164", credit_card: "\u0631\u0642\u0645 \u0628\u0637\u0627\u0642\u0629 \u0627\u0644\u0627\u0626\u062A\u0645\u0627\u0646", + currency_code: "\u0631\u0645\u0632 \u0627\u0644\u0639\u0645\u0644\u0629", + iban: "IBAN", jwt: "JWT", template_literal: "\u0645\u062F\u062E\u0644" }; @@ -12277,6 +12437,8 @@ var error2 = () => { json_string: "JSON string", e164: "E.164 number", credit_card: "kredit kart\u0131 n\xF6mr\u0259si", + currency_code: "valyuta kodu", + iban: "IBAN", jwt: "JWT", template_literal: "input" }; @@ -12436,6 +12598,8 @@ var error3 = () => { json_string: "JSON \u0440\u0430\u0434\u043E\u043A", e164: "\u043D\u0443\u043C\u0430\u0440 E.164", credit_card: "\u043D\u0443\u043C\u0430\u0440 \u043A\u0440\u044D\u0434\u044B\u0442\u043D\u0430\u0439 \u043A\u0430\u0440\u0442\u044B", + currency_code: "\u043A\u043E\u0434 \u0432\u0430\u043B\u044E\u0442\u044B", + iban: "IBAN", jwt: "JWT", template_literal: "\u0443\u0432\u043E\u0434" }; @@ -12553,6 +12717,8 @@ var error4 = () => { json_string: "JSON \u043D\u0438\u0437", e164: "E.164 \u043D\u043E\u043C\u0435\u0440", credit_card: "\u043D\u043E\u043C\u0435\u0440 \u043D\u0430 \u043A\u0440\u0435\u0434\u0438\u0442\u043D\u0430 \u043A\u0430\u0440\u0442\u0430", + currency_code: "\u043A\u043E\u0434 \u043D\u0430 \u0432\u0430\u043B\u0443\u0442\u0430", + iban: "IBAN", jwt: "JWT", template_literal: "\u0432\u0445\u043E\u0434" }; @@ -12677,6 +12843,8 @@ var error5 = () => { json_string: "JSON \u09B8\u09CD\u099F\u09CD\u09B0\u09BF\u0982", e164: "E.164 \u09A8\u09AE\u09CD\u09AC\u09B0", credit_card: "\u0995\u09CD\u09B0\u09C7\u09A1\u09BF\u099F \u0995\u09BE\u09B0\u09CD\u09A1 \u09A8\u09AE\u09CD\u09AC\u09B0", + currency_code: "\u09AE\u09C1\u09A6\u09CD\u09B0\u09BE \u0995\u09CB\u09A1", + iban: "IBAN", jwt: "JWT", template_literal: "\u0987\u09A8\u09AA\u09C1\u099F" }; @@ -12789,6 +12957,8 @@ var error6 = () => { json_string: "cadena JSON", e164: "n\xFAmero E.164", credit_card: "n\xFAmero de targeta de cr\xE8dit", + currency_code: "codi de moneda", + iban: "IBAN", jwt: "JWT", template_literal: "entrada" }; @@ -12901,6 +13071,8 @@ var error7 = () => { json_string: "\u062F\u06D5\u0642\u06CC JSON", e164: "\u0698\u0645\u0627\u0631\u06D5\u06CC E.164", credit_card: "\u0698\u0645\u0627\u0631\u06D5\u06CC \u06A9\u0627\u0631\u062A\u06CC \u06A9\u0631\u06CE\u062F\u06CC\u062A", + currency_code: "\u06A9\u06C6\u062F\u06CC \u062F\u0631\u0627\u0648", + iban: "IBAN", jwt: "JWT", template_literal: "\u062A\u06CE\u06A9\u0631\u062F\u06D5" }; @@ -13032,6 +13204,8 @@ var error8 = () => { json_string: "\u0159et\u011Bzec ve form\xE1tu JSON", e164: "\u010D\xEDslo E.164", credit_card: "\u010D\xEDslo kreditn\xED karty", + currency_code: "k\xF3d m\u011Bny", + iban: "IBAN", jwt: "JWT", template_literal: "vstup" }; @@ -13147,6 +13321,8 @@ var error9 = () => { json_string: "JSON-streng", e164: "E.164-nummer", credit_card: "kreditkortnummer", + currency_code: "valutakode", + iban: "IBAN", jwt: "JWT", template_literal: "input" }; @@ -13266,6 +13442,8 @@ var error10 = () => { json_string: "JSON-String", e164: "E.164-Nummer", credit_card: "Kreditkartennummer", + currency_code: "W\xE4hrungscode", + iban: "IBAN", jwt: "JWT", template_literal: "Eingabe" }; @@ -13378,6 +13556,8 @@ var error11 = () => { json_string: "\u03C3\u03C5\u03BC\u03B2\u03BF\u03BB\u03BF\u03C3\u03B5\u03B9\u03C1\u03AC JSON", e164: "\u03B1\u03C1\u03B9\u03B8\u03BC\u03CC\u03C2 E.164", credit_card: "\u03B1\u03C1\u03B9\u03B8\u03BC\u03CC\u03C2 \u03C0\u03B9\u03C3\u03C4\u03C9\u03C4\u03B9\u03BA\u03AE\u03C2 \u03BA\u03AC\u03C1\u03C4\u03B1\u03C2", + currency_code: "\u03BA\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 \u03BD\u03BF\u03BC\u03AF\u03C3\u03BC\u03B1\u03C4\u03BF\u03C2", + iban: "IBAN", jwt: "JWT", template_literal: "\u03B5\u03AF\u03C3\u03BF\u03B4\u03BF\u03C2" }; @@ -13488,7 +13668,9 @@ var error12 = () => { base64url: "base64url-encoded string", json_string: "JSON string", e164: "E.164 number", + currency_code: "currency code", credit_card: "credit card number", + iban: "IBAN", jwt: "JWT", template_literal: "input" }; @@ -13612,6 +13794,8 @@ var error13 = () => { json_string: "JSON-karaktraro", e164: "E.164-nombro", credit_card: "kreditkarta numero", + currency_code: "valuta kodo", + iban: "IBAN", jwt: "JWT", template_literal: "enigo" }; @@ -13724,6 +13908,8 @@ var error14 = () => { json_string: "cadena JSON", e164: "n\xFAmero E.164", credit_card: "n\xFAmero de tarjeta de cr\xE9dito", + currency_code: "c\xF3digo de moneda", + iban: "IBAN", jwt: "JWT", template_literal: "entrada" }; @@ -13860,6 +14046,8 @@ var error15 = () => { json_string: "JSON \u0631\u0634\u062A\u0647", e164: "E.164 \u0639\u062F\u062F", credit_card: "\u0634\u0645\u0627\u0631\u0647 \u06A9\u0627\u0631\u062A \u0627\u0639\u062A\u0628\u0627\u0631\u06CC", + currency_code: "\u06A9\u062F \u0627\u0631\u0632", + iban: "IBAN", jwt: "JWT", template_literal: "\u0648\u0631\u0648\u062F\u06CC" }; @@ -13982,6 +14170,8 @@ var error16 = () => { json_string: "JSON-merkkijono", e164: "E.164-luku", credit_card: "luottokortin numero", + currency_code: "valuuttakoodi", + iban: "IBAN", jwt: "JWT", template_literal: "templaattimerkkijono" }; @@ -14093,6 +14283,8 @@ var error17 = () => { json_string: "cha\xEEne de caract\xE8res JSON", e164: "num\xE9ro au format E.164", credit_card: "num\xE9ro de carte de cr\xE9dit", + currency_code: "code de devise", + iban: "IBAN", jwt: "JWT", template_literal: "entr\xE9e" }; @@ -14222,6 +14414,8 @@ var error18 = () => { json_string: "cha\xEEne JSON", e164: "num\xE9ro E.164", credit_card: "num\xE9ro de carte de cr\xE9dit", + currency_code: "code de devise", + iban: "IBAN", jwt: "JWT", template_literal: "entr\xE9e" }; @@ -14333,6 +14527,8 @@ var error19 = () => { json_string: "JSON \u0AB8\u0ACD\u0A9F\u0ACD\u0AB0\u0ABF\u0A82\u0A97", e164: "E.164 \u0AA8\u0A82\u0AAC\u0AB0", credit_card: "\u0A95\u0ACD\u0AB0\u0AC7\u0AA1\u0ABF\u0A9F \u0A95\u0ABE\u0AB0\u0ACD\u0AA1 \u0AA8\u0A82\u0AAC\u0AB0", + currency_code: "\u0A9A\u0AB2\u0AA3 \u0A95\u0ACB\u0AA1", + iban: "IBAN", jwt: "JWT", template_literal: "\u0A87\u0AA8\u0AAA\u0AC1\u0A9F" }; @@ -14481,6 +14677,8 @@ var error20 = () => { json_string: { label: "\u05DE\u05D7\u05E8\u05D5\u05D6\u05EA JSON", gender: "f" }, e164: { label: "\u05DE\u05E1\u05E4\u05E8 E.164", gender: "m" }, credit_card: { label: "\u05DE\u05E1\u05E4\u05E8 \u05DB\u05E8\u05D8\u05D9\u05E1 \u05D0\u05E9\u05E8\u05D0\u05D9", gender: "m" }, + currency_code: { label: "\u05E7\u05D5\u05D3 \u05DE\u05D8\u05D1\u05E2", gender: "m" }, + iban: { label: "IBAN", gender: "m" }, jwt: { label: "JWT", gender: "m" }, template_literal: { label: "\u05E7\u05DC\u05D8", gender: "m" }, ends_with: { label: "\u05E7\u05DC\u05D8", gender: "m" }, @@ -14645,6 +14843,8 @@ var error21 = () => { json_string: "JSON \u0938\u094D\u091F\u094D\u0930\u093F\u0902\u0917", e164: "E.164 \u0938\u0902\u0916\u094D\u092F\u093E", credit_card: "\u0915\u094D\u0930\u0947\u0921\u093F\u091F \u0915\u093E\u0930\u094D\u0921 \u0938\u0902\u0916\u094D\u092F\u093E", + currency_code: "\u092E\u0941\u0926\u094D\u0930\u093E \u0915\u094B\u0921", + iban: "IBAN", jwt: "JWT", template_literal: "\u0907\u0928\u092A\u0941\u091F" }; @@ -14754,6 +14954,8 @@ var error22 = () => { json_string: "JSON tekst", e164: "E.164 broj", credit_card: "broj kreditne kartice", + currency_code: "kod valute", + iban: "IBAN", jwt: "JWT", template_literal: "unos" }; @@ -14880,6 +15082,8 @@ var error23 = () => { json_string: "JSON string", e164: "E.164 sz\xE1m", credit_card: "hitelk\xE1rtyasz\xE1m", + currency_code: "p\xE9nznemk\xF3d", + iban: "IBAN", jwt: "JWT", template_literal: "bemenet" }; @@ -15032,6 +15236,8 @@ var error24 = () => { json_string: "JSON \u057F\u0578\u0572", e164: "E.164 \u0570\u0561\u0574\u0561\u0580", credit_card: "\u056F\u0580\u0565\u0564\u056B\u057F \u0584\u0561\u0580\u057F\u056B \u0570\u0561\u0574\u0561\u0580", + currency_code: "\u0561\u0580\u056A\u0578\u0582\u0575\u0569\u056B \u056F\u0578\u0564", + iban: "IBAN", jwt: "JWT", template_literal: "\u0574\u0578\u0582\u057F\u0584" }; @@ -15149,6 +15355,8 @@ var error25 = () => { json_string: "string JSON", e164: "angka E.164", credit_card: "nomor kartu kredit", + currency_code: "kode mata uang", + iban: "IBAN", jwt: "JWT", template_literal: "input" }; @@ -15259,6 +15467,8 @@ var error26 = () => { json_string: "JSON strengur", e164: "E.164 t\xF6lugildi", credit_card: "kreditkortan\xFAmer", + currency_code: "gjaldmi\xF0ilsk\xF3\xF0i", + iban: "IBAN", jwt: "JWT", template_literal: "gildi" }; @@ -15372,6 +15582,8 @@ var error27 = () => { json_string: "stringa JSON", e164: "numero E.164", credit_card: "numero di carta di credito", + currency_code: "codice valuta", + iban: "IBAN", jwt: "JWT", template_literal: "input" }; @@ -15484,6 +15696,8 @@ var error28 = () => { json_string: "JSON\u6587\u5B57\u5217", e164: "E.164\u756A\u53F7", credit_card: "\u30AF\u30EC\u30B8\u30C3\u30C8\u30AB\u30FC\u30C9\u756A\u53F7", + currency_code: "\u901A\u8CA8\u30B3\u30FC\u30C9", + iban: "IBAN", jwt: "JWT", template_literal: "\u5165\u529B\u5024" }; @@ -15595,6 +15809,8 @@ var error29 = () => { json_string: "JSON \u10D5\u10D4\u10DA\u10D8", e164: "E.164 \u10DC\u10DD\u10DB\u10D4\u10E0\u10D8", credit_card: "\u10E1\u10D0\u10D9\u10E0\u10D4\u10D3\u10D8\u10E2\u10DD \u10D1\u10D0\u10E0\u10D0\u10D7\u10D8\u10E1 \u10DC\u10DD\u10DB\u10D4\u10E0\u10D8", + currency_code: "\u10D5\u10D0\u10DA\u10E3\u10E2\u10D8\u10E1 \u10D9\u10DD\u10D3\u10D8", + iban: "IBAN", jwt: "JWT", template_literal: "\u10E8\u10D4\u10E7\u10D5\u10D0\u10DC\u10D0" }; @@ -15711,6 +15927,8 @@ var error30 = () => { json_string: "\u1781\u17D2\u179F\u17C2\u17A2\u1780\u17D2\u179F\u179A JSON", e164: "\u179B\u17C1\u1781 E.164", credit_card: "\u179B\u17C1\u1781\u1794\u17D0\u178E\u17D2\u178E\u17A5\u178E\u1791\u17B6\u1793", + currency_code: "\u1780\u17BC\u178A\u179A\u17BC\u1794\u17B7\u1799\u1794\u17D0\u178E\u17D2\u178E", + iban: "IBAN", jwt: "JWT", template_literal: "\u1791\u17B7\u1793\u17D2\u1793\u1793\u17D0\u1799\u1794\u1789\u17D2\u1785\u17BC\u179B" }; @@ -15830,6 +16048,8 @@ var error31 = () => { json_string: "JSON\u0CB8\u0CCD\u0C9F\u0CCD\u0CB0\u0CBF\u0C82\u0C97\u0CCD", e164: "E.164 \u0CB8\u0C82\u0C96\u0CCD\u0CAF\u0CC6", credit_card: "\u0C95\u0CCD\u0CB0\u0CC6\u0CA1\u0CBF\u0C9F\u0CCD \u0C95\u0CBE\u0CB0\u0CCD\u0CA1\u0CCD \u0CB8\u0C82\u0C96\u0CCD\u0CAF\u0CC6", + currency_code: "\u0C95\u0CB0\u0CC6\u0CA8\u0CCD\u0CB8\u0CBF \u0C95\u0CCB\u0CA1\u0CCD", + iban: "IBAN", jwt: "JWT", template_literal: "\u0C87\u0CA8\u0CCD\u0CAA\u0CC1\u0C9F\u0CCD" }; @@ -15944,6 +16164,8 @@ var error32 = () => { json_string: "JSON \uBB38\uC790\uC5F4", e164: "E.164 \uBC88\uD638", credit_card: "\uC2E0\uC6A9\uCE74\uB4DC \uBC88\uD638", + currency_code: "\uD1B5\uD654 \uCF54\uB4DC", + iban: "IBAN", jwt: "JWT", template_literal: "\uC785\uB825" }; @@ -16141,6 +16363,8 @@ var error33 = () => { json_string: "JSON eilut\u0117", e164: "E.164 numeris", credit_card: "kredito kortel\u0117s numeris", + currency_code: "valiutos kodas", + iban: "IBAN", jwt: "JWT", template_literal: "\u012Fvestis" }; @@ -16265,6 +16489,8 @@ var error34 = () => { json_string: "JSON \u043D\u0438\u0437\u0430", e164: "E.164 \u0431\u0440\u043E\u0458", credit_card: "\u0431\u0440\u043E\u0458 \u043D\u0430 \u043A\u0440\u0435\u0434\u0438\u0442\u043D\u0430 \u043A\u0430\u0440\u0442\u0438\u0447\u043A\u0430", + currency_code: "\u043A\u043E\u0434 \u043D\u0430 \u0432\u0430\u043B\u0443\u0442\u0430", + iban: "IBAN", jwt: "JWT", template_literal: "\u0432\u043D\u0435\u0441" }; @@ -16378,6 +16604,8 @@ var error35 = () => { json_string: "string JSON", e164: "nombor E.164", credit_card: "nombor kad kredit", + currency_code: "kod mata wang", + iban: "IBAN", jwt: "JWT", template_literal: "input" }; @@ -16489,6 +16717,8 @@ var error36 = () => { json_string: "JSON \u0938\u094D\u091F\u094D\u0930\u093F\u0919", e164: "E.164 \u0928\u092E\u094D\u092C\u0930", credit_card: "\u0915\u094D\u0930\u0947\u0921\u093F\u091F \u0915\u093E\u0930\u094D\u0921 \u0928\u092E\u094D\u092C\u0930", + currency_code: "\u092E\u0941\u0926\u094D\u0930\u093E \u0915\u094B\u0921", + iban: "IBAN", jwt: "JWT", template_literal: "\u0907\u0928\u092A\u0941\u091F" }; @@ -16599,6 +16829,8 @@ var error37 = () => { json_string: "JSON string", e164: "E.164-nummer", credit_card: "creditcardnummer", + currency_code: "valutacode", + iban: "IBAN", jwt: "JWT", template_literal: "invoer" }; @@ -16713,6 +16945,8 @@ var error38 = () => { json_string: "JSON-streng", e164: "E.164-nummer", credit_card: "kredittkortnummer", + currency_code: "valutakode", + iban: "IBAN", jwt: "JWT", template_literal: "input" }; @@ -16825,6 +17059,8 @@ var error39 = () => { json_string: "JSON-streng", e164: "E.164-nummer", credit_card: "kredittkortnummer", + currency_code: "valutakode", + iban: "IBAN", jwt: "JWT", template_literal: "input" }; @@ -16937,6 +17173,8 @@ var error40 = () => { json_string: "JSON metin", e164: "E.164 say\u0131s\u0131", credit_card: "i'tib\xE2r kart\u0131 numaras\u0131", + currency_code: "para birimi kodu", + iban: "IBAN", jwt: "JWT", template_literal: "giren" }; @@ -17050,6 +17288,8 @@ var error41 = () => { json_string: "JSON \u0645\u062A\u0646", e164: "\u062F E.164 \u0634\u0645\u06D0\u0631\u0647", credit_card: "\u062F \u06A9\u0631\u06CC\u0689\u06CC\u067C \u06A9\u0627\u0631\u062A \u0634\u0645\u06CC\u0631\u0647", + currency_code: "\u062F \u0627\u0633\u0639\u0627\u0631\u0648 \u06A9\u0648\u0689", + iban: "IBAN", jwt: "JWT", template_literal: "\u0648\u0631\u0648\u062F\u064A" }; @@ -17168,6 +17408,8 @@ var error42 = () => { json_string: "ci\u0105g znak\xF3w w formacie JSON", e164: "liczba E.164", credit_card: "numer karty kredytowej", + currency_code: "kod waluty", + iban: "IBAN", jwt: "JWT", template_literal: "wej\u015Bcie" }; @@ -17281,6 +17523,8 @@ var error43 = () => { json_string: "o texto JSON", e164: "o n\xFAmero E.164", credit_card: "o n\xFAmero de cart\xE3o de cr\xE9dito", + currency_code: "o c\xF3digo de moeda", + iban: "o IBAN", jwt: "o JWT", template_literal: "a entrada" }; @@ -17358,8 +17602,8 @@ var error43 = () => { case "not_multiple_of": return `N\xFAmero inv\xE1lido: deve ser m\xFAltiplo de ${issue2.divisor}`; case "unrecognized_keys": { - const plural = issue2.keys.length > 1 ? "s" : ""; - return `Chave${plural} inv\xE1lida${plural}: ${joinValues(issue2.keys, ", ")}`; + const plural2 = issue2.keys.length > 1 ? "s" : ""; + return `Chave${plural2} inv\xE1lida${plural2}: ${joinValues(issue2.keys, ", ")}`; } case "invalid_key": return `Entrada inv\xE1lida n${translateOriginWithArticle(issue2.origin, "definite")}`; @@ -17423,6 +17667,8 @@ var error44 = () => { json_string: "o texto JSON", e164: "o n\xFAmero E.164", credit_card: "o n\xFAmero de cart\xE3o de cr\xE9dito", + currency_code: "o c\xF3digo de moeda", + iban: "o IBAN", jwt: "o JWT", template_literal: "a entrada" }; @@ -17501,8 +17747,8 @@ var error44 = () => { case "not_multiple_of": return `N\xFAmero inv\xE1lido: deve ser m\xFAltiplo de ${issue2.divisor}`; case "unrecognized_keys": { - const plural = issue2.keys.length > 1 ? "s" : ""; - return `Chave${plural} inv\xE1lida${plural}: ${joinValues(issue2.keys, ", ")}`; + const plural2 = issue2.keys.length > 1 ? "s" : ""; + return `Chave${plural2} inv\xE1lida${plural2}: ${joinValues(issue2.keys, ", ")}`; } case "invalid_key": return `Entrada inv\xE1lida n${translateOriginWithArticle(issue2.origin, "definite")}`; @@ -17566,6 +17812,8 @@ var error45 = () => { json_string: "\u0219ir JSON", e164: "num\u0103r E.164", credit_card: "num\u0103r de card de credit", + currency_code: "cod valutar", + iban: "IBAN", jwt: "JWT", template_literal: "intrare" }; @@ -17737,6 +17985,8 @@ var error46 = () => { json_string: "JSON \u0441\u0442\u0440\u043E\u043A\u0430", e164: "\u043D\u043E\u043C\u0435\u0440 E.164", credit_card: "\u043D\u043E\u043C\u0435\u0440 \u043A\u0440\u0435\u0434\u0438\u0442\u043D\u043E\u0439 \u043A\u0430\u0440\u0442\u044B", + currency_code: "\u043A\u043E\u0434 \u0432\u0430\u043B\u044E\u0442\u044B", + iban: "IBAN", jwt: "JWT", template_literal: "\u0432\u0432\u043E\u0434" }; @@ -17854,6 +18104,8 @@ var error47 = () => { json_string: "re\u0165azec vo form\xE1te JSON", e164: "\u010D\xEDslo E.164", credit_card: "\u010D\xEDslo kreditnej karty", + currency_code: "k\xF3d meny", + iban: "IBAN", jwt: "JWT", template_literal: "vstup" }; @@ -17969,6 +18221,8 @@ var error48 = () => { json_string: "JSON niz", e164: "E.164 \u0161tevilka", credit_card: "\u0161tevilka kreditne kartice", + currency_code: "koda valute", + iban: "IBAN", jwt: "JWT", template_literal: "vnos" }; @@ -18082,6 +18336,8 @@ var error49 = () => { json_string: "JSON-str\xE4ng", e164: "E.164-nummer", credit_card: "kreditkortsnummer", + currency_code: "valutakod", + iban: "IBAN", jwt: "JWT", template_literal: "mall-literal" }; @@ -18196,6 +18452,8 @@ var error50 = () => { json_string: "JSON \u0B9A\u0BB0\u0BAE\u0BCD", e164: "E.164 \u0B8E\u0BA3\u0BCD", credit_card: "\u0B95\u0B9F\u0BA9\u0BCD \u0B85\u0B9F\u0BCD\u0B9F\u0BC8 \u0B8E\u0BA3\u0BCD", + currency_code: "\u0BA8\u0BBE\u0BA3\u0BAF\u0B95\u0BCD \u0B95\u0BC1\u0BB1\u0BBF\u0BAF\u0BC0\u0B9F\u0BC1", + iban: "IBAN", jwt: "JWT", template_literal: "input" }; @@ -18269,23 +18527,23 @@ function ta_default() { }; } -// node_modules/zod/v4/locales/th.js +// node_modules/zod/v4/locales/tg.js var error51 = () => { const Sizable = { - string: { unit: "\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" }, - file: { unit: "\u0E44\u0E1A\u0E15\u0E4C", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" }, - array: { unit: "\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" }, - set: { unit: "\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" }, - map: { unit: "\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" } + string: { unit: "\u0430\u043B\u043E\u043C\u0430\u0442", verb: "\u0434\u043E\u0448\u0442\u0430 \u0431\u043E\u0448\u0430\u0434" }, + file: { unit: "\u0431\u0430\u0439\u0442", verb: "\u0434\u043E\u0448\u0442\u0430 \u0431\u043E\u0448\u0430\u0434" }, + array: { unit: "\u0443\u043D\u0441\u0443\u0440", verb: "\u0434\u043E\u0448\u0442\u0430 \u0431\u043E\u0448\u0430\u0434" }, + set: { unit: "\u0443\u043D\u0441\u0443\u0440", verb: "\u0434\u043E\u0448\u0442\u0430 \u0431\u043E\u0448\u0430\u0434" }, + map: { unit: "\u0441\u0430\u0431\u0442", verb: "\u0434\u043E\u0448\u0442\u0430 \u0431\u043E\u0448\u0430\u0434" } }; function getSizing(origin) { return Sizable[origin] ?? null; } const FormatDictionary = { - regex: "\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E17\u0E35\u0E48\u0E1B\u0E49\u0E2D\u0E19", - email: "\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48\u0E2D\u0E35\u0E40\u0E21\u0E25", + regex: "\u0432\u0443\u0440\u0443\u0434", + email: "\u0441\u0443\u0440\u043E\u0493\u0430\u0438 email", url: "URL", - emoji: "\u0E2D\u0E34\u0E42\u0E21\u0E08\u0E34", + emoji: "\u044D\u043C\u043E\u04B7\u0438", uuid: "UUID", uuidv4: "UUIDv4", uuidv6: "UUIDv6", @@ -18296,28 +18554,147 @@ var error51 = () => { ulid: "ULID", xid: "XID", ksuid: "KSUID", - datetime: "\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E40\u0E27\u0E25\u0E32\u0E41\u0E1A\u0E1A ISO", - date: "\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E41\u0E1A\u0E1A ISO", - time: "\u0E40\u0E27\u0E25\u0E32\u0E41\u0E1A\u0E1A ISO", - duration: "\u0E0A\u0E48\u0E27\u0E07\u0E40\u0E27\u0E25\u0E32\u0E41\u0E1A\u0E1A ISO", - ipv4: "\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 IPv4", - ipv6: "\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 IPv6", - mac: "\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 MAC", - cidrv4: "\u0E0A\u0E48\u0E27\u0E07 IP \u0E41\u0E1A\u0E1A IPv4", - cidrv6: "\u0E0A\u0E48\u0E27\u0E07 IP \u0E41\u0E1A\u0E1A IPv6", - base64: "\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E41\u0E1A\u0E1A Base64", - base64url: "\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E41\u0E1A\u0E1A Base64 \u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A URL", - json_string: "\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E41\u0E1A\u0E1A JSON", - e164: "\u0E40\u0E1A\u0E2D\u0E23\u0E4C\u0E42\u0E17\u0E23\u0E28\u0E31\u0E1E\u0E17\u0E4C\u0E23\u0E30\u0E2B\u0E27\u0E48\u0E32\u0E07\u0E1B\u0E23\u0E30\u0E40\u0E17\u0E28 (E.164)", - credit_card: "\u0E2B\u0E21\u0E32\u0E22\u0E40\u0E25\u0E02\u0E1A\u0E31\u0E15\u0E23\u0E40\u0E04\u0E23\u0E14\u0E34\u0E15", - jwt: "\u0E42\u0E17\u0E40\u0E04\u0E19 JWT", - template_literal: "\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E17\u0E35\u0E48\u0E1B\u0E49\u0E2D\u0E19" + datetime: "\u0441\u0430\u043D\u0430\u0432\u0443 \u0432\u0430\u049B\u0442\u0438 ISO", + date: "\u0441\u0430\u043D\u0430\u0438 ISO", + time: "\u0432\u0430\u049B\u0442\u0438 ISO", + duration: "\u0434\u0430\u0432\u043E\u043C\u043D\u043E\u043A\u0438\u0438 ISO", + ipv4: "\u0441\u0443\u0440\u043E\u0493\u0430\u0438 IPv4", + ipv6: "\u0441\u0443\u0440\u043E\u0493\u0430\u0438 IPv6", + mac: "\u0441\u0443\u0440\u043E\u0493\u0430\u0438 MAC", + cidrv4: "\u043C\u0430\u04B3\u0434\u0443\u0434\u0430\u0438 IPv4", + cidrv6: "\u043C\u0430\u04B3\u0434\u0443\u0434\u0430\u0438 IPv6", + base64: "\u0441\u0430\u0442\u0440\u0438 \u0434\u0430\u0440 \u0444\u043E\u0440\u043C\u0430\u0442\u0438 base64", + base64url: "\u0441\u0430\u0442\u0440\u0438 \u0434\u0430\u0440 \u0444\u043E\u0440\u043C\u0430\u0442\u0438 base64url", + json_string: "\u0441\u0430\u0442\u0440\u0438 JSON", + e164: "\u0440\u0430\u049B\u0430\u043C\u0438 E.164", + credit_card: "\u0440\u0430\u049B\u0430\u043C\u0438 \u043A\u043E\u0440\u0442\u0438 \u043A\u0440\u0435\u0434\u0438\u0442\u04E3", + currency_code: "\u0440\u0430\u043C\u0437\u0438 \u0430\u0441\u044A\u043E\u0440", + iban: "IBAN", + jwt: "JWT", + template_literal: "\u0432\u0443\u0440\u0443\u0434" }; const TypeDictionary = { nan: "NaN", - number: "\u0E15\u0E31\u0E27\u0E40\u0E25\u0E02", - array: "\u0E2D\u0E32\u0E23\u0E4C\u0E40\u0E23\u0E22\u0E4C (Array)", - null: "\u0E44\u0E21\u0E48\u0E21\u0E35\u0E04\u0E48\u0E32 (null)" + number: "\u0440\u0430\u049B\u0430\u043C", + string: "\u0441\u0430\u0442\u0440", + array: "\u043C\u0430\u0441\u0441\u0438\u0432", + object: "\u043E\u0431\u044A\u0435\u043A\u0442", + date: "\u0441\u0430\u043D\u0430" + }; + return (issue2) => { + switch (issue2.code) { + case "invalid_type": { + const expected = TypeDictionary[issue2.expected] ?? issue2.expected; + const receivedType = parsedType(issue2.input); + const received = TypeDictionary[receivedType] ?? receivedType; + return `\u0412\u0443\u0440\u0443\u0434\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442: ${expected} \u0438\u043D\u0442\u0438\u0437\u043E\u0440 \u043C\u0435\u0440\u0430\u0444\u0442, ${received} \u0433\u0438\u0440\u0438\u0444\u0442\u0430 \u0448\u0443\u0434`; + } + case "invalid_value": + if (issue2.values.length === 1) + return `\u0412\u0443\u0440\u0443\u0434\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442: ${stringifyPrimitive(issue2.values[0])} \u0438\u043D\u0442\u0438\u0437\u043E\u0440 \u043C\u0435\u0440\u0430\u0444\u0442`; + return `\u0418\u043D\u0442\u0438\u0445\u043E\u0431\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442: \u044F\u043A\u0435 \u0430\u0437 ${joinValues(issue2.values, "|")} \u0438\u043D\u0442\u0438\u0437\u043E\u0440 \u043C\u0435\u0440\u0430\u0444\u0442`; + case "too_big": { + const adj = issue2.inclusive ? "<=" : "<"; + const sizing = getSizing(issue2.origin); + if (sizing) + return `\u0425\u0435\u043B\u0435 \u043A\u0430\u043B\u043E\u043D: ${issue2.origin ?? "\u049B\u0438\u043C\u0430\u0442"} \u0431\u043E\u044F\u0434 ${adj}${issue2.maximum.toString()} ${sizing.unit} ${sizing.verb}`; + return `\u0425\u0435\u043B\u0435 \u043A\u0430\u043B\u043E\u043D: ${issue2.origin ?? "\u049B\u0438\u043C\u0430\u0442"} \u0431\u043E\u044F\u0434 ${adj}${issue2.maximum.toString()} \u0431\u043E\u0448\u0430\u0434`; + } + case "too_small": { + const adj = issue2.inclusive ? ">=" : ">"; + const sizing = getSizing(issue2.origin); + if (sizing) + return `\u0425\u0435\u043B\u0435 \u0445\u0443\u0440\u0434: ${issue2.origin} \u0431\u043E\u044F\u0434 ${adj}${issue2.minimum.toString()} ${sizing.unit} ${sizing.verb}`; + return `\u0425\u0435\u043B\u0435 \u0445\u0443\u0440\u0434: ${issue2.origin} \u0431\u043E\u044F\u0434 ${adj}${issue2.minimum.toString()} \u0431\u043E\u0448\u0430\u0434`; + } + case "invalid_format": { + const _issue = issue2; + if (_issue.format === "starts_with") + return `\u0421\u0430\u0442\u0440\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442: \u0431\u043E\u044F\u0434 \u0431\u043E "${_issue.prefix}" \u043E\u0493\u043E\u0437 \u0448\u0430\u0432\u0430\u0434`; + if (_issue.format === "ends_with") + return `\u0421\u0430\u0442\u0440\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442: \u0431\u043E\u044F\u0434 \u0431\u043E "${_issue.suffix}" \u0430\u043D\u04B7\u043E\u043C \u0451\u0431\u0430\u0434`; + if (_issue.format === "includes") + return `\u0421\u0430\u0442\u0440\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442: \u0431\u043E\u044F\u0434 "${_issue.includes}"-\u0440\u043E \u0434\u0430\u0440 \u0431\u0430\u0440 \u0433\u0438\u0440\u0430\u0434`; + if (_issue.format === "regex") + return `\u0421\u0430\u0442\u0440\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442: \u0431\u043E\u044F\u0434 \u0431\u0430 \u043D\u0430\u043C\u0443\u043D\u0430\u0438 ${_issue.pattern} \u043C\u0443\u0432\u043E\u0444\u0438\u049B\u0430\u0442 \u043A\u0443\u043D\u0430\u0434`; + return `${FormatDictionary[_issue.format] ?? issue2.format}-\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442`; + } + case "not_multiple_of": + return `\u0420\u0430\u049B\u0430\u043C\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442: \u0431\u043E\u044F\u0434 \u0431\u0430 ${issue2.divisor} \u0431\u0435 \u0431\u0430\u049B\u0438\u044F \u0442\u0430\u049B\u0441\u0438\u043C \u0448\u0430\u0432\u0430\u0434`; + case "unrecognized_keys": + return `\u041A\u0430\u043B\u0438\u0434${issue2.keys.length > 1 ? "\u04B3\u043E\u0438" : "\u0438"} \u043D\u043E\u043C\u0430\u044A\u043B\u0443\u043C: ${joinValues(issue2.keys, ", ")}`; + case "invalid_key": + return `\u041A\u0430\u043B\u0438\u0434\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442 \u0434\u0430\u0440 ${issue2.origin}`; + case "invalid_union": + if (issue2.options && Array.isArray(issue2.options) && issue2.options.length > 0) { + const opts = issue2.options.map((o) => `'${o}'`).join(" | "); + return `\u049A\u0438\u043C\u0430\u0442\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442\u0438 \u0434\u0438\u0441\u043A\u0440\u0438\u043C\u0438\u043D\u0430\u0442\u043E\u0440: ${opts} \u0438\u043D\u0442\u0438\u0437\u043E\u0440 \u043C\u0435\u0440\u0430\u0444\u0442`; + } + return "\u0412\u0443\u0440\u0443\u0434\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442"; + case "invalid_element": + return `\u049A\u0438\u043C\u0430\u0442\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442 \u0434\u0430\u0440 ${issue2.origin}`; + default: + return `\u0412\u0443\u0440\u0443\u0434\u0438 \u043D\u043E\u0434\u0443\u0440\u0443\u0441\u0442`; + } + }; +}; +function tg_default() { + return { + localeError: error51() + }; +} + +// node_modules/zod/v4/locales/th.js +var error52 = () => { + const Sizable = { + string: { unit: "\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" }, + file: { unit: "\u0E44\u0E1A\u0E15\u0E4C", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" }, + array: { unit: "\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" }, + set: { unit: "\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" }, + map: { unit: "\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" } + }; + function getSizing(origin) { + return Sizable[origin] ?? null; + } + const FormatDictionary = { + regex: "\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E17\u0E35\u0E48\u0E1B\u0E49\u0E2D\u0E19", + email: "\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48\u0E2D\u0E35\u0E40\u0E21\u0E25", + url: "URL", + emoji: "\u0E2D\u0E34\u0E42\u0E21\u0E08\u0E34", + uuid: "UUID", + uuidv4: "UUIDv4", + uuidv6: "UUIDv6", + nanoid: "nanoid", + guid: "GUID", + cuid: "cuid", + cuid2: "cuid2", + ulid: "ULID", + xid: "XID", + ksuid: "KSUID", + datetime: "\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E40\u0E27\u0E25\u0E32\u0E41\u0E1A\u0E1A ISO", + date: "\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E41\u0E1A\u0E1A ISO", + time: "\u0E40\u0E27\u0E25\u0E32\u0E41\u0E1A\u0E1A ISO", + duration: "\u0E0A\u0E48\u0E27\u0E07\u0E40\u0E27\u0E25\u0E32\u0E41\u0E1A\u0E1A ISO", + ipv4: "\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 IPv4", + ipv6: "\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 IPv6", + mac: "\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48 MAC", + cidrv4: "\u0E0A\u0E48\u0E27\u0E07 IP \u0E41\u0E1A\u0E1A IPv4", + cidrv6: "\u0E0A\u0E48\u0E27\u0E07 IP \u0E41\u0E1A\u0E1A IPv6", + base64: "\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E41\u0E1A\u0E1A Base64", + base64url: "\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E41\u0E1A\u0E1A Base64 \u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A URL", + json_string: "\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E41\u0E1A\u0E1A JSON", + e164: "\u0E40\u0E1A\u0E2D\u0E23\u0E4C\u0E42\u0E17\u0E23\u0E28\u0E31\u0E1E\u0E17\u0E4C\u0E23\u0E30\u0E2B\u0E27\u0E48\u0E32\u0E07\u0E1B\u0E23\u0E30\u0E40\u0E17\u0E28 (E.164)", + credit_card: "\u0E2B\u0E21\u0E32\u0E22\u0E40\u0E25\u0E02\u0E1A\u0E31\u0E15\u0E23\u0E40\u0E04\u0E23\u0E14\u0E34\u0E15", + currency_code: "\u0E23\u0E2B\u0E31\u0E2A\u0E2A\u0E01\u0E38\u0E25\u0E40\u0E07\u0E34\u0E19", + iban: "IBAN", + jwt: "\u0E42\u0E17\u0E40\u0E04\u0E19 JWT", + template_literal: "\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E17\u0E35\u0E48\u0E1B\u0E49\u0E2D\u0E19" + }; + const TypeDictionary = { + nan: "NaN", + number: "\u0E15\u0E31\u0E27\u0E40\u0E25\u0E02", + array: "\u0E2D\u0E32\u0E23\u0E4C\u0E40\u0E23\u0E22\u0E4C (Array)", + null: "\u0E44\u0E21\u0E48\u0E21\u0E35\u0E04\u0E48\u0E32 (null)" }; return (issue2) => { switch (issue2.code) { @@ -18379,12 +18756,12 @@ var error51 = () => { }; function th_default() { return { - localeError: error51() + localeError: error52() }; } // node_modules/zod/v4/locales/tk.js -var error52 = () => { +var error53 = () => { const Sizable = { string: { unit: "simwol", verb: "bolmaly" }, file: { unit: "ba\xFDt", verb: "bolmaly" }, @@ -18424,6 +18801,8 @@ var error52 = () => { json_string: "JSON setiri", e164: "E.164 nomeri", credit_card: "kredit kartyny\u0148 nomeri", + currency_code: "wal\xFDuta kody", + iban: "IBAN", jwt: "JWT", template_literal: "\u015Fablon" }; @@ -18485,12 +18864,12 @@ var error52 = () => { }; function tk_default() { return { - localeError: error52() + localeError: error53() }; } // node_modules/zod/v4/locales/tr.js -var error53 = () => { +var error54 = () => { const Sizable = { string: { unit: "karakter", verb: "olmal\u0131" }, file: { unit: "bayt", verb: "olmal\u0131" }, @@ -18530,6 +18909,8 @@ var error53 = () => { json_string: "JSON dizesi", e164: "E.164 say\u0131s\u0131", credit_card: "kredi kart\u0131 numaras\u0131", + currency_code: "para birimi kodu", + iban: "IBAN", jwt: "JWT", template_literal: "\u015Eablon dizesi" }; @@ -18594,12 +18975,12 @@ var error53 = () => { }; function tr_default() { return { - localeError: error53() + localeError: error54() }; } // node_modules/zod/v4/locales/uk.js -var error54 = () => { +var error55 = () => { const Sizable = { string: { unit: "\u0441\u0438\u043C\u0432\u043E\u043B\u0456\u0432", verb: "\u043C\u0430\u0442\u0438\u043C\u0435" }, file: { unit: "\u0431\u0430\u0439\u0442\u0456\u0432", verb: "\u043C\u0430\u0442\u0438\u043C\u0435" }, @@ -18639,6 +19020,8 @@ var error54 = () => { json_string: "\u0440\u044F\u0434\u043E\u043A JSON", e164: "\u043D\u043E\u043C\u0435\u0440 E.164", credit_card: "\u043D\u043E\u043C\u0435\u0440 \u043A\u0440\u0435\u0434\u0438\u0442\u043D\u043E\u0457 \u043A\u0430\u0440\u0442\u043A\u0438", + currency_code: "\u043A\u043E\u0434 \u0432\u0430\u043B\u044E\u0442\u0438", + iban: "IBAN", jwt: "JWT", template_literal: "\u0432\u0445\u0456\u0434\u043D\u0456 \u0434\u0430\u043D\u0456" }; @@ -18706,7 +19089,7 @@ var error54 = () => { }; function uk_default() { return { - localeError: error54() + localeError: error55() }; } @@ -18716,7 +19099,7 @@ function ua_default() { } // node_modules/zod/v4/locales/ur.js -var error55 = () => { +var error56 = () => { const Sizable = { string: { unit: "\u062D\u0631\u0648\u0641", verb: "\u06C1\u0648\u0646\u0627" }, file: { unit: "\u0628\u0627\u0626\u0679\u0633", verb: "\u06C1\u0648\u0646\u0627" }, @@ -18756,6 +19139,8 @@ var error55 = () => { json_string: "\u062C\u06D2 \u0627\u06CC\u0633 \u0627\u0648 \u0627\u06CC\u0646 \u0633\u0679\u0631\u0646\u06AF", e164: "\u0627\u06CC 164 \u0646\u0645\u0628\u0631", credit_card: "\u06A9\u0631\u06CC\u0688\u0679 \u06A9\u0627\u0631\u0688 \u0646\u0645\u0628\u0631", + currency_code: "\u06A9\u0631\u0646\u0633\u06CC \u06A9\u0648\u0688", + iban: "IBAN", jwt: "\u062C\u06D2 \u0688\u0628\u0644\u06CC\u0648 \u0679\u06CC", template_literal: "\u0627\u0646 \u067E\u0679" }; @@ -18825,12 +19210,12 @@ var error55 = () => { }; function ur_default() { return { - localeError: error55() + localeError: error56() }; } // node_modules/zod/v4/locales/uz.js -var error56 = () => { +var error57 = () => { const Sizable = { string: { unit: "belgi", verb: "bo\u2018lishi kerak" }, file: { unit: "bayt", verb: "bo\u2018lishi kerak" }, @@ -18870,6 +19255,8 @@ var error56 = () => { json_string: "JSON satr", e164: "E.164 raqam", credit_card: "kredit karta raqami", + currency_code: "valyuta kodi", + iban: "IBAN", jwt: "JWT", template_literal: "kirish" }; @@ -18937,12 +19324,12 @@ var error56 = () => { }; function uz_default() { return { - localeError: error56() + localeError: error57() }; } // node_modules/zod/v4/locales/vi.js -var error57 = () => { +var error58 = () => { const Sizable = { string: { unit: "k\xFD t\u1EF1", verb: "c\xF3" }, file: { unit: "byte", verb: "c\xF3" }, @@ -18982,6 +19369,8 @@ var error57 = () => { json_string: "chu\u1ED7i JSON", e164: "s\u1ED1 E.164", credit_card: "s\u1ED1 th\u1EBB t\xEDn d\u1EE5ng", + currency_code: "m\xE3 ti\u1EC1n t\u1EC7", + iban: "IBAN", jwt: "JWT", template_literal: "\u0111\u1EA7u v\xE0o" }; @@ -19049,12 +19438,12 @@ var error57 = () => { }; function vi_default() { return { - localeError: error57() + localeError: error58() }; } // node_modules/zod/v4/locales/zh-CN.js -var error58 = () => { +var error59 = () => { const Sizable = { string: { unit: "\u5B57\u7B26", verb: "\u5305\u542B" }, file: { unit: "\u5B57\u8282", verb: "\u5305\u542B" }, @@ -19094,6 +19483,8 @@ var error58 = () => { json_string: "JSON\u5B57\u7B26\u4E32", e164: "E.164\u53F7\u7801", credit_card: "\u4FE1\u7528\u5361\u53F7", + currency_code: "\u8D27\u5E01\u4EE3\u7801", + iban: "IBAN", jwt: "JWT", template_literal: "\u8F93\u5165" }; @@ -19162,12 +19553,12 @@ var error58 = () => { }; function zh_CN_default() { return { - localeError: error58() + localeError: error59() }; } // node_modules/zod/v4/locales/zh-TW.js -var error59 = () => { +var error60 = () => { const Sizable = { string: { unit: "\u5B57\u5143", verb: "\u64C1\u6709" }, file: { unit: "\u4F4D\u5143\u7D44", verb: "\u64C1\u6709" }, @@ -19207,6 +19598,8 @@ var error59 = () => { json_string: "JSON \u5B57\u4E32", e164: "E.164 \u6578\u503C", credit_card: "\u4FE1\u7528\u5361\u865F", + currency_code: "\u8CA8\u5E63\u4EE3\u78BC", + iban: "IBAN", jwt: "JWT", template_literal: "\u8F38\u5165" }; @@ -19273,12 +19666,12 @@ var error59 = () => { }; function zh_TW_default() { return { - localeError: error59() + localeError: error60() }; } // node_modules/zod/v4/locales/yo.js -var error60 = () => { +var error61 = () => { const Sizable = { string: { unit: "\xE0mi", verb: "n\xED" }, file: { unit: "bytes", verb: "n\xED" }, @@ -19318,6 +19711,8 @@ var error60 = () => { json_string: "\u1ECD\u0300r\u1ECD\u0300 JSON", e164: "n\u1ECD\u0301mb\xE0 E.164", credit_card: "n\u1ECDmba kaadi gbese", + currency_code: "koodu ow\xF3", + iban: "IBAN", jwt: "JWT", template_literal: "\u1EB9\u0300r\u1ECD \xECb\xE1w\u1ECDl\xE9" }; @@ -19384,7 +19779,7 @@ var error60 = () => { }; function yo_default() { return { - localeError: error60() + localeError: error61() }; } @@ -19464,31 +19859,8 @@ function compileValidator(schema, parser) { function compile(schema, options) { try { const parser = compileFn(schema); - const clone2 = clone(schema); - const liveRun = schema._zod.run; - const originalRun = liveRun.__originalRun ?? liveRun; - const wrapped = (payload, ctx) => { - if (ctx?.async || ctx?.direction === "backward" || ctx?.skipChecks || ctx?.[FALLBACK_FLAG]) { - return originalRun(payload, ctx); - } - if (ctx && isBackEdge(ctx, payload.value)) { - return originalRun(payload, ctx); - } - const out = parser(payload.value); - if (out !== INVALID) { - payload.value = out; - return payload; - } - if (ctx) - ctx[FALLBACK_FLAG] = true; - return originalRun(payload, ctx); - }; - wrapped.__originalRun = originalRun; - clone2._zod.bag.fallbackRun = originalRun; + const clone2 = withParser(schema, parser); clone2._zod.bag.validator = compileValidator(schema, parser); - clone2._zod.run = wrapped; - if (!liveRun.__originalRun) - installCompiledUserMethods(clone2, schema, parser); return clone2; } catch (err) { if (options?.strict) @@ -19496,6 +19868,37 @@ function compile(schema, options) { return schema; } } +function withParser(schema, parser) { + if (isRecursiveSchema(schema)) { + throw new ZodCompileUnsupportedError("a schema whose subtree contains a reference cycle"); + } + const clone2 = clone(schema); + const liveRun = schema._zod.run; + const originalRun = liveRun.__originalRun ?? liveRun; + const wrapped = (payload, ctx) => { + if (ctx?.async || ctx?.direction === "backward" || ctx?.skipChecks || ctx?.[FALLBACK_FLAG]) { + return originalRun(payload, ctx); + } + if (ctx && isBackEdge(ctx, payload.value)) { + return originalRun(payload, ctx); + } + const out = parser(payload.value); + if (out !== INVALID) { + payload.value = out; + return payload; + } + if (ctx) + ctx[FALLBACK_FLAG] = true; + return originalRun(payload, ctx); + }; + wrapped.__originalRun = originalRun; + clone2._zod.bag.fallbackRun = originalRun; + clone2._zod.bag.validator = parser; + clone2._zod.run = wrapped; + if (!liveRun.__originalRun) + installCompiledUserMethods(clone2, schema, parser); + return clone2; +} function installCompiledUserMethods(target, source, parser) { const targetAny = target; const sourceAny = source; @@ -19532,7 +19935,8 @@ function compileFn(schema, options) { const ctx = { constants: /* @__PURE__ */ new Map(), constantCounter: 0, - varCounter: 0 + varCounter: 0, + definite: true }; const doc = new Doc(["input"]); const outputAccessor = generateCheck(doc, ctx, schema, "input", !options?.assertOnly); @@ -19556,6 +19960,7 @@ ${code} if (options?.debug) { fn.code = fullCode; } + fn.definite = ctx.definite; return fn; } function addConstant(ctx, value) { @@ -19567,6 +19972,10 @@ function addConstant(ctx, value) { ctx.constants.set(name, value); return name; } +function addUserConstant(ctx, fn) { + ctx.definite = false; + return addConstant(ctx, fn); +} function newVar(ctx) { return `v${ctx.varCounter++}`; } @@ -19599,6 +20008,7 @@ function compileChild(doc, ctx, schema, accessor, needsValue = true) { } } function emitRuntimeIsland(doc, ctx, schema, accessor) { + ctx.definite = false; const schemaConst = addConstant(ctx, schema); const runConst = addConstant(ctx, runtimeRun); const outVar = newVar(ctx); @@ -19679,6 +20089,9 @@ function generateChecks(doc, ctx, schema, accessor) { case "property": generatePropertyCheck(doc, ctx, def, currentAccessor); break; + case "properties": + generatePropertiesChecks(doc, ctx, def, currentAccessor); + break; case "overwrite": { const newAccessor = newVar(ctx); generateOverwriteCheck(doc, ctx, check2, currentAccessor, newAccessor); @@ -19787,6 +20200,19 @@ function generateMimeTypeCheck(doc, ctx, def, accessor) { doc.write(`if (!${mimeSet}.has(${accessor}.type)) return INVALID;`); } } +function generatePropertiesChecks(doc, ctx, def, accessor) { + if (def.when) { + throw new ZodCompileUnsupportedError(`check with a custom "when" condition`); + } + doc.write(`if (${accessor} == null) return INVALID;`); + const shape = def.shape; + for (const key of Reflect.ownKeys(shape)) { + const keyExpr = typeof key === "symbol" ? addConstant(ctx, key) : esc(key); + const inputVar = newVar(ctx); + doc.write(`const ${inputVar} = ${accessor}[${keyExpr}];`); + compileChild(doc, ctx, shape[key], inputVar, false); + } +} function generatePropertyCheck(doc, ctx, def, accessor) { const propAccessor = `${accessor}[${JSON.stringify(def.property)}]`; generateCheck(doc, ctx, def.schema, propAccessor); @@ -19814,7 +20240,7 @@ function generateCustomRefineCheck(doc, ctx, check2, accessor) { if (isAsyncFunction(def.fn)) { throw new ZodCompileAsyncError("z.compile: async .refine() predicates are not supported"); } - const fnConst = addConstant(ctx, def.fn); + const fnConst = addUserConstant(ctx, def.fn); const throwAsyncConst = addConstant(ctx, throwAsync); const resVar = newVar(ctx); doc.write(`const ${resVar} = ${fnConst}(${accessor});`); @@ -19834,7 +20260,7 @@ function generateCustomRefineCheck(doc, ctx, check2, accessor) { throwAsync(); return fakePayload.issues.length === 0 ? fakePayload.value : INVALID; }; - const helperConst = addConstant(ctx, helperFn); + const helperConst = addUserConstant(ctx, helperFn); const outVar = newVar(ctx); doc.write(`const ${outVar} = ${helperConst}(${accessor});`); doc.write(`if (${outVar} === INVALID) return INVALID;`); @@ -19868,7 +20294,7 @@ var PATTERN_IS_COMPLETE = /* @__PURE__ */ new Set([ "uuid", "xid" ]); -function generateStringFormatCheck(doc, ctx, def, accessor) { +function generateStringFormatCheck(doc, ctx, def, accessor, needsValue = true) { const fmt = def.format; if (fmt === "base64") { const validator = addConstant(ctx, isValidBase64); @@ -19901,9 +20327,14 @@ function generateStringFormatCheck(doc, ctx, def, accessor) { doc.write(`if (!${validator}(${accessor})) return INVALID;`); return accessor; } + if (fmt === "iban") { + const validator = addConstant(ctx, isValidIBAN); + doc.write(`if (!${validator}(${accessor})) return INVALID;`); + return accessor; + } const formatDef = def; if (fmt === "url" || fmt === "httpurl" || formatDef.normalize || formatDef.hostname !== void 0 || formatDef.protocol !== void 0) { - const parseConst = addConstant(ctx, parseURLObject); + const parseConst = addConstant(ctx, validateURL); const defConst = addConstant(ctx, def); const trimVar = newVar(ctx); const urlVar = newVar(ctx); @@ -19918,6 +20349,8 @@ function generateStringFormatCheck(doc, ctx, def, accessor) { const protocolConst = addConstant(ctx, urlProtocolOk); doc.write(`if (!${protocolConst}(${urlVar}, ${defConst}.protocol)) return INVALID;`); } + if (!needsValue) + return null; const outputVar = newVar(ctx); const outputExpr = formatDef.normalize ? `${urlVar}.href` : `${addConstant(ctx, stripTabAndNewline)}(${trimVar})`; doc.write(`const ${outputVar} = ${outputExpr};`); @@ -19977,7 +20410,7 @@ function generateCheck(doc, ctx, schema, accessor, needsValue = true) { let typeAccessor; switch (type) { case "string": - typeAccessor = generateStringCheck(doc, ctx, schema, accessor); + typeAccessor = generateStringCheck(doc, ctx, schema, accessor, buildsValue); break; case "number": typeAccessor = generateNumberCheck(doc, schema, accessor); @@ -20098,12 +20531,12 @@ function generateCheck(doc, ctx, schema, accessor, needsValue = true) { return null; return generateChecks(doc, ctx, schema, typeAccessor); } -function generateStringCheck(doc, ctx, schema, accessor) { +function generateStringCheck(doc, ctx, schema, accessor, needsValue = true) { doc.write(`if (typeof ${accessor} !== "string") return INVALID;`); const def = schema._zod.def; if (def.format === void 0) return accessor; - return generateStringFormatCheck(doc, ctx, def, accessor); + return generateStringFormatCheck(doc, ctx, def, accessor, needsValue); } function generateNumberCheck(doc, schema, accessor) { doc.write(`if (typeof ${accessor} !== "number" || !Number.isFinite(${accessor})) return INVALID;`); @@ -20221,7 +20654,7 @@ function generateObjectCheck(doc, ctx, schema, accessor, buildsValue = true) { } } const outputVar = newVar(ctx); - const hasConditionalKeys = allKeys.some((k2) => mayOutputUndefined(propShape[k2]) || dropsWhenAbsent(propShape[k2])); + const hasConditionalKeys = allKeys.some((k2) => mayOmitUndefined(propShape[k2]) || dropsWhenAbsent(propShape[k2])); if (!buildsValue) { if (unknownKeysMode === "schema") { const knownSet = keys.length > 0 ? addConstant(ctx, new Set(keys)) : null; @@ -20248,7 +20681,7 @@ function generateObjectCheck(doc, ctx, schema, accessor, buildsValue = true) { const out = propOutputs.get(k2); if (dropsWhenAbsent(propShape[k2])) { doc.write(`if (${kx} in ${accessor}) ${outputVar}[${kx}] = ${out};`); - } else if (mayOutputUndefined(propShape[k2])) { + } else if (mayOmitUndefined(propShape[k2])) { doc.write(`if (${out} !== undefined || ${kx} in ${accessor}) ${outputVar}[${kx}] = ${out};`); } else { doc.write(`${outputVar}[${kx}] = ${out};`); @@ -20381,6 +20814,9 @@ function fastPathAcceptsAbsence(schema) { function dropsWhenAbsent(schema) { return schema._zod.optin === "optional" && schema._zod.optout === "optional"; } +function mayOmitUndefined(schema) { + return (schema._zod.optin !== "defaulted" || schema._zod.optout === "optional") && mayOutputUndefined(schema); +} function mayOutputUndefined(schema) { const def = schema._zod.def; switch (def.type) { @@ -20723,6 +21159,7 @@ function literalEquality(ctx, accessor, value) { } function generateIntersectionCheck(doc, ctx, schema, accessor) { const def = schema._zod.def; + ctx.definite = false; const leftOutput = compileChild(doc, ctx, def.left, accessor); const rightOutput = compileChild(doc, ctx, def.right, accessor); const mergeConst = addConstant(ctx, mergeValues); @@ -20776,14 +21213,13 @@ function generateRecordCheck(doc, ctx, schema, accessor) { const keyIsBareString = keyDef.type === "string" && keyDef.format === void 0 && !keyDef.coerce && (keyDef.checks?.length ?? 0) === 0; if (!keyIsBareString) { const isLoose = def.mode === "loose"; - const keyFast = addConstant(ctx, compileFn(def.keyType)); + const keyFn = compileFn(def.keyType); + if (keyFn.definite === false) + ctx.definite = false; + const keyFast = addConstant(ctx, keyFn); const numericConst = addConstant(ctx, number); - const propIsEnumerableConst = addConstant(ctx, Object.prototype.propertyIsEnumerable); const outKeyVar = newVar(ctx); - doc.write(`for (const ${kVar} of Reflect.ownKeys(${accessor})) {`); - doc.indented((d2) => { - d2.write(`if (${kVar} === "__proto__") continue;`); - d2.write(`if (!${propIsEnumerableConst}.call(${accessor}, ${kVar})) continue;`); + emitOwnKeys(doc, ctx, accessor, kVar, (d2) => { d2.write(`let ${outKeyVar} = ${keyFast}(${kVar});`); d2.write(`if (${outKeyVar} === INVALID && typeof ${kVar} === "string" && ${numericConst}.test(${kVar})) ${outKeyVar} = ${keyFast}(Number(${kVar}));`); if (isLoose) { @@ -20797,21 +21233,39 @@ function generateRecordCheck(doc, ctx, schema, accessor) { const valOutput = compileChild(d2, ctx, def.valueType, valueVar); d2.write(`${outputVar}[${outKeyVar}] = ${valOutput};`); }); - doc.write(`}`); return outputVar; } - const propIsEnumerable = addConstant(ctx, Object.prototype.propertyIsEnumerable); - doc.write(`for (const ${kVar} of Reflect.ownKeys(${accessor})) {`); - doc.indented((d2) => { - d2.write(`if (${kVar} === "__proto__") continue;`); - d2.write(`if (!${propIsEnumerable}.call(${accessor}, ${kVar})) continue;`); - d2.write(`if (typeof ${kVar} !== "string") return INVALID;`); + emitOwnKeys(doc, ctx, accessor, kVar, (d2) => { d2.write(`const ${valVar} = ${accessor}[${kVar}];`); const valOutput = compileChild(d2, ctx, def.valueType, valVar); d2.write(`${outputVar}[${kVar}] = ${valOutput};`); + }, `return INVALID;`); + return outputVar; +} +function emitOwnKeys(doc, ctx, accessor, kVar, body, onSymbol) { + const propIsEnumerableConst = addConstant(ctx, Object.prototype.propertyIsEnumerable); + const symsVar = newVar(ctx); + const keysVar = newVar(ctx); + const iVar = newVar(ctx); + doc.write(`const ${symsVar} = Object.getOwnPropertySymbols(${accessor});`); + doc.write(`const ${keysVar} = Object.getOwnPropertyNames(${accessor});`); + doc.write(`for (let ${iVar} = 0; ${iVar} < ${keysVar}.length; ${iVar}++) {`); + doc.indented((d2) => { + d2.write(`const ${kVar} = ${keysVar}[${iVar}];`); + d2.write(`if (${kVar} === "__proto__" || !${propIsEnumerableConst}.call(${accessor}, ${kVar})) continue;`); + body(d2); + }); + doc.write(`}`); + doc.write(`for (let ${iVar} = 0; ${iVar} < ${symsVar}.length; ${iVar}++) {`); + doc.indented((d2) => { + d2.write(`const ${kVar} = ${symsVar}[${iVar}];`); + d2.write(`if (!${propIsEnumerableConst}.call(${accessor}, ${kVar})) continue;`); + if (onSymbol) + d2.write(onSymbol); + else + body(d2); }); doc.write(`}`); - return outputVar; } function literalPropertyKey(ctx, key) { if (typeof key === "string") @@ -20864,7 +21318,7 @@ function generateTemplateLiteralCheck(doc, ctx, schema, accessor) { } function generateLazyCheck(doc, ctx, schema, accessor) { const def = schema._zod.def; - const getterConst = addConstant(ctx, def.getter); + const getterConst = addUserConstant(ctx, def.getter); const cacheConst = addConstant(ctx, { parser: null }); doc.write(`if (!${cacheConst}.parser) {`); doc.indented((d2) => { @@ -20897,7 +21351,7 @@ function generatePipeCheck(doc, ctx, schema, accessor) { return INVALID; return fakePayload.issues.length === 0 ? result : INVALID; }; - const helperConst = addConstant(ctx, helperFn); + const helperConst = addUserConstant(ctx, helperFn); const transformedVar = newVar(ctx); doc.write(`const ${transformedVar} = ${helperConst}(${inputOutput});`); doc.write(`if (${transformedVar} === INVALID) return INVALID;`); @@ -20915,7 +21369,7 @@ function generateCustomCheck(doc, ctx, schema, accessor) { if (isAsyncFunction(def.fn)) { throw new ZodCompileAsyncError("z.compile: async custom predicates are not supported"); } - const fnConst = addConstant(ctx, def.fn); + const fnConst = addUserConstant(ctx, def.fn); const throwAsyncConst = addConstant(ctx, throwAsync); const resVar = newVar(ctx); doc.write(`const ${resVar} = ${fnConst}(${accessor});`); @@ -20948,7 +21402,7 @@ function generateCatchCheck(doc, ctx, schema, accessor) { }); doc.write(`})();`); const innerConst = addConstant(ctx, def.innerType); - const catchConst = addConstant(ctx, def.catchValue); + const catchConst = addUserConstant(ctx, def.catchValue); const catchHelperConst = addConstant(ctx, runtimeCatch); doc.write(`if (${outputVar} === INVALID) {`); doc.indented((d2) => { @@ -20972,7 +21426,7 @@ function generateTransformCheck(doc, ctx, schema, accessor) { return INVALID; return fakePayload.issues.length === 0 ? result : INVALID; }; - const helperConst = addConstant(ctx, helperFn); + const helperConst = addUserConstant(ctx, helperFn); const outputVar = newVar(ctx); doc.write(`const ${outputVar} = ${helperConst}(${accessor});`); doc.write(`if (${outputVar} === INVALID) return INVALID;`); @@ -20982,20 +21436,18 @@ function generateTransformCheck(doc, ctx, schema, accessor) { } // node_modules/zod/v4/core/api.js +function snapshotChecks(def) { + if (def.checks) + def.checks = [...def.checks]; + return def; +} // @__NO_SIDE_EFFECTS__ function _string(Class2, params) { - return new Class2({ - type: "string", - ...normalizeParams(params) - }); + return new Class2(snapshotChecks({ type: "string", ...normalizeParams(params) })); } // @__NO_SIDE_EFFECTS__ function _coercedString(Class2, params) { - return new Class2({ - type: "string", - coerce: true, - ...normalizeParams(params) - }); + return new Class2(snapshotChecks({ type: "string", coerce: true, ...normalizeParams(params) })); } // @__NO_SIDE_EFFECTS__ function _email(Class2, params) { @@ -21231,6 +21683,16 @@ function _creditCard(Class2, params) { }); } // @__NO_SIDE_EFFECTS__ +function _iban(Class2, params) { + return new Class2({ + type: "string", + format: "iban", + check: "string_format", + abort: false, + ...normalizeParams(params) + }); +} +// @__NO_SIDE_EFFECTS__ function _jwt(Class2, params) { return new Class2({ type: "string", @@ -21289,20 +21751,11 @@ function _isoDuration(Class2, params) { } // @__NO_SIDE_EFFECTS__ function _number(Class2, params) { - return new Class2({ - type: "number", - checks: [], - ...normalizeParams(params) - }); + return new Class2(snapshotChecks({ type: "number", checks: [], ...normalizeParams(params) })); } // @__NO_SIDE_EFFECTS__ function _coercedNumber(Class2, params) { - return new Class2({ - type: "number", - coerce: true, - checks: [], - ...normalizeParams(params) - }); + return new Class2(snapshotChecks({ type: "number", coerce: true, checks: [], ...normalizeParams(params) })); } // @__NO_SIDE_EFFECTS__ function _int(Class2, params) { @@ -21644,8 +22097,12 @@ function _property(property, schema, params) { }); } // @__NO_SIDE_EFFECTS__ -function _properties(shape) { - return Object.entries(shape).map(([property, schema]) => new $ZodCheckProperty({ check: "property", property, schema })); +function _properties(shape, params) { + return new $ZodCheckProperties({ + check: "properties", + shape, + ...normalizeParams(params) + }); } // @__NO_SIDE_EFFECTS__ function _mime(types, params) { @@ -22082,7 +22539,7 @@ function handleUnrepresentable(schema, ctx, json2, params, message) { Object.assign(json2, result); return true; } -function process2(schema, ctx, _params = { path: [], schemaPath: [] }) { +function processSchema(schema, ctx, _params = { path: [], schemaPath: [] }) { var _a3; const def = schema._zod.def; const seen = ctx.seen.get(schema); @@ -22121,7 +22578,7 @@ function process2(schema, ctx, _params = { path: [], schemaPath: [] }) { if (parent) { if (!result.ref) result.ref = parent; - process2(parent, ctx, params); + processSchema(parent, ctx, params); ctx.seen.get(parent).isParent = true; } } @@ -22228,7 +22685,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs. if (seen.count > 1) { if (ctx.reused === "ref") { extractToDef(entry); - continue; } } } @@ -22556,19 +23012,107 @@ function isTransforming(_schema, _ctx) { } var createToJSONSchemaMethod = (schema, processors = {}) => (params) => { const ctx = initializeContext({ ...params, processors }); - process2(schema, ctx); + processSchema(schema, ctx); extractDefs(ctx, schema); return finalize(ctx, schema); }; var createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => { const { libraryOptions, target } = params ?? {}; const ctx = initializeContext({ ...libraryOptions ?? {}, target, io, processors }); - process2(schema, ctx); + processSchema(schema, ctx); extractDefs(ctx, schema); return finalize(ctx, schema); }; // node_modules/zod/v4/core/json-schema-processors.js +var narrowMin = (agg, key, value) => { + if (agg[key] === void 0 || value > agg[key]) + agg[key] = value; +}; +var narrowMax = (agg, key, value) => { + if (agg[key] === void 0 || value < agg[key]) + agg[key] = value; +}; +var narrowBoth = (agg, value) => { + narrowMin(agg, "minimum", value); + narrowMax(agg, "maximum", value); +}; +var addDivisor = (agg, value) => { + agg.multipleOf ?? (agg.multipleOf = []); + if (!agg.multipleOf.includes(value)) + agg.multipleOf.push(value); +}; +var addPattern = (agg, pattern) => { + agg.patterns ?? (agg.patterns = /* @__PURE__ */ new Set()); + agg.patterns.add(pattern); +}; +var intersectMime = (agg, mime) => { + agg.mime = agg.mime ? agg.mime.filter((m2) => mime.includes(m2)) : [...mime]; +}; +var setFormat = (agg, format) => { + agg.format = format; + if (format.includes("int")) + agg.isInt = true; +}; +var minContributor = (agg, def) => narrowMin(agg, "minimum", def.minimum); +var maxContributor = (agg, def) => narrowMax(agg, "maximum", def.maximum); +var formatContributor = (ranges) => (agg, def) => { + setFormat(agg, def.format); + const [minimum, maximum] = ranges[def.format]; + narrowMin(agg, "minimum", minimum); + narrowMax(agg, "maximum", maximum); +}; +var contributors = { + greater_than: (agg, def) => narrowMin(agg, def.inclusive ? "minimum" : "exclusiveMinimum", def.value), + less_than: (agg, def) => narrowMax(agg, def.inclusive ? "maximum" : "exclusiveMaximum", def.value), + multiple_of: (agg, def) => addDivisor(agg, def.value), + number_format: formatContributor(NUMBER_FORMAT_RANGES), + bigint_format: formatContributor(BIGINT_FORMAT_RANGES), + min_length: minContributor, + max_length: maxContributor, + length_equals: (agg, def) => narrowBoth(agg, def.length), + min_size: minContributor, + max_size: maxContributor, + size_equals: (agg, def) => narrowBoth(agg, def.size), + string_format: (agg, def) => { + setFormat(agg, def.format); + if (def.pattern) + addPattern(agg, def.pattern); + if (def.format === "base64" || def.format === "base64url") + agg.contentEncoding = def.format; + if (def.local || def.precision === -1) + agg.laxFormat = true; + }, + mime_type: (agg, def) => intersectMime(agg, def.mime) +}; +function aggregateChecks(schema) { + const agg = {}; + const def = schema._zod.def; + const list = schema._zod.traits.has("$ZodCheck") ? [schema, ...def.checks ?? []] : def.checks ?? []; + for (const ch of list) + contributors[ch._zod.def.check]?.(agg, ch._zod.def); + const bag = schema._zod.bag; + if (bag.minimum !== void 0) + narrowMin(agg, "minimum", bag.minimum); + if (bag.exclusiveMinimum !== void 0) + narrowMin(agg, "exclusiveMinimum", bag.exclusiveMinimum); + if (bag.maximum !== void 0) + narrowMax(agg, "maximum", bag.maximum); + if (bag.exclusiveMaximum !== void 0) + narrowMax(agg, "exclusiveMaximum", bag.exclusiveMaximum); + if (bag.multipleOf !== void 0) + addDivisor(agg, bag.multipleOf); + if (bag.format !== void 0) { + agg.format ?? (agg.format = bag.format); + if (bag.format.includes("int")) + agg.isInt = true; + } + if (bag.mime) + intersectMime(agg, bag.mime); + for (const pattern of bag.patterns ?? []) + addPattern(agg, pattern); + return agg; +} var formatMap = { guid: "uuid", url: "uri", @@ -22577,10 +23121,15 @@ var formatMap = { regex: "" // do not set }; +var exactPatterns = /* @__PURE__ */ new Map([ + [base64Charset, base64], + [base64urlCharset, base64url] +]); +var exactPattern = (p) => exactPatterns.get(p) ?? p; var stringProcessor = (schema, ctx, _json, _params) => { const json2 = _json; json2.type = "string"; - const { minimum, maximum, format, patterns, contentEncoding, laxFormat } = schema._zod.bag; + const { minimum, maximum, format, patterns, contentEncoding, laxFormat } = aggregateChecks(schema); if (typeof minimum === "number") json2.minLength = minimum; if (typeof maximum === "number") @@ -22596,7 +23145,7 @@ var stringProcessor = (schema, ctx, _json, _params) => { if (contentEncoding) json2.contentEncoding = contentEncoding; if (patterns && patterns.size > 0) { - const patternList = [...patterns]; + const patternList = [...patterns].map(exactPattern); if (patternList.length === 1) json2.pattern = patternList[0].source; else if (patternList.length > 1) { @@ -22611,11 +23160,8 @@ var stringProcessor = (schema, ctx, _json, _params) => { }; var numberProcessor = (schema, ctx, _json, params) => { const json2 = _json; - const { minimum, maximum, format, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag; - if (typeof format === "string" && format.includes("int")) - json2.type = "integer"; - else - json2.type = "number"; + const { minimum, maximum, multipleOf, exclusiveMaximum, exclusiveMinimum, isInt } = aggregateChecks(schema); + json2.type = isInt ? "integer" : "number"; const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY); const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY); const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0"; @@ -22639,11 +23185,19 @@ var numberProcessor = (schema, ctx, _json, params) => { } else if (typeof maximum === "number") { json2.maximum = maximum; } - if (typeof multipleOf === "number") { - if (Number.isFinite(multipleOf) && multipleOf !== 0) - json2.multipleOf = Math.abs(multipleOf); - else - handleUnrepresentable(schema, ctx, json2, params, `A multipleOf divisor of ${multipleOf} cannot be represented in JSON Schema`); + if (multipleOf) { + const divisors = /* @__PURE__ */ new Set(); + for (const divisor of multipleOf) { + if (Number.isFinite(divisor) && divisor !== 0) + divisors.add(Math.abs(divisor)); + else + handleUnrepresentable(schema, ctx, json2, params, `A multipleOf divisor of ${divisor} cannot be represented in JSON Schema`); + } + const [first, ...rest] = divisors; + if (first !== void 0) + json2.multipleOf = first; + if (rest.length) + json2.allOf = [...json2.allOf ?? [], ...rest.map((m2) => ({ multipleOf: m2 }))]; } }; var booleanProcessor = (_schema, _ctx, json2, _params) => { @@ -22746,27 +23300,22 @@ var templateLiteralProcessor = (schema, _ctx, json2, _params) => { }; var fileProcessor = (schema, _ctx, json2, _params) => { const _json = json2; - const file2 = { - type: "string", - format: "binary", - contentEncoding: "binary" - }; - const { minimum, maximum, mime } = schema._zod.bag; + _json.type = "string"; + _json.format = "binary"; + _json.contentEncoding = "binary"; + const { minimum, maximum, mime } = aggregateChecks(schema); if (minimum !== void 0) - file2.minLength = minimum; + _json.minLength = minimum; if (maximum !== void 0) - file2.maxLength = maximum; - if (mime) { - if (mime.length === 1) { - file2.contentMediaType = mime[0]; - Object.assign(_json, file2); - } else { - Object.assign(_json, file2); - _json.anyOf = mime.map((m2) => ({ contentMediaType: m2 })); - } - } else { - Object.assign(_json, file2); - } + _json.maxLength = maximum; + if (!mime) + return; + if (mime.length === 0) + _json.not = {}; + else if (mime.length === 1) + _json.contentMediaType = mime[0]; + else + _json.anyOf = mime.map((m2) => ({ contentMediaType: m2 })); }; var successProcessor = (_schema, _ctx, json2, _params) => { json2.type = "boolean"; @@ -22789,13 +23338,13 @@ var setProcessor = (schema, ctx, json2, params) => { var arrayProcessor = (schema, ctx, _json, params) => { const json2 = _json; const def = schema._zod.def; - const { minimum, maximum } = schema._zod.bag; + const { minimum, maximum } = aggregateChecks(schema); if (typeof minimum === "number") json2.minItems = minimum; if (typeof maximum === "number") json2.maxItems = maximum; json2.type = "array"; - json2.items = process2(def.element, ctx, { + json2.items = processSchema(def.element, ctx, { ...params, path: [...params.path, "items"] }); @@ -22821,22 +23370,20 @@ var objectProcessor = (schema, ctx, _json, params) => { json2.type = "object"; json2.properties = {}; for (const key in shape) { - assignProp(json2.properties, key, process2(shape[key], ctx, { + assignProp(json2.properties, key, processSchema(shape[key], ctx, { ...params, path: [...params.path, "properties", key] })); } - const allKeys = new Set(Object.keys(shape)); - const requiredKeys = new Set([...allKeys].filter((key) => { + const requiredKeys = []; + for (const key of Object.keys(shape)) { const field = def.shape[key]; - if (ctx.io === "input") { - return inputOptin(field) === void 0; - } else { - return field._zod.optout === void 0; + if (ctx.io === "input" ? inputOptin(field) === void 0 : field._zod.optout === void 0) { + requiredKeys.push(key); } - })); - if (requiredKeys.size > 0) { - json2.required = Array.from(requiredKeys); + } + if (requiredKeys.length > 0) { + json2.required = requiredKeys; } if (def.catchall?._zod.def.type === "never") { json2.additionalProperties = false; @@ -22844,7 +23391,7 @@ var objectProcessor = (schema, ctx, _json, params) => { if (ctx.io === "output") json2.additionalProperties = false; } else if (def.catchall) { - json2.additionalProperties = process2(def.catchall, ctx, { + json2.additionalProperties = processSchema(def.catchall, ctx, { ...params, path: [...params.path, "additionalProperties"] }); @@ -22853,7 +23400,7 @@ var objectProcessor = (schema, ctx, _json, params) => { var unionProcessor = (schema, ctx, json2, params) => { const def = schema._zod.def; const isExclusive = def.inclusive === false; - const options = def.options.map((x2, i) => process2(x2, ctx, { + const options = def.options.map((x2, i) => processSchema(x2, ctx, { ...params, path: [...params.path, isExclusive ? "oneOf" : "anyOf", i] })); @@ -22865,11 +23412,11 @@ var unionProcessor = (schema, ctx, json2, params) => { }; var intersectionProcessor = (schema, ctx, json2, params) => { const def = schema._zod.def; - const a = process2(def.left, ctx, { + const a = processSchema(def.left, ctx, { ...params, path: [...params.path, "allOf", 0] }); - const b2 = process2(def.right, ctx, { + const b2 = processSchema(def.right, ctx, { ...params, path: [...params.path, "allOf", 1] }); @@ -22887,11 +23434,11 @@ var tupleProcessor = (schema, ctx, _json, params) => { json2.type = "array"; const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items"; const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems"; - const prefixItems = def.items.map((x2, i) => process2(x2, ctx, { + const prefixItems = def.items.map((x2, i) => processSchema(x2, ctx, { ...params, path: [...params.path, prefixPath, i] })); - const rest = def.rest ? process2(def.rest, ctx, { + const rest = def.rest ? processSchema(def.rest, ctx, { ...params, path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []] }) : null; @@ -22939,7 +23486,7 @@ var tupleProcessor = (schema, ctx, _json, params) => { if (isClosed) json2.maxItems = maxItems; } - const { minimum, maximum } = schema._zod.bag; + const { minimum, maximum } = aggregateChecks(schema); if (typeof minimum === "number") json2.minItems = minimum; if (typeof maximum === "number") @@ -23013,20 +23560,19 @@ var recordProcessor = (schema, ctx, _json, params) => { const def = schema._zod.def; json2.type = "object"; const keyType = def.keyType; - const keyBag = keyType._zod.bag; - const patterns = keyBag?.patterns; + const patterns = aggregateChecks(keyType).patterns; if (def.mode === "loose" && patterns && patterns.size > 0) { - const valueSchema = process2(def.valueType, ctx, { + const valueSchema = processSchema(def.valueType, ctx, { ...params, path: [...params.path, "patternProperties", "*"] }); json2.patternProperties = {}; for (const pattern of patterns) { - assignProp(json2.patternProperties, pattern.source, valueSchema); + assignProp(json2.patternProperties, exactPattern(pattern).source, valueSchema); } } else { if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") { - json2.propertyNames = process2(def.keyType, ctx, { + json2.propertyNames = processSchema(def.keyType, ctx, { ...params, path: [...params.path, "propertyNames"] }); @@ -23038,7 +23584,7 @@ var recordProcessor = (schema, ctx, _json, params) => { } pending.push(schema); } - json2.additionalProperties = process2(def.valueType, ctx, { + json2.additionalProperties = processSchema(def.valueType, ctx, { ...params, path: [...params.path, "additionalProperties"] }); @@ -23054,7 +23600,7 @@ var recordProcessor = (schema, ctx, _json, params) => { }; var nullableProcessor = (schema, ctx, json2, params) => { const def = schema._zod.def; - const inner = process2(def.innerType, ctx, params); + const inner = processSchema(def.innerType, ctx, params); const seen = ctx.seen.get(schema); if (ctx.target === "openapi-3.0") { seen.ref = def.innerType; @@ -23065,7 +23611,7 @@ var nullableProcessor = (schema, ctx, json2, params) => { }; var nonoptionalProcessor = (schema, ctx, _json, params) => { const def = schema._zod.def; - process2(def.innerType, ctx, params); + processSchema(def.innerType, ctx, params); const seen = ctx.seen.get(schema); seen.ref = def.innerType; }; @@ -23085,7 +23631,7 @@ function serializeDefaultValue(value, schema, ctx, json2, params) { } var defaultProcessor = (schema, ctx, json2, params) => { const def = schema._zod.def; - process2(def.innerType, ctx, params); + processSchema(def.innerType, ctx, params); const seen = ctx.seen.get(schema); seen.ref = def.innerType; const value = serializeDefaultValue(def.defaultValue, schema, ctx, json2, params); @@ -23094,7 +23640,7 @@ var defaultProcessor = (schema, ctx, json2, params) => { }; var prefaultProcessor = (schema, ctx, json2, params) => { const def = schema._zod.def; - process2(def.innerType, ctx, params); + processSchema(def.innerType, ctx, params); const seen = ctx.seen.get(schema); seen.ref = def.innerType; if (ctx.io !== "input") @@ -23105,7 +23651,7 @@ var prefaultProcessor = (schema, ctx, json2, params) => { }; var catchProcessor = (schema, ctx, json2, params) => { const def = schema._zod.def; - process2(def.innerType, ctx, params); + processSchema(def.innerType, ctx, params); const seen = ctx.seen.get(schema); seen.ref = def.innerType; let catchValue; @@ -23121,32 +23667,32 @@ var pipeProcessor = (schema, ctx, _json, params) => { const def = schema._zod.def; const inIsTransform = def.in._zod.traits.has("$ZodTransform"); const innerType = ctx.io === "input" ? inIsTransform ? def.out : def.in : def.out; - process2(innerType, ctx, params); + processSchema(innerType, ctx, params); const seen = ctx.seen.get(schema); seen.ref = innerType; }; var readonlyProcessor = (schema, ctx, json2, params) => { const def = schema._zod.def; - process2(def.innerType, ctx, params); + processSchema(def.innerType, ctx, params); const seen = ctx.seen.get(schema); seen.ref = def.innerType; json2.readOnly = true; }; var promiseProcessor = (schema, ctx, _json, params) => { const def = schema._zod.def; - process2(def.innerType, ctx, params); + processSchema(def.innerType, ctx, params); const seen = ctx.seen.get(schema); seen.ref = def.innerType; }; var optionalProcessor = (schema, ctx, _json, params) => { const def = schema._zod.def; - process2(def.innerType, ctx, params); + processSchema(def.innerType, ctx, params); const seen = ctx.seen.get(schema); seen.ref = def.innerType; }; var lazyProcessor = (schema, ctx, _json, params) => { const innerType = schema._zod.innerType; - process2(innerType, ctx, params); + processSchema(innerType, ctx, params); const seen = ctx.seen.get(schema); seen.ref = innerType; }; @@ -23198,7 +23744,7 @@ function toJSONSchema(input2, params) { const defs = {}; for (const entry of registry2._idmap.entries()) { const [_2, schema] = entry; - process2(schema, ctx2); + processSchema(schema, ctx2); } const schemas = {}; const external = { @@ -23221,7 +23767,7 @@ function toJSONSchema(input2, params) { return { schemas }; } const ctx = initializeContext({ ...params, processors: allProcessors }); - process2(input2, ctx); + processSchema(input2, ctx); extractDefs(ctx, input2); return finalize(ctx, input2); } @@ -23280,7 +23826,7 @@ var JSONSchemaGenerator = class { * This must be called before emit(). */ process(schema, _params = { path: [], schemaPath: [] }) { - return process2(schema, this.ctx, _params); + return processSchema(schema, this.ctx, _params); } /** * Emit the final JSON Schema after processing. @@ -23479,24 +24025,24 @@ function safeParse2(schema, data) { function getObjectShape(schema) { if (!schema) return void 0; - let rawShape; + let rawShape2; if (isZ4Schema(schema)) { const v4Schema = schema; - rawShape = v4Schema._zod?.def?.shape; + rawShape2 = v4Schema._zod?.def?.shape; } else { const v3Schema = schema; - rawShape = v3Schema.shape; + rawShape2 = v3Schema.shape; } - if (!rawShape) + if (!rawShape2) return void 0; - if (typeof rawShape === "function") { + if (typeof rawShape2 === "function") { try { - return rawShape(); + return rawShape2(); } catch { return void 0; } } - return rawShape; + return rawShape2; } function getLiteralValue(schema) { if (isZ4Schema(schema)) { @@ -23531,6 +24077,7 @@ __export(external_exports, { $brand: () => $brand, $input: () => $input, $output: () => $output, + INVALID: () => INVALID, NEVER: () => NEVER, TimePrecision: () => TimePrecision, ZodAny: () => ZodAny, @@ -23564,12 +24111,14 @@ __export(external_exports, { ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind, ZodFunction: () => ZodFunction, ZodGUID: () => ZodGUID, + ZodIBAN: () => ZodIBAN, ZodIPv4: () => ZodIPv4, ZodIPv6: () => ZodIPv6, ZodISODate: () => ZodISODate, ZodISODateTime: () => ZodISODateTime, ZodISODuration: () => ZodISODuration, ZodISOTime: () => ZodISOTime, + ZodInstanceOf: () => ZodInstanceOf, ZodIntersection: () => ZodIntersection, ZodIssueCode: () => ZodIssueCode, ZodJWT: () => ZodJWT, @@ -23635,6 +24184,7 @@ __export(external_exports, { creditCard: () => creditCard2, cuid: () => cuid3, cuid2: () => cuid22, + currencyCode: () => currencyCode2, custom: () => custom, date: () => date2, decode: () => decode2, @@ -23667,6 +24217,7 @@ __export(external_exports, { hex: () => hex2, hostname: () => hostname2, httpUrl: () => httpUrl, + iban: () => iban2, includes: () => _includes, input: () => input, instanceof: () => _instanceof, @@ -23778,6 +24329,7 @@ __export(external_exports, { validate: () => validate, validateAsync: () => validateAsync, void: () => _void2, + withParser: () => withParser, xid: () => xid2, xor: () => xor }); @@ -23812,12 +24364,14 @@ __export(schemas_exports2, { ZodFile: () => ZodFile, ZodFunction: () => ZodFunction, ZodGUID: () => ZodGUID, + ZodIBAN: () => ZodIBAN, ZodIPv4: () => ZodIPv4, ZodIPv6: () => ZodIPv6, ZodISODate: () => ZodISODate, ZodISODateTime: () => ZodISODateTime, ZodISODuration: () => ZodISODuration, ZodISOTime: () => ZodISOTime, + ZodInstanceOf: () => ZodInstanceOf, ZodIntersection: () => ZodIntersection, ZodJWT: () => ZodJWT, ZodKSUID: () => ZodKSUID, @@ -23876,6 +24430,7 @@ __export(schemas_exports2, { creditCard: () => creditCard2, cuid: () => cuid3, cuid2: () => cuid22, + currencyCode: () => currencyCode2, custom: () => custom, date: () => date2, describe: () => describe2, @@ -23894,6 +24449,7 @@ __export(schemas_exports2, { hex: () => hex2, hostname: () => hostname2, httpUrl: () => httpUrl, + iban: () => iban2, instanceof: () => _instanceof, int: () => int, int32: () => int32, @@ -24196,6 +24752,12 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => { set spa(value) { util_exports.own(this, "spa", value); }, + validate(data, params) { + return validate(this, data, params); + }, + validateAsync(data, params) { + return validateAsync(this, data, params); + }, encode: function _encode2(data, params) { return encode2(this, data, params, { callee: _encode2 }); }, @@ -24232,61 +24794,65 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => { return this._zod.def; } }); -var _ZodString = /* @__PURE__ */ $constructor("_ZodString", (inst, def) => { - $ZodString.init(inst, def); - ZodType.init(inst, def); - inst._zod.processJSONSchema = (ctx, json2, params) => stringProcessor(inst, ctx, json2, params); - const bag = inst._zod.bag; - inst.format = bag.format ?? null; - inst.minLength = bag.minimum ?? null; - inst.maxLength = bag.maximum ?? null; -}, { - regex(...args) { - return this.check(_regex(...args)); - }, - includes(...args) { - return this.check(_includes(...args)); - }, - startsWith(...args) { - return this.check(_startsWith(...args)); - }, - endsWith(...args) { - return this.check(_endsWith(...args)); - }, - min(...args) { - return this.check(_minLength(...args)); +var _ZodString = /* @__PURE__ */ $constructor( + "_ZodString", + (inst, def) => { + $ZodString.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json2, params) => stringProcessor(inst, ctx, json2, params); }, - max(...args) { - return this.check(_maxLength(...args)); - }, - length(...args) { - return this.check(_length(...args)); - }, - nonempty(...args) { - return this.check(_minLength(1, ...args)); - }, - lowercase(params) { - return this.check(_lowercase(params)); - }, - uppercase(params) { - return this.check(_uppercase(params)); - }, - trim() { - return this.check(_trim()); - }, - normalize(...args) { - return this.check(_normalize(...args)); - }, - toLowerCase() { - return this.check(_toLowerCase()); - }, - toUpperCase() { - return this.check(_toUpperCase()); - }, - slugify() { - return this.check(_slugify()); - } -}); + /* @__PURE__ */ util_exports.derived({ + format: (inst) => aggregateChecks(inst).format ?? null, + minLength: (inst) => aggregateChecks(inst).minimum ?? null, + maxLength: (inst) => aggregateChecks(inst).maximum ?? null + }, { + regex(...args) { + return this.check(_regex(...args)); + }, + includes(...args) { + return this.check(_includes(...args)); + }, + startsWith(...args) { + return this.check(_startsWith(...args)); + }, + endsWith(...args) { + return this.check(_endsWith(...args)); + }, + min(...args) { + return this.check(_minLength(...args)); + }, + max(...args) { + return this.check(_maxLength(...args)); + }, + length(...args) { + return this.check(_length(...args)); + }, + nonempty(...args) { + return this.check(_minLength(1, ...args)); + }, + lowercase(params) { + return this.check(_lowercase(params)); + }, + uppercase(params) { + return this.check(_uppercase(params)); + }, + trim() { + return this.check(_trim()); + }, + normalize(...args) { + return this.check(_normalize(...args)); + }, + toLowerCase() { + return this.check(_toLowerCase()); + }, + toUpperCase() { + return this.check(_toUpperCase()); + }, + slugify() { + return this.check(_slugify()); + } + }) +); var ZodString = /* @__PURE__ */ $constructor("ZodString", (inst, def) => { $ZodString.init(inst, def); _ZodString.init(inst, def); @@ -24432,8 +24998,8 @@ function url(params) { } function httpUrl(params) { return _url(ZodURL, { - protocol: regexes_exports.httpProtocol, - hostname: regexes_exports.domain, + protocol: httpProtocol, + hostname: domain, ...util_exports.normalizeParams(params) }); } @@ -24549,6 +25115,13 @@ var ZodCreditCard = /* @__PURE__ */ $constructor("ZodCreditCard", (inst, def) => function creditCard2(params) { return _creditCard(ZodCreditCard, params); } +var ZodIBAN = /* @__PURE__ */ $constructor("ZodIBAN", (inst, def) => { + $ZodIBAN.init(inst, def); + ZodStringFormat.init(inst, def); +}); +function iban2(params) { + return _iban(ZodIBAN, params); +} var ZodJWT = /* @__PURE__ */ $constructor("ZodJWT", (inst, def) => { $ZodJWT.init(inst, def); ZodStringFormat.init(inst, def); @@ -24564,10 +25137,13 @@ function stringFormat(format, fnOrRegex, _params = {}) { return _stringFormat(ZodCustomStringFormat, format, fnOrRegex, _params); } function hostname2(_params) { - return _stringFormat(ZodCustomStringFormat, "hostname", regexes_exports.hostname, _params); + return _stringFormat(ZodCustomStringFormat, "hostname", hostname, _params); } function hex2(_params) { - return _stringFormat(ZodCustomStringFormat, "hex", regexes_exports.hex, _params); + return _stringFormat(ZodCustomStringFormat, "hex", hex, _params); +} +function currencyCode2(_params) { + return _stringFormat(ZodCustomStringFormat, "currency_code", currencyCode, _params); } function hash(alg, params) { const enc = params?.enc ?? "hex"; @@ -24577,63 +25153,76 @@ function hash(alg, params) { throw new Error(`Unrecognized hash format: ${format}`); return _stringFormat(ZodCustomStringFormat, format, regex, params); } -var ZodNumber = /* @__PURE__ */ $constructor("ZodNumber", (inst, def) => { - $ZodNumber.init(inst, def); - ZodType.init(inst, def); - inst._zod.processJSONSchema = (ctx, json2, params) => numberProcessor(inst, ctx, json2, params); - const bag = inst._zod.bag; - inst.minValue = Math.max(bag.minimum ?? Number.NEGATIVE_INFINITY, bag.exclusiveMinimum ?? Number.NEGATIVE_INFINITY) ?? null; - inst.maxValue = Math.min(bag.maximum ?? Number.POSITIVE_INFINITY, bag.exclusiveMaximum ?? Number.POSITIVE_INFINITY) ?? null; - inst.isInt = (bag.format ?? "").includes("int") || Number.isSafeInteger(bag.multipleOf ?? 0.5); - inst.isFinite = true; - inst.format = bag.format ?? null; -}, { - gt(value, params) { - return this.check(_gt(value, params)); - }, - gte(value, params) { - return this.check(_gte(value, params)); - }, - min(value, params) { - return this.check(_gte(value, params)); - }, - lt(value, params) { - return this.check(_lt(value, params)); - }, - lte(value, params) { - return this.check(_lte(value, params)); - }, - max(value, params) { - return this.check(_lte(value, params)); - }, - int(params) { - return this.check(int(params)); - }, - safe(params) { - return this.check(int(params)); +var ZodNumber = /* @__PURE__ */ $constructor( + "ZodNumber", + (inst, def) => { + $ZodNumber.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json2, params) => numberProcessor(inst, ctx, json2, params); + inst.isFinite = true; }, - positive(params) { - return this.check(_gt(0, params)); - }, - nonnegative(params) { - return this.check(_gte(0, params)); - }, - negative(params) { - return this.check(_lt(0, params)); - }, - nonpositive(params) { - return this.check(_lte(0, params)); - }, - multipleOf(value, params) { - return this.check(_multipleOf(value, params)); - }, - step(value, params) { - return this.check(_multipleOf(value, params)); - }, - finite() { - return this; - } -}); + /* @__PURE__ */ util_exports.derived({ + minValue: (inst) => { + const { minimum, exclusiveMinimum } = aggregateChecks(inst); + return Math.max(minimum ?? Number.NEGATIVE_INFINITY, exclusiveMinimum ?? Number.NEGATIVE_INFINITY); + }, + maxValue: (inst) => { + const { maximum, exclusiveMaximum } = aggregateChecks(inst); + return Math.min(maximum ?? Number.POSITIVE_INFINITY, exclusiveMaximum ?? Number.POSITIVE_INFINITY); + }, + isInt: (inst) => { + const { isInt, multipleOf } = aggregateChecks(inst); + return !!isInt || !!multipleOf?.some(Number.isSafeInteger); + }, + format: (inst) => aggregateChecks(inst).format ?? null + }, { + gt(value, params) { + return this.check(_gt(value, params)); + }, + gte(value, params) { + return this.check(_gte(value, params)); + }, + min(value, params) { + return this.check(_gte(value, params)); + }, + lt(value, params) { + return this.check(_lt(value, params)); + }, + lte(value, params) { + return this.check(_lte(value, params)); + }, + max(value, params) { + return this.check(_lte(value, params)); + }, + int(params) { + return this.check(int(params)); + }, + safe(params) { + return this.check(int(params)); + }, + positive(params) { + return this.check(_gt(0, params)); + }, + nonnegative(params) { + return this.check(_gte(0, params)); + }, + negative(params) { + return this.check(_lt(0, params)); + }, + nonpositive(params) { + return this.check(_lte(0, params)); + }, + multipleOf(value, params) { + return this.check(_multipleOf(value, params)); + }, + step(value, params) { + return this.check(_multipleOf(value, params)); + }, + finite() { + return this; + } + }) +); function number2(params) { return _number(ZodNumber, params); } @@ -24664,49 +25253,53 @@ var ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => { function boolean2(params) { return _boolean(ZodBoolean, params); } -var ZodBigInt = /* @__PURE__ */ $constructor("ZodBigInt", (inst, def) => { - $ZodBigInt.init(inst, def); - ZodType.init(inst, def); - inst._zod.processJSONSchema = (ctx, json2, params) => bigintProcessor(inst, ctx, json2, params); - const bag = inst._zod.bag; - inst.minValue = bag.minimum ?? null; - inst.maxValue = bag.maximum ?? null; - inst.format = bag.format ?? null; -}, { - gte(value, params) { - return this.check(_gte(value, params)); - }, - min(value, params) { - return this.check(_gte(value, params)); - }, - gt(value, params) { - return this.check(_gt(value, params)); - }, - lt(value, params) { - return this.check(_lt(value, params)); +var ZodBigInt = /* @__PURE__ */ $constructor( + "ZodBigInt", + (inst, def) => { + $ZodBigInt.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json2, params) => bigintProcessor(inst, ctx, json2, params); }, - lte(value, params) { - return this.check(_lte(value, params)); - }, - max(value, params) { - return this.check(_lte(value, params)); - }, - positive(params) { - return this.check(_gt(BigInt(0), params)); - }, - negative(params) { - return this.check(_lt(BigInt(0), params)); - }, - nonpositive(params) { - return this.check(_lte(BigInt(0), params)); - }, - nonnegative(params) { - return this.check(_gte(BigInt(0), params)); - }, - multipleOf(value, params) { - return this.check(_multipleOf(value, params)); - } -}); + /* @__PURE__ */ util_exports.derived({ + minValue: (inst) => aggregateChecks(inst).minimum ?? null, + maxValue: (inst) => aggregateChecks(inst).maximum ?? null, + format: (inst) => aggregateChecks(inst).format ?? null + }, { + gte(value, params) { + return this.check(_gte(value, params)); + }, + min(value, params) { + return this.check(_gte(value, params)); + }, + gt(value, params) { + return this.check(_gt(value, params)); + }, + lt(value, params) { + return this.check(_lt(value, params)); + }, + lte(value, params) { + return this.check(_lte(value, params)); + }, + max(value, params) { + return this.check(_lte(value, params)); + }, + positive(params) { + return this.check(_gt(BigInt(0), params)); + }, + negative(params) { + return this.check(_lt(BigInt(0), params)); + }, + nonpositive(params) { + return this.check(_lte(BigInt(0), params)); + }, + nonnegative(params) { + return this.check(_gte(BigInt(0), params)); + }, + multipleOf(value, params) { + return this.check(_multipleOf(value, params)); + } + }) +); function bigint2(params) { return _bigint(ZodBigInt, params); } @@ -24776,16 +25369,26 @@ var ZodVoid = /* @__PURE__ */ $constructor("ZodVoid", (inst, def) => { function _void2(params) { return _void(ZodVoid, params); } -var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => { - $ZodDate.init(inst, def); - ZodType.init(inst, def); - inst._zod.processJSONSchema = (ctx, json2, params) => dateProcessor(inst, ctx, json2, params); - inst.min = (value, params) => inst.check(_gte(value, params)); - inst.max = (value, params) => inst.check(_lte(value, params)); - const c = inst._zod.bag; - inst.minDate = c.minimum ? new Date(c.minimum) : null; - inst.maxDate = c.maximum ? new Date(c.maximum) : null; -}); +var ZodDate = /* @__PURE__ */ $constructor( + "ZodDate", + (inst, def) => { + $ZodDate.init(inst, def); + ZodType.init(inst, def); + inst._zod.processJSONSchema = (ctx, json2, params) => dateProcessor(inst, ctx, json2, params); + inst.min = (value, params) => inst.check(_gte(value, params)); + inst.max = (value, params) => inst.check(_lte(value, params)); + }, + /* @__PURE__ */ util_exports.derived({ + minDate: (inst) => { + const { minimum } = aggregateChecks(inst); + return minimum ? new Date(minimum) : null; + }, + maxDate: (inst) => { + const { maximum } = aggregateChecks(inst); + return maximum ? new Date(maximum) : null; + } + }, {}) +); function date2(params) { return _date(ZodDate, params); } @@ -24830,19 +25433,19 @@ var ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => { return _enum2(Object.keys(this._zod.def.shape)); }, catchall(catchall) { - return this.clone({ ...this._zod.def, catchall }); + return this.clone(util_exports.mergeDefs(this._zod.def, { catchall })); }, passthrough() { - return this.clone({ ...this._zod.def, catchall: unknown() }); + return this.clone(util_exports.mergeDefs(this._zod.def, { catchall: unknown() })); }, loose() { - return this.clone({ ...this._zod.def, catchall: unknown() }); + return this.clone(util_exports.mergeDefs(this._zod.def, { catchall: unknown() })); }, strict() { - return this.clone({ ...this._zod.def, catchall: never() }); + return this.clone(util_exports.mergeDefs(this._zod.def, { catchall: never() })); }, strip() { - return this.clone({ ...this._zod.def, catchall: void 0 }); + return this.clone(util_exports.mergeDefs(this._zod.def, { catchall: void 0 })); }, extend(incoming) { return util_exports.extend(this, incoming); @@ -25061,7 +25664,7 @@ var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => { ZodType.init(inst, def); inst._zod.processJSONSchema = (ctx, json2, params) => enumProcessor(inst, ctx, json2, params); inst.enum = def.entries; - inst.options = Object.values(def.entries); + inst.options = [...inst._zod.values]; const keys = new Set(Object.keys(def.entries)); inst.extract = (values, params) => { const newEntries = {}; @@ -25424,8 +26027,15 @@ function superRefine(fn, params) { } var describe2 = describe; var meta2 = meta; +var ZodInstanceOf = /* @__PURE__ */ $constructor("ZodInstanceOf", (inst, def) => { + ZodCustom.init(inst, def); +}, { + properties(shape, params) { + return this.check(_properties(shape, params)); + } +}); function _instanceof(cls, params = {}) { - const inst = new ZodCustom({ + const inst = new ZodInstanceOf({ type: "custom", check: "custom", fn: (data) => data instanceof cls, @@ -25630,27 +26240,188 @@ function resolveRef(ref, ctx) { } throw new Error(`Reference not found: ${ref}`); } -function checkPropertyNames(objectSchema, keySchema) { +function checkObjectGuards(objectSchema, guards) { const guard = z.transform((value) => value).check((payload) => { const value = payload.value; if (typeof value !== "object" || value === null || Array.isArray(value)) return; - for (const key of Object.getOwnPropertyNames(value)) { - const result = keySchema.safeParse(key); - if (result.success) - continue; + const keys = Object.getOwnPropertyNames(value); + if (guards.minProperties !== void 0 && keys.length < guards.minProperties) { payload.issues.push({ - code: "invalid_key", - origin: "record", - issues: result.error.issues, - input: key, - path: [key], + origin: "object", + code: "too_small", + minimum: guards.minProperties, + inclusive: true, + message: `Too small: expected object to have >=${guards.minProperties} properties`, + input: value, + inst: objectSchema, + continue: true + }); + } + if (guards.maxProperties !== void 0 && keys.length > guards.maxProperties) { + payload.issues.push({ + origin: "object", + code: "too_big", + maximum: guards.maxProperties, + inclusive: true, + message: `Too big: expected object to have <=${guards.maxProperties} properties`, + input: value, + inst: objectSchema, continue: true }); } + if (guards.keySchema) { + for (const key of keys) { + const result = guards.keySchema.safeParse(key); + if (result.success) + continue; + payload.issues.push({ + code: "invalid_key", + origin: "record", + issues: result.error.issues, + input: key, + path: [key], + continue: true + }); + } + } }); return guard.pipe(objectSchema); } +function canonicalKey(value, seen) { + if (value === null) + return "z"; + const type = typeof value; + if (type !== "object") { + if (type === "number" && Number.isNaN(value)) + return null; + const raw = String(value); + return `${type[0]}${raw.length}:${raw}`; + } + if (seen.has(value)) + return null; + seen.add(value); + try { + if (Array.isArray(value)) { + const parts2 = []; + for (const item of value) { + const key = canonicalKey(item, seen); + if (key === null) + return null; + parts2.push(key); + } + return `a${parts2.length}:[${parts2.join(",")}]`; + } + const keys = Object.keys(value).sort(); + const parts = []; + for (const k2 of keys) { + const key = canonicalKey(value[k2], seen); + if (key === null) + return null; + parts.push(`${k2.length}:${k2}=${key}`); + } + return `o${parts.length}:{${parts.join(",")}}`; + } finally { + seen.delete(value); + } +} +var SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([ + "items", + "prefixItems", + "additionalItems", + "additionalProperties", + "contains", + "propertyNames", + "not", + "if", + "then", + "else", + "allOf", + "anyOf", + "oneOf", + "unevaluatedItems", + "unevaluatedProperties", + "contentSchema" +]); +var SCHEMA_MAP_KEYWORDS = /* @__PURE__ */ new Set([ + "properties", + "patternProperties", + "dependentSchemas", + "dependencies", + "$defs", + "definitions" +]); +function containsRef(value) { + if (typeof value !== "object" || value === null) + return false; + if (Array.isArray(value)) + return value.some(containsRef); + if (typeof value.$ref === "string") + return true; + return Object.entries(value).some(([key, sub]) => { + if (SCHEMA_KEYWORDS.has(key)) + return containsRef(sub); + if (!SCHEMA_MAP_KEYWORDS.has(key) || typeof sub !== "object" || sub === null) + return false; + return Object.values(sub).some(containsRef); + }); +} +function plural(n) { + return n === 1 ? "element" : "elements"; +} +function checkArrayGuards(arraySchema, guards) { + const guard = z.transform((value) => value).check((payload) => { + const items = payload.value; + if (!Array.isArray(items)) + return; + if (guards.uniqueItems === true) { + const firstSeen = /* @__PURE__ */ new Map(); + for (let i = 0; i < items.length; i++) { + const key = canonicalKey(items[i], /* @__PURE__ */ new Set()); + if (key === null) + continue; + const first = firstSeen.get(key); + if (first === void 0) { + firstSeen.set(key, i); + continue; + } + payload.issues.push({ + code: "custom", + message: `Array items must be unique: element at index ${i} duplicates the one at index ${first}`, + input: items, + path: [i], + continue: true + }); + } + } + if (guards.containsSchema) { + const minContains = guards.minContains ?? 1; + const ceiling = guards.maxContains !== void 0 ? guards.maxContains + 1 : Number.POSITIVE_INFINITY; + let matches = 0; + for (const item of items) { + if (guards.containsSchema.safeParse(item).success && ++matches >= ceiling) + break; + } + if (matches < minContains) { + payload.issues.push({ + code: "custom", + message: `Array must contain at least ${minContains} matching ${plural(minContains)}; found ${matches}`, + input: items, + continue: true + }); + } + if (guards.maxContains !== void 0 && matches > guards.maxContains) { + payload.issues.push({ + code: "custom", + message: `Array must contain at most ${guards.maxContains} matching ${plural(guards.maxContains)}`, + input: items, + continue: true + }); + } + } + }); + return guard.pipe(arraySchema); +} function getTupleRest(restSchema, ctx) { if (restSchema === false) { return void 0; @@ -25780,6 +26551,8 @@ function convertBaseSchema(schema, ctx) { stringSchema = stringSchema.check(z.e164()); } else if (format === "credit_card") { stringSchema = stringSchema.check(z.creditCard()); + } else if (format === "iban") { + stringSchema = stringSchema.check(z.iban()); } else if (format === "jwt") { stringSchema = stringSchema.check(z.jwt()); } else if (format === "emoji") { @@ -25912,9 +26685,16 @@ function convertBaseSchema(schema, ctx) { zodSchema = objectSchema.passthrough(); } } - if (schema.propertyNames !== void 0 && schema.propertyNames !== true) { - const keyJSONSchema = typeof schema.propertyNames === "object" && schema.propertyNames.type === void 0 ? { type: "string", ...schema.propertyNames } : schema.propertyNames; - zodSchema = checkPropertyNames(zodSchema, convertSchema(keyJSONSchema, ctx)); + const hasKeyGuard = schema.propertyNames !== void 0 && schema.propertyNames !== true; + const minProperties = typeof schema.minProperties === "number" ? schema.minProperties : void 0; + const maxProperties = typeof schema.maxProperties === "number" ? schema.maxProperties : void 0; + if (hasKeyGuard || minProperties !== void 0 || maxProperties !== void 0) { + let keySchema; + if (hasKeyGuard) { + const keyJSONSchema = typeof schema.propertyNames === "object" && schema.propertyNames.type === void 0 ? { type: "string", ...schema.propertyNames } : schema.propertyNames; + keySchema = convertSchema(keyJSONSchema, ctx); + } + zodSchema = checkObjectGuards(zodSchema, { keySchema, minProperties, maxProperties }); } break; } @@ -25960,6 +26740,14 @@ function convertBaseSchema(schema, ctx) { } else { zodSchema = z.array(z.any()); } + if (schema.uniqueItems === true || schema.contains !== void 0) { + zodSchema = checkArrayGuards(zodSchema, { + uniqueItems: schema.uniqueItems === true, + containsSchema: schema.contains !== void 0 ? convertSchema(schema.contains, ctx) : void 0, + minContains: typeof schema.minContains === "number" ? schema.minContains : void 0, + maxContains: typeof schema.maxContains === "number" ? schema.maxContains : void 0 + }); + } break; } default: @@ -26017,8 +26805,23 @@ function convertSchema(schema, ctx) { extraMeta[key] = schema[key]; } } - if (schema.propertyNames !== void 0 && schema.type === "object" && schema.$ref === void 0) { - extraMeta.propertyNames = schema.propertyNames; + if (schema.type === "object" && schema.$ref === void 0) { + if (schema.propertyNames !== void 0 && !containsRef(schema.propertyNames)) { + extraMeta.propertyNames = schema.propertyNames; + } + for (const key of ["minProperties", "maxProperties"]) { + if (schema[key] !== void 0) + extraMeta[key] = schema[key]; + } + } + if (schema.type === "array" && schema.$ref === void 0) { + if (schema.contains !== void 0 && !containsRef(schema.contains)) { + extraMeta.contains = schema.contains; + } + for (const key of ["uniqueItems", "minContains", "maxContains"]) { + if (schema[key] !== void 0) + extraMeta[key] = schema[key]; + } } for (const key of Object.keys(schema)) { if (!RECOGNIZED_KEYS.has(key)) { @@ -27715,6 +28518,9 @@ var Protocol = class { this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => { const handleTaskResult = async () => { const taskId = request.params.taskId; + if (!await this._taskStore.getTask(taskId, extra.sessionId)) { + throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`); + } if (this._taskMessageQueue) { let queuedMessage; while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) { @@ -27728,8 +28534,8 @@ var Protocol = class { resolver(message); } else { const errorMessage = message; - const error61 = new McpError(errorMessage.error.code, errorMessage.error.message, errorMessage.error.data); - resolver(error61); + const error62 = new McpError(errorMessage.error.code, errorMessage.error.message, errorMessage.error.data); + resolver(error62); } } else { const messageType = queuedMessage.type === "response" ? "Response" : "Error"; @@ -27745,12 +28551,12 @@ var Protocol = class { throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`); } if (!isTerminal(task.status)) { - await this._waitForTaskUpdate(taskId, extra.signal); + await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId); return await handleTaskResult(); } if (isTerminal(task.status)) { const result = await this._taskStore.getTaskResult(taskId, extra.sessionId); - this._clearTaskQueue(taskId); + this._clearTaskQueue(taskId, extra.sessionId); return { ...result, _meta: { @@ -27773,8 +28579,8 @@ var Protocol = class { nextCursor, _meta: {} }; - } catch (error61) { - throw new McpError(ErrorCode.InvalidParams, `Failed to list tasks: ${error61 instanceof Error ? error61.message : String(error61)}`); + } catch (error62) { + throw new McpError(ErrorCode.InvalidParams, `Failed to list tasks: ${error62 instanceof Error ? error62.message : String(error62)}`); } }); this.setRequestHandler(CancelTaskRequestSchema, async (request, extra) => { @@ -27787,7 +28593,7 @@ var Protocol = class { throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`); } await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId); - this._clearTaskQueue(request.params.taskId); + this._clearTaskQueue(request.params.taskId, extra.sessionId); const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId); if (!cancelledTask) { throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`); @@ -27796,11 +28602,11 @@ var Protocol = class { _meta: {}, ...cancelledTask }; - } catch (error61) { - if (error61 instanceof McpError) { - throw error61; + } catch (error62) { + if (error62 instanceof McpError) { + throw error62; } - throw new McpError(ErrorCode.InvalidRequest, `Failed to cancel task: ${error61 instanceof Error ? error61.message : String(error61)}`); + throw new McpError(ErrorCode.InvalidRequest, `Failed to cancel task: ${error62 instanceof Error ? error62.message : String(error62)}`); } }); } @@ -27861,9 +28667,9 @@ var Protocol = class { this._onclose(); }; const _onerror = this.transport?.onerror; - this._transport.onerror = (error61) => { - _onerror?.(error61); - this._onerror(error61); + this._transport.onerror = (error62) => { + _onerror?.(error62); + this._onerror(error62); }; const _onmessage = this._transport?.onmessage; this._transport.onmessage = (message, extra) => { @@ -27894,27 +28700,40 @@ var Protocol = class { controller.abort(); } this._requestHandlerAbortControllers.clear(); - const error61 = McpError.fromError(ErrorCode.ConnectionClosed, "Connection closed"); + const error62 = McpError.fromError(ErrorCode.ConnectionClosed, "Connection closed"); this._transport = void 0; this.onclose?.(); for (const handler of responseHandlers.values()) { - handler(error61); + handler(error62); } } - _onerror(error61) { - this.onerror?.(error61); + _onerror(error62) { + this.onerror?.(error62); } _onnotification(notification) { const handler = this._notificationHandlers.get(notification.method) ?? this.fallbackNotificationHandler; if (handler === void 0) { return; } - Promise.resolve().then(() => handler(notification)).catch((error61) => this._onerror(new Error(`Uncaught error in notification handler: ${error61}`))); + Promise.resolve().then(() => handler(notification)).catch((error62) => this._onerror(new Error(`Uncaught error in notification handler: ${error62}`))); } _onrequest(request, extra) { const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler; const capturedTransport = this._transport; const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId; + const sessionId = capturedTransport?.sessionId; + const store = this._taskStore; + let relatedTaskFound = true; + let relatedTaskLookup; + if (relatedTaskId && store && this._taskMessageQueue && sessionId !== void 0) { + relatedTaskFound = false; + relatedTaskLookup = (async () => { + if (!await store.getTask(relatedTaskId, sessionId)) { + throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`); + } + relatedTaskFound = true; + })(); + } if (handler === void 0) { const errorResponse = { jsonrpc: "2.0", @@ -27924,14 +28743,17 @@ var Protocol = class { message: "Method not found" } }; - if (relatedTaskId && this._taskMessageQueue) { + if (relatedTaskId && relatedTaskLookup) { + const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() }; + relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error62) => this._onerror(new Error(`Failed to send an error response: ${error62}`))); + } else if (relatedTaskId && this._taskMessageQueue) { this._enqueueTaskMessage(relatedTaskId, { type: "error", message: errorResponse, timestamp: Date.now() - }, capturedTransport?.sessionId).catch((error61) => this._onerror(new Error(`Failed to enqueue error response: ${error61}`))); + }, capturedTransport?.sessionId).catch((error62) => this._onerror(new Error(`Failed to enqueue error response: ${error62}`))); } else { - capturedTransport?.send(errorResponse).catch((error61) => this._onerror(new Error(`Failed to send an error response: ${error61}`))); + capturedTransport?.send(errorResponse).catch((error62) => this._onerror(new Error(`Failed to send an error response: ${error62}`))); } return; } @@ -27975,7 +28797,10 @@ var Protocol = class { closeSSEStream: extra?.closeSSEStream, closeStandaloneSSEStream: extra?.closeStandaloneSSEStream }; - Promise.resolve().then(() => { + (relatedTaskLookup ?? Promise.resolve()).then(() => { + if (relatedTaskLookup && abortController.signal.aborted) { + throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled"); + } if (taskCreationParams) { this.assertTaskHandlerCapability(request.method); } @@ -27997,7 +28822,7 @@ var Protocol = class { } else { await capturedTransport?.send(response); } - }, async (error61) => { + }, async (error62) => { if (abortController.signal.aborted) { return; } @@ -28005,12 +28830,12 @@ var Protocol = class { jsonrpc: "2.0", id: request.id, error: { - code: Number.isSafeInteger(error61["code"]) ? error61["code"] : ErrorCode.InternalError, - message: error61.message ?? "Internal error", - ...error61["data"] !== void 0 && { data: error61["data"] } + code: Number.isSafeInteger(error62["code"]) ? error62["code"] : ErrorCode.InternalError, + message: error62.message ?? "Internal error", + ...error62["data"] !== void 0 && { data: error62["data"] } } }; - if (relatedTaskId && this._taskMessageQueue) { + if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) { await this._enqueueTaskMessage(relatedTaskId, { type: "error", message: errorResponse, @@ -28019,7 +28844,7 @@ var Protocol = class { } else { await capturedTransport?.send(errorResponse); } - }).catch((error61) => this._onerror(new Error(`Failed to send response: ${error61}`))).finally(() => { + }).catch((error62) => this._onerror(new Error(`Failed to send response: ${error62}`))).finally(() => { if (this._requestHandlerAbortControllers.get(request.id) === abortController) { this._requestHandlerAbortControllers.delete(request.id); } @@ -28038,11 +28863,11 @@ var Protocol = class { if (timeoutInfo && responseHandler && timeoutInfo.resetTimeoutOnProgress) { try { this._resetTimeout(messageId); - } catch (error61) { + } catch (error62) { this._responseHandlers.delete(messageId); this._progressHandlers.delete(messageId); this._cleanupTimeout(messageId); - responseHandler(error61); + responseHandler(error62); return; } } @@ -28056,8 +28881,8 @@ var Protocol = class { if (isJSONRPCResultResponse(response)) { resolver(response); } else { - const error61 = new McpError(response.error.code, response.error.message, response.error.data); - resolver(error61); + const error62 = new McpError(response.error.code, response.error.message, response.error.data); + resolver(error62); } return; } @@ -28085,8 +28910,8 @@ var Protocol = class { if (isJSONRPCResultResponse(response)) { handler(response); } else { - const error61 = McpError.fromError(response.error.code, response.error.message, response.error.data); - handler(error61); + const error62 = McpError.fromError(response.error.code, response.error.message, response.error.data); + handler(error62); } } get transport() { @@ -28131,10 +28956,10 @@ var Protocol = class { try { const result = await this.request(request, resultSchema, options); yield { type: "result", result }; - } catch (error61) { + } catch (error62) { yield { type: "error", - error: error61 instanceof McpError ? error61 : new McpError(ErrorCode.InternalError, String(error61)) + error: error62 instanceof McpError ? error62 : new McpError(ErrorCode.InternalError, String(error62)) }; } return; @@ -28177,10 +29002,10 @@ var Protocol = class { await new Promise((resolve) => setTimeout(resolve, pollInterval)); options?.signal?.throwIfAborted(); } - } catch (error61) { + } catch (error62) { yield { type: "error", - error: error61 instanceof McpError ? error61 : new McpError(ErrorCode.InternalError, String(error61)) + error: error62 instanceof McpError ? error62 : new McpError(ErrorCode.InternalError, String(error62)) }; } } @@ -28192,8 +29017,8 @@ var Protocol = class { request(request, resultSchema, options) { const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {}; return new Promise((resolve, reject) => { - const earlyReject = (error61) => { - reject(error61); + const earlyReject = (error62) => { + reject(error62); }; if (!this._transport) { earlyReject(new Error("Not connected")); @@ -28253,9 +29078,9 @@ var Protocol = class { requestId: messageId, reason: String(reason) } - }, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error62) => this._onerror(new Error(`Failed to send cancellation: ${error62}`))); - const error61 = reason instanceof McpError ? reason : new McpError(ErrorCode.RequestTimeout, String(reason)); - reject(error61); + }, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error63) => this._onerror(new Error(`Failed to send cancellation: ${error63}`))); + const error62 = reason instanceof McpError ? reason : new McpError(ErrorCode.RequestTimeout, String(reason)); + reject(error62); }; this._responseHandlers.set(messageId, (response) => { if (options?.signal?.aborted) { @@ -28271,8 +29096,8 @@ var Protocol = class { } else { resolve(parseResult.data); } - } catch (error61) { - reject(error61); + } catch (error62) { + reject(error62); } }); options?.signal?.addEventListener("abort", () => { @@ -28296,14 +29121,14 @@ var Protocol = class { type: "request", message: jsonrpcRequest, timestamp: Date.now() - }).catch((error61) => { + }).catch((error62) => { this._cleanupTimeout(messageId); - reject(error61); + reject(error62); }); } else { - this._transport.send(jsonrpcRequest, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error61) => { + this._transport.send(jsonrpcRequest, { relatedRequestId, resumptionToken, onresumptiontoken }).catch((error62) => { this._cleanupTimeout(messageId); - reject(error61); + reject(error62); }); } }); @@ -28396,7 +29221,7 @@ var Protocol = class { } }; } - this._transport?.send(jsonrpcNotification2, options).catch((error61) => this._onerror(error61)); + this._transport?.send(jsonrpcNotification2, options).catch((error62) => this._onerror(error62)); }); return; } @@ -28490,7 +29315,7 @@ var Protocol = class { throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured"); } const maxQueueSize = this._options?.maxTaskQueueSize; - await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize); + await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize); } /** * Clears the message queue for a task and rejects any pending request resolvers. @@ -28519,12 +29344,13 @@ var Protocol = class { * Uses polling to check for updates at the task's configured poll interval. * @param taskId The task ID to wait for * @param signal Abort signal to cancel the wait + * @param sessionId Session of the request that waits, passed to the task store * @returns Promise that resolves when an update occurs or rejects if aborted */ - async _waitForTaskUpdate(taskId, signal) { + async _waitForTaskUpdate(taskId, signal, sessionId) { let interval = this._options?.defaultTaskPollInterval ?? 1e3; try { - const task = await this._taskStore?.getTask(taskId); + const task = await this._taskStore?.getTask(taskId, sessionId); if (task?.pollInterval) { interval = task.pollInterval; } @@ -29249,11 +30075,11 @@ var Server = class extends Protocol { if (!validationResult.valid) { throw new McpError(ErrorCode.InvalidParams, `Elicitation response content does not match requested schema: ${validationResult.errorMessage}`); } - } catch (error61) { - if (error61 instanceof McpError) { - throw error61; + } catch (error62) { + if (error62 instanceof McpError) { + throw error62; } - throw new McpError(ErrorCode.InternalError, `Error validating elicitation response: ${error61 instanceof Error ? error61.message : String(error61)}`); + throw new McpError(ErrorCode.InternalError, `Error validating elicitation response: ${error62 instanceof Error ? error62.message : String(error62)}`); } } return result; @@ -29316,7 +30142,7 @@ var Server = class extends Protocol { }; // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js -import process3 from "node:process"; +import process2 from "node:process"; // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024; @@ -29357,7 +30183,7 @@ function serializeMessage(message) { // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js var StdioServerTransport = class { - constructor(_stdin = process3.stdin, _stdout = process3.stdout, options) { + constructor(_stdin = process2.stdin, _stdout = process2.stdout, options) { this._stdin = _stdin; this._stdout = _stdout; this._started = false; @@ -29365,14 +30191,14 @@ var StdioServerTransport = class { try { this._readBuffer.append(chunk); this.processReadBuffer(); - } catch (error61) { - this.onerror?.(error61); + } catch (error62) { + this.onerror?.(error62); this.close().catch(() => { }); } }; - this._onerror = (error61) => { - this.onerror?.(error61); + this._onerror = (error62) => { + this.onerror?.(error62); }; this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize }); } @@ -29395,8 +30221,8 @@ var StdioServerTransport = class { break; } this.onmessage?.(message); - } catch (error61) { - this.onerror?.(error61); + } catch (error62) { + this.onerror?.(error62); } } } @@ -29454,6 +30280,16 @@ function getSuperpowersDir() { } return ensureDir(dir); } +function getModelCacheDir() { + const override = process.env.EPISODIC_MEMORY_MODEL_CACHE_DIR; + if (override) { + if (!path.isAbsolute(override)) { + throw new Error("EPISODIC_MEMORY_MODEL_CACHE_DIR must be an absolute path"); + } + return ensureDir(override); + } + return ensureDir(path.join(getSuperpowersDir(), "models")); +} function getIndexDir() { return ensureDir(path.join(getSuperpowersDir(), "conversation-index")); } @@ -29652,16 +30488,20 @@ var EmbeddingsUnavailableError = class extends Error { }; async function initEmbeddings() { if (embeddingPipeline) return; + const modelCacheDir = getModelCacheDir(); + const offline = process.env.EPISODIC_MEMORY_OFFLINE === "1"; let pipeline; try { const transformers = await import("@huggingface/transformers"); + transformers.env.cacheDir = modelCacheDir; transformers.env.allowLocalModels = true; + transformers.env.allowRemoteModels = !offline; transformers.env.useBrowserCache = false; pipeline = transformers.pipeline; - } catch (error61) { + } catch (error62) { throw new EmbeddingsUnavailableError( - `Failed to load the embedding backend (@huggingface/transformers). This usually means the native "sharp" binding could not load libvips; semantic search and indexing are unavailable until it is fixed. Underlying error: ${error61 instanceof Error ? error61.message : String(error61)}`, - { cause: error61 } + `Failed to load the embedding backend (@huggingface/transformers). This usually means the native "sharp" binding could not load libvips; semantic search and indexing are unavailable until it is fixed. Underlying error: ${error62 instanceof Error ? error62.message : String(error62)}`, + { cause: error62 } ); } console.error("Loading embedding model (first run may take time)..."); @@ -29677,7 +30517,12 @@ async function initEmbeddings() { interOpNumThreads: 1 }; } - embeddingPipeline = await pipeline("feature-extraction", MODEL_ID, options); + try { + embeddingPipeline = await pipeline("feature-extraction", MODEL_ID, options); + } catch (error62) { + const message = offline ? "Embedding model unavailable in the local cache while EPISODIC_MEMORY_OFFLINE=1; pre-seed the model cache or disable offline mode." : "Embedding model unavailable; check the model cache and remote model access."; + throw new EmbeddingsUnavailableError(message, { cause: error62 }); + } console.error("Embedding model loaded"); } async function generateEmbedding(text) { @@ -29913,7 +30758,7 @@ async function countLines(filePath) { if (line.trim()) count++; } return count; - } catch (error61) { + } catch (error62) { return 0; } } @@ -29921,7 +30766,7 @@ function getFileSizeInKB(filePath) { try { const stats = fs3.statSync(filePath); return Math.round(stats.size / 1024 * 10) / 10; - } catch (error61) { + } catch (error62) { return 0; } } @@ -30046,140 +30891,147 @@ function L() { return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null }; } var T = L(); -function G(u3) { - T = u3; +function G(l3) { + T = l3; } -var I = { exec: () => null }; -function d(u3, e = "") { - let t = typeof u3 == "string" ? u3 : u3.source, n = { replace: (r, i) => { +var E = { exec: () => null }; +function d(l3, e = "") { + let t = typeof l3 == "string" ? l3 : l3.source, n = { replace: (r, i) => { let s = typeof i == "string" ? i : i.source; return s = s.replace(m.caret, "$1"), t = t.replace(r, s), n; }, getRegex: () => new RegExp(t, e) }; return n; } -var m = { codeRemoveIndent: /^(?: {1,4}| {0,3}\t)/gm, outputLinkReplace: /\\([\[\]])/g, indentCodeCompensation: /^(\s+)(?:```)/, beginningSpace: /^\s+/, endingHash: /#$/, startingSpaceChar: /^ /, endingSpaceChar: / $/, nonSpaceChar: /[^ ]/, newLineCharGlobal: /\n/g, tabCharGlobal: /\t/g, multipleSpaceGlobal: /\s+/g, blankLine: /^[ \t]*$/, doubleBlankLine: /\n[ \t]*\n[ \t]*$/, blockquoteStart: /^ {0,3}>/, blockquoteSetextReplace: /\n {0,3}((?:=+|-+) *)(?=\n|$)/g, blockquoteSetextReplace2: /^ {0,3}>[ \t]?/gm, listReplaceTabs: /^\t+/, listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g, listIsTask: /^\[[ xX]\] /, listReplaceTask: /^\[[ xX]\] +/, anyLine: /\n.*\n/, hrefBrackets: /^<(.*)>$/, tableDelimiter: /[:|]/, tableAlignChars: /^\||\| *$/g, tableRowBlankLine: /\n[ \t]*$/, tableAlignRight: /^ *-+: *$/, tableAlignCenter: /^ *:-+: *$/, tableAlignLeft: /^ *:-+ *$/, startATag: /^/i, startPreScriptTag: /^<(pre|code|kbd|script)(\s|>)/i, endPreScriptTag: /^<\/(pre|code|kbd|script)(\s|>)/i, startAngleBracket: /^$/, pedanticHrefTitle: /^([^'"]*[^\s])\s+(['"])(.*)\2/, unicodeAlphaNumeric: /[\p{L}\p{N}]/u, escapeTest: /[&<>"']/, escapeReplace: /[&<>"']/g, escapeTestNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/, escapeReplaceNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, unescapeTest: /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, caret: /(^|[^\[])\^/g, percentDecode: /%25/g, findPipe: /\|/g, splitPipe: / \|/, slashPipe: /\\\|/g, carriageReturn: /\r\n|\r/g, spaceLine: /^ +$/gm, notSpaceStart: /^\S*/, endingNewline: /\n$/, listItemRegex: (u3) => new RegExp(`^( {0,3}${u3})((?:[ ][^\\n]*)?(?:\\n|$))`), nextBulletRegex: (u3) => new RegExp(`^ {0,${Math.min(3, u3 - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`), hrRegex: (u3) => new RegExp(`^ {0,${Math.min(3, u3 - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`), fencesBeginRegex: (u3) => new RegExp(`^ {0,${Math.min(3, u3 - 1)}}(?:\`\`\`|~~~)`), headingBeginRegex: (u3) => new RegExp(`^ {0,${Math.min(3, u3 - 1)}}#`), htmlBeginRegex: (u3) => new RegExp(`^ {0,${Math.min(3, u3 - 1)}}<(?:[a-z].*>|!--)`, "i") }; -var be = /^(?:[ \t]*(?:\n|$))+/; -var Re = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/; -var Te = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/; -var E = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/; -var Oe = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/; +var be = (() => { + try { + return !!new RegExp("(?<=1)(?/, blockquoteSetextReplace: /\n {0,3}((?:=+|-+) *)(?=\n|$)/g, blockquoteSetextReplace2: /^ {0,3}>[ \t]?/gm, listReplaceTabs: /^\t+/, listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g, listIsTask: /^\[[ xX]\] /, listReplaceTask: /^\[[ xX]\] +/, anyLine: /\n.*\n/, hrefBrackets: /^<(.*)>$/, tableDelimiter: /[:|]/, tableAlignChars: /^\||\| *$/g, tableRowBlankLine: /\n[ \t]*$/, tableAlignRight: /^ *-+: *$/, tableAlignCenter: /^ *:-+: *$/, tableAlignLeft: /^ *:-+ *$/, startATag: /^/i, startPreScriptTag: /^<(pre|code|kbd|script)(\s|>)/i, endPreScriptTag: /^<\/(pre|code|kbd|script)(\s|>)/i, startAngleBracket: /^$/, pedanticHrefTitle: /^([^'"]*[^\s])\s+(['"])(.*)\2/, unicodeAlphaNumeric: /[\p{L}\p{N}]/u, escapeTest: /[&<>"']/, escapeReplace: /[&<>"']/g, escapeTestNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/, escapeReplaceNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, unescapeTest: /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, caret: /(^|[^\[])\^/g, percentDecode: /%25/g, findPipe: /\|/g, splitPipe: / \|/, slashPipe: /\\\|/g, carriageReturn: /\r\n|\r/g, spaceLine: /^ +$/gm, notSpaceStart: /^\S*/, endingNewline: /\n$/, listItemRegex: (l3) => new RegExp(`^( {0,3}${l3})((?:[ ][^\\n]*)?(?:\\n|$))`), nextBulletRegex: (l3) => new RegExp(`^ {0,${Math.min(3, l3 - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`), hrRegex: (l3) => new RegExp(`^ {0,${Math.min(3, l3 - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`), fencesBeginRegex: (l3) => new RegExp(`^ {0,${Math.min(3, l3 - 1)}}(?:\`\`\`|~~~)`), headingBeginRegex: (l3) => new RegExp(`^ {0,${Math.min(3, l3 - 1)}}#`), htmlBeginRegex: (l3) => new RegExp(`^ {0,${Math.min(3, l3 - 1)}}<(?:[a-z].*>|!--)`, "i") }; +var Re = /^(?:[ \t]*(?:\n|$))+/; +var Te = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/; +var Oe = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/; +var I = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/; +var we = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/; var F = /(?:[*+-]|\d{1,9}[.)])/; var ie = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/; var oe = d(ie).replace(/bull/g, F).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/\|table/g, "").getRegex(); -var we = d(ie).replace(/bull/g, F).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(); +var ye = d(ie).replace(/bull/g, F).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(); var j = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/; -var ye = /^[^\n]+/; +var Pe = /^[^\n]+/; var Q = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/; -var Pe = d(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", Q).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(); -var Se = d(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g, F).getRegex(); +var Se = d(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", Q).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(); +var $e = d(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g, F).getRegex(); var v = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul"; var U = /|$))/; -var $e = d("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))", "i").replace("comment", U).replace("tag", v).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(); -var ae = d(j).replace("hr", E).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", ")|<(?:script|pre|style|textarea|!--)").replace("tag", v).getRegex(); -var _e = d(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", ae).getRegex(); -var K = { blockquote: _e, code: Re, def: Pe, fences: Te, heading: Oe, hr: E, html: $e, lheading: oe, list: Se, newline: be, paragraph: ae, table: I, text: ye }; -var re = d("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", E).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3} )[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", ")|<(?:script|pre|style|textarea|!--)").replace("tag", v).getRegex(); -var Le = { ...K, lheading: we, table: re, paragraph: d(j).replace("hr", E).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", re).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", ")|<(?:script|pre|style|textarea|!--)").replace("tag", v).getRegex() }; -var Me = { ...K, html: d(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment", U).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: I, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: d(j).replace("hr", E).replace("heading", ` *#{1,6} *[^ +var _e = d("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))", "i").replace("comment", U).replace("tag", v).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(); +var ae = d(j).replace("hr", I).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", ")|<(?:script|pre|style|textarea|!--)").replace("tag", v).getRegex(); +var Le = d(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", ae).getRegex(); +var K = { blockquote: Le, code: Te, def: Se, fences: Oe, heading: we, hr: I, html: _e, lheading: oe, list: $e, newline: Re, paragraph: ae, table: E, text: Pe }; +var re = d("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", I).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3} )[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", ")|<(?:script|pre|style|textarea|!--)").replace("tag", v).getRegex(); +var Me = { ...K, lheading: ye, table: re, paragraph: d(j).replace("hr", I).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", re).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", ")|<(?:script|pre|style|textarea|!--)").replace("tag", v).getRegex() }; +var ze = { ...K, html: d(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment", U).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: E, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: d(j).replace("hr", I).replace("heading", ` *#{1,6} *[^ ]`).replace("lheading", oe).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() }; -var ze = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/; -var Ae = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/; +var Ae = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/; +var Ee = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/; var le = /^( {2,}|\\)\n(?!\s*$)/; var Ie = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\]*?>/g; +var Be = /(?!~)[\s\p{P}\p{S}]/u; +var qe = /(?:[^\s\p{P}\p{S}]|~)/u; +var ve = d(/link|precode-code|html/, "g").replace("link", /\[(?:[^\[\]`]|(?`+)[^`]+\k(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-", be ? "(?`+)[^`]+\k(?!`)/).replace("html", /<(?! )[^<>]*?>/).getRegex(); var ce = /^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/; -var ve = d(ce, "u").replace(/punct/g, D).getRegex(); -var De = d(ce, "u").replace(/punct/g, pe).getRegex(); +var De = d(ce, "u").replace(/punct/g, D).getRegex(); +var He = d(ce, "u").replace(/punct/g, pe).getRegex(); var he = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)"; -var He = d(he, "gu").replace(/notPunctSpace/g, ue).replace(/punctSpace/g, W).replace(/punct/g, D).getRegex(); -var Ze = d(he, "gu").replace(/notPunctSpace/g, Be).replace(/punctSpace/g, Ce).replace(/punct/g, pe).getRegex(); -var Ge = d("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, ue).replace(/punctSpace/g, W).replace(/punct/g, D).getRegex(); -var Ne = d(/\\(punct)/, "gu").replace(/punct/g, D).getRegex(); -var Fe = d(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(); -var je = d(U).replace("(?:-->|$)", "-->").getRegex(); -var Qe = d("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment", je).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(); +var Ze = d(he, "gu").replace(/notPunctSpace/g, ue).replace(/punctSpace/g, W).replace(/punct/g, D).getRegex(); +var Ge = d(he, "gu").replace(/notPunctSpace/g, qe).replace(/punctSpace/g, Be).replace(/punct/g, pe).getRegex(); +var Ne = d("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, ue).replace(/punctSpace/g, W).replace(/punct/g, D).getRegex(); +var Fe = d(/\\(punct)/, "gu").replace(/punct/g, D).getRegex(); +var je = d(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(); +var Qe = d(U).replace("(?:-->|$)", "-->").getRegex(); +var Ue = d("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment", Qe).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(); var q = /(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+[^`]*?`+(?!`)|[^\[\]\\`])*?/; -var Ue = d(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]*(?:\n[ \t]*)?)(title))?\s*\)/).replace("label", q).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(); +var Ke = d(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]*(?:\n[ \t]*)?)(title))?\s*\)/).replace("label", q).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(); var de = d(/^!?\[(label)\]\[(ref)\]/).replace("label", q).replace("ref", Q).getRegex(); var ke = d(/^!?\[(ref)\](?:\[\])?/).replace("ref", Q).getRegex(); -var Ke = d("reflink|nolink(?!\\()", "g").replace("reflink", de).replace("nolink", ke).getRegex(); +var We = d("reflink|nolink(?!\\()", "g").replace("reflink", de).replace("nolink", ke).getRegex(); var se = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/; -var X = { _backpedal: I, anyPunctuation: Ne, autolink: Fe, blockSkip: qe, br: le, code: Ae, del: I, emStrongLDelim: ve, emStrongRDelimAst: He, emStrongRDelimUnd: Ge, escape: ze, link: Ue, nolink: ke, punctuation: Ee, reflink: de, reflinkSearch: Ke, tag: Qe, text: Ie, url: I }; -var We = { ...X, link: d(/^!?\[(label)\]\((.*?)\)/).replace("label", q).getRegex(), reflink: d(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", q).getRegex() }; -var N = { ...X, emStrongRDelimAst: Ze, emStrongLDelim: De, url: d(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol", se).replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/, text: d(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\": ">", '"': """, "'": "'" }; -var ge = (u3) => Je[u3]; -function w(u3, e) { +var X = { _backpedal: E, anyPunctuation: Fe, autolink: je, blockSkip: ve, br: le, code: Ee, del: E, emStrongLDelim: De, emStrongRDelimAst: Ze, emStrongRDelimUnd: Ne, escape: Ae, link: Ke, nolink: ke, punctuation: Ce, reflink: de, reflinkSearch: We, tag: Ue, text: Ie, url: E }; +var Xe = { ...X, link: d(/^!?\[(label)\]\((.*?)\)/).replace("label", q).getRegex(), reflink: d(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", q).getRegex() }; +var N = { ...X, emStrongRDelimAst: Ge, emStrongLDelim: He, url: d(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol", se).replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/, text: d(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\": ">", '"': """, "'": "'" }; +var ge = (l3) => Ve[l3]; +function w(l3, e) { if (e) { - if (m.escapeTest.test(u3)) return u3.replace(m.escapeReplace, ge); - } else if (m.escapeTestNoEncode.test(u3)) return u3.replace(m.escapeReplaceNoEncode, ge); - return u3; + if (m.escapeTest.test(l3)) return l3.replace(m.escapeReplace, ge); + } else if (m.escapeTestNoEncode.test(l3)) return l3.replace(m.escapeReplaceNoEncode, ge); + return l3; } -function J(u3) { +function J(l3) { try { - u3 = encodeURI(u3).replace(m.percentDecode, "%"); + l3 = encodeURI(l3).replace(m.percentDecode, "%"); } catch { return null; } - return u3; + return l3; } -function V(u3, e) { - let t = u3.replace(m.findPipe, (i, s, o) => { - let a = false, l = s; - for (; --l >= 0 && o[l] === "\\"; ) a = !a; - return a ? "|" : " |"; +function V(l3, e) { + let t = l3.replace(m.findPipe, (i, s, a) => { + let o = false, p = s; + for (; --p >= 0 && a[p] === "\\"; ) o = !o; + return o ? "|" : " |"; }), n = t.split(m.splitPipe), r = 0; if (n[0].trim() || n.shift(), n.length > 0 && !n.at(-1)?.trim() && n.pop(), e) if (n.length > e) n.splice(e); else for (; n.length < e; ) n.push(""); for (; r < n.length; r++) n[r] = n[r].trim().replace(m.slashPipe, "|"); return n; } -function z2(u3, e, t) { - let n = u3.length; +function z2(l3, e, t) { + let n = l3.length; if (n === 0) return ""; let r = 0; for (; r < n; ) { - let i = u3.charAt(n - r - 1); + let i = l3.charAt(n - r - 1); if (i === e && !t) r++; else if (i !== e && t) r++; else break; } - return u3.slice(0, n - r); + return l3.slice(0, n - r); } -function fe(u3, e) { - if (u3.indexOf(e[1]) === -1) return -1; +function fe(l3, e) { + if (l3.indexOf(e[1]) === -1) return -1; let t = 0; - for (let n = 0; n < u3.length; n++) if (u3[n] === "\\") n++; - else if (u3[n] === e[0]) t++; - else if (u3[n] === e[1] && (t--, t < 0)) return n; + for (let n = 0; n < l3.length; n++) if (l3[n] === "\\") n++; + else if (l3[n] === e[0]) t++; + else if (l3[n] === e[1] && (t--, t < 0)) return n; return t > 0 ? -2 : -1; } -function me(u3, e, t, n, r) { - let i = e.href, s = e.title || null, o = u3[1].replace(r.other.outputLinkReplace, "$1"); +function me(l3, e, t, n, r) { + let i = e.href, s = e.title || null, a = l3[1].replace(r.other.outputLinkReplace, "$1"); n.state.inLink = true; - let a = { type: u3[0].charAt(0) === "!" ? "image" : "link", raw: t, href: i, title: s, text: o, tokens: n.inlineTokens(o) }; - return n.state.inLink = false, a; + let o = { type: l3[0].charAt(0) === "!" ? "image" : "link", raw: t, href: i, title: s, text: a, tokens: n.inlineTokens(a) }; + return n.state.inLink = false, o; } -function Ve(u3, e, t) { - let n = u3.match(t.other.indentCodeCompensation); +function Ye(l3, e, t) { + let n = l3.match(t.other.indentCodeCompensation); if (n === null) return e; let r = n[1]; return e.split(` `).map((i) => { let s = i.match(t.other.beginningSpace); if (s === null) return i; - let [o] = s; - return o.length >= r.length ? i.slice(r.length) : i; + let [a] = s; + return a.length >= r.length ? i.slice(r.length) : i; }).join(` `); } @@ -30205,7 +31057,7 @@ var y = class { fences(e) { let t = this.rules.block.fences.exec(e); if (t) { - let n = t[0], r = Ve(n, t[3] || "", this.rules); + let n = t[0], r = Ye(n, t[3] || "", this.rules); return { type: "code", raw: n, lang: t[2] ? t[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : t[2], text: r }; } } @@ -30232,19 +31084,19 @@ var y = class { `).split(` `), r = "", i = "", s = []; for (; n.length > 0; ) { - let o = false, a = [], l; - for (l = 0; l < n.length; l++) if (this.rules.other.blockquoteStart.test(n[l])) a.push(n[l]), o = true; - else if (!o) a.push(n[l]); + let a = false, o = [], p; + for (p = 0; p < n.length; p++) if (this.rules.other.blockquoteStart.test(n[p])) o.push(n[p]), a = true; + else if (!a) o.push(n[p]); else break; - n = n.slice(l); - let c = a.join(` -`), p = c.replace(this.rules.other.blockquoteSetextReplace, ` + n = n.slice(p); + let u = o.join(` +`), c = u.replace(this.rules.other.blockquoteSetextReplace, ` $1`).replace(this.rules.other.blockquoteSetextReplace2, ""); r = r ? `${r} -${c}` : c, i = i ? `${i} -${p}` : p; +${u}` : u, i = i ? `${i} +${c}` : c; let g = this.lexer.state.top; - if (this.lexer.state.top = true, this.lexer.blockTokens(p, s, true), this.lexer.state.top = g, n.length === 0) break; + if (this.lexer.state.top = true, this.lexer.blockTokens(c, s, true), this.lexer.state.top = g, n.length === 0) break; let h = s.at(-1); if (h?.type === "code") break; if (h?.type === "blockquote") { @@ -30270,45 +31122,45 @@ ${p}` : p; if (t) { let n = t[1].trim(), r = n.length > 1, i = { type: "list", raw: "", ordered: r, start: r ? +n.slice(0, -1) : "", loose: false, items: [] }; n = r ? `\\d{1,9}\\${n.slice(-1)}` : `\\${n}`, this.options.pedantic && (n = r ? n : "[*+-]"); - let s = this.rules.other.listItemRegex(n), o = false; + let s = this.rules.other.listItemRegex(n), a = false; for (; e; ) { - let l = false, c = "", p = ""; + let p = false, u = "", c = ""; if (!(t = s.exec(e)) || this.rules.block.hr.test(e)) break; - c = t[0], e = e.substring(c.length); + u = t[0], e = e.substring(u.length); let g = t[2].split(` `, 1)[0].replace(this.rules.other.listReplaceTabs, (H) => " ".repeat(3 * H.length)), h = e.split(` `, 1)[0], R = !g.trim(), f = 0; - if (this.options.pedantic ? (f = 2, p = g.trimStart()) : R ? f = t[1].length + 1 : (f = t[2].search(this.rules.other.nonSpaceChar), f = f > 4 ? 1 : f, p = g.slice(f), f += t[1].length), R && this.rules.other.blankLine.test(h) && (c += h + ` -`, e = e.substring(h.length + 1), l = true), !l) { + if (this.options.pedantic ? (f = 2, c = g.trimStart()) : R ? f = t[1].length + 1 : (f = t[2].search(this.rules.other.nonSpaceChar), f = f > 4 ? 1 : f, c = g.slice(f), f += t[1].length), R && this.rules.other.blankLine.test(h) && (u += h + ` +`, e = e.substring(h.length + 1), p = true), !p) { let H = this.rules.other.nextBulletRegex(f), ee = this.rules.other.hrRegex(f), te = this.rules.other.fencesBeginRegex(f), ne = this.rules.other.headingBeginRegex(f), xe = this.rules.other.htmlBeginRegex(f); for (; e; ) { let Z = e.split(` `, 1)[0], A; if (h = Z, this.options.pedantic ? (h = h.replace(this.rules.other.listReplaceNesting, " "), A = h) : A = h.replace(this.rules.other.tabCharGlobal, " "), te.test(h) || ne.test(h) || xe.test(h) || H.test(h) || ee.test(h)) break; - if (A.search(this.rules.other.nonSpaceChar) >= f || !h.trim()) p += ` + if (A.search(this.rules.other.nonSpaceChar) >= f || !h.trim()) c += ` ` + A.slice(f); else { if (R || g.replace(this.rules.other.tabCharGlobal, " ").search(this.rules.other.nonSpaceChar) >= 4 || te.test(g) || ne.test(g) || ee.test(g)) break; - p += ` + c += ` ` + h; } - !R && !h.trim() && (R = true), c += Z + ` + !R && !h.trim() && (R = true), u += Z + ` `, e = e.substring(Z.length + 1), g = A.slice(f); } } - i.loose || (o ? i.loose = true : this.rules.other.doubleBlankLine.test(c) && (o = true)); + i.loose || (a ? i.loose = true : this.rules.other.doubleBlankLine.test(u) && (a = true)); let O = null, Y; - this.options.gfm && (O = this.rules.other.listIsTask.exec(p), O && (Y = O[0] !== "[ ] ", p = p.replace(this.rules.other.listReplaceTask, ""))), i.items.push({ type: "list_item", raw: c, task: !!O, checked: Y, loose: false, text: p, tokens: [] }), i.raw += c; + this.options.gfm && (O = this.rules.other.listIsTask.exec(c), O && (Y = O[0] !== "[ ] ", c = c.replace(this.rules.other.listReplaceTask, ""))), i.items.push({ type: "list_item", raw: u, task: !!O, checked: Y, loose: false, text: c, tokens: [] }), i.raw += u; } - let a = i.items.at(-1); - if (a) a.raw = a.raw.trimEnd(), a.text = a.text.trimEnd(); + let o = i.items.at(-1); + if (o) o.raw = o.raw.trimEnd(), o.text = o.text.trimEnd(); else return; i.raw = i.raw.trimEnd(); - for (let l = 0; l < i.items.length; l++) if (this.lexer.state.top = false, i.items[l].tokens = this.lexer.blockTokens(i.items[l].text, []), !i.loose) { - let c = i.items[l].tokens.filter((g) => g.type === "space"), p = c.length > 0 && c.some((g) => this.rules.other.anyLine.test(g.raw)); - i.loose = p; + for (let p = 0; p < i.items.length; p++) if (this.lexer.state.top = false, i.items[p].tokens = this.lexer.blockTokens(i.items[p].text, []), !i.loose) { + let u = i.items[p].tokens.filter((g) => g.type === "space"), c = u.length > 0 && u.some((g) => this.rules.other.anyLine.test(g.raw)); + i.loose = c; } - if (i.loose) for (let l = 0; l < i.items.length; l++) i.items[l].loose = true; + if (i.loose) for (let p = 0; p < i.items.length; p++) i.items[p].loose = true; return i; } } @@ -30329,9 +31181,9 @@ ${p}` : p; let n = V(t[1]), r = t[2].replace(this.rules.other.tableAlignChars, "").split("|"), i = t[3]?.trim() ? t[3].replace(this.rules.other.tableRowBlankLine, "").split(` `) : [], s = { type: "table", raw: t[0], header: [], align: [], rows: [] }; if (n.length === r.length) { - for (let o of r) this.rules.other.tableAlignRight.test(o) ? s.align.push("right") : this.rules.other.tableAlignCenter.test(o) ? s.align.push("center") : this.rules.other.tableAlignLeft.test(o) ? s.align.push("left") : s.align.push(null); - for (let o = 0; o < n.length; o++) s.header.push({ text: n[o], tokens: this.lexer.inline(n[o]), header: true, align: s.align[o] }); - for (let o of i) s.rows.push(V(o, s.header.length).map((a, l) => ({ text: a, tokens: this.lexer.inline(a), header: false, align: s.align[l] }))); + for (let a of r) this.rules.other.tableAlignRight.test(a) ? s.align.push("right") : this.rules.other.tableAlignCenter.test(a) ? s.align.push("center") : this.rules.other.tableAlignLeft.test(a) ? s.align.push("left") : s.align.push(null); + for (let a = 0; a < n.length; a++) s.header.push({ text: n[a], tokens: this.lexer.inline(n[a]), header: true, align: s.align[a] }); + for (let a of i) s.rows.push(V(a, s.header.length).map((o, p) => ({ text: o, tokens: this.lexer.inline(o), header: false, align: s.align[p] }))); return s; } } @@ -30371,8 +31223,8 @@ ${p}` : p; let s = fe(t[2], "()"); if (s === -2) return; if (s > -1) { - let a = (t[0].indexOf("!") === 0 ? 5 : 4) + t[1].length + s; - t[2] = t[2].substring(0, s), t[0] = t[0].substring(0, a).trim(), t[3] = ""; + let o = (t[0].indexOf("!") === 0 ? 5 : 4) + t[1].length + s; + t[2] = t[2].substring(0, s), t[0] = t[0].substring(0, o).trim(), t[3] = ""; } } let r = t[2], i = ""; @@ -30398,20 +31250,20 @@ ${p}` : p; let r = this.rules.inline.emStrongLDelim.exec(e); if (!r || r[3] && n.match(this.rules.other.unicodeAlphaNumeric)) return; if (!(r[1] || r[2] || "") || !n || this.rules.inline.punctuation.exec(n)) { - let s = [...r[0]].length - 1, o, a, l = s, c = 0, p = r[0][0] === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd; - for (p.lastIndex = 0, t = t.slice(-1 * e.length + s); (r = p.exec(t)) != null; ) { - if (o = r[1] || r[2] || r[3] || r[4] || r[5] || r[6], !o) continue; - if (a = [...o].length, r[3] || r[4]) { - l += a; + let s = [...r[0]].length - 1, a, o, p = s, u = 0, c = r[0][0] === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd; + for (c.lastIndex = 0, t = t.slice(-1 * e.length + s); (r = c.exec(t)) != null; ) { + if (a = r[1] || r[2] || r[3] || r[4] || r[5] || r[6], !a) continue; + if (o = [...a].length, r[3] || r[4]) { + p += o; continue; - } else if ((r[5] || r[6]) && s % 3 && !((s + a) % 3)) { - c += a; + } else if ((r[5] || r[6]) && s % 3 && !((s + o) % 3)) { + u += o; continue; } - if (l -= a, l > 0) continue; - a = Math.min(a, a + l + c); - let g = [...r[0]][0].length, h = e.slice(0, s + r.index + g + a); - if (Math.min(s, a) % 2) { + if (p -= o, p > 0) continue; + o = Math.min(o, o + p + u); + let g = [...r[0]][0].length, h = e.slice(0, s + r.index + g + o); + if (Math.min(s, o) % 2) { let f = h.slice(1, -1); return { type: "em", raw: h, text: f, tokens: this.lexer.inlineTokens(f) }; } @@ -30465,7 +31317,7 @@ ${p}` : p; } } }; -var x = class u { +var x = class l { tokens; options; state; @@ -30480,10 +31332,10 @@ var x = class u { return { block: C, inline: M }; } static lex(e, t) { - return new u(t).lex(e); + return new l(t).lex(e); } static lexInline(e, t) { - return new u(t).inlineTokens(e); + return new l(t).inlineTokens(e); } lex(e) { e = e.replace(m.carriageReturn, ` @@ -30557,9 +31409,9 @@ var x = class u { } let i = e; if (this.options.extensions?.startBlock) { - let s = 1 / 0, o = e.slice(1), a; - this.options.extensions.startBlock.forEach((l) => { - a = l.call({ lexer: this }, o), typeof a == "number" && a >= 0 && (s = Math.min(s, a)); + let s = 1 / 0, a = e.slice(1), o; + this.options.extensions.startBlock.forEach((p) => { + o = p.call({ lexer: this }, a), typeof o == "number" && o >= 0 && (s = Math.min(s, o)); }), s < 1 / 0 && s >= 0 && (i = e.substring(0, s + 1)); } if (this.state.top && (r = this.tokenizer.paragraph(i))) { @@ -30599,13 +31451,14 @@ var x = class u { if (o.length > 0) for (; (r = this.tokenizer.rules.inline.reflinkSearch.exec(n)) != null; ) o.includes(r[0].slice(r[0].lastIndexOf("[") + 1, -1)) && (n = n.slice(0, r.index) + "[" + "a".repeat(r[0].length - 2) + "]" + n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex)); } for (; (r = this.tokenizer.rules.inline.anyPunctuation.exec(n)) != null; ) n = n.slice(0, r.index) + "++" + n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex); - for (; (r = this.tokenizer.rules.inline.blockSkip.exec(n)) != null; ) n = n.slice(0, r.index) + "[" + "a".repeat(r[0].length - 2) + "]" + n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex); + let i; + for (; (r = this.tokenizer.rules.inline.blockSkip.exec(n)) != null; ) i = r[2] ? r[2].length : 0, n = n.slice(0, r.index + i) + "[" + "a".repeat(r[0].length - i - 2) + "]" + n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex); n = this.options.hooks?.emStrongMask?.call({ lexer: this }, n) ?? n; - let i = false, s = ""; + let s = false, a = ""; for (; e; ) { - i || (s = ""), i = false; + s || (a = ""), s = false; let o; - if (this.options.extensions?.inline?.some((l) => (o = l.call({ lexer: this }, e, t)) ? (e = e.substring(o.raw.length), t.push(o), true) : false)) continue; + if (this.options.extensions?.inline?.some((u) => (o = u.call({ lexer: this }, e, t)) ? (e = e.substring(o.raw.length), t.push(o), true) : false)) continue; if (o = this.tokenizer.escape(e)) { e = e.substring(o.raw.length), t.push(o); continue; @@ -30620,11 +31473,11 @@ var x = class u { } if (o = this.tokenizer.reflink(e, this.tokens.links)) { e = e.substring(o.raw.length); - let l = t.at(-1); - o.type === "text" && l?.type === "text" ? (l.raw += o.raw, l.text += o.text) : t.push(o); + let u = t.at(-1); + o.type === "text" && u?.type === "text" ? (u.raw += o.raw, u.text += o.text) : t.push(o); continue; } - if (o = this.tokenizer.emStrong(e, n, s)) { + if (o = this.tokenizer.emStrong(e, n, a)) { e = e.substring(o.raw.length), t.push(o); continue; } @@ -30648,25 +31501,25 @@ var x = class u { e = e.substring(o.raw.length), t.push(o); continue; } - let a = e; + let p = e; if (this.options.extensions?.startInline) { - let l = 1 / 0, c = e.slice(1), p; - this.options.extensions.startInline.forEach((g) => { - p = g.call({ lexer: this }, c), typeof p == "number" && p >= 0 && (l = Math.min(l, p)); - }), l < 1 / 0 && l >= 0 && (a = e.substring(0, l + 1)); - } - if (o = this.tokenizer.inlineText(a)) { - e = e.substring(o.raw.length), o.raw.slice(-1) !== "_" && (s = o.raw.slice(-1)), i = true; - let l = t.at(-1); - l?.type === "text" ? (l.raw += o.raw, l.text += o.text) : t.push(o); + let u = 1 / 0, c = e.slice(1), g; + this.options.extensions.startInline.forEach((h) => { + g = h.call({ lexer: this }, c), typeof g == "number" && g >= 0 && (u = Math.min(u, g)); + }), u < 1 / 0 && u >= 0 && (p = e.substring(0, u + 1)); + } + if (o = this.tokenizer.inlineText(p)) { + e = e.substring(o.raw.length), o.raw.slice(-1) !== "_" && (a = o.raw.slice(-1)), s = true; + let u = t.at(-1); + u?.type === "text" ? (u.raw += o.raw, u.text += o.text) : t.push(o); continue; } if (e) { - let l = "Infinite loop on byte: " + e.charCodeAt(0); + let u = "Infinite loop on byte: " + e.charCodeAt(0); if (this.options.silent) { - console.error(l); + console.error(u); break; - } else throw new Error(l); + } else throw new Error(u); } } return t; @@ -30709,9 +31562,9 @@ ${this.parser.parse(e)} } list(e) { let t = e.ordered, n = e.start, r = ""; - for (let o = 0; o < e.items.length; o++) { - let a = e.items[o]; - r += this.listitem(a); + for (let a = 0; a < e.items.length; a++) { + let o = e.items[a]; + r += this.listitem(o); } let i = t ? "ol" : "ul", s = t && n !== 1 ? ' start="' + n + '"' : ""; return "<" + i + s + `> @@ -30742,7 +31595,7 @@ ${this.parser.parse(e)} for (let i = 0; i < e.rows.length; i++) { let s = e.rows[i]; n = ""; - for (let o = 0; o < s.length; o++) n += this.tablecell(s[o]); + for (let a = 0; a < s.length; a++) n += this.tablecell(s[a]); r += this.tablerow({ text: n }); } return r && (r = `${r}`), ` @@ -30824,7 +31677,7 @@ var $ = class { return ""; } }; -var b = class u2 { +var b = class l2 { options; renderer; textRenderer; @@ -30832,19 +31685,19 @@ var b = class u2 { this.options = e || T, this.options.renderer = this.options.renderer || new P(), this.renderer = this.options.renderer, this.renderer.options = this.options, this.renderer.parser = this, this.textRenderer = new $(); } static parse(e, t) { - return new u2(t).parse(e); + return new l2(t).parse(e); } static parseInline(e, t) { - return new u2(t).parseInline(e); + return new l2(t).parseInline(e); } parse(e, t = true) { let n = ""; for (let r = 0; r < e.length; r++) { let i = e[r]; if (this.options.extensions?.renderers?.[i.type]) { - let o = i, a = this.options.extensions.renderers[o.type].call({ parser: this }, o); - if (a !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "def", "paragraph", "text"].includes(o.type)) { - n += a || ""; + let a = i, o = this.options.extensions.renderers[a.type].call({ parser: this }, a); + if (o !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "def", "paragraph", "text"].includes(a.type)) { + n += o || ""; continue; } } @@ -30891,16 +31744,16 @@ var b = class u2 { continue; } case "text": { - let o = s, a = this.renderer.text(o); - for (; r + 1 < e.length && e[r + 1].type === "text"; ) o = e[++r], a += ` -` + this.renderer.text(o); - t ? n += this.renderer.paragraph({ type: "paragraph", raw: a, text: a, tokens: [{ type: "text", raw: a, text: a, escaped: true }] }) : n += a; + let a = s, o = this.renderer.text(a); + for (; r + 1 < e.length && e[r + 1].type === "text"; ) a = e[++r], o += ` +` + this.renderer.text(a); + t ? n += this.renderer.paragraph({ type: "paragraph", raw: o, text: o, tokens: [{ type: "text", raw: o, text: o, escaped: true }] }) : n += o; continue; } default: { - let o = 'Token with "' + s.type + '" type was not found.'; - if (this.options.silent) return console.error(o), ""; - throw new Error(o); + let a = 'Token with "' + s.type + '" type was not found.'; + if (this.options.silent) return console.error(a), ""; + throw new Error(a); } } } @@ -30911,9 +31764,9 @@ var b = class u2 { for (let r = 0; r < e.length; r++) { let i = e[r]; if (this.options.extensions?.renderers?.[i.type]) { - let o = this.options.extensions.renderers[i.type].call({ parser: this }, i); - if (o !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(i.type)) { - n += o || ""; + let a = this.options.extensions.renderers[i.type].call({ parser: this }, i); + if (a !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(i.type)) { + n += a || ""; continue; } } @@ -30960,9 +31813,9 @@ var b = class u2 { break; } default: { - let o = 'Token with "' + s.type + '" type was not found.'; - if (this.options.silent) return console.error(o), ""; - throw new Error(o); + let a = 'Token with "' + s.type + '" type was not found.'; + if (this.options.silent) return console.error(a), ""; + throw new Error(a); } } } @@ -31016,7 +31869,7 @@ var B = class { case "table": { let i = r; for (let s of i.header) n = n.concat(this.walkTokens(s.tokens, t)); - for (let s of i.rows) for (let o of s) n = n.concat(this.walkTokens(o.tokens, t)); + for (let s of i.rows) for (let a of s) n = n.concat(this.walkTokens(a.tokens, t)); break; } case "list": { @@ -31027,8 +31880,8 @@ var B = class { default: { let i = r; this.defaults.extensions?.childTokens?.[i.type] ? this.defaults.extensions.childTokens[i.type].forEach((s) => { - let o = i[s].flat(1 / 0); - n = n.concat(this.walkTokens(o, t)); + let a = i[s].flat(1 / 0); + n = n.concat(this.walkTokens(a, t)); }) : i.tokens && (n = n.concat(this.walkTokens(i.tokens, t))); } } @@ -31042,9 +31895,9 @@ var B = class { if (!i.name) throw new Error("extension name required"); if ("renderer" in i) { let s = t.renderers[i.name]; - s ? t.renderers[i.name] = function(...o) { - let a = i.renderer.apply(this, o); - return a === false && (a = s.apply(this, o)), a; + s ? t.renderers[i.name] = function(...a) { + let o = i.renderer.apply(this, a); + return o === false && (o = s.apply(this, a)), o; } : t.renderers[i.name] = i.renderer; } if ("tokenizer" in i) { @@ -31058,10 +31911,10 @@ var B = class { for (let s in n.renderer) { if (!(s in i)) throw new Error(`renderer '${s}' does not exist`); if (["options", "parser"].includes(s)) continue; - let o = s, a = n.renderer[o], l = i[o]; - i[o] = (...c) => { - let p = a.apply(i, c); - return p === false && (p = l.apply(i, c)), p || ""; + let a = s, o = n.renderer[a], p = i[a]; + i[a] = (...u) => { + let c = o.apply(i, u); + return c === false && (c = p.apply(i, u)), c || ""; }; } r.renderer = i; @@ -31071,10 +31924,10 @@ var B = class { for (let s in n.tokenizer) { if (!(s in i)) throw new Error(`tokenizer '${s}' does not exist`); if (["options", "rules", "lexer"].includes(s)) continue; - let o = s, a = n.tokenizer[o], l = i[o]; - i[o] = (...c) => { - let p = a.apply(i, c); - return p === false && (p = l.apply(i, c)), p; + let a = s, o = n.tokenizer[a], p = i[a]; + i[a] = (...u) => { + let c = o.apply(i, u); + return c === false && (c = p.apply(i, u)), c; }; } r.tokenizer = i; @@ -31084,30 +31937,30 @@ var B = class { for (let s in n.hooks) { if (!(s in i)) throw new Error(`hook '${s}' does not exist`); if (["options", "block"].includes(s)) continue; - let o = s, a = n.hooks[o], l = i[o]; - S.passThroughHooks.has(s) ? i[o] = (c) => { + let a = s, o = n.hooks[a], p = i[a]; + S.passThroughHooks.has(s) ? i[a] = (u) => { if (this.defaults.async && S.passThroughHooksRespectAsync.has(s)) return (async () => { - let g = await a.call(i, c); - return l.call(i, g); + let g = await o.call(i, u); + return p.call(i, g); })(); - let p = a.call(i, c); - return l.call(i, p); - } : i[o] = (...c) => { + let c = o.call(i, u); + return p.call(i, c); + } : i[a] = (...u) => { if (this.defaults.async) return (async () => { - let g = await a.apply(i, c); - return g === false && (g = await l.apply(i, c)), g; + let g = await o.apply(i, u); + return g === false && (g = await p.apply(i, u)), g; })(); - let p = a.apply(i, c); - return p === false && (p = l.apply(i, c)), p; + let c = o.apply(i, u); + return c === false && (c = p.apply(i, u)), c; }; } r.hooks = i; } if (n.walkTokens) { let i = this.defaults.walkTokens, s = n.walkTokens; - r.walkTokens = function(o) { - let a = []; - return a.push(s.call(this, o)), i && (a = a.concat(i.call(this, o))), a; + r.walkTokens = function(a) { + let o = []; + return o.push(s.call(this, a)), i && (o = o.concat(i.call(this, a))), o; }; } this.defaults = { ...this.defaults, ...r }; @@ -31124,24 +31977,24 @@ var B = class { } parseMarkdown(e) { return (n, r) => { - let i = { ...r }, s = { ...this.defaults, ...i }, o = this.onError(!!s.silent, !!s.async); - if (this.defaults.async === true && i.async === false) return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise.")); - if (typeof n > "u" || n === null) return o(new Error("marked(): input parameter is undefined or null")); - if (typeof n != "string") return o(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(n) + ", string expected")); + let i = { ...r }, s = { ...this.defaults, ...i }, a = this.onError(!!s.silent, !!s.async); + if (this.defaults.async === true && i.async === false) return a(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise.")); + if (typeof n > "u" || n === null) return a(new Error("marked(): input parameter is undefined or null")); + if (typeof n != "string") return a(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(n) + ", string expected")); if (s.hooks && (s.hooks.options = s, s.hooks.block = e), s.async) return (async () => { - let a = s.hooks ? await s.hooks.preprocess(n) : n, c = await (s.hooks ? await s.hooks.provideLexer() : e ? x.lex : x.lexInline)(a, s), p = s.hooks ? await s.hooks.processAllTokens(c) : c; - s.walkTokens && await Promise.all(this.walkTokens(p, s.walkTokens)); - let h = await (s.hooks ? await s.hooks.provideParser() : e ? b.parse : b.parseInline)(p, s); + let o = s.hooks ? await s.hooks.preprocess(n) : n, u = await (s.hooks ? await s.hooks.provideLexer() : e ? x.lex : x.lexInline)(o, s), c = s.hooks ? await s.hooks.processAllTokens(u) : u; + s.walkTokens && await Promise.all(this.walkTokens(c, s.walkTokens)); + let h = await (s.hooks ? await s.hooks.provideParser() : e ? b.parse : b.parseInline)(c, s); return s.hooks ? await s.hooks.postprocess(h) : h; - })().catch(o); + })().catch(a); try { s.hooks && (n = s.hooks.preprocess(n)); - let l = (s.hooks ? s.hooks.provideLexer() : e ? x.lex : x.lexInline)(n, s); - s.hooks && (l = s.hooks.processAllTokens(l)), s.walkTokens && this.walkTokens(l, s.walkTokens); - let p = (s.hooks ? s.hooks.provideParser() : e ? b.parse : b.parseInline)(l, s); - return s.hooks && (p = s.hooks.postprocess(p)), p; - } catch (a) { - return o(a); + let p = (s.hooks ? s.hooks.provideLexer() : e ? x.lex : x.lexInline)(n, s); + s.hooks && (p = s.hooks.processAllTokens(p)), s.walkTokens && this.walkTokens(p, s.walkTokens); + let c = (s.hooks ? s.hooks.provideParser() : e ? b.parse : b.parseInline)(p, s); + return s.hooks && (c = s.hooks.postprocess(c)), c; + } catch (o) { + return a(o); } }; } @@ -31158,19 +32011,19 @@ Please report this to https://github.com/markedjs/marked.`, e) { } }; var _ = new B(); -function k(u3, e) { - return _.parse(u3, e); +function k(l3, e) { + return _.parse(l3, e); } -k.options = k.setOptions = function(u3) { - return _.setOptions(u3), k.defaults = _.defaults, G(k.defaults), k; +k.options = k.setOptions = function(l3) { + return _.setOptions(l3), k.defaults = _.defaults, G(k.defaults), k; }; k.getDefaults = L; k.defaults = T; -k.use = function(...u3) { - return _.use(...u3), k.defaults = _.defaults, G(k.defaults), k; +k.use = function(...l3) { + return _.use(...l3), k.defaults = _.defaults, G(k.defaults), k; }; -k.walkTokens = function(u3, e) { - return _.walkTokens(u3, e); +k.walkTokens = function(l3, e) { + return _.walkTokens(l3, e); }; k.parseInline = _.parseInline; k.Parser = b; @@ -31182,13 +32035,13 @@ k.lexer = x.lex; k.Tokenizer = y; k.Hooks = S; k.parse = k; -var Ht = k.options; -var Zt = k.setOptions; -var Gt = k.use; -var Nt = k.walkTokens; -var Ft = k.parseInline; -var Qt = b.parse; -var Ut = x.lex; +var Zt = k.options; +var Gt = k.setOptions; +var Nt = k.use; +var Ft = k.walkTokens; +var jt = k.parseInline; +var Ut = b.parse; +var Kt = x.lex; // src/show.ts function formatConversationAsMarkdown(jsonl, startLine, endLine) { @@ -31892,11 +32745,11 @@ var ShowConversationInputSchema = external_exports.object({ startLine: external_exports.number().int().min(1).optional().describe("Starting line number (1-indexed, inclusive). Omit to start from beginning."), endLine: external_exports.number().int().min(1).optional().describe("Ending line number (1-indexed, inclusive). Omit to read to end.") }).strict(); -function handleError(error61) { - if (error61 instanceof Error) { - return `Error: ${error61.message}`; +function handleError(error62) { + if (error62 instanceof Error) { + return `Error: ${error62.message}`; } - return `Error: ${String(error61)}`; + return `Error: ${String(error62)}`; } var server = new Server( { @@ -32059,12 +32912,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { }; } throw new Error(`Unknown tool: ${name}`); - } catch (error61) { + } catch (error62) { return { content: [ { type: "text", - text: handleError(error61) + text: handleError(error62) } ], isError: true @@ -32076,7 +32929,7 @@ async function main() { const transport = new StdioServerTransport(); await server.connect(transport); } -main().catch((error61) => { - console.error("Server error:", error61); +main().catch((error62) => { + console.error("Server error:", error62); process.exit(1); }); diff --git a/dist/parser.js b/dist/parser.js index dcc1c270..7a2108f8 100644 --- a/dist/parser.js +++ b/dist/parser.js @@ -71,6 +71,16 @@ export async function parseConversation(filePath, projectName, archivePath) { } return parseClaudeConversation(filePath, projectName, archivePath); } +// Channel-bridge plugins (Discord, Slack, ...) deliver the user's own words as +// isMeta:true user lines with origin.kind === "channel" (anthropics/claude-code#44828), +// so isMeta alone does not mean "not the user's input"; provenance is in origin.kind. +const HUMAN_ORIGIN_KINDS = new Set(['channel', 'human']); +function isInjectedMetaLine(msg) { + if (msg.isMeta !== true) + return false; + const kind = msg.origin?.kind; + return !(typeof kind === 'string' && HUMAN_ORIGIN_KINDS.has(kind)); +} async function parseClaudeConversation(filePath, projectName, archivePath) { const exchanges = []; const fileStream = fs.createReadStream(filePath); @@ -129,6 +139,19 @@ async function parseClaudeConversation(filePath, projectName, archivePath) { if (!parsed.message) { continue; } + // Harness-injected user lines carry isMeta:true: image-paste placeholders + // ("[Image: source: ...]"), Skill tool bodies, task/system notifications, + // local-command caveats, coordinator messages, "Continue from where you + // left off.". They are not the user's words, so while an exchange is open + // they must not start a new one: a pasted image yields the real prompt line + // followed by an isMeta placeholder line with no assistant reply between, + // and finalizeExchange() would drop the real prompt. Their text is not + // indexed; the assistant lines that follow attach to the open exchange. + // With no exchange open (a session that opens with a notification) the + // line still starts one, so no assistant text is ever lost. + if (parsed.message.role === 'user' && currentExchange && isInjectedMetaLine(parsed)) { + continue; + } // Extract text from message content let text = ''; const toolCalls = []; @@ -630,6 +653,50 @@ async function parseOmpConversation(filePath, projectName, archivePath) { finalizeExchange(); return exchanges; } +// Codex injects system context as ordinary user-role message items with no field +// that tells them apart from typed prompts. The only safe content signal is a +// COMPLETE canonical fragment: an input_text block that is exactly one wrapper +// element, or the AGENTS.md instructions block. A prefix is not enough — a typed +// prompt may open with an XML snippet or a look-alike heading. Only wrappers +// that Codex emits with role "user" are listed: observed in rollouts +// (, , , "# AGENTS.md +// instructions" + ) or defined with role user in codex-rs +// (legacy , ). Developer-role wrappers +// (, , ...) never reach the user branch. +const CODEX_INJECTED_OPEN = /^<(environment_context|recommended_plugins|skill|user_instructions|subagent_notification)(?:\s[^>]*)?>/; +const CODEX_AGENTS_MD_OPEN = /^# AGENTS\.md instructions(?: for [^\n]*)?\n\n\n/; +// Exactly one wrapper element: the block opens with the tag and the FIRST matching +// closing tag is the very end of the block — so ".. question +// .." (text between elements, or several elements) is user text. +function endsAtFirstClose(text, closing) { + const close = text.indexOf(closing); + return close !== -1 && close + closing.length === text.length; +} +function isCodexInjectedBlock(text) { + const trimmed = text.trim(); + if (CODEX_AGENTS_MD_OPEN.test(trimmed)) { + return endsAtFirstClose(trimmed, ''); + } + const open = CODEX_INJECTED_OPEN.exec(trimmed); + return open !== null && endsAtFirstClose(trimmed, ''); +} +// Split a Codex user item into the user's own text and the number of injected +// blocks it carried — block by block, so a real request that shares an item with +// an injected block is kept. +function splitCodexUserContent(content) { + const blocks = typeof content === 'string' + ? [{ type: 'input_text', text: content }] + : Array.isArray(content) ? content : []; + let injected = 0; + const kept = blocks.filter(block => { + if (block && typeof block.text === 'string' && isCodexInjectedBlock(block.text)) { + injected++; + return false; + } + return true; + }); + return { userText: extractTextFromContent(kept), injected }; +} async function parseCodexConversation(filePath, projectName, archivePath) { const exchanges = []; const fileStream = fs.createReadStream(filePath); @@ -645,6 +712,11 @@ async function parseCodexConversation(filePath, projectName, archivePath) { let model; let modelProvider; let currentExchange = null; + // A user item from which injected blocks were removed: either held back entirely + // (injected-only, while an exchange was open) or trimmed to its remaining text. + // If the very next event vouches for the ORIGINAL text as a typed UserMessage, + // the full authored prompt is restored. + let pendingInjected = null; const toolCallsByCallId = new Map(); const currentProject = () => projectFromCwd(cwd) || projectName; const applyMetadataToCurrentExchange = () => { @@ -692,14 +764,14 @@ async function parseCodexConversation(filePath, projectName, archivePath) { currentExchange = null; toolCallsByCallId.clear(); }; - const startExchange = (text, timestamp) => { + const startExchange = (text, timestamp, line = lineNumber) => { finalizeExchange(); currentExchange = { project: currentProject(), userMessage: text, - userLine: lineNumber, + userLine: line, assistantMessages: [], - lastAssistantLine: lineNumber, + lastAssistantLine: line, timestamp, harness: 'codex', sessionId, @@ -777,16 +849,62 @@ async function parseCodexConversation(filePath, projectName, archivePath) { applyMetadataToCurrentExchange(); continue; } + // Positive provenance (newer rollouts): each typed prompt is followed by an + // item_completed UserMessage event (legacy: a user_message event). If one + // vouches for the item we just held back as injected, it was typed after all. + if (parsed.type === 'event_msg' && payload && pendingInjected) { + let vouched; + if (payload.type === 'item_completed' && payload.item?.type === 'UserMessage') { + vouched = extractTextFromContent(payload.item.content); + } + else if (payload.type === 'user_message' && typeof payload.message === 'string') { + vouched = payload.message; + } + if (vouched !== undefined && (!vouched.trim() || vouched.trim() === pendingInjected.text.trim())) { + if (pendingInjected.held) { + startExchange(pendingInjected.text, pendingInjected.timestamp, pendingInjected.line); + } + else { + // Trimmed item: the exchange it started is the current one. + const exchange = currentExchange; + if (exchange && exchange.userLine === pendingInjected.line) { + exchange.userMessage = pendingInjected.text; + } + } + pendingInjected = null; + } + continue; + } if (parsed.type !== 'response_item' || !payload) { continue; } + pendingInjected = null; if (payload.type === 'message') { const text = extractTextFromContent(payload.content); if (!text.trim()) { continue; } if (payload.role === 'user') { - startExchange(text, timestamp); + const { userText, injected } = splitCodexUserContent(payload.content); + if (userText.trim()) { + // The user's own words; injected blocks in the same item are dropped, but + // the original text is kept so a UserMessage event can restore it. + startExchange(userText, timestamp); + if (injected > 0) { + pendingInjected = { text, line: lineNumber, timestamp, held: false }; + } + } + else if (injected > 0 && currentExchange) { + // Injected-only item while an exchange is open: it must not split the + // exchange; the reply attaches to the typed prompt. Held back in case + // the next event proves it was typed. + pendingInjected = { text, line: lineNumber, timestamp, held: true }; + } + else { + // Nothing open yet (a rollout that starts with injected context): + // unchanged behavior, the item starts an exchange. + startExchange(text, timestamp); + } } else if (payload.role === 'assistant') { const exchange = currentExchange; @@ -1036,13 +1154,10 @@ async function parseCursorConversation(filePath, projectName, archivePath) { * Extracts project name from the file path and returns exchanges with metadata */ export async function parseConversationFile(filePath) { - // Extract project name from path (directory name before the .jsonl file) - const pathParts = filePath.split('/'); - let project = 'unknown'; - // Find the parent directory name (second to last part) - if (pathParts.length >= 2) { - project = pathParts[pathParts.length - 2]; - } + // Extract project name from path (directory name before the .jsonl file). + // path.dirname uses the platform's separators, so Windows paths with `\` work too. + const parentDir = path.basename(path.dirname(filePath)); + const project = parentDir && parentDir !== '.' ? parentDir : 'unknown'; const exchanges = await parseConversation(filePath, project, filePath); return { project, diff --git a/dist/paths.d.ts b/dist/paths.d.ts index 6cee3813..2e83417f 100644 --- a/dist/paths.d.ts +++ b/dist/paths.d.ts @@ -82,6 +82,12 @@ export declare function getSuperpowersDir(): string; * Get conversation archive directory */ export declare function getArchiveDir(): string; +/** + * Keep downloaded embedding models outside npm-owned node_modules so plugin + * upgrades do not discard the cache. An explicit override supports shared or + * pre-seeded caches on hosts without model-network access. + */ +export declare function getModelCacheDir(): string; /** * Get conversation index directory */ diff --git a/dist/paths.js b/dist/paths.js index e80076b1..d4d1df09 100644 --- a/dist/paths.js +++ b/dist/paths.js @@ -190,6 +190,21 @@ export function getArchiveDir() { } return ensureDir(path.join(getSuperpowersDir(), 'conversation-archive')); } +/** + * Keep downloaded embedding models outside npm-owned node_modules so plugin + * upgrades do not discard the cache. An explicit override supports shared or + * pre-seeded caches on hosts without model-network access. + */ +export function getModelCacheDir() { + const override = process.env.EPISODIC_MEMORY_MODEL_CACHE_DIR; + if (override) { + if (!path.isAbsolute(override)) { + throw new Error('EPISODIC_MEMORY_MODEL_CACHE_DIR must be an absolute path'); + } + return ensureDir(override); + } + return ensureDir(path.join(getSuperpowersDir(), 'models')); +} /** * Get conversation index directory */ diff --git a/dist/sync-cli.js b/dist/sync-cli.js index 26172c70..e444fd81 100644 --- a/dist/sync-cli.js +++ b/dist/sync-cli.js @@ -203,7 +203,7 @@ async function syncAll() { totals.summarized += result.summarized; totals.errors.push(...result.errors); } - console.log(`\n✅ Sync complete!`); + console.log(totals.errors.length > 0 ? '\n⚠️ Sync finished with errors.' : '\n✅ Sync complete!'); console.log(` Copied: ${totals.copied}`); console.log(` Skipped: ${totals.skipped}`); console.log(` Indexed: ${totals.indexed}`); diff --git a/package.json b/package.json index 58e050c9..8bc858cd 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "./package.json": "./package.json" }, "allowScripts": { - "better-sqlite3": true, + "better-sqlite3": false, "onnxruntime-node": true, "sharp": false }, @@ -35,7 +35,7 @@ "build": "tsc && npm run bundle", "bundle": "esbuild src/mcp-server.ts --bundle --platform=node --format=esm --outfile=dist/mcp-server.js --external:fsevents --external:@anthropic-ai/claude-agent-sdk --external:sharp --external:onnxruntime-node --external:better-sqlite3 --external:@huggingface/transformers --external:sqlite-vec --external:proper-lockfile", "postinstall": "node scripts/postinstall.js", - "pretest": "npm run generate-version", + "pretest": "npm run generate-version && tsx scripts/prepare-test-model.ts", "test": "vitest run", "test:claude-e2e": "node scripts/claude-e2e.js", "test:codex-e2e": "node scripts/codex-e2e.js", @@ -58,9 +58,9 @@ "type": "module", "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.126", - "@huggingface/transformers": "^4.2.0", + "@huggingface/transformers": "4.2.0", "@modelcontextprotocol/sdk": "^1.20.0", - "better-sqlite3": "^12.4.1", + "better-sqlite3": "^13.0.3", "marked": "^16.4.0", "proper-lockfile": "^4.1.2", "sqlite-vec": "^0.1.7-alpha.2", diff --git a/scripts/postinstall.js b/scripts/postinstall.js index b60431bb..f9dc2347 100644 --- a/scripts/postinstall.js +++ b/scripts/postinstall.js @@ -1,7 +1,7 @@ #!/usr/bin/env node /** - * Cross-platform postinstall: get better-sqlite3's native binding into a state - * where it actually loads, and refuse to report success until it does. + * Cross-platform postinstall: verify that better-sqlite3 and sqlite-vec work + * together, and refuse to report success until they do. * * Replaces the unix-only shell idiom that lived in package.json: * @@ -11,59 +11,43 @@ * and `|| true` doesn't behave the same — which makes `npm install` exit * non-zero even when every dependency installed correctly (#95). * - * Why the exit status of `npm rebuild` cannot be trusted (#100) - * ------------------------------------------------------------ - * `npm rebuild better-sqlite3` does not reliably run better-sqlite3's own - * install script (`prebuild-install || node-gyp rebuild --release`). On the npm - * shipped with recent Node it prints "rebuilt dependencies successfully", - * exits 0, and builds nothing. Separately, better-sqlite3 publishes prebuilds - * only for the Node versions in its `engines` range, so on a newer host Node - * `prebuild-install` can leave a binary compiled for an older ABI in place. + * Why this no longer rebuilds better-sqlite3 (#100) + * ------------------------------------------------- + * better-sqlite3 13.x ships N-API platform binaries in the npm package. They + * are not tied to a single Node module ABI and do not need an install script. + * Rebuilding the old 12.x addon was both unreliable and unsafe: a rebuild with + * Node 24.19-24.21 headers could produce a binding that loaded successfully but + * later aborted during statement garbage collection. * - * Both failures look identical from the outside: a clean install, and a plugin - * whose search silently returns nothing because the MCP server dies loading the - * binding — in a log nobody reads. + * A broken or partial install still looks like a clean install from the + * outside, while the MCP server dies loading the binding in a log nobody reads. * - * So this script does three things `status !== 0` cannot: + * So this script verifies behavior rather than trusting package-manager status: * * 1. Verifies by INSTANTIATING a database, not by requiring the module. * `require('better-sqlite3')` succeeds with no binding at all, because the * addon is loaded lazily inside `new Database()` (#100). - * 2. Verifies in a CHILD process. A native addon cannot be un-loaded, so a - * failed load poisons the module cache and an in-process re-check after a - * repair attempt would be meaningless. - * 3. On failure, falls back to better-sqlite3's real build path - * (`npm run build-release` = `node-gyp rebuild --release`) and re-verifies, - * rather than printing a recovery hint naming the command that just failed. + * 2. Loads sqlite-vec and performs a real vec0 insert plus nearest-neighbor + * query, rather than stopping at `vec_version()`. + * 3. Verifies in a CHILD process so native failures cannot poison the + * postinstall process. * - * Exit code reflects the binding, not the tooling: a noisy `npm rebuild` whose - * binding nevertheless loads is NOT fatal (that is the #95 false alarm), and a - * clean `npm rebuild` that leaves an unloadable binding IS. + * There is deliberately no automatic source-build fallback. If the bundled + * N-API binary cannot run, failing closed preserves the original evidence and + * avoids replacing it with a runtime-specific local build. */ import { spawnSync } from 'child_process'; -import { existsSync } from 'fs'; import { dirname, join } from 'path'; import { fileURLToPath } from 'url'; const PLUGIN_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); -const BETTER_SQLITE3_DIR = join(PLUGIN_ROOT, 'node_modules', 'better-sqlite3'); - -const isWindows = process.platform === 'win32'; -const npmBin = isWindows ? 'npm.cmd' : 'npm'; - -function npm(args, cwd) { - return spawnSync(npmBin, args, { - cwd, - stdio: ['ignore', 'inherit', 'inherit'], - shell: isWindows, - }); -} /** - * Load the native stack the way the MCP server will — instantiate a database, - * then load sqlite-vec into it — in a throwaway child process. + * Load the native stack the way the MCP server will: instantiate a database, + * load sqlite-vec, write a vector, and run a nearest-neighbor query. * - * Returns null on success, or { stderr } describing the failure. + * Returns the installed better-sqlite3 version on success, or a failure with + * stderr on error. * * sqlite-vec is only fatal when it is actually installed; during some install * orderings it is not resolvable yet, which is a dependency problem the @@ -74,12 +58,23 @@ function verifyNativeStack() { const script = ` const { createRequire } = require('module'); const req = createRequire(${pkgJson}); + const version = req('better-sqlite3/package.json').version; const Database = req('better-sqlite3'); const db = new Database(':memory:'); let vec = null; try { vec = req('sqlite-vec'); } catch (e) { vec = null; } - if (vec) { vec.load(db); db.prepare('select vec_version()').get(); } + if (vec) { + vec.load(db); + db.exec('CREATE VIRTUAL TABLE native_probe USING vec0(id TEXT PRIMARY KEY, embedding FLOAT[2])'); + const embedding = Buffer.from(new Float32Array([1, 0]).buffer); + db.prepare('INSERT INTO native_probe (id, embedding) VALUES (?, ?)').run('probe', embedding); + const row = db.prepare( + 'SELECT id FROM native_probe WHERE embedding MATCH ? AND k = 1' + ).get(embedding); + if (!row || row.id !== 'probe') throw new Error('sqlite-vec query returned the wrong row'); + } db.close(); + process.stdout.write(version); `; const result = spawnSync(process.execPath, ['-e', script], { @@ -87,44 +82,28 @@ function verifyNativeStack() { encoding: 'utf-8', }); - if (result.status === 0) return null; - return { stderr: (result.stderr || '').trim() || `child exited ${result.status}` }; + if (result.status === 0) { + return { version: (result.stdout || '').trim() || 'unknown', failure: null }; + } + return { + version: null, + failure: (result.stderr || '').trim() || `child exited ${result.status}`, + }; } -// Attempt 1: the cheap path that works on most hosts. -const rebuild = npm(['rebuild', 'better-sqlite3'], PLUGIN_ROOT); -let failure = verifyNativeStack(); +const verification = verifyNativeStack(); +const failure = verification.failure; -// Attempt 2: better-sqlite3's real build path. `npm rebuild` frequently does -// not run it, and it is the step that actually compiles for this Node's ABI. -let fallback = null; -if (failure && existsSync(BETTER_SQLITE3_DIR)) { +if (!failure) { console.error( - 'episodic-memory: better-sqlite3 binding did not load after `npm rebuild`; ' + - 'compiling from source with `npm run build-release`...' + `episodic-memory: native stack verified (better-sqlite3 ${verification.version}, ` + + `${process.version}, N-API ${process.versions.napi}).` ); - fallback = npm(['run', 'build-release'], BETTER_SQLITE3_DIR); - failure = verifyNativeStack(); - if (!failure) { - console.error('episodic-memory: source build succeeded — native binding loads.'); - } -} - -if (!failure) { - if (rebuild.status !== 0 && !fallback) { - // Rebuild complained but the binding loads — the #95 false-alarm case. - console.error( - `episodic-memory: 'npm rebuild better-sqlite3' exited ${rebuild.status}, ` + - 'but the native binding loads correctly for this Node ' + - `(${process.version}, NODE_MODULE_VERSION ${process.versions.modules}). ` + - 'Continuing.' - ); - } process.exit(0); } -const compiledFor = /NODE_MODULE_VERSION (\d+)/.exec(failure.stderr); -const noBindings = /Could not locate the bindings file/.test(failure.stderr); +const compiledFor = /NODE_MODULE_VERSION (\d+)/.exec(failure); +const noBindings = /Could not locate the bindings file/.test(failure); console.error(''); console.error('='.repeat(72)); @@ -137,21 +116,15 @@ if (compiledFor) { if (noBindings) { console.error(' binary : missing entirely (nothing was compiled)'); } -console.error(` npm rebuild exit : ${rebuild.status}`); -if (fallback) { - console.error(` source build exit: ${fallback.status}`); -} console.error(''); console.error(' underlying error:'); -for (const line of failure.stderr.split('\n').slice(0, 12)) { +for (const line of failure.split('\n').slice(0, 12)) { console.error(` ${line}`); } console.error(''); -console.error(' A source build needs a working toolchain: Xcode Command Line Tools on'); -console.error(' macOS, build-essential + python3 on Linux, VS Build Tools on Windows.'); -console.error(''); -console.error(' Recover with:'); -console.error(` cd "${BETTER_SQLITE3_DIR}" && npm run build-release`); +console.error(' better-sqlite3 13.x includes N-API platform binaries; do not compile'); +console.error(' the old 12.x addon as a fallback. Reinstall episodic-memory with the'); +console.error(' same package manifest, then rerun this check.'); console.error(''); console.error(' Failing the install deliberately: passing silently here is what lets'); console.error(' search disappear without anyone noticing.'); diff --git a/scripts/prepare-test-model.ts b/scripts/prepare-test-model.ts new file mode 100644 index 00000000..d7c61ce2 --- /dev/null +++ b/scripts/prepare-test-model.ts @@ -0,0 +1,12 @@ +import { initEmbeddings } from '../src/embeddings.js'; +import { testModelCacheDir } from '../test/test-model-cache.js'; + +process.env.EPISODIC_MEMORY_MODEL_CACHE_DIR = testModelCacheDir; + +try { + await initEmbeddings(); +} catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.error(`Test embedding model preparation failed: ${message}`); + process.exitCode = 1; +} diff --git a/src/embeddings.ts b/src/embeddings.ts index 131f9e40..b55fadf4 100644 --- a/src/embeddings.ts +++ b/src/embeddings.ts @@ -1,4 +1,5 @@ import type { FeatureExtractionPipeline } from '@huggingface/transformers'; +import { getModelCacheDir } from './paths.js'; /** * Embedding model configuration. @@ -70,6 +71,8 @@ export class EmbeddingsUnavailableError extends Error { export async function initEmbeddings(): Promise { if (embeddingPipeline) return; + const modelCacheDir = getModelCacheDir(); + const offline = process.env.EPISODIC_MEMORY_OFFLINE === '1'; // Load @huggingface/transformers lazily. Its module graph eagerly requires // `sharp`, so a static top-level import would crash *every* consumer of this @@ -79,9 +82,11 @@ export async function initEmbeddings(): Promise { let pipeline: typeof import('@huggingface/transformers').pipeline; try { const transformers = await import('@huggingface/transformers'); - // Disable progress callbacks / remote cache to prevent stdout pollution in - // MCP context, where stdout is reserved for JSON-RPC communication. + // Keep model files in durable operator-owned state. Offline mode is an + // explicit choice; a fresh default install can still fetch its model. + transformers.env.cacheDir = modelCacheDir; transformers.env.allowLocalModels = true; + transformers.env.allowRemoteModels = !offline; transformers.env.useBrowserCache = false; pipeline = transformers.pipeline; } catch (error) { @@ -106,7 +111,14 @@ export async function initEmbeddings(): Promise { interOpNumThreads: 1, }; } - embeddingPipeline = await pipeline('feature-extraction', MODEL_ID, options); + try { + embeddingPipeline = await pipeline('feature-extraction', MODEL_ID, options); + } catch (error) { + const message = offline + ? 'Embedding model unavailable in the local cache while EPISODIC_MEMORY_OFFLINE=1; pre-seed the model cache or disable offline mode.' + : 'Embedding model unavailable; check the model cache and remote model access.'; + throw new EmbeddingsUnavailableError(message, { cause: error }); + } console.error('Embedding model loaded'); } diff --git a/src/parser.ts b/src/parser.ts index a416a113..5cc32e93 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -15,6 +15,8 @@ interface JSONLMessage { uuid?: string; parentUuid?: string; isSidechain?: boolean; + isMeta?: boolean; + origin?: { kind?: string; [key: string]: unknown }; sessionId?: string; cwd?: string; gitBranch?: string; @@ -169,6 +171,17 @@ export async function parseConversation( return parseClaudeConversation(filePath, projectName, archivePath); } +// Channel-bridge plugins (Discord, Slack, ...) deliver the user's own words as +// isMeta:true user lines with origin.kind === "channel" (anthropics/claude-code#44828), +// so isMeta alone does not mean "not the user's input"; provenance is in origin.kind. +const HUMAN_ORIGIN_KINDS = new Set(['channel', 'human']); + +function isInjectedMetaLine(msg: JSONLMessage): boolean { + if (msg.isMeta !== true) return false; + const kind = msg.origin?.kind; + return !(typeof kind === 'string' && HUMAN_ORIGIN_KINDS.has(kind)); +} + async function parseClaudeConversation( filePath: string, projectName: string, @@ -240,6 +253,20 @@ async function parseClaudeConversation( continue; } + // Harness-injected user lines carry isMeta:true: image-paste placeholders + // ("[Image: source: ...]"), Skill tool bodies, task/system notifications, + // local-command caveats, coordinator messages, "Continue from where you + // left off.". They are not the user's words, so while an exchange is open + // they must not start a new one: a pasted image yields the real prompt line + // followed by an isMeta placeholder line with no assistant reply between, + // and finalizeExchange() would drop the real prompt. Their text is not + // indexed; the assistant lines that follow attach to the open exchange. + // With no exchange open (a session that opens with a notification) the + // line still starts one, so no assistant text is ever lost. + if (parsed.message.role === 'user' && currentExchange && isInjectedMetaLine(parsed)) { + continue; + } + // Extract text from message content let text = ''; const toolCalls: ToolCall[] = []; @@ -805,6 +832,54 @@ async function parseOmpConversation( return exchanges; } +// Codex injects system context as ordinary user-role message items with no field +// that tells them apart from typed prompts. The only safe content signal is a +// COMPLETE canonical fragment: an input_text block that is exactly one wrapper +// element, or the AGENTS.md instructions block. A prefix is not enough — a typed +// prompt may open with an XML snippet or a look-alike heading. Only wrappers +// that Codex emits with role "user" are listed: observed in rollouts +// (, , , "# AGENTS.md +// instructions" + ) or defined with role user in codex-rs +// (legacy , ). Developer-role wrappers +// (, , ...) never reach the user branch. +const CODEX_INJECTED_OPEN = /^<(environment_context|recommended_plugins|skill|user_instructions|subagent_notification)(?:\s[^>]*)?>/; +const CODEX_AGENTS_MD_OPEN = /^# AGENTS\.md instructions(?: for [^\n]*)?\n\n\n/; + +// Exactly one wrapper element: the block opens with the tag and the FIRST matching +// closing tag is the very end of the block — so ".. question +// .." (text between elements, or several elements) is user text. +function endsAtFirstClose(text: string, closing: string): boolean { + const close = text.indexOf(closing); + return close !== -1 && close + closing.length === text.length; +} + +function isCodexInjectedBlock(text: string): boolean { + const trimmed = text.trim(); + if (CODEX_AGENTS_MD_OPEN.test(trimmed)) { + return endsAtFirstClose(trimmed, ''); + } + const open = CODEX_INJECTED_OPEN.exec(trimmed); + return open !== null && endsAtFirstClose(trimmed, ''); +} + +// Split a Codex user item into the user's own text and the number of injected +// blocks it carried — block by block, so a real request that shares an item with +// an injected block is kept. +function splitCodexUserContent(content: unknown): { userText: string; injected: number } { + const blocks: any[] = typeof content === 'string' + ? [{ type: 'input_text', text: content }] + : Array.isArray(content) ? content : []; + let injected = 0; + const kept = blocks.filter(block => { + if (block && typeof block.text === 'string' && isCodexInjectedBlock(block.text)) { + injected++; + return false; + } + return true; + }); + return { userText: extractTextFromContent(kept), injected }; +} + async function parseCodexConversation( filePath: string, projectName: string, @@ -825,6 +900,11 @@ async function parseCodexConversation( let model: string | undefined; let modelProvider: string | undefined; let currentExchange: ExchangeBuilder | null = null; + // A user item from which injected blocks were removed: either held back entirely + // (injected-only, while an exchange was open) or trimmed to its remaining text. + // If the very next event vouches for the ORIGINAL text as a typed UserMessage, + // the full authored prompt is restored. + let pendingInjected: { text: string; line: number; timestamp: string; held: boolean } | null = null; const toolCallsByCallId = new Map(); const currentProject = () => projectFromCwd(cwd) || projectName; @@ -878,14 +958,14 @@ async function parseCodexConversation( toolCallsByCallId.clear(); }; - const startExchange = (text: string, timestamp: string) => { + const startExchange = (text: string, timestamp: string, line: number = lineNumber) => { finalizeExchange(); currentExchange = { project: currentProject(), userMessage: text, - userLine: lineNumber, + userLine: line, assistantMessages: [], - lastAssistantLine: lineNumber, + lastAssistantLine: line, timestamp, harness: 'codex', sessionId, @@ -971,9 +1051,35 @@ async function parseCodexConversation( continue; } + // Positive provenance (newer rollouts): each typed prompt is followed by an + // item_completed UserMessage event (legacy: a user_message event). If one + // vouches for the item we just held back as injected, it was typed after all. + if (parsed.type === 'event_msg' && payload && pendingInjected) { + let vouched: string | undefined; + if (payload.type === 'item_completed' && payload.item?.type === 'UserMessage') { + vouched = extractTextFromContent(payload.item.content); + } else if (payload.type === 'user_message' && typeof payload.message === 'string') { + vouched = payload.message; + } + if (vouched !== undefined && (!vouched.trim() || vouched.trim() === pendingInjected.text.trim())) { + if (pendingInjected.held) { + startExchange(pendingInjected.text, pendingInjected.timestamp, pendingInjected.line); + } else { + // Trimmed item: the exchange it started is the current one. + const exchange = currentExchange as ExchangeBuilder | null; + if (exchange && exchange.userLine === pendingInjected.line) { + exchange.userMessage = pendingInjected.text; + } + } + pendingInjected = null; + } + continue; + } + if (parsed.type !== 'response_item' || !payload) { continue; } + pendingInjected = null; if (payload.type === 'message') { const text = extractTextFromContent(payload.content); @@ -982,7 +1088,24 @@ async function parseCodexConversation( } if (payload.role === 'user') { - startExchange(text, timestamp); + const { userText, injected } = splitCodexUserContent(payload.content); + if (userText.trim()) { + // The user's own words; injected blocks in the same item are dropped, but + // the original text is kept so a UserMessage event can restore it. + startExchange(userText, timestamp); + if (injected > 0) { + pendingInjected = { text, line: lineNumber, timestamp, held: false }; + } + } else if (injected > 0 && currentExchange) { + // Injected-only item while an exchange is open: it must not split the + // exchange; the reply attaches to the typed prompt. Held back in case + // the next event proves it was typed. + pendingInjected = { text, line: lineNumber, timestamp, held: true }; + } else { + // Nothing open yet (a rollout that starts with injected context): + // unchanged behavior, the item starts an exchange. + startExchange(text, timestamp); + } } else if (payload.role === 'assistant') { const exchange = currentExchange as ExchangeBuilder | null; if (exchange) { @@ -1261,14 +1384,10 @@ export async function parseConversationFile(filePath: string): Promise<{ project: string; exchanges: ConversationExchange[]; }> { - // Extract project name from path (directory name before the .jsonl file) - const pathParts = filePath.split('/'); - let project = 'unknown'; - - // Find the parent directory name (second to last part) - if (pathParts.length >= 2) { - project = pathParts[pathParts.length - 2]; - } + // Extract project name from path (directory name before the .jsonl file). + // path.dirname uses the platform's separators, so Windows paths with `\` work too. + const parentDir = path.basename(path.dirname(filePath)); + const project = parentDir && parentDir !== '.' ? parentDir : 'unknown'; const exchanges = await parseConversation(filePath, project, filePath); diff --git a/src/paths.ts b/src/paths.ts index 4a08f2fe..8a02a510 100644 --- a/src/paths.ts +++ b/src/paths.ts @@ -204,6 +204,22 @@ export function getArchiveDir(): string { return ensureDir(path.join(getSuperpowersDir(), 'conversation-archive')); } +/** + * Keep downloaded embedding models outside npm-owned node_modules so plugin + * upgrades do not discard the cache. An explicit override supports shared or + * pre-seeded caches on hosts without model-network access. + */ +export function getModelCacheDir(): string { + const override = process.env.EPISODIC_MEMORY_MODEL_CACHE_DIR; + if (override) { + if (!path.isAbsolute(override)) { + throw new Error('EPISODIC_MEMORY_MODEL_CACHE_DIR must be an absolute path'); + } + return ensureDir(override); + } + return ensureDir(path.join(getSuperpowersDir(), 'models')); +} + /** * Get conversation index directory */ diff --git a/src/sync-cli.ts b/src/sync-cli.ts index 297b20f8..bc629f20 100644 --- a/src/sync-cli.ts +++ b/src/sync-cli.ts @@ -224,7 +224,7 @@ async function syncAll() { totals.errors.push(...result.errors); } - console.log(`\n✅ Sync complete!`); + console.log(totals.errors.length > 0 ? '\n⚠️ Sync finished with errors.' : '\n✅ Sync complete!'); console.log(` Copied: ${totals.copied}`); console.log(` Skipped: ${totals.skipped}`); console.log(` Indexed: ${totals.indexed}`); diff --git a/test/allow-scripts.test.ts b/test/allow-scripts.test.ts index 6f5c2e83..7c4cc942 100644 --- a/test/allow-scripts.test.ts +++ b/test/allow-scripts.test.ts @@ -5,17 +5,16 @@ import { join } from 'path'; const REPO_ROOT = join(import.meta.dirname, '..'); describe('package.json allowScripts (npm 12 install-script gating, #162)', () => { - it('approves the native-binding installs indexing depends on', () => { + it('allows only the native install scripts indexing still needs', () => { const pkg = JSON.parse(readFileSync(join(REPO_ROOT, 'package.json'), 'utf-8')); // Under npm 12 (and npm 11.16+ with blocking opted in), a dependency's // install/postinstall script is skipped unless the ROOT package's - // allowScripts explicitly permits it. Without this, `npm install` - // exits 0 while better-sqlite3 and onnxruntime-node silently ship - // with no native binding, and indexing/search fail forever with - // nothing surfacing the problem to the user. + // allowScripts explicitly permits it. onnxruntime-node still needs that + // permission; better-sqlite3 13.x bundles N-API binaries and must not fall + // back to a runtime-specific source build. expect(pkg.allowScripts).toBeDefined(); - expect(pkg.allowScripts['better-sqlite3']).toBe(true); + expect(pkg.allowScripts['better-sqlite3']).toBe(false); expect(pkg.allowScripts['onnxruntime-node']).toBe(true); // Bare package names, not pinned versions: a pinned key (e.g. @@ -26,6 +25,16 @@ describe('package.json allowScripts (npm 12 install-script gating, #162)', () => } }); + it('uses the N-API better-sqlite3 line that works across Node ABIs', () => { + const pkg = JSON.parse(readFileSync(join(REPO_ROOT, 'package.json'), 'utf-8')); + const postinstall = readFileSync(join(REPO_ROOT, 'scripts', 'postinstall.js'), 'utf-8'); + + expect(pkg.dependencies['better-sqlite3']).toBe('^13.0.3'); + expect(postinstall).not.toContain("npm(['rebuild', 'better-sqlite3']"); + expect(postinstall).not.toContain("npm(['run', 'build-release']"); + expect(postinstall).not.toContain('failure.stderr'); + }); + it('explicitly denies sharp\'s postinstall (#102)', () => { const pkg = JSON.parse(readFileSync(join(REPO_ROOT, 'package.json'), 'utf-8')); diff --git a/test/codex-plugin.test.ts b/test/codex-plugin.test.ts index 8c6cd2a5..9de5df81 100644 --- a/test/codex-plugin.test.ts +++ b/test/codex-plugin.test.ts @@ -40,6 +40,8 @@ describe('Codex plugin packaging', () => { 'PERSONAL_SUPERPOWERS_DIR', 'XDG_CONFIG_HOME', 'EPISODIC_MEMORY_DB_PATH', + 'EPISODIC_MEMORY_MODEL_CACHE_DIR', + 'EPISODIC_MEMORY_OFFLINE', 'CONVERSATION_SEARCH_EXCLUDE_PROJECTS' ] } diff --git a/test/codex-transcripts.test.ts b/test/codex-transcripts.test.ts index 9b39c58c..3da09217 100644 --- a/test/codex-transcripts.test.ts +++ b/test/codex-transcripts.test.ts @@ -305,3 +305,224 @@ describe('Codex transcript support', () => { db.close(); }); }); + +describe('Codex transcripts - injected system items must not split an exchange', () => { + let dir: string; + beforeEach(() => { dir = mkdtempSync(join(tmpdir(), 'episodic-memory-codex-injected-')); }); + afterEach(() => { rmSync(dir, { recursive: true, force: true }); }); + + const meta = { + timestamp: '2026-09-10T13:34:21.000Z', + type: 'session_meta', + payload: { + id: '01a08b18-ea48-7e83-8503-3e21d476d9fa', + timestamp: '2026-09-10T13:34:21.000Z', + cwd: '/Users/testuser/Documents/GitHub/example-project', + originator: 'codex_cli_rs', + cli_version: '0.153.4', + source: 'cli', + model_provider: 'openai' + } + }; + const user = (text: string, ts: string) => ({ + timestamp: ts, + type: 'response_item', + payload: { type: 'message', role: 'user', content: [{ type: 'input_text', text }] } + }); + const userBlocks = (texts: string[], ts: string) => ({ + timestamp: ts, + type: 'response_item', + payload: { type: 'message', role: 'user', content: texts.map(text => ({ type: 'input_text', text })) } + }); + const assistant = (text: string, ts: string) => ({ + timestamp: ts, + type: 'response_item', + payload: { type: 'message', role: 'assistant', content: [{ type: 'output_text', text }] } + }); + // Newer Codex builds log each typed prompt as an item_completed UserMessage event + const userEvent = (text: string, ts: string) => ({ + timestamp: ts, + type: 'event_msg', + payload: { type: 'item_completed', item: { id: 'item_user_1', type: 'UserMessage', content: [{ type: 'text', text }] } } + }); + const agentsMd = '# AGENTS.md instructions\n\n\n# Standing rules\nNothing leaves this machine.\n'; + const envContext = (cwd: string) => `\n ${cwd}\n zsh\n`; + const plugins = '\nHere is a list of plugins the user may find useful.\n'; + const skillBody = '\nagent-chat\n/Users/testuser/.codex/skills/agent-chat/SKILL.md\n---\nname: agent-chat\n---\n# Agent Chat\nCommands: register, send, read.\n'; + + async function parse(lines: unknown[]) { + const file = join(dir, 'rollout-2026-09-10T13-34-21-01a08b18-ea48-7e83-8503-3e21d476d9fa.jsonl'); + writeJsonl(file, lines); + return parseConversation(file, '2026', file); + } + + it('keeps the typed prompt when a body is injected before the reply (real rollout shape)', async () => { + const exchanges = await parse([ + meta, + user(agentsMd, '2026-09-10T13:34:21.100Z'), + user(envContext('/Users/testuser/Documents/GitHub/example-project'), '2026-09-10T13:34:21.200Z'), + user('register in agent-chat as episodic-codex', '2026-09-10T13:34:30.000Z'), + userEvent('register in agent-chat as episodic-codex', '2026-09-10T13:34:30.100Z'), + user(skillBody, '2026-09-10T13:34:31.000Z'), + assistant('Registered as episodic-codex in the project room.', '2026-09-10T13:34:40.000Z') + ]); + + expect(exchanges).toHaveLength(1); + expect(exchanges[0].userMessage).toBe('register in agent-chat as episodic-codex'); + expect(exchanges[0].assistantMessage).toBe('Registered as episodic-codex in the project room.'); + expect(exchanges[0].lineStart).toBe(4); + expect(exchanges[0].lineEnd).toBe(7); + expect(exchanges[0].harness).toBe('codex'); + }); + + it('ignores user-role context re-injected between turns (single and multi-block items)', async () => { + const exchanges = await parse([ + meta, + user('First question.', '2026-09-10T14:00:00.000Z'), + assistant('First answer.', '2026-09-10T14:00:05.000Z'), + userBlocks([plugins, envContext('/Users/testuser/Documents/GitHub/example-project')], '2026-09-10T14:01:00.000Z'), + user('Second question.', '2026-09-10T14:01:01.000Z'), + assistant('Second answer.', '2026-09-10T14:01:06.000Z') + ]); + + expect(exchanges.map(e => [e.userMessage, e.assistantMessage])).toEqual([ + ['First question.', 'First answer.'], + ['Second question.', 'Second answer.'] + ]); + expect(exchanges[1].lineStart).toBe(5); + }); + + it('keeps a real request that shares an item with an injected block', async () => { + const exchanges = await parse([ + meta, + user('Warm-up.', '2026-09-10T14:10:00.000Z'), + assistant('Ready.', '2026-09-10T14:10:02.000Z'), + userBlocks([envContext('/Users/testuser/x'), 'Please rename the config loader.'], '2026-09-10T14:11:00.000Z'), + assistant('Renamed.', '2026-09-10T14:11:04.000Z') + ]); + + expect(exchanges).toHaveLength(2); + expect(exchanges[1].userMessage).toBe('Please rename the config loader.'); + expect(exchanges[1].assistantMessage).toBe('Renamed.'); + }); + + it('does not mistake typed text for an injected item on its opening prefix alone', async () => { + const exchanges = await parse([ + meta, + user('Here is my pom.', '2026-09-10T14:20:00.000Z'), + assistant('Go on.', '2026-09-10T14:20:02.000Z'), + // A typed Maven snippet that opens like a wrapper tag, followed by the question + user('\n maven-surefire-plugin\n\nWhy are my tests skipped?', '2026-09-10T14:21:00.000Z'), + assistant('Because skipTests is set.', '2026-09-10T14:21:05.000Z'), + // A heading that merely resembles the AGENTS.md header + user('# AGENTS.md instructions need cleanup\nPlease remove the obsolete setup instructions.', '2026-09-10T14:22:00.000Z'), + assistant('Removed them.', '2026-09-10T14:22:05.000Z'), + // A complete -like element the user pasted, but with trailing text + user('\nx\n\nIs this the right skill format?', '2026-09-10T14:23:00.000Z'), + assistant('Yes.', '2026-09-10T14:23:03.000Z') + ]); + + expect(exchanges.map(e => e.userMessage)).toEqual([ + 'Here is my pom.', + '\n maven-surefire-plugin\n\nWhy are my tests skipped?', + '# AGENTS.md instructions need cleanup\nPlease remove the obsolete setup instructions.', + '\nx\n\nIs this the right skill format?' + ]); + }); + + it('trusts a UserMessage event over the content heuristic', async () => { + const pasted = envContext('/Users/testuser/y'); // user pasted a complete wrapper block verbatim + const exchanges = await parse([ + meta, + user('Look at this.', '2026-09-10T14:30:00.000Z'), + assistant('Looking.', '2026-09-10T14:30:02.000Z'), + user(pasted, '2026-09-10T14:31:00.000Z'), + userEvent(pasted, '2026-09-10T14:31:00.100Z'), + assistant('That is an environment block.', '2026-09-10T14:31:05.000Z') + ]); + + expect(exchanges).toHaveLength(2); + expect(exchanges[1].userMessage).toBe(pasted); + expect(exchanges[1].lineStart).toBe(4); + expect(exchanges[1].assistantMessage).toBe('That is an environment block.'); + }); + + it('still treats user-input wrappers and image captions as prompts', async () => { + const exchanges = await parse([ + meta, + user('Look at the config.', '2026-09-10T15:00:00.000Z'), + assistant('Looking.', '2026-09-10T15:00:03.000Z'), + user('ls src', '2026-09-10T15:00:10.000Z'), + assistant('parser.ts show.ts', '2026-09-10T15:00:12.000Z'), + { + timestamp: '2026-09-10T15:01:00.000Z', + type: 'response_item', + payload: { type: 'message', role: 'user', content: [ + { type: 'input_text', text: ' ' }, + { type: 'input_image', image_url: 'data:image/png;base64,iVBORw0KGgo=' }, + { type: 'input_text', text: '' }, + { type: 'input_text', text: '[Image #1] please enable experimental context management.' } + ] } + }, + assistant('Enabled.', '2026-09-10T15:01:04.000Z') + ]); + + expect(exchanges).toHaveLength(3); + expect(exchanges[1].userMessage).toContain('ls src'); + expect(exchanges[2].userMessage).toContain('please enable experimental context management'); + }); + + it('treats several wrapper elements, or text between them, as user text (single-fragment rule)', async () => { + const twoSkills = 'old\nWhich definition should I keep?\nnew'; + const exchanges = await parse([ + meta, + user('Compare these.', '2026-09-10T14:40:00.000Z'), + assistant('Paste them.', '2026-09-10T14:40:02.000Z'), + user(twoSkills, '2026-09-10T14:41:00.000Z'), + assistant('Keep the new definition.', '2026-09-10T14:41:05.000Z') + ]); + + expect(exchanges).toHaveLength(2); + expect(exchanges[1].userMessage).toBe(twoSkills); + expect(exchanges[1].assistantMessage).toBe('Keep the new definition.'); + expect(exchanges[0].assistantMessage).toBe('Paste them.'); + }); + + it('restores the full authored prompt of a mixed item when a UserMessage event vouches for it', async () => { + const env = envContext('/Users/testuser/wrong-dir'); + const question = 'Why is this pointing at the wrong directory?'; + const exchanges = await parse([ + meta, + user('Hi.', '2026-09-10T14:50:00.000Z'), + assistant('Hello.', '2026-09-10T14:50:02.000Z'), + userBlocks([env, question], '2026-09-10T14:51:00.000Z'), + { + timestamp: '2026-09-10T14:51:00.100Z', + type: 'event_msg', + payload: { type: 'item_completed', item: { id: 'item_user_2', type: 'UserMessage', content: [ + { type: 'text', text: env }, { type: 'text', text: question } + ] } } + }, + assistant('Because cwd is stale.', '2026-09-10T14:51:05.000Z') + ]); + + expect(exchanges).toHaveLength(2); + expect(exchanges[1].userMessage).toBe(`${env}\n${question}`); + expect(exchanges[1].lineStart).toBe(4); + expect(exchanges[1].assistantMessage).toBe('Because cwd is stale.'); + }); + + it('lets an injected item open a session that has no prompt yet (unchanged behavior)', async () => { + const exchanges = await parse([ + meta, + user(envContext('/Users/testuser/x'), '2026-09-10T16:00:00.000Z'), + assistant('Ready.', '2026-09-10T16:00:02.000Z'), + user('Now the real prompt.', '2026-09-10T16:00:10.000Z'), + assistant('Real answer.', '2026-09-10T16:00:14.000Z') + ]); + + expect(exchanges).toHaveLength(2); + expect(exchanges[0].userMessage).toContain(''); + expect(exchanges[1].userMessage).toBe('Now the real prompt.'); + }); +}); diff --git a/test/file-lock.test.ts b/test/file-lock.test.ts index d01f776b..a1383309 100644 --- a/test/file-lock.test.ts +++ b/test/file-lock.test.ts @@ -66,7 +66,9 @@ describe('file-lock — proper-lockfile wrapper (#97)', () => { expect(readLockHolder(lockPath)).toBeNull(); }); - it('propagates unexpected I/O errors instead of masking them as "lock contention"', () => { + // POSIX only: Windows ignores directory mode bits, so the chmod below can't + // make the directory unwritable. + it.skipIf(process.platform === 'win32')('propagates unexpected I/O errors instead of masking them as "lock contention"', () => { // chmod the directory read-only so openSync('a') hits EACCES on the lock // target. The wrapper must throw rather than return null — otherwise sync // would report "already running" for what's actually a disk problem. diff --git a/test/fixtures/channel-plugin-conversation.jsonl b/test/fixtures/channel-plugin-conversation.jsonl new file mode 100644 index 00000000..e636f8ce --- /dev/null +++ b/test/fixtures/channel-plugin-conversation.jsonl @@ -0,0 +1,4 @@ +{"parentUuid":null,"isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"3fa92c26-0000-4000-8000-000000000003","version":"2.1.267","gitBranch":"main","type":"user","message":{"role":"user","content":"List the files in src."},"uuid":"c0000000-0000-4000-8000-000000000001","timestamp":"2026-09-10T11:00:00.000Z"} +{"parentUuid":"c0000000-0000-4000-8000-000000000001","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"3fa92c26-0000-4000-8000-000000000003","version":"2.1.267","gitBranch":"main","message":{"id":"msg_01Chan0000000000000000001","type":"message","role":"assistant","model":"claude-opus-4-1-20250805","content":[{"type":"text","text":"parser.ts and show.ts."}],"stop_reason":"end_turn","usage":{"input_tokens":500,"output_tokens":8}},"requestId":"req_chan_000001","type":"assistant","uuid":"c0000000-0000-4000-8000-000000000002","timestamp":"2026-09-10T11:00:05.000Z"} +{"parentUuid":"c0000000-0000-4000-8000-000000000002","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"3fa92c26-0000-4000-8000-000000000003","version":"2.1.267","gitBranch":"main","type":"user","message":{"role":"user","content":[{"type":"text","text":"Please explain the retry policy."}]},"isMeta":true,"origin":{"kind":"channel","server":"plugin:discord:discord"},"uuid":"c0000000-0000-4000-8000-000000000003","timestamp":"2026-09-10T11:02:00.000Z"} +{"parentUuid":"c0000000-0000-4000-8000-000000000003","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"3fa92c26-0000-4000-8000-000000000003","version":"2.1.267","gitBranch":"main","message":{"id":"msg_01Chan0000000000000000002","type":"message","role":"assistant","model":"claude-opus-4-1-20250805","content":[{"type":"text","text":"Retries use exponential backoff with a cap of five attempts."}],"stop_reason":"end_turn","usage":{"input_tokens":700,"output_tokens":14}},"requestId":"req_chan_000002","type":"assistant","uuid":"c0000000-0000-4000-8000-000000000004","timestamp":"2026-09-10T11:02:06.000Z"} diff --git a/test/fixtures/image-paste-conversation.jsonl b/test/fixtures/image-paste-conversation.jsonl new file mode 100644 index 00000000..23e47844 --- /dev/null +++ b/test/fixtures/image-paste-conversation.jsonl @@ -0,0 +1,3 @@ +{"parentUuid":null,"isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"1fa92c26-0000-4000-8000-000000000001","version":"2.1.267","gitBranch":"main","type":"user","message":{"role":"user","content":[{"type":"text","text":"[Image #1] I want to make Codex not ask any questions about permissions - can you help me with configuring it?"},{"type":"image","source":{"type":"base64","media_type":"image/png","data":"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="}}]},"uuid":"a0000000-0000-4000-8000-000000000001","timestamp":"2026-09-09T16:56:10.000Z","thinkingMetadata":{"level":"high","disabled":false,"triggers":[]}} +{"parentUuid":"a0000000-0000-4000-8000-000000000001","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"1fa92c26-0000-4000-8000-000000000001","version":"2.1.267","gitBranch":"main","type":"user","message":{"role":"user","content":[{"type":"text","text":"[Image: source: /Users/testuser/Downloads/Image 09-09-2026 at 18.56.jpg]"}]},"isMeta":true,"uuid":"a0000000-0000-4000-8000-000000000002","timestamp":"2026-09-09T16:56:10.100Z"} +{"parentUuid":"a0000000-0000-4000-8000-000000000002","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"1fa92c26-0000-4000-8000-000000000001","version":"2.1.267","gitBranch":"main","message":{"id":"msg_01Image0000000000000000001","type":"message","role":"assistant","model":"claude-opus-4-1-20250805","content":[{"type":"text","text":"Yes. Codex reads its approval policy from ~/.codex/config.toml. Set approval_policy = \"never\" and sandbox_mode = \"danger-full-access\" to stop the permission prompts."}],"stop_reason":"end_turn","usage":{"input_tokens":1200,"output_tokens":60}},"requestId":"req_image_000001","type":"assistant","uuid":"a0000000-0000-4000-8000-000000000003","timestamp":"2026-09-09T16:56:20.000Z"} diff --git a/test/fixtures/meta-first-conversation.jsonl b/test/fixtures/meta-first-conversation.jsonl new file mode 100644 index 00000000..38f02960 --- /dev/null +++ b/test/fixtures/meta-first-conversation.jsonl @@ -0,0 +1,4 @@ +{"parentUuid":null,"isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"4fa92c26-0000-4000-8000-000000000004","version":"2.1.267","gitBranch":"main","type":"user","message":{"role":"user","content":"[SYSTEM NOTIFICATION - NOT USER INPUT]\nThis is an automated background-task event.\nb1completed"},"isMeta":true,"origin":{"kind":"task-notification"},"uuid":"d0000000-0000-4000-8000-000000000001","timestamp":"2026-09-10T12:00:00.000Z"} +{"parentUuid":"d0000000-0000-4000-8000-000000000001","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"4fa92c26-0000-4000-8000-000000000004","version":"2.1.267","gitBranch":"main","message":{"id":"msg_01Meta0000000000000000001","type":"message","role":"assistant","model":"claude-opus-4-1-20250805","content":[{"type":"text","text":"The background task finished; nothing else is pending."}],"stop_reason":"end_turn","usage":{"input_tokens":300,"output_tokens":12}},"requestId":"req_meta_000001","type":"assistant","uuid":"d0000000-0000-4000-8000-000000000002","timestamp":"2026-09-10T12:00:04.000Z"} +{"parentUuid":"d0000000-0000-4000-8000-000000000002","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"4fa92c26-0000-4000-8000-000000000004","version":"2.1.267","gitBranch":"main","type":"user","message":{"role":"user","content":"Now summarize what changed."},"uuid":"d0000000-0000-4000-8000-000000000003","timestamp":"2026-09-10T12:01:00.000Z"} +{"parentUuid":"d0000000-0000-4000-8000-000000000003","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"4fa92c26-0000-4000-8000-000000000004","version":"2.1.267","gitBranch":"main","message":{"id":"msg_01Meta0000000000000000002","type":"message","role":"assistant","model":"claude-opus-4-1-20250805","content":[{"type":"text","text":"Two files changed: parser.ts and show.ts."}],"stop_reason":"end_turn","usage":{"input_tokens":420,"output_tokens":10}},"requestId":"req_meta_000002","type":"assistant","uuid":"d0000000-0000-4000-8000-000000000004","timestamp":"2026-09-10T12:01:05.000Z"} diff --git a/test/fixtures/skill-invocation-conversation.jsonl b/test/fixtures/skill-invocation-conversation.jsonl new file mode 100644 index 00000000..9f542e1d --- /dev/null +++ b/test/fixtures/skill-invocation-conversation.jsonl @@ -0,0 +1,8 @@ +{"parentUuid":null,"isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"2fa92c26-0000-4000-8000-000000000002","version":"2.1.267","gitBranch":"main","type":"user","message":{"role":"user","content":"register as summarizer in agent-chat"},"uuid":"b0000000-0000-4000-8000-000000000001","timestamp":"2026-09-10T10:00:00.000Z","thinkingMetadata":{"level":"high","disabled":false,"triggers":[]}} +{"parentUuid":"b0000000-0000-4000-8000-000000000001","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"2fa92c26-0000-4000-8000-000000000002","version":"2.1.267","gitBranch":"main","message":{"id":"msg_01Skill000000000000000000","type":"message","role":"assistant","model":"claude-opus-4-1-20250805","content":[{"type":"text","text":"I'll load the agent-chat skill to register under that name."}],"stop_reason":"end_turn","usage":{"input_tokens":880,"output_tokens":15}},"requestId":"req_skill_000000","type":"assistant","uuid":"b0000000-0000-4000-8000-000000000010","timestamp":"2026-09-10T10:00:03.000Z"} +{"parentUuid":"b0000000-0000-4000-8000-000000000010","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"2fa92c26-0000-4000-8000-000000000002","version":"2.1.267","gitBranch":"main","message":{"id":"msg_01Skill000000000000000001","type":"message","role":"assistant","model":"claude-opus-4-1-20250805","content":[{"type":"tool_use","id":"toolu_01skill0001","name":"Skill","input":{"skill":"agent-chat","args":"register as summarizer"}}],"stop_reason":"tool_use","usage":{"input_tokens":900,"output_tokens":40}},"requestId":"req_skill_000001","type":"assistant","uuid":"b0000000-0000-4000-8000-000000000002","timestamp":"2026-09-10T10:00:05.000Z"} +{"parentUuid":"b0000000-0000-4000-8000-000000000002","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"2fa92c26-0000-4000-8000-000000000002","version":"2.1.267","gitBranch":"main","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01skill0001","type":"tool_result","content":"Launching skill: agent-chat"}]},"uuid":"b0000000-0000-4000-8000-000000000003","timestamp":"2026-09-10T10:00:05.200Z"} +{"parentUuid":"b0000000-0000-4000-8000-000000000003","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"2fa92c26-0000-4000-8000-000000000002","version":"2.1.267","gitBranch":"main","type":"user","message":{"role":"user","content":[{"type":"text","text":"Base directory for this skill: /Users/testuser/.claude/skills/agent-chat\n\n# Agent Chat\n\nServerless chat for concurrent sessions. Commands: register, send, read, who.\n\nARGUMENTS: register as summarizer"}]},"isMeta":true,"uuid":"b0000000-0000-4000-8000-000000000004","timestamp":"2026-09-10T10:00:05.300Z"} +{"parentUuid":"b0000000-0000-4000-8000-000000000004","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"2fa92c26-0000-4000-8000-000000000002","version":"2.1.267","gitBranch":"main","message":{"id":"msg_01Skill000000000000000002","type":"message","role":"assistant","model":"claude-opus-4-1-20250805","content":[{"type":"text","text":"Registered as summarizer in the project room."}],"stop_reason":"end_turn","usage":{"input_tokens":1500,"output_tokens":20}},"requestId":"req_skill_000002","type":"assistant","uuid":"b0000000-0000-4000-8000-000000000005","timestamp":"2026-09-10T10:00:12.000Z"} +{"parentUuid":"b0000000-0000-4000-8000-000000000005","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"2fa92c26-0000-4000-8000-000000000002","version":"2.1.267","gitBranch":"main","type":"user","message":{"role":"user","content":"Continue from where you left off."},"isMeta":true,"uuid":"b0000000-0000-4000-8000-000000000006","timestamp":"2026-09-10T10:00:13.000Z"} +{"parentUuid":"b0000000-0000-4000-8000-000000000006","isSidechain":false,"userType":"external","cwd":"/Users/testuser/Documents/GitHub/example-project","sessionId":"2fa92c26-0000-4000-8000-000000000002","version":"2.1.267","gitBranch":"main","message":{"id":"msg_01Skill000000000000000003","type":"message","role":"assistant","model":"claude-opus-4-1-20250805","content":[{"type":"text","text":"No unread messages. Standing by."}],"stop_reason":"end_turn","usage":{"input_tokens":1600,"output_tokens":10}},"requestId":"req_skill_000003","type":"assistant","uuid":"b0000000-0000-4000-8000-000000000007","timestamp":"2026-09-10T10:00:15.000Z"} diff --git a/test/mcp-install-runner.test.ts b/test/mcp-install-runner.test.ts index 28cc4140..93c9e800 100644 --- a/test/mcp-install-runner.test.ts +++ b/test/mcp-install-runner.test.ts @@ -149,7 +149,10 @@ describe('install-runner — runNpmInstall termination handling (#161)', () => { }); }); -describe('mcp-server-wrapper — real spawn, orphan prevention on SIGTERM (#161)', () => { +// POSIX only: the stub `npm` is an extensionless shebang script, which Windows +// can't run from PATH, and Windows has no catchable SIGTERM for the wrapper to +// handle. +describe.skipIf(process.platform === 'win32')('mcp-server-wrapper — real spawn, orphan prevention on SIGTERM (#161)', () => { let root: string; let binDir: string; diff --git a/test/mcp-server.test.ts b/test/mcp-server.test.ts index 47382c96..566decfb 100644 --- a/test/mcp-server.test.ts +++ b/test/mcp-server.test.ts @@ -5,6 +5,8 @@ import { existsSync, mkdirSync, mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; +import { indexTestFiles } from './test-indexer.js'; +import { getFixturePath } from './test-utils.js'; const serverPath = fileURLToPath(new URL('../dist/mcp-server.js', import.meta.url)); @@ -65,6 +67,18 @@ describe('MCP search tool', () => { mkdirSync(join(testDir, 'archive'), { recursive: true }); mkdirSync(join(testDir, 'projects'), { recursive: true }); + const previousDbPath = process.env.TEST_DB_PATH; + process.env.TEST_DB_PATH = testDbPath; + try { + await indexTestFiles([getFixturePath('short-conversation.jsonl')]); + } finally { + if (previousDbPath === undefined) { + delete process.env.TEST_DB_PATH; + } else { + process.env.TEST_DB_PATH = previousDbPath; + } + } + client = new Client({ name: 'episodic-memory-test', version: '1.0.0' }, { capabilities: {} }); transport = new StdioClientTransport({ command: process.execPath, @@ -121,4 +135,45 @@ describe('MCP search tool', () => { }); expect(existsSync(testDbPath)).toBe(true); }); + + it('completes the real MCP text, vector, and archive-read path', async () => { + const tools = await client.listTools(); + expect(tools.tools.map((tool) => tool.name)).toEqual(expect.arrayContaining(['search', 'read'])); + + const textResult = await client.callTool({ + name: 'search', + arguments: { + query: 'Employee class', + mode: 'text', + limit: 1, + response_format: 'json', + }, + }); + expect(textResult.isError).toBeFalsy(); + const textPayload = JSON.parse(getTextContent(textResult.content as ToolContent[])); + expect(textPayload.count).toBeGreaterThan(0); + + const vectorResult = await client.callTool({ + name: 'search', + arguments: { + query: 'Python employee data design', + mode: 'vector', + limit: 1, + response_format: 'json', + }, + }); + expect(vectorResult.isError).toBeFalsy(); + + const vectorPayload = JSON.parse(getTextContent(vectorResult.content as ToolContent[])); + expect(vectorPayload.count).toBeGreaterThan(0); + const archivePath = vectorPayload.results[0].exchange.archivePath; + expect(archivePath).toBe(getFixturePath('short-conversation.jsonl')); + + const readResult = await client.callTool({ + name: 'read', + arguments: { path: archivePath, startLine: 1, endLine: 3 }, + }); + expect(readResult.isError).toBeFalsy(); + expect(getTextContent(readResult.content as ToolContent[])).toBeTruthy(); + }); }); diff --git a/test/model-cache-policy.test.ts b/test/model-cache-policy.test.ts new file mode 100644 index 00000000..359aa024 --- /dev/null +++ b/test/model-cache-policy.test.ts @@ -0,0 +1,77 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +vi.mock('@huggingface/transformers', () => ({ + env: { cacheDir: 'package-cache', allowLocalModels: false, allowRemoteModels: true, useBrowserCache: true }, + pipeline: vi.fn(async () => async () => ({ data: new Float32Array(384) })), +})); + +describe('embedding model cache and network policy', () => { + let directory: string; + let previous: NodeJS.ProcessEnv; + + beforeEach(() => { + previous = { ...process.env }; + directory = fs.mkdtempSync(path.join(os.tmpdir(), 'episodic-model-policy-')); + process.env.EPISODIC_MEMORY_CONFIG_DIR = path.join(directory, 'config'); + delete process.env.EPISODIC_MEMORY_MODEL_CACHE_DIR; + delete process.env.EPISODIC_MEMORY_OFFLINE; + vi.resetModules(); + }); + + afterEach(() => { + process.env = previous; + fs.rmSync(directory, { recursive: true, force: true }); + }); + + async function loadPolicy() { + const transformers = await import('@huggingface/transformers'); + const { initEmbeddings } = await import('../src/embeddings.js'); + await initEmbeddings(); + return transformers.env; + } + + it('keeps the model cache in the durable configuration directory by default', async () => { + const env = await loadPolicy(); + expect(env.cacheDir).toBe(path.join(directory, 'config', 'models')); + expect(fs.statSync(env.cacheDir).isDirectory()).toBe(true); + }); + + it('accepts an explicit cache directory without a machine-specific default', async () => { + const modelCache = path.join(directory, 'shared-models'); + process.env.EPISODIC_MEMORY_MODEL_CACHE_DIR = modelCache; + const env = await loadPolicy(); + expect(env.cacheDir).toBe(modelCache); + }); + + it('rejects a relative cache override whose meaning depends on cwd', async () => { + process.env.EPISODIC_MEMORY_MODEL_CACHE_DIR = 'relative-model-cache'; + const { getModelCacheDir } = await import('../src/paths.js'); + expect(() => getModelCacheDir()).toThrow(/absolute path/); + }); + + it('blocks remote model loading only when offline mode is explicit', async () => { + process.env.EPISODIC_MEMORY_OFFLINE = '1'; + const env = await loadPolicy(); + expect(env.allowRemoteModels).toBe(false); + }); + + it('retains first-install model download behavior by default', async () => { + const env = await loadPolicy(); + expect(env.allowRemoteModels).toBe(true); + }); + + it('reports an unavailable pre-seeded model clearly in offline mode', async () => { + process.env.EPISODIC_MEMORY_OFFLINE = '1'; + const transformers = await import('@huggingface/transformers'); + vi.mocked(transformers.pipeline).mockRejectedValueOnce(new Error('model files not found')); + const { initEmbeddings, EmbeddingsUnavailableError } = await import('../src/embeddings.js'); + + let failure: unknown; + try { await initEmbeddings(); } catch (error) { failure = error; } + expect(failure).toBeInstanceOf(EmbeddingsUnavailableError); + expect((failure as Error).message).toMatch(/offline|cache/i); + }); +}); diff --git a/test/parser.test.ts b/test/parser.test.ts index 003d15b8..5d375175 100644 --- a/test/parser.test.ts +++ b/test/parser.test.ts @@ -139,3 +139,92 @@ describe('Parser - Real Conversation Data', () => { }); }); }); + +describe('Parser - isMeta user lines (harness-injected vs. human provenance)', () => { + describe('Image paste: real prompt + isMeta "[Image: source: ...]" placeholder', () => { + const fixturePath = getFixturePath('image-paste-conversation.jsonl'); + + it('keeps the real prompt as the user message, not the placeholder', async () => { + const result = await parseConversationFile(fixturePath); + expect(result.exchanges).toHaveLength(1); + + const [exchange] = result.exchanges; + expect(exchange.userMessage).toBe( + '[Image #1] I want to make Codex not ask any questions about permissions - can you help me with configuring it?' + ); + expect(exchange.userMessage).not.toContain('[Image: source:'); + expect(exchange.assistantMessage).toContain('approval_policy'); + }); + + it('anchors the exchange at the real prompt line', async () => { + const result = await parseConversationFile(fixturePath); + const [exchange] = result.exchanges; + expect(exchange.lineStart).toBe(1); + expect(exchange.lineEnd).toBe(3); + // First-line metadata comes from the real prompt, not the placeholder + expect(exchange.thinkingLevel).toBe('high'); + }); + }); + + describe('Skill invocation: isMeta skill body and "Continue" line inside one turn', () => { + const fixturePath = getFixturePath('skill-invocation-conversation.jsonl'); + + it('does not split an already-populated turn at the injected skill body', async () => { + const result = await parseConversationFile(fixturePath); + expect(result.exchanges).toHaveLength(1); + + const [exchange] = result.exchanges; + expect(exchange.userMessage).toBe('register as summarizer in agent-chat'); + expect(exchange.userMessage).not.toContain('Base directory for this skill'); + expect(exchange.assistantMessage).not.toContain('Base directory for this skill'); + // The assistant text that preceded the Skill tool call is kept + expect(exchange.assistantMessage).toContain("I'll load the agent-chat skill"); + }); + + it('accumulates replies across isMeta lines into the same exchange', async () => { + const result = await parseConversationFile(fixturePath); + const [exchange] = result.exchanges; + expect(exchange.assistantMessage).toContain('Registered as summarizer'); + expect(exchange.assistantMessage).toContain('Standing by'); + expect(exchange.lineStart).toBe(1); + expect(exchange.lineEnd).toBe(8); + expect(exchange.toolCalls?.map(tc => tc.toolName)).toEqual(['Skill']); + }); + }); + + describe('Channel-bridge prompt: isMeta but origin.kind === "channel" (claude-code#44828)', () => { + const fixturePath = getFixturePath('channel-plugin-conversation.jsonl'); + + it('treats the channel message as a real prompt and starts a new exchange', async () => { + const result = await parseConversationFile(fixturePath); + expect(result.exchanges).toHaveLength(2); + + const [typed, channel] = result.exchanges; + expect(typed.userMessage).toBe('List the files in src.'); + expect(typed.assistantMessage).toBe('parser.ts and show.ts.'); + expect(typed.lineEnd).toBe(2); + + expect(channel.userMessage).toContain('Please explain the retry policy.'); + expect(channel.assistantMessage).toContain('exponential backoff'); + expect(channel.lineStart).toBe(3); + expect(channel.lineEnd).toBe(4); + }); + }); + + describe('Session that opens with an injected notification (no exchange open yet)', () => { + const fixturePath = getFixturePath('meta-first-conversation.jsonl'); + + it('still starts an exchange so the assistant reply is not lost', async () => { + const result = await parseConversationFile(fixturePath); + expect(result.exchanges).toHaveLength(2); + + const [notice, typed] = result.exchanges; + expect(notice.userMessage).toContain('[SYSTEM NOTIFICATION - NOT USER INPUT]'); + expect(notice.assistantMessage).toContain('background task finished'); + expect(notice.lineStart).toBe(1); + + expect(typed.userMessage).toBe('Now summarize what changed.'); + expect(typed.lineStart).toBe(3); + }); + }); +}); diff --git a/test/postinstall-native-check.test.ts b/test/postinstall-native-check.test.ts new file mode 100644 index 00000000..9718c173 --- /dev/null +++ b/test/postinstall-native-check.test.ts @@ -0,0 +1,47 @@ +import { afterEach, describe, expect, it } from 'vitest'; +import { copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { spawnSync } from 'node:child_process'; + +const REPO_ROOT = join(import.meta.dirname, '..'); + +describe('postinstall native-stack verification', () => { + let testDir: string | undefined; + + afterEach(() => { + if (testDir) rmSync(testDir, { recursive: true, force: true }); + }); + + it('reports an ABI mismatch without attempting a source rebuild', () => { + testDir = mkdtempSync(join(tmpdir(), 'episodic-memory-postinstall-')); + const scriptsDir = join(testDir, 'scripts'); + const packageDir = join(testDir, 'node_modules', 'better-sqlite3'); + mkdirSync(scriptsDir, { recursive: true }); + mkdirSync(packageDir, { recursive: true }); + copyFileSync(join(REPO_ROOT, 'scripts', 'postinstall.js'), join(scriptsDir, 'postinstall.js')); + writeFileSync(join(testDir, 'package.json'), JSON.stringify({ type: 'module' })); + writeFileSync( + join(packageDir, 'package.json'), + JSON.stringify({ name: 'better-sqlite3', version: '13.0.3', main: 'index.js' }) + ); + writeFileSync( + join(packageDir, 'index.js'), + `module.exports = class Database { + constructor() { + throw new Error('compiled using NODE_MODULE_VERSION 147; this Node requires NODE_MODULE_VERSION 137'); + } + };` + ); + + const result = spawnSync(process.execPath, [join(scriptsDir, 'postinstall.js')], { + encoding: 'utf-8', + }); + + expect(result.status).toBe(1); + expect(result.stderr).toContain('NATIVE BINDING IS BROKEN'); + expect(result.stderr).toContain('binary built for : NODE_MODULE_VERSION 147'); + expect(result.stderr).not.toContain('TypeError'); + expect(result.stderr).not.toContain('build-release'); + }); +}); diff --git a/test/setup-isolated-config.ts b/test/setup-isolated-config.ts index 71b3e795..9394c438 100644 --- a/test/setup-isolated-config.ts +++ b/test/setup-isolated-config.ts @@ -1,6 +1,7 @@ import { mkdtempSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; +import { testModelCacheDir } from './test-model-cache.js'; /** * Isolate every test run from the developer's real ~/.config/superpowers. @@ -13,6 +14,9 @@ const isolatedRoot = mkdtempSync(join(tmpdir(), 'episodic-memory-vitest-')); process.env.EPISODIC_MEMORY_CONFIG_DIR = join(isolatedRoot, 'superpowers'); process.env.CLAUDE_CONFIG_DIR = join(isolatedRoot, 'claude'); process.env.CODEX_HOME = join(isolatedRoot, 'codex'); +process.env.OMP_HOME = join(isolatedRoot, 'omp'); +process.env.EPISODIC_MEMORY_MODEL_CACHE_DIR = testModelCacheDir; +process.env.EPISODIC_MEMORY_OFFLINE = '1'; // Clear any ambient summarizer-billing signals so tests get deterministic // cost-guard (#104) and timeout (#160) behavior regardless of the developer's diff --git a/test/sync-cli-single-instance.test.ts b/test/sync-cli-single-instance.test.ts index b1505559..32010a76 100644 --- a/test/sync-cli-single-instance.test.ts +++ b/test/sync-cli-single-instance.test.ts @@ -70,6 +70,8 @@ describe('sync-cli single-instance lock (#97)', () => { TEST_ARCHIVE_DIR: join(testDir, 'archive'), TEST_DB_PATH: join(testDir, 'test.db'), EPISODIC_MEMORY_CONFIG_DIR: join(testDir, 'config'), + EPISODIC_MEMORY_OPENCODE_DB_PATH: join(testDir, 'opencode-missing.db'), + EPISODIC_MEMORY_OPENCODE_TRANSCRIPT_DIR: join(testDir, 'opencode-transcripts'), }; }); @@ -103,6 +105,24 @@ describe('sync-cli single-instance lock (#97)', () => { expect(result.stdout).toMatch(/Sync complete/); }); + it('does not print a green completion headline when the offline model is unavailable', () => { + const transcript = join(testDir, 'projects', 'project-a', '00000000-0000-0000-0000-000000000001.jsonl'); + writeFileSync(transcript, [ + JSON.stringify({ type: 'user', uuid: 'user-1', parentUuid: null, + timestamp: '2026-01-01T00:00:00Z', message: { role: 'user', content: 'What changed?' } }), + JSON.stringify({ type: 'assistant', uuid: 'assistant-1', parentUuid: 'user-1', + timestamp: '2026-01-01T00:00:01Z', message: { role: 'assistant', content: [{ type: 'text', text: 'The build changed.' }] } }) + ].join('\n')); + + const result = runWith({ ...envOverrides, + EPISODIC_MEMORY_MODEL_CACHE_DIR: join(testDir, 'empty-model-cache'), + EPISODIC_MEMORY_OFFLINE: '1', EPISODIC_MEMORY_SKIP_SUMMARIES: '1' }); + expect(result.status).toBe(0); + expect(result.stdout).toContain('Sync finished with errors'); + expect(result.stdout).not.toContain('✅ Sync complete!'); + expect(result.stdout).toContain('Indexed: 0'); + }); + it('releases the lock on normal exit — a subsequent run is not skipped', () => { const first = runWith(envOverrides); expect(first.status).toBe(0); diff --git a/test/test-model-cache.ts b/test/test-model-cache.ts new file mode 100644 index 00000000..a48f8c23 --- /dev/null +++ b/test/test-model-cache.ts @@ -0,0 +1,6 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +export const testModelCacheDir = path.join( + path.dirname(fileURLToPath(import.meta.url)), '..', 'tmp', 'test-model-cache' +); diff --git a/test/test-runtime-isolation.test.ts b/test/test-runtime-isolation.test.ts new file mode 100644 index 00000000..1fc72625 --- /dev/null +++ b/test/test-runtime-isolation.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from 'vitest'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); + +describe('test runtime isolation', () => { + it('uses a repository-owned model cache and disables worker downloads', () => { + expect(process.env.EPISODIC_MEMORY_MODEL_CACHE_DIR).toBe(path.join(projectRoot, 'tmp', 'test-model-cache')); + expect(process.env.EPISODIC_MEMORY_OFFLINE).toBe('1'); + }); + + it('does not discover ambient OMP sessions', () => { + const configDir = process.env.EPISODIC_MEMORY_CONFIG_DIR; + expect(configDir).toBeDefined(); + expect(process.env.OMP_HOME).toBe(path.join(path.dirname(configDir!), 'omp')); + }); +});