@openclaw/sms 0.0.0 → 2026.6.11-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -2
- package/dist/api.js +8 -0
- package/dist/channel-plugin-api.js +1313 -0
- package/dist/index.js +18 -0
- package/dist/secret-contract-CS-JLPcU.js +69 -0
- package/dist/secret-contract-api.js +2 -0
- package/node_modules/zod/LICENSE +21 -0
- package/node_modules/zod/README.md +191 -0
- package/node_modules/zod/index.cjs +33 -0
- package/node_modules/zod/index.d.cts +4 -0
- package/node_modules/zod/index.d.ts +4 -0
- package/node_modules/zod/index.js +4 -0
- package/node_modules/zod/locales/index.cjs +17 -0
- package/node_modules/zod/locales/index.d.cts +1 -0
- package/node_modules/zod/locales/index.d.ts +1 -0
- package/node_modules/zod/locales/index.js +1 -0
- package/node_modules/zod/locales/package.json +7 -0
- package/node_modules/zod/mini/index.cjs +32 -0
- package/node_modules/zod/mini/index.d.cts +3 -0
- package/node_modules/zod/mini/index.d.ts +3 -0
- package/node_modules/zod/mini/index.js +3 -0
- package/node_modules/zod/mini/package.json +7 -0
- package/node_modules/zod/package.json +135 -0
- package/node_modules/zod/src/index.ts +4 -0
- package/node_modules/zod/src/locales/index.ts +1 -0
- package/node_modules/zod/src/mini/index.ts +3 -0
- package/node_modules/zod/src/v3/ZodError.ts +330 -0
- package/node_modules/zod/src/v3/benchmarks/datetime.ts +58 -0
- package/node_modules/zod/src/v3/benchmarks/discriminatedUnion.ts +80 -0
- package/node_modules/zod/src/v3/benchmarks/index.ts +59 -0
- package/node_modules/zod/src/v3/benchmarks/ipv4.ts +57 -0
- package/node_modules/zod/src/v3/benchmarks/object.ts +69 -0
- package/node_modules/zod/src/v3/benchmarks/primitives.ts +162 -0
- package/node_modules/zod/src/v3/benchmarks/realworld.ts +63 -0
- package/node_modules/zod/src/v3/benchmarks/string.ts +55 -0
- package/node_modules/zod/src/v3/benchmarks/union.ts +80 -0
- package/node_modules/zod/src/v3/errors.ts +13 -0
- package/node_modules/zod/src/v3/external.ts +6 -0
- package/node_modules/zod/src/v3/helpers/enumUtil.ts +17 -0
- package/node_modules/zod/src/v3/helpers/errorUtil.ts +8 -0
- package/node_modules/zod/src/v3/helpers/parseUtil.ts +176 -0
- package/node_modules/zod/src/v3/helpers/partialUtil.ts +34 -0
- package/node_modules/zod/src/v3/helpers/typeAliases.ts +2 -0
- package/node_modules/zod/src/v3/helpers/util.ts +224 -0
- package/node_modules/zod/src/v3/index.ts +4 -0
- package/node_modules/zod/src/v3/locales/en.ts +124 -0
- package/node_modules/zod/src/v3/standard-schema.ts +113 -0
- package/node_modules/zod/src/v3/tests/Mocker.ts +54 -0
- package/node_modules/zod/src/v3/tests/all-errors.test.ts +157 -0
- package/node_modules/zod/src/v3/tests/anyunknown.test.ts +28 -0
- package/node_modules/zod/src/v3/tests/array.test.ts +71 -0
- package/node_modules/zod/src/v3/tests/async-parsing.test.ts +388 -0
- package/node_modules/zod/src/v3/tests/async-refinements.test.ts +46 -0
- package/node_modules/zod/src/v3/tests/base.test.ts +29 -0
- package/node_modules/zod/src/v3/tests/bigint.test.ts +55 -0
- package/node_modules/zod/src/v3/tests/branded.test.ts +53 -0
- package/node_modules/zod/src/v3/tests/catch.test.ts +220 -0
- package/node_modules/zod/src/v3/tests/coerce.test.ts +133 -0
- package/node_modules/zod/src/v3/tests/complex.test.ts +70 -0
- package/node_modules/zod/src/v3/tests/custom.test.ts +31 -0
- package/node_modules/zod/src/v3/tests/date.test.ts +32 -0
- package/node_modules/zod/src/v3/tests/deepmasking.test.ts +186 -0
- package/node_modules/zod/src/v3/tests/default.test.ts +112 -0
- package/node_modules/zod/src/v3/tests/description.test.ts +33 -0
- package/node_modules/zod/src/v3/tests/discriminated-unions.test.ts +315 -0
- package/node_modules/zod/src/v3/tests/enum.test.ts +80 -0
- package/node_modules/zod/src/v3/tests/error.test.ts +551 -0
- package/node_modules/zod/src/v3/tests/firstparty.test.ts +87 -0
- package/node_modules/zod/src/v3/tests/firstpartyschematypes.test.ts +21 -0
- package/node_modules/zod/src/v3/tests/function.test.ts +261 -0
- package/node_modules/zod/src/v3/tests/generics.test.ts +48 -0
- package/node_modules/zod/src/v3/tests/instanceof.test.ts +37 -0
- package/node_modules/zod/src/v3/tests/intersection.test.ts +110 -0
- package/node_modules/zod/src/v3/tests/language-server.source.ts +76 -0
- package/node_modules/zod/src/v3/tests/language-server.test.ts +207 -0
- package/node_modules/zod/src/v3/tests/literal.test.ts +36 -0
- package/node_modules/zod/src/v3/tests/map.test.ts +110 -0
- package/node_modules/zod/src/v3/tests/masking.test.ts +4 -0
- package/node_modules/zod/src/v3/tests/mocker.test.ts +19 -0
- package/node_modules/zod/src/v3/tests/nan.test.ts +24 -0
- package/node_modules/zod/src/v3/tests/nativeEnum.test.ts +87 -0
- package/node_modules/zod/src/v3/tests/nullable.test.ts +42 -0
- package/node_modules/zod/src/v3/tests/number.test.ts +176 -0
- package/node_modules/zod/src/v3/tests/object-augmentation.test.ts +29 -0
- package/node_modules/zod/src/v3/tests/object-in-es5-env.test.ts +29 -0
- package/node_modules/zod/src/v3/tests/object.test.ts +434 -0
- package/node_modules/zod/src/v3/tests/optional.test.ts +42 -0
- package/node_modules/zod/src/v3/tests/parseUtil.test.ts +23 -0
- package/node_modules/zod/src/v3/tests/parser.test.ts +41 -0
- package/node_modules/zod/src/v3/tests/partials.test.ts +243 -0
- package/node_modules/zod/src/v3/tests/pickomit.test.ts +111 -0
- package/node_modules/zod/src/v3/tests/pipeline.test.ts +29 -0
- package/node_modules/zod/src/v3/tests/preprocess.test.ts +186 -0
- package/node_modules/zod/src/v3/tests/primitive.test.ts +440 -0
- package/node_modules/zod/src/v3/tests/promise.test.ts +90 -0
- package/node_modules/zod/src/v3/tests/readonly.test.ts +194 -0
- package/node_modules/zod/src/v3/tests/record.test.ts +171 -0
- package/node_modules/zod/src/v3/tests/recursive.test.ts +197 -0
- package/node_modules/zod/src/v3/tests/refine.test.ts +313 -0
- package/node_modules/zod/src/v3/tests/safeparse.test.ts +27 -0
- package/node_modules/zod/src/v3/tests/set.test.ts +142 -0
- package/node_modules/zod/src/v3/tests/standard-schema.test.ts +83 -0
- package/node_modules/zod/src/v3/tests/string.test.ts +916 -0
- package/node_modules/zod/src/v3/tests/transformer.test.ts +233 -0
- package/node_modules/zod/src/v3/tests/tuple.test.ts +90 -0
- package/node_modules/zod/src/v3/tests/unions.test.ts +57 -0
- package/node_modules/zod/src/v3/tests/validations.test.ts +133 -0
- package/node_modules/zod/src/v3/tests/void.test.ts +15 -0
- package/node_modules/zod/src/v3/types.ts +5138 -0
- package/node_modules/zod/src/v4/classic/checks.ts +32 -0
- package/node_modules/zod/src/v4/classic/coerce.ts +27 -0
- package/node_modules/zod/src/v4/classic/compat.ts +70 -0
- package/node_modules/zod/src/v4/classic/errors.ts +82 -0
- package/node_modules/zod/src/v4/classic/external.ts +52 -0
- package/node_modules/zod/src/v4/classic/from-json-schema.ts +659 -0
- package/node_modules/zod/src/v4/classic/index.ts +5 -0
- package/node_modules/zod/src/v4/classic/iso.ts +90 -0
- package/node_modules/zod/src/v4/classic/parse.ts +82 -0
- package/node_modules/zod/src/v4/classic/schemas.ts +2672 -0
- package/node_modules/zod/src/v4/classic/tests/anyunknown.test.ts +26 -0
- package/node_modules/zod/src/v4/classic/tests/apply.test.ts +59 -0
- package/node_modules/zod/src/v4/classic/tests/array.test.ts +264 -0
- package/node_modules/zod/src/v4/classic/tests/assignability.test.ts +216 -0
- package/node_modules/zod/src/v4/classic/tests/async-parsing.test.ts +381 -0
- package/node_modules/zod/src/v4/classic/tests/async-refinements.test.ts +68 -0
- package/node_modules/zod/src/v4/classic/tests/base.test.ts +7 -0
- package/node_modules/zod/src/v4/classic/tests/bigint.test.ts +54 -0
- package/node_modules/zod/src/v4/classic/tests/brand.test.ts +106 -0
- package/node_modules/zod/src/v4/classic/tests/catch.test.ts +326 -0
- package/node_modules/zod/src/v4/classic/tests/coalesce.test.ts +20 -0
- package/node_modules/zod/src/v4/classic/tests/codec-examples.test.ts +573 -0
- package/node_modules/zod/src/v4/classic/tests/codec.test.ts +703 -0
- package/node_modules/zod/src/v4/classic/tests/coerce.test.ts +160 -0
- package/node_modules/zod/src/v4/classic/tests/continuability.test.ts +374 -0
- package/node_modules/zod/src/v4/classic/tests/custom.test.ts +40 -0
- package/node_modules/zod/src/v4/classic/tests/date.test.ts +62 -0
- package/node_modules/zod/src/v4/classic/tests/datetime.test.ts +302 -0
- package/node_modules/zod/src/v4/classic/tests/default.test.ts +409 -0
- package/node_modules/zod/src/v4/classic/tests/describe-meta-checks.test.ts +27 -0
- package/node_modules/zod/src/v4/classic/tests/description.test.ts +32 -0
- package/node_modules/zod/src/v4/classic/tests/detached-methods.test.ts +197 -0
- package/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts +694 -0
- package/node_modules/zod/src/v4/classic/tests/enum.test.ts +285 -0
- package/node_modules/zod/src/v4/classic/tests/error-utils.test.ts +807 -0
- package/node_modules/zod/src/v4/classic/tests/error.test.ts +711 -0
- package/node_modules/zod/src/v4/classic/tests/file.test.ts +96 -0
- package/node_modules/zod/src/v4/classic/tests/firstparty.test.ts +179 -0
- package/node_modules/zod/src/v4/classic/tests/fix-json-issue.test.ts +26 -0
- package/node_modules/zod/src/v4/classic/tests/from-json-schema.test.ts +895 -0
- package/node_modules/zod/src/v4/classic/tests/function.test.ts +360 -0
- package/node_modules/zod/src/v4/classic/tests/generics.test.ts +72 -0
- package/node_modules/zod/src/v4/classic/tests/global-config.test.ts +39 -0
- package/node_modules/zod/src/v4/classic/tests/hash.test.ts +68 -0
- package/node_modules/zod/src/v4/classic/tests/index.test.ts +939 -0
- package/node_modules/zod/src/v4/classic/tests/instanceof.test.ts +60 -0
- package/node_modules/zod/src/v4/classic/tests/intersection.test.ts +198 -0
- package/node_modules/zod/src/v4/classic/tests/jitless-allows-eval.test.ts +46 -0
- package/node_modules/zod/src/v4/classic/tests/json.test.ts +109 -0
- package/node_modules/zod/src/v4/classic/tests/lazy.test.ts +227 -0
- package/node_modules/zod/src/v4/classic/tests/literal.test.ts +117 -0
- package/node_modules/zod/src/v4/classic/tests/locales_ka.test.ts +29 -0
- package/node_modules/zod/src/v4/classic/tests/locales_ro.test.ts +24 -0
- package/node_modules/zod/src/v4/classic/tests/map.test.ts +330 -0
- package/node_modules/zod/src/v4/classic/tests/nan.test.ts +21 -0
- package/node_modules/zod/src/v4/classic/tests/nested-refine.test.ts +168 -0
- package/node_modules/zod/src/v4/classic/tests/nonoptional.test.ts +101 -0
- package/node_modules/zod/src/v4/classic/tests/nullable.test.ts +22 -0
- package/node_modules/zod/src/v4/classic/tests/number.test.ts +325 -0
- package/node_modules/zod/src/v4/classic/tests/object.test.ts +717 -0
- package/node_modules/zod/src/v4/classic/tests/optional.test.ts +333 -0
- package/node_modules/zod/src/v4/classic/tests/partial.test.ts +450 -0
- package/node_modules/zod/src/v4/classic/tests/pickomit.test.ts +211 -0
- package/node_modules/zod/src/v4/classic/tests/pipe.test.ts +101 -0
- package/node_modules/zod/src/v4/classic/tests/prefault.test.ts +74 -0
- package/node_modules/zod/src/v4/classic/tests/preprocess-types.test.ts +26 -0
- package/node_modules/zod/src/v4/classic/tests/preprocess.test.ts +351 -0
- package/node_modules/zod/src/v4/classic/tests/primitive.test.ts +175 -0
- package/node_modules/zod/src/v4/classic/tests/promise.test.ts +81 -0
- package/node_modules/zod/src/v4/classic/tests/prototypes.test.ts +23 -0
- package/node_modules/zod/src/v4/classic/tests/readonly.test.ts +252 -0
- package/node_modules/zod/src/v4/classic/tests/record.test.ts +717 -0
- package/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts +631 -0
- package/node_modules/zod/src/v4/classic/tests/refine.test.ts +633 -0
- package/node_modules/zod/src/v4/classic/tests/registries.test.ts +243 -0
- package/node_modules/zod/src/v4/classic/tests/set.test.ts +181 -0
- package/node_modules/zod/src/v4/classic/tests/standard-schema.test.ts +134 -0
- package/node_modules/zod/src/v4/classic/tests/string-formats.test.ts +125 -0
- package/node_modules/zod/src/v4/classic/tests/string.test.ts +1224 -0
- package/node_modules/zod/src/v4/classic/tests/stringbool.test.ts +106 -0
- package/node_modules/zod/src/v4/classic/tests/template-literal.test.ts +771 -0
- package/node_modules/zod/src/v4/classic/tests/to-json-schema-methods.test.ts +438 -0
- package/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts +3125 -0
- package/node_modules/zod/src/v4/classic/tests/transform.test.ts +378 -0
- package/node_modules/zod/src/v4/classic/tests/tuple.test.ts +496 -0
- package/node_modules/zod/src/v4/classic/tests/union.test.ts +273 -0
- package/node_modules/zod/src/v4/classic/tests/url.test.ts +13 -0
- package/node_modules/zod/src/v4/classic/tests/validations.test.ts +283 -0
- package/node_modules/zod/src/v4/classic/tests/void.test.ts +12 -0
- package/node_modules/zod/src/v4/core/api.ts +1823 -0
- package/node_modules/zod/src/v4/core/checks.ts +1293 -0
- package/node_modules/zod/src/v4/core/config.ts +15 -0
- package/node_modules/zod/src/v4/core/core.ts +153 -0
- package/node_modules/zod/src/v4/core/doc.ts +44 -0
- package/node_modules/zod/src/v4/core/errors.ts +455 -0
- package/node_modules/zod/src/v4/core/index.ts +16 -0
- package/node_modules/zod/src/v4/core/json-schema-generator.ts +126 -0
- package/node_modules/zod/src/v4/core/json-schema-processors.ts +666 -0
- package/node_modules/zod/src/v4/core/json-schema.ts +147 -0
- package/node_modules/zod/src/v4/core/parse.ts +195 -0
- package/node_modules/zod/src/v4/core/regexes.ts +190 -0
- package/node_modules/zod/src/v4/core/registries.ts +105 -0
- package/node_modules/zod/src/v4/core/schemas.ts +4730 -0
- package/node_modules/zod/src/v4/core/standard-schema.ts +159 -0
- package/node_modules/zod/src/v4/core/tests/extend.test.ts +59 -0
- package/node_modules/zod/src/v4/core/tests/index.test.ts +46 -0
- package/node_modules/zod/src/v4/core/tests/locales/be.test.ts +124 -0
- package/node_modules/zod/src/v4/core/tests/locales/el.test.ts +215 -0
- package/node_modules/zod/src/v4/core/tests/locales/en.test.ts +22 -0
- package/node_modules/zod/src/v4/core/tests/locales/es.test.ts +181 -0
- package/node_modules/zod/src/v4/core/tests/locales/fr.test.ts +72 -0
- package/node_modules/zod/src/v4/core/tests/locales/he.test.ts +379 -0
- package/node_modules/zod/src/v4/core/tests/locales/hr.test.ts +163 -0
- package/node_modules/zod/src/v4/core/tests/locales/nl.test.ts +46 -0
- package/node_modules/zod/src/v4/core/tests/locales/ru.test.ts +128 -0
- package/node_modules/zod/src/v4/core/tests/locales/tr.test.ts +69 -0
- package/node_modules/zod/src/v4/core/tests/locales/uz.test.ts +105 -0
- package/node_modules/zod/src/v4/core/tests/record-constructor.test.ts +125 -0
- package/node_modules/zod/src/v4/core/tests/recursive-tuples.test.ts +45 -0
- package/node_modules/zod/src/v4/core/to-json-schema.ts +622 -0
- package/node_modules/zod/src/v4/core/util.ts +983 -0
- package/node_modules/zod/src/v4/core/versions.ts +5 -0
- package/node_modules/zod/src/v4/core/zsf.ts +323 -0
- package/node_modules/zod/src/v4/index.ts +4 -0
- package/node_modules/zod/src/v4/locales/ar.ts +115 -0
- package/node_modules/zod/src/v4/locales/az.ts +111 -0
- package/node_modules/zod/src/v4/locales/be.ts +176 -0
- package/node_modules/zod/src/v4/locales/bg.ts +128 -0
- package/node_modules/zod/src/v4/locales/ca.ts +116 -0
- package/node_modules/zod/src/v4/locales/cs.ts +118 -0
- package/node_modules/zod/src/v4/locales/da.ts +123 -0
- package/node_modules/zod/src/v4/locales/de.ts +116 -0
- package/node_modules/zod/src/v4/locales/el.ts +121 -0
- package/node_modules/zod/src/v4/locales/en.ts +123 -0
- package/node_modules/zod/src/v4/locales/eo.ts +118 -0
- package/node_modules/zod/src/v4/locales/es.ts +141 -0
- package/node_modules/zod/src/v4/locales/fa.ts +126 -0
- package/node_modules/zod/src/v4/locales/fi.ts +121 -0
- package/node_modules/zod/src/v4/locales/fr-CA.ts +116 -0
- package/node_modules/zod/src/v4/locales/fr.ts +132 -0
- package/node_modules/zod/src/v4/locales/he.ts +246 -0
- package/node_modules/zod/src/v4/locales/hr.ts +131 -0
- package/node_modules/zod/src/v4/locales/hu.ts +117 -0
- package/node_modules/zod/src/v4/locales/hy.ts +164 -0
- package/node_modules/zod/src/v4/locales/id.ts +115 -0
- package/node_modules/zod/src/v4/locales/index.ts +52 -0
- package/node_modules/zod/src/v4/locales/is.ts +119 -0
- package/node_modules/zod/src/v4/locales/it.ts +116 -0
- package/node_modules/zod/src/v4/locales/ja.ts +114 -0
- package/node_modules/zod/src/v4/locales/ka.ts +123 -0
- package/node_modules/zod/src/v4/locales/kh.ts +7 -0
- package/node_modules/zod/src/v4/locales/km.ts +119 -0
- package/node_modules/zod/src/v4/locales/ko.ts +121 -0
- package/node_modules/zod/src/v4/locales/lt.ts +239 -0
- package/node_modules/zod/src/v4/locales/mk.ts +118 -0
- package/node_modules/zod/src/v4/locales/ms.ts +115 -0
- package/node_modules/zod/src/v4/locales/nl.ts +121 -0
- package/node_modules/zod/src/v4/locales/no.ts +116 -0
- package/node_modules/zod/src/v4/locales/ota.ts +117 -0
- package/node_modules/zod/src/v4/locales/pl.ts +118 -0
- package/node_modules/zod/src/v4/locales/ps.ts +126 -0
- package/node_modules/zod/src/v4/locales/pt.ts +116 -0
- package/node_modules/zod/src/v4/locales/ro.ts +129 -0
- package/node_modules/zod/src/v4/locales/ru.ts +176 -0
- package/node_modules/zod/src/v4/locales/sl.ts +118 -0
- package/node_modules/zod/src/v4/locales/sv.ts +119 -0
- package/node_modules/zod/src/v4/locales/ta.ts +118 -0
- package/node_modules/zod/src/v4/locales/th.ts +119 -0
- package/node_modules/zod/src/v4/locales/tr.ts +111 -0
- package/node_modules/zod/src/v4/locales/ua.ts +7 -0
- package/node_modules/zod/src/v4/locales/uk.ts +117 -0
- package/node_modules/zod/src/v4/locales/ur.ts +119 -0
- package/node_modules/zod/src/v4/locales/uz.ts +117 -0
- package/node_modules/zod/src/v4/locales/vi.ts +117 -0
- package/node_modules/zod/src/v4/locales/yo.ts +124 -0
- package/node_modules/zod/src/v4/locales/zh-CN.ts +116 -0
- package/node_modules/zod/src/v4/locales/zh-TW.ts +115 -0
- package/node_modules/zod/src/v4/mini/checks.ts +32 -0
- package/node_modules/zod/src/v4/mini/coerce.ts +27 -0
- package/node_modules/zod/src/v4/mini/external.ts +41 -0
- package/node_modules/zod/src/v4/mini/index.ts +3 -0
- package/node_modules/zod/src/v4/mini/iso.ts +66 -0
- package/node_modules/zod/src/v4/mini/parse.ts +14 -0
- package/node_modules/zod/src/v4/mini/schemas.ts +1947 -0
- package/node_modules/zod/src/v4/mini/tests/apply.test.ts +24 -0
- package/node_modules/zod/src/v4/mini/tests/assignability.test.ts +129 -0
- package/node_modules/zod/src/v4/mini/tests/brand.test.ts +94 -0
- package/node_modules/zod/src/v4/mini/tests/checks.test.ts +144 -0
- package/node_modules/zod/src/v4/mini/tests/codec.test.ts +548 -0
- package/node_modules/zod/src/v4/mini/tests/computed.test.ts +36 -0
- package/node_modules/zod/src/v4/mini/tests/error.test.ts +22 -0
- package/node_modules/zod/src/v4/mini/tests/functions.test.ts +5 -0
- package/node_modules/zod/src/v4/mini/tests/index.test.ts +993 -0
- package/node_modules/zod/src/v4/mini/tests/number.test.ts +95 -0
- package/node_modules/zod/src/v4/mini/tests/object.test.ts +227 -0
- package/node_modules/zod/src/v4/mini/tests/prototypes.test.ts +43 -0
- package/node_modules/zod/src/v4/mini/tests/recursive-types.test.ts +325 -0
- package/node_modules/zod/src/v4/mini/tests/standard-schema.test.ts +50 -0
- package/node_modules/zod/src/v4/mini/tests/string.test.ts +352 -0
- package/node_modules/zod/src/v4-mini/index.ts +3 -0
- package/node_modules/zod/v3/ZodError.cjs +138 -0
- package/node_modules/zod/v3/ZodError.d.cts +164 -0
- package/node_modules/zod/v3/ZodError.d.ts +164 -0
- package/node_modules/zod/v3/ZodError.js +133 -0
- package/node_modules/zod/v3/errors.cjs +17 -0
- package/node_modules/zod/v3/errors.d.cts +5 -0
- package/node_modules/zod/v3/errors.d.ts +5 -0
- package/node_modules/zod/v3/errors.js +9 -0
- package/node_modules/zod/v3/external.cjs +22 -0
- package/node_modules/zod/v3/external.d.cts +6 -0
- package/node_modules/zod/v3/external.d.ts +6 -0
- package/node_modules/zod/v3/external.js +6 -0
- package/node_modules/zod/v3/helpers/enumUtil.cjs +2 -0
- package/node_modules/zod/v3/helpers/enumUtil.d.cts +8 -0
- package/node_modules/zod/v3/helpers/enumUtil.d.ts +8 -0
- package/node_modules/zod/v3/helpers/enumUtil.js +1 -0
- package/node_modules/zod/v3/helpers/errorUtil.cjs +9 -0
- package/node_modules/zod/v3/helpers/errorUtil.d.cts +9 -0
- package/node_modules/zod/v3/helpers/errorUtil.d.ts +9 -0
- package/node_modules/zod/v3/helpers/errorUtil.js +6 -0
- package/node_modules/zod/v3/helpers/parseUtil.cjs +124 -0
- package/node_modules/zod/v3/helpers/parseUtil.d.cts +78 -0
- package/node_modules/zod/v3/helpers/parseUtil.d.ts +78 -0
- package/node_modules/zod/v3/helpers/parseUtil.js +109 -0
- package/node_modules/zod/v3/helpers/partialUtil.cjs +2 -0
- package/node_modules/zod/v3/helpers/partialUtil.d.cts +8 -0
- package/node_modules/zod/v3/helpers/partialUtil.d.ts +8 -0
- package/node_modules/zod/v3/helpers/partialUtil.js +1 -0
- package/node_modules/zod/v3/helpers/typeAliases.cjs +2 -0
- package/node_modules/zod/v3/helpers/typeAliases.d.cts +2 -0
- package/node_modules/zod/v3/helpers/typeAliases.d.ts +2 -0
- package/node_modules/zod/v3/helpers/typeAliases.js +1 -0
- package/node_modules/zod/v3/helpers/util.cjs +137 -0
- package/node_modules/zod/v3/helpers/util.d.cts +85 -0
- package/node_modules/zod/v3/helpers/util.d.ts +85 -0
- package/node_modules/zod/v3/helpers/util.js +133 -0
- package/node_modules/zod/v3/index.cjs +33 -0
- package/node_modules/zod/v3/index.d.cts +4 -0
- package/node_modules/zod/v3/index.d.ts +4 -0
- package/node_modules/zod/v3/index.js +4 -0
- package/node_modules/zod/v3/locales/en.cjs +112 -0
- package/node_modules/zod/v3/locales/en.d.cts +3 -0
- package/node_modules/zod/v3/locales/en.d.ts +3 -0
- package/node_modules/zod/v3/locales/en.js +109 -0
- package/node_modules/zod/v3/package.json +7 -0
- package/node_modules/zod/v3/standard-schema.cjs +2 -0
- package/node_modules/zod/v3/standard-schema.d.cts +102 -0
- package/node_modules/zod/v3/standard-schema.d.ts +102 -0
- package/node_modules/zod/v3/standard-schema.js +1 -0
- package/node_modules/zod/v3/types.cjs +3777 -0
- package/node_modules/zod/v3/types.d.cts +1034 -0
- package/node_modules/zod/v3/types.d.ts +1034 -0
- package/node_modules/zod/v3/types.js +3695 -0
- package/node_modules/zod/v4/classic/checks.cjs +33 -0
- package/node_modules/zod/v4/classic/checks.d.cts +1 -0
- package/node_modules/zod/v4/classic/checks.d.ts +1 -0
- package/node_modules/zod/v4/classic/checks.js +1 -0
- package/node_modules/zod/v4/classic/coerce.cjs +47 -0
- package/node_modules/zod/v4/classic/coerce.d.cts +17 -0
- package/node_modules/zod/v4/classic/coerce.d.ts +17 -0
- package/node_modules/zod/v4/classic/coerce.js +17 -0
- package/node_modules/zod/v4/classic/compat.cjs +61 -0
- package/node_modules/zod/v4/classic/compat.d.cts +50 -0
- package/node_modules/zod/v4/classic/compat.d.ts +50 -0
- package/node_modules/zod/v4/classic/compat.js +31 -0
- package/node_modules/zod/v4/classic/errors.cjs +74 -0
- package/node_modules/zod/v4/classic/errors.d.cts +30 -0
- package/node_modules/zod/v4/classic/errors.d.ts +30 -0
- package/node_modules/zod/v4/classic/errors.js +48 -0
- package/node_modules/zod/v4/classic/external.cjs +73 -0
- package/node_modules/zod/v4/classic/external.d.cts +16 -0
- package/node_modules/zod/v4/classic/external.d.ts +16 -0
- package/node_modules/zod/v4/classic/external.js +20 -0
- package/node_modules/zod/v4/classic/from-json-schema.cjs +625 -0
- package/node_modules/zod/v4/classic/from-json-schema.d.cts +12 -0
- package/node_modules/zod/v4/classic/from-json-schema.d.ts +12 -0
- package/node_modules/zod/v4/classic/from-json-schema.js +599 -0
- package/node_modules/zod/v4/classic/index.cjs +33 -0
- package/node_modules/zod/v4/classic/index.d.cts +4 -0
- package/node_modules/zod/v4/classic/index.d.ts +4 -0
- package/node_modules/zod/v4/classic/index.js +4 -0
- package/node_modules/zod/v4/classic/iso.cjs +60 -0
- package/node_modules/zod/v4/classic/iso.d.cts +22 -0
- package/node_modules/zod/v4/classic/iso.d.ts +22 -0
- package/node_modules/zod/v4/classic/iso.js +30 -0
- package/node_modules/zod/v4/classic/package.json +7 -0
- package/node_modules/zod/v4/classic/parse.cjs +41 -0
- package/node_modules/zod/v4/classic/parse.d.cts +31 -0
- package/node_modules/zod/v4/classic/parse.d.ts +31 -0
- package/node_modules/zod/v4/classic/parse.js +15 -0
- package/node_modules/zod/v4/classic/schemas.cjs +1511 -0
- package/node_modules/zod/v4/classic/schemas.d.cts +767 -0
- package/node_modules/zod/v4/classic/schemas.d.ts +767 -0
- package/node_modules/zod/v4/classic/schemas.js +1395 -0
- package/node_modules/zod/v4/core/api.cjs +1227 -0
- package/node_modules/zod/v4/core/api.d.cts +325 -0
- package/node_modules/zod/v4/core/api.d.ts +325 -0
- package/node_modules/zod/v4/core/api.js +1087 -0
- package/node_modules/zod/v4/core/checks.cjs +601 -0
- package/node_modules/zod/v4/core/checks.d.cts +278 -0
- package/node_modules/zod/v4/core/checks.d.ts +278 -0
- package/node_modules/zod/v4/core/checks.js +575 -0
- package/node_modules/zod/v4/core/core.cjs +85 -0
- package/node_modules/zod/v4/core/core.d.cts +70 -0
- package/node_modules/zod/v4/core/core.d.ts +70 -0
- package/node_modules/zod/v4/core/core.js +78 -0
- package/node_modules/zod/v4/core/doc.cjs +39 -0
- package/node_modules/zod/v4/core/doc.d.cts +14 -0
- package/node_modules/zod/v4/core/doc.d.ts +14 -0
- package/node_modules/zod/v4/core/doc.js +35 -0
- package/node_modules/zod/v4/core/errors.cjs +216 -0
- package/node_modules/zod/v4/core/errors.d.cts +221 -0
- package/node_modules/zod/v4/core/errors.d.ts +221 -0
- package/node_modules/zod/v4/core/errors.js +185 -0
- package/node_modules/zod/v4/core/index.cjs +47 -0
- package/node_modules/zod/v4/core/index.d.cts +16 -0
- package/node_modules/zod/v4/core/index.d.ts +16 -0
- package/node_modules/zod/v4/core/index.js +16 -0
- package/node_modules/zod/v4/core/json-schema-generator.cjs +99 -0
- package/node_modules/zod/v4/core/json-schema-generator.d.cts +65 -0
- package/node_modules/zod/v4/core/json-schema-generator.d.ts +65 -0
- package/node_modules/zod/v4/core/json-schema-generator.js +95 -0
- package/node_modules/zod/v4/core/json-schema-processors.cjs +644 -0
- package/node_modules/zod/v4/core/json-schema-processors.d.cts +49 -0
- package/node_modules/zod/v4/core/json-schema-processors.d.ts +49 -0
- package/node_modules/zod/v4/core/json-schema-processors.js +601 -0
- package/node_modules/zod/v4/core/json-schema.cjs +2 -0
- package/node_modules/zod/v4/core/json-schema.d.cts +88 -0
- package/node_modules/zod/v4/core/json-schema.d.ts +88 -0
- package/node_modules/zod/v4/core/json-schema.js +1 -0
- package/node_modules/zod/v4/core/package.json +7 -0
- package/node_modules/zod/v4/core/parse.cjs +131 -0
- package/node_modules/zod/v4/core/parse.d.cts +49 -0
- package/node_modules/zod/v4/core/parse.d.ts +49 -0
- package/node_modules/zod/v4/core/parse.js +93 -0
- package/node_modules/zod/v4/core/regexes.cjs +172 -0
- package/node_modules/zod/v4/core/regexes.d.cts +85 -0
- package/node_modules/zod/v4/core/regexes.d.ts +85 -0
- package/node_modules/zod/v4/core/regexes.js +139 -0
- package/node_modules/zod/v4/core/registries.cjs +56 -0
- package/node_modules/zod/v4/core/registries.d.cts +35 -0
- package/node_modules/zod/v4/core/registries.d.ts +35 -0
- package/node_modules/zod/v4/core/registries.js +51 -0
- package/node_modules/zod/v4/core/schemas.cjs +2270 -0
- package/node_modules/zod/v4/core/schemas.d.cts +1184 -0
- package/node_modules/zod/v4/core/schemas.d.ts +1184 -0
- package/node_modules/zod/v4/core/schemas.js +2239 -0
- package/node_modules/zod/v4/core/standard-schema.cjs +2 -0
- package/node_modules/zod/v4/core/standard-schema.d.cts +126 -0
- package/node_modules/zod/v4/core/standard-schema.d.ts +126 -0
- package/node_modules/zod/v4/core/standard-schema.js +1 -0
- package/node_modules/zod/v4/core/to-json-schema.cjs +457 -0
- package/node_modules/zod/v4/core/to-json-schema.d.cts +114 -0
- package/node_modules/zod/v4/core/to-json-schema.d.ts +114 -0
- package/node_modules/zod/v4/core/to-json-schema.js +448 -0
- package/node_modules/zod/v4/core/util.cjs +734 -0
- package/node_modules/zod/v4/core/util.d.cts +200 -0
- package/node_modules/zod/v4/core/util.d.ts +200 -0
- package/node_modules/zod/v4/core/util.js +674 -0
- package/node_modules/zod/v4/core/versions.cjs +8 -0
- package/node_modules/zod/v4/core/versions.d.cts +5 -0
- package/node_modules/zod/v4/core/versions.d.ts +5 -0
- package/node_modules/zod/v4/core/versions.js +5 -0
- package/node_modules/zod/v4/index.cjs +22 -0
- package/node_modules/zod/v4/index.d.cts +3 -0
- package/node_modules/zod/v4/index.d.ts +3 -0
- package/node_modules/zod/v4/index.js +3 -0
- package/node_modules/zod/v4/locales/ar.cjs +133 -0
- package/node_modules/zod/v4/locales/ar.d.cts +5 -0
- package/node_modules/zod/v4/locales/ar.d.ts +4 -0
- package/node_modules/zod/v4/locales/ar.js +106 -0
- package/node_modules/zod/v4/locales/az.cjs +132 -0
- package/node_modules/zod/v4/locales/az.d.cts +5 -0
- package/node_modules/zod/v4/locales/az.d.ts +4 -0
- package/node_modules/zod/v4/locales/az.js +105 -0
- package/node_modules/zod/v4/locales/be.cjs +183 -0
- package/node_modules/zod/v4/locales/be.d.cts +5 -0
- package/node_modules/zod/v4/locales/be.d.ts +4 -0
- package/node_modules/zod/v4/locales/be.js +156 -0
- package/node_modules/zod/v4/locales/bg.cjs +147 -0
- package/node_modules/zod/v4/locales/bg.d.cts +5 -0
- package/node_modules/zod/v4/locales/bg.d.ts +4 -0
- package/node_modules/zod/v4/locales/bg.js +120 -0
- package/node_modules/zod/v4/locales/ca.cjs +134 -0
- package/node_modules/zod/v4/locales/ca.d.cts +5 -0
- package/node_modules/zod/v4/locales/ca.d.ts +4 -0
- package/node_modules/zod/v4/locales/ca.js +107 -0
- package/node_modules/zod/v4/locales/cs.cjs +138 -0
- package/node_modules/zod/v4/locales/cs.d.cts +5 -0
- package/node_modules/zod/v4/locales/cs.d.ts +4 -0
- package/node_modules/zod/v4/locales/cs.js +111 -0
- package/node_modules/zod/v4/locales/da.cjs +142 -0
- package/node_modules/zod/v4/locales/da.d.cts +5 -0
- package/node_modules/zod/v4/locales/da.d.ts +4 -0
- package/node_modules/zod/v4/locales/da.js +115 -0
- package/node_modules/zod/v4/locales/de.cjs +135 -0
- package/node_modules/zod/v4/locales/de.d.cts +5 -0
- package/node_modules/zod/v4/locales/de.d.ts +4 -0
- package/node_modules/zod/v4/locales/de.js +108 -0
- package/node_modules/zod/v4/locales/el.cjs +136 -0
- package/node_modules/zod/v4/locales/el.d.cts +5 -0
- package/node_modules/zod/v4/locales/el.d.ts +4 -0
- package/node_modules/zod/v4/locales/el.js +109 -0
- package/node_modules/zod/v4/locales/en.cjs +140 -0
- package/node_modules/zod/v4/locales/en.d.cts +5 -0
- package/node_modules/zod/v4/locales/en.d.ts +4 -0
- package/node_modules/zod/v4/locales/en.js +113 -0
- package/node_modules/zod/v4/locales/eo.cjs +136 -0
- package/node_modules/zod/v4/locales/eo.d.cts +5 -0
- package/node_modules/zod/v4/locales/eo.d.ts +4 -0
- package/node_modules/zod/v4/locales/eo.js +109 -0
- package/node_modules/zod/v4/locales/es.cjs +159 -0
- package/node_modules/zod/v4/locales/es.d.cts +5 -0
- package/node_modules/zod/v4/locales/es.d.ts +4 -0
- package/node_modules/zod/v4/locales/es.js +132 -0
- package/node_modules/zod/v4/locales/fa.cjs +141 -0
- package/node_modules/zod/v4/locales/fa.d.cts +5 -0
- package/node_modules/zod/v4/locales/fa.d.ts +4 -0
- package/node_modules/zod/v4/locales/fa.js +114 -0
- package/node_modules/zod/v4/locales/fi.cjs +139 -0
- package/node_modules/zod/v4/locales/fi.d.cts +5 -0
- package/node_modules/zod/v4/locales/fi.d.ts +4 -0
- package/node_modules/zod/v4/locales/fi.js +112 -0
- package/node_modules/zod/v4/locales/fr-CA.cjs +134 -0
- package/node_modules/zod/v4/locales/fr-CA.d.cts +5 -0
- package/node_modules/zod/v4/locales/fr-CA.d.ts +4 -0
- package/node_modules/zod/v4/locales/fr-CA.js +107 -0
- package/node_modules/zod/v4/locales/fr.cjs +152 -0
- package/node_modules/zod/v4/locales/fr.d.cts +5 -0
- package/node_modules/zod/v4/locales/fr.d.ts +4 -0
- package/node_modules/zod/v4/locales/fr.js +125 -0
- package/node_modules/zod/v4/locales/he.cjs +241 -0
- package/node_modules/zod/v4/locales/he.d.cts +5 -0
- package/node_modules/zod/v4/locales/he.d.ts +4 -0
- package/node_modules/zod/v4/locales/he.js +214 -0
- package/node_modules/zod/v4/locales/hr.cjs +149 -0
- package/node_modules/zod/v4/locales/hr.d.cts +5 -0
- package/node_modules/zod/v4/locales/hr.d.ts +4 -0
- package/node_modules/zod/v4/locales/hr.js +122 -0
- package/node_modules/zod/v4/locales/hu.cjs +135 -0
- package/node_modules/zod/v4/locales/hu.d.cts +5 -0
- package/node_modules/zod/v4/locales/hu.d.ts +4 -0
- package/node_modules/zod/v4/locales/hu.js +108 -0
- package/node_modules/zod/v4/locales/hy.cjs +174 -0
- package/node_modules/zod/v4/locales/hy.d.cts +5 -0
- package/node_modules/zod/v4/locales/hy.d.ts +4 -0
- package/node_modules/zod/v4/locales/hy.js +147 -0
- package/node_modules/zod/v4/locales/id.cjs +133 -0
- package/node_modules/zod/v4/locales/id.d.cts +5 -0
- package/node_modules/zod/v4/locales/id.d.ts +4 -0
- package/node_modules/zod/v4/locales/id.js +106 -0
- package/node_modules/zod/v4/locales/index.cjs +111 -0
- package/node_modules/zod/v4/locales/index.d.cts +52 -0
- package/node_modules/zod/v4/locales/index.d.ts +52 -0
- package/node_modules/zod/v4/locales/index.js +52 -0
- package/node_modules/zod/v4/locales/is.cjs +136 -0
- package/node_modules/zod/v4/locales/is.d.cts +5 -0
- package/node_modules/zod/v4/locales/is.d.ts +4 -0
- package/node_modules/zod/v4/locales/is.js +109 -0
- package/node_modules/zod/v4/locales/it.cjs +135 -0
- package/node_modules/zod/v4/locales/it.d.cts +5 -0
- package/node_modules/zod/v4/locales/it.d.ts +4 -0
- package/node_modules/zod/v4/locales/it.js +108 -0
- package/node_modules/zod/v4/locales/ja.cjs +134 -0
- package/node_modules/zod/v4/locales/ja.d.cts +5 -0
- package/node_modules/zod/v4/locales/ja.d.ts +4 -0
- package/node_modules/zod/v4/locales/ja.js +107 -0
- package/node_modules/zod/v4/locales/ka.cjs +139 -0
- package/node_modules/zod/v4/locales/ka.d.cts +5 -0
- package/node_modules/zod/v4/locales/ka.d.ts +4 -0
- package/node_modules/zod/v4/locales/ka.js +112 -0
- package/node_modules/zod/v4/locales/kh.cjs +12 -0
- package/node_modules/zod/v4/locales/kh.d.cts +5 -0
- package/node_modules/zod/v4/locales/kh.d.ts +5 -0
- package/node_modules/zod/v4/locales/kh.js +5 -0
- package/node_modules/zod/v4/locales/km.cjs +137 -0
- package/node_modules/zod/v4/locales/km.d.cts +5 -0
- package/node_modules/zod/v4/locales/km.d.ts +4 -0
- package/node_modules/zod/v4/locales/km.js +110 -0
- package/node_modules/zod/v4/locales/ko.cjs +138 -0
- package/node_modules/zod/v4/locales/ko.d.cts +5 -0
- package/node_modules/zod/v4/locales/ko.d.ts +4 -0
- package/node_modules/zod/v4/locales/ko.js +111 -0
- package/node_modules/zod/v4/locales/lt.cjs +230 -0
- package/node_modules/zod/v4/locales/lt.d.cts +5 -0
- package/node_modules/zod/v4/locales/lt.d.ts +4 -0
- package/node_modules/zod/v4/locales/lt.js +203 -0
- package/node_modules/zod/v4/locales/mk.cjs +136 -0
- package/node_modules/zod/v4/locales/mk.d.cts +5 -0
- package/node_modules/zod/v4/locales/mk.d.ts +4 -0
- package/node_modules/zod/v4/locales/mk.js +109 -0
- package/node_modules/zod/v4/locales/ms.cjs +134 -0
- package/node_modules/zod/v4/locales/ms.d.cts +5 -0
- package/node_modules/zod/v4/locales/ms.d.ts +4 -0
- package/node_modules/zod/v4/locales/ms.js +107 -0
- package/node_modules/zod/v4/locales/nl.cjs +137 -0
- package/node_modules/zod/v4/locales/nl.d.cts +5 -0
- package/node_modules/zod/v4/locales/nl.d.ts +4 -0
- package/node_modules/zod/v4/locales/nl.js +110 -0
- package/node_modules/zod/v4/locales/no.cjs +135 -0
- package/node_modules/zod/v4/locales/no.d.cts +5 -0
- package/node_modules/zod/v4/locales/no.d.ts +4 -0
- package/node_modules/zod/v4/locales/no.js +108 -0
- package/node_modules/zod/v4/locales/ota.cjs +136 -0
- package/node_modules/zod/v4/locales/ota.d.cts +5 -0
- package/node_modules/zod/v4/locales/ota.d.ts +4 -0
- package/node_modules/zod/v4/locales/ota.js +109 -0
- package/node_modules/zod/v4/locales/package.json +7 -0
- package/node_modules/zod/v4/locales/pl.cjs +136 -0
- package/node_modules/zod/v4/locales/pl.d.cts +5 -0
- package/node_modules/zod/v4/locales/pl.d.ts +4 -0
- package/node_modules/zod/v4/locales/pl.js +109 -0
- package/node_modules/zod/v4/locales/ps.cjs +141 -0
- package/node_modules/zod/v4/locales/ps.d.cts +5 -0
- package/node_modules/zod/v4/locales/ps.d.ts +4 -0
- package/node_modules/zod/v4/locales/ps.js +114 -0
- package/node_modules/zod/v4/locales/pt.cjs +135 -0
- package/node_modules/zod/v4/locales/pt.d.cts +5 -0
- package/node_modules/zod/v4/locales/pt.d.ts +4 -0
- package/node_modules/zod/v4/locales/pt.js +108 -0
- package/node_modules/zod/v4/locales/ro.cjs +146 -0
- package/node_modules/zod/v4/locales/ro.d.cts +5 -0
- package/node_modules/zod/v4/locales/ro.d.ts +4 -0
- package/node_modules/zod/v4/locales/ro.js +119 -0
- package/node_modules/zod/v4/locales/ru.cjs +183 -0
- package/node_modules/zod/v4/locales/ru.d.cts +5 -0
- package/node_modules/zod/v4/locales/ru.d.ts +4 -0
- package/node_modules/zod/v4/locales/ru.js +156 -0
- package/node_modules/zod/v4/locales/sl.cjs +136 -0
- package/node_modules/zod/v4/locales/sl.d.cts +5 -0
- package/node_modules/zod/v4/locales/sl.d.ts +4 -0
- package/node_modules/zod/v4/locales/sl.js +109 -0
- package/node_modules/zod/v4/locales/sv.cjs +137 -0
- package/node_modules/zod/v4/locales/sv.d.cts +5 -0
- package/node_modules/zod/v4/locales/sv.d.ts +4 -0
- package/node_modules/zod/v4/locales/sv.js +110 -0
- package/node_modules/zod/v4/locales/ta.cjs +137 -0
- package/node_modules/zod/v4/locales/ta.d.cts +5 -0
- package/node_modules/zod/v4/locales/ta.d.ts +4 -0
- package/node_modules/zod/v4/locales/ta.js +110 -0
- package/node_modules/zod/v4/locales/th.cjs +137 -0
- package/node_modules/zod/v4/locales/th.d.cts +5 -0
- package/node_modules/zod/v4/locales/th.d.ts +4 -0
- package/node_modules/zod/v4/locales/th.js +110 -0
- package/node_modules/zod/v4/locales/tr.cjs +132 -0
- package/node_modules/zod/v4/locales/tr.d.cts +5 -0
- package/node_modules/zod/v4/locales/tr.d.ts +4 -0
- package/node_modules/zod/v4/locales/tr.js +105 -0
- package/node_modules/zod/v4/locales/ua.cjs +12 -0
- package/node_modules/zod/v4/locales/ua.d.cts +5 -0
- package/node_modules/zod/v4/locales/ua.d.ts +5 -0
- package/node_modules/zod/v4/locales/ua.js +5 -0
- package/node_modules/zod/v4/locales/uk.cjs +135 -0
- package/node_modules/zod/v4/locales/uk.d.cts +5 -0
- package/node_modules/zod/v4/locales/uk.d.ts +4 -0
- package/node_modules/zod/v4/locales/uk.js +108 -0
- package/node_modules/zod/v4/locales/ur.cjs +137 -0
- package/node_modules/zod/v4/locales/ur.d.cts +5 -0
- package/node_modules/zod/v4/locales/ur.d.ts +4 -0
- package/node_modules/zod/v4/locales/ur.js +110 -0
- package/node_modules/zod/v4/locales/uz.cjs +137 -0
- package/node_modules/zod/v4/locales/uz.d.cts +5 -0
- package/node_modules/zod/v4/locales/uz.d.ts +4 -0
- package/node_modules/zod/v4/locales/uz.js +110 -0
- package/node_modules/zod/v4/locales/vi.cjs +135 -0
- package/node_modules/zod/v4/locales/vi.d.cts +5 -0
- package/node_modules/zod/v4/locales/vi.d.ts +4 -0
- package/node_modules/zod/v4/locales/vi.js +108 -0
- package/node_modules/zod/v4/locales/yo.cjs +134 -0
- package/node_modules/zod/v4/locales/yo.d.cts +5 -0
- package/node_modules/zod/v4/locales/yo.d.ts +4 -0
- package/node_modules/zod/v4/locales/yo.js +107 -0
- package/node_modules/zod/v4/locales/zh-CN.cjs +136 -0
- package/node_modules/zod/v4/locales/zh-CN.d.cts +5 -0
- package/node_modules/zod/v4/locales/zh-CN.d.ts +4 -0
- package/node_modules/zod/v4/locales/zh-CN.js +109 -0
- package/node_modules/zod/v4/locales/zh-TW.cjs +134 -0
- package/node_modules/zod/v4/locales/zh-TW.d.cts +5 -0
- package/node_modules/zod/v4/locales/zh-TW.d.ts +4 -0
- package/node_modules/zod/v4/locales/zh-TW.js +107 -0
- package/node_modules/zod/v4/mini/checks.cjs +34 -0
- package/node_modules/zod/v4/mini/checks.d.cts +1 -0
- package/node_modules/zod/v4/mini/checks.d.ts +1 -0
- package/node_modules/zod/v4/mini/checks.js +1 -0
- package/node_modules/zod/v4/mini/coerce.cjs +52 -0
- package/node_modules/zod/v4/mini/coerce.d.cts +7 -0
- package/node_modules/zod/v4/mini/coerce.d.ts +7 -0
- package/node_modules/zod/v4/mini/coerce.js +22 -0
- package/node_modules/zod/v4/mini/external.cjs +63 -0
- package/node_modules/zod/v4/mini/external.d.cts +13 -0
- package/node_modules/zod/v4/mini/external.d.ts +13 -0
- package/node_modules/zod/v4/mini/external.js +14 -0
- package/node_modules/zod/v4/mini/index.cjs +32 -0
- package/node_modules/zod/v4/mini/index.d.cts +3 -0
- package/node_modules/zod/v4/mini/index.d.ts +3 -0
- package/node_modules/zod/v4/mini/index.js +3 -0
- package/node_modules/zod/v4/mini/iso.cjs +64 -0
- package/node_modules/zod/v4/mini/iso.d.cts +22 -0
- package/node_modules/zod/v4/mini/iso.d.ts +22 -0
- package/node_modules/zod/v4/mini/iso.js +34 -0
- package/node_modules/zod/v4/mini/package.json +7 -0
- package/node_modules/zod/v4/mini/parse.cjs +16 -0
- package/node_modules/zod/v4/mini/parse.d.cts +1 -0
- package/node_modules/zod/v4/mini/parse.d.ts +1 -0
- package/node_modules/zod/v4/mini/parse.js +1 -0
- package/node_modules/zod/v4/mini/schemas.cjs +1083 -0
- package/node_modules/zod/v4/mini/schemas.d.cts +445 -0
- package/node_modules/zod/v4/mini/schemas.d.ts +445 -0
- package/node_modules/zod/v4/mini/schemas.js +961 -0
- package/node_modules/zod/v4/package.json +7 -0
- package/node_modules/zod/v4-mini/index.cjs +32 -0
- package/node_modules/zod/v4-mini/index.d.cts +3 -0
- package/node_modules/zod/v4-mini/index.d.ts +3 -0
- package/node_modules/zod/v4-mini/index.js +3 -0
- package/node_modules/zod/v4-mini/package.json +7 -0
- package/npm-shrinkwrap.json +24 -0
- package/openclaw.plugin.json +374 -0
- package/package.json +61 -7
|
@@ -0,0 +1,1313 @@
|
|
|
1
|
+
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-CS-JLPcU.js";
|
|
2
|
+
import { DEFAULT_ACCOUNT_ID, normalizeOptionalAccountId } from "openclaw/plugin-sdk/account-id";
|
|
3
|
+
import { createHybridChannelConfigAdapter, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
4
|
+
import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
5
|
+
import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, waitUntilAbort } from "openclaw/plugin-sdk/channel-outbound";
|
|
6
|
+
import { createConditionalWarningCollector } from "openclaw/plugin-sdk/channel-policy";
|
|
7
|
+
import { createEmptyChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
|
|
8
|
+
import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
|
+
import { chunkTextForOutbound, stripMarkdown } from "openclaw/plugin-sdk/text-chunking";
|
|
10
|
+
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, listCombinedAccountIds, resolveAccountEntry, resolveListedDefaultAccountId, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
|
|
11
|
+
import { parseStrictInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
12
|
+
import { buildSecretInputSchema, hasConfiguredSecretInput, normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
13
|
+
import { AllowFromListSchema, DmPolicySchema, buildChannelConfigSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-primitives";
|
|
14
|
+
import { requireChannelOpenAllowFrom } from "openclaw/plugin-sdk/extension-shared";
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
import { createFixedWindowRateLimiter, readRequestBodyWithLimit, registerPluginHttpRoute } from "openclaw/plugin-sdk/webhook-ingress";
|
|
17
|
+
import { resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
18
|
+
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
19
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
20
|
+
import * as querystring from "node:querystring";
|
|
21
|
+
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
22
|
+
//#region extensions/sms/src/phone.ts
|
|
23
|
+
function normalizeSmsPhoneNumber(raw) {
|
|
24
|
+
const trimmed = raw.trim().replace(/^(?:sms|twilio-sms):/i, "");
|
|
25
|
+
if (!trimmed) return "";
|
|
26
|
+
return (trimmed.startsWith("+") ? trimmed : `+${trimmed}`).replace(/[^\d+]/g, "");
|
|
27
|
+
}
|
|
28
|
+
function looksLikeSmsPhoneNumber(raw) {
|
|
29
|
+
const normalized = normalizeSmsPhoneNumber(raw);
|
|
30
|
+
return /^\+[1-9]\d{6,14}$/.test(normalized);
|
|
31
|
+
}
|
|
32
|
+
function normalizeSmsAllowFrom(raw) {
|
|
33
|
+
if (raw.trim() === "*") return "*";
|
|
34
|
+
return normalizeSmsPhoneNumber(raw).toLowerCase();
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region extensions/sms/src/accounts.ts
|
|
38
|
+
const CHANNEL_ID$3 = "sms";
|
|
39
|
+
const DEFAULT_WEBHOOK_PATH = "/webhooks/sms";
|
|
40
|
+
const DEFAULT_TEXT_CHUNK_LIMIT = 1500;
|
|
41
|
+
function getChannelConfig(cfg) {
|
|
42
|
+
return cfg?.channels?.[CHANNEL_ID$3];
|
|
43
|
+
}
|
|
44
|
+
function parseList(raw) {
|
|
45
|
+
if (!raw) return [];
|
|
46
|
+
return (Array.isArray(raw) ? raw : typeof raw === "string" ? normalizeStringEntries(raw.split(",")) : [raw]).map((entry) => normalizeSmsAllowFrom(String(entry))).filter(Boolean);
|
|
47
|
+
}
|
|
48
|
+
function parseTextChunkLimit(raw) {
|
|
49
|
+
if (typeof raw === "number" && Number.isSafeInteger(raw) && raw > 0) return raw;
|
|
50
|
+
if (typeof raw === "string" && /^\d+$/.test(raw.trim())) return parseStrictInteger(raw.trim()) ?? DEFAULT_TEXT_CHUNK_LIMIT;
|
|
51
|
+
return DEFAULT_TEXT_CHUNK_LIMIT;
|
|
52
|
+
}
|
|
53
|
+
function firstNonBlankEnv(...values) {
|
|
54
|
+
return values.find((value) => value?.trim());
|
|
55
|
+
}
|
|
56
|
+
function hasBaseAccount(channelCfg) {
|
|
57
|
+
return Boolean(channelCfg?.accountSid || hasConfiguredSecretInput(channelCfg?.authToken) || channelCfg?.fromNumber || channelCfg?.messagingServiceSid || process.env.TWILIO_ACCOUNT_SID || process.env.TWILIO_AUTH_TOKEN || process.env.TWILIO_PHONE_NUMBER || process.env.TWILIO_SMS_FROM || process.env.TWILIO_MESSAGING_SERVICE_SID);
|
|
58
|
+
}
|
|
59
|
+
function listSmsAccountIds(cfg) {
|
|
60
|
+
const channelCfg = getChannelConfig(cfg);
|
|
61
|
+
return listCombinedAccountIds({
|
|
62
|
+
configuredAccountIds: Object.keys(channelCfg?.accounts ?? {}),
|
|
63
|
+
implicitAccountId: hasBaseAccount(channelCfg) ? DEFAULT_ACCOUNT_ID$1 : void 0
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function resolveDefaultSmsAccountId(cfg) {
|
|
67
|
+
const channelCfg = getChannelConfig(cfg);
|
|
68
|
+
return resolveListedDefaultAccountId({
|
|
69
|
+
accountIds: listSmsAccountIds(cfg),
|
|
70
|
+
configuredDefaultAccountId: normalizeOptionalAccountId(channelCfg?.defaultAccount)
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function resolveSmsAccount(cfg, accountId) {
|
|
74
|
+
const channelCfg = getChannelConfig(cfg) ?? {};
|
|
75
|
+
const id = normalizeOptionalAccountId(accountId) ?? resolveDefaultSmsAccountId(cfg);
|
|
76
|
+
const accountConfig = resolveAccountEntry(channelCfg.accounts, id);
|
|
77
|
+
const merged = resolveMergedAccountConfig({
|
|
78
|
+
channelConfig: { ...channelCfg },
|
|
79
|
+
accounts: channelCfg.accounts ? Object.fromEntries(Object.entries(channelCfg.accounts).map(([accountKey, account]) => [accountKey, { ...account }])) : void 0,
|
|
80
|
+
accountId: id,
|
|
81
|
+
omitKeys: ["defaultAccount"]
|
|
82
|
+
});
|
|
83
|
+
const useEnvFallbacks = id === DEFAULT_ACCOUNT_ID$1;
|
|
84
|
+
const envAccountSid = useEnvFallbacks ? process.env.TWILIO_ACCOUNT_SID : void 0;
|
|
85
|
+
const envAuthToken = useEnvFallbacks ? process.env.TWILIO_AUTH_TOKEN : void 0;
|
|
86
|
+
const envFromNumber = useEnvFallbacks ? firstNonBlankEnv(process.env.TWILIO_PHONE_NUMBER, process.env.TWILIO_SMS_FROM) : void 0;
|
|
87
|
+
const envMessagingServiceSid = useEnvFallbacks ? process.env.TWILIO_MESSAGING_SERVICE_SID : void 0;
|
|
88
|
+
const envWebhookPath = useEnvFallbacks ? process.env.SMS_WEBHOOK_PATH : void 0;
|
|
89
|
+
const envPublicWebhookUrl = useEnvFallbacks ? process.env.SMS_PUBLIC_WEBHOOK_URL : void 0;
|
|
90
|
+
const envAllowFrom = useEnvFallbacks ? process.env.SMS_ALLOWED_USERS : void 0;
|
|
91
|
+
const envTextChunkLimit = useEnvFallbacks ? process.env.SMS_TEXT_CHUNK_LIMIT : void 0;
|
|
92
|
+
const envDisableSignatureValidation = useEnvFallbacks ? process.env.SMS_DANGEROUSLY_DISABLE_SIGNATURE_VALIDATION : void 0;
|
|
93
|
+
const webhookPath = (merged.webhookPath ?? envWebhookPath ?? DEFAULT_WEBHOOK_PATH).trim();
|
|
94
|
+
const publicWebhookUrl = (merged.publicWebhookUrl ?? envPublicWebhookUrl ?? "").trim();
|
|
95
|
+
const authToken = normalizeResolvedSecretInputString({
|
|
96
|
+
value: merged.authToken ?? envAuthToken,
|
|
97
|
+
path: id === DEFAULT_ACCOUNT_ID$1 ? "channels.sms.authToken" : `channels.sms.accounts.${id}.authToken`
|
|
98
|
+
}) ?? "";
|
|
99
|
+
return {
|
|
100
|
+
accountId: id,
|
|
101
|
+
enabled: channelCfg.enabled !== false && accountConfig?.enabled !== false,
|
|
102
|
+
accountSid: (merged.accountSid ?? envAccountSid ?? "").trim(),
|
|
103
|
+
authToken,
|
|
104
|
+
fromNumber: normalizeSmsPhoneNumber(merged.fromNumber ?? envFromNumber ?? ""),
|
|
105
|
+
messagingServiceSid: (merged.messagingServiceSid ?? envMessagingServiceSid ?? "").trim(),
|
|
106
|
+
defaultTo: normalizeSmsPhoneNumber(merged.defaultTo ?? ""),
|
|
107
|
+
webhookPath: webhookPath || DEFAULT_WEBHOOK_PATH,
|
|
108
|
+
publicWebhookUrl,
|
|
109
|
+
dangerouslyDisableSignatureValidation: merged.dangerouslyDisableSignatureValidation === true || envDisableSignatureValidation === "true",
|
|
110
|
+
dmPolicy: merged.dmPolicy ?? "pairing",
|
|
111
|
+
allowFrom: parseList(merged.allowFrom ?? envAllowFrom),
|
|
112
|
+
textChunkLimit: parseTextChunkLimit(merged.textChunkLimit ?? envTextChunkLimit)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function inspectSmsAccount(cfg, accountId) {
|
|
116
|
+
const account = resolveSmsAccount(cfg, accountId);
|
|
117
|
+
const configured = isSmsAccountConfigured(account);
|
|
118
|
+
return {
|
|
119
|
+
enabled: account.enabled,
|
|
120
|
+
configured,
|
|
121
|
+
tokenStatus: account.authToken ? "available" : "missing",
|
|
122
|
+
webhookPath: account.webhookPath,
|
|
123
|
+
signatureValidation: account.dangerouslyDisableSignatureValidation || account.publicWebhookUrl ? "configured" : "missing-public-url"
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function isSmsAccountConfigured(account) {
|
|
127
|
+
return Boolean(account.accountSid && account.authToken && (account.fromNumber || account.messagingServiceSid));
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region extensions/sms/src/config-schema.ts
|
|
131
|
+
const SecretInputSchema = buildSecretInputSchema();
|
|
132
|
+
const SmsAccountConfigSchema = z.object({
|
|
133
|
+
name: z.string().optional(),
|
|
134
|
+
enabled: z.boolean().optional(),
|
|
135
|
+
accountSid: z.string().optional(),
|
|
136
|
+
authToken: SecretInputSchema.optional(),
|
|
137
|
+
fromNumber: z.string().optional(),
|
|
138
|
+
messagingServiceSid: z.string().optional(),
|
|
139
|
+
defaultTo: z.string().optional(),
|
|
140
|
+
webhookPath: z.string().optional(),
|
|
141
|
+
publicWebhookUrl: z.string().optional(),
|
|
142
|
+
dangerouslyDisableSignatureValidation: z.boolean().optional(),
|
|
143
|
+
dmPolicy: DmPolicySchema.optional().default("pairing"),
|
|
144
|
+
allowFrom: AllowFromListSchema,
|
|
145
|
+
textChunkLimit: z.number().int().positive().optional()
|
|
146
|
+
}).strict().superRefine((value, ctx) => {
|
|
147
|
+
requireChannelOpenAllowFrom({
|
|
148
|
+
channel: "sms",
|
|
149
|
+
policy: value.dmPolicy,
|
|
150
|
+
allowFrom: value.allowFrom,
|
|
151
|
+
ctx,
|
|
152
|
+
requireOpenAllowFrom
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
const SmsChannelConfigSchema = buildChannelConfigSchema(SmsAccountConfigSchema.extend({
|
|
156
|
+
accounts: z.record(z.string(), SmsAccountConfigSchema.optional()).optional(),
|
|
157
|
+
defaultAccount: z.string().optional()
|
|
158
|
+
}), { uiHints: {
|
|
159
|
+
"": {
|
|
160
|
+
label: "SMS",
|
|
161
|
+
help: "Twilio SMS channel configuration for inbound webhooks and outbound text replies."
|
|
162
|
+
},
|
|
163
|
+
accountSid: {
|
|
164
|
+
label: "Twilio Account SID",
|
|
165
|
+
help: "Twilio Account SID used for SMS outbound API calls."
|
|
166
|
+
},
|
|
167
|
+
authToken: {
|
|
168
|
+
label: "Twilio Auth Token",
|
|
169
|
+
help: "Twilio Auth Token used to sign webhook validation and SMS outbound API calls."
|
|
170
|
+
},
|
|
171
|
+
fromNumber: {
|
|
172
|
+
label: "SMS From Number",
|
|
173
|
+
help: "Twilio SMS-capable phone number in E.164 format, for example +15551234567."
|
|
174
|
+
},
|
|
175
|
+
messagingServiceSid: {
|
|
176
|
+
label: "Twilio Messaging Service SID",
|
|
177
|
+
help: "Twilio Messaging Service SID to use instead of a dedicated fromNumber."
|
|
178
|
+
},
|
|
179
|
+
defaultTo: {
|
|
180
|
+
label: "SMS Default To Number",
|
|
181
|
+
help: "Optional default outbound phone number used when a send flow omits an explicit SMS target."
|
|
182
|
+
},
|
|
183
|
+
publicWebhookUrl: {
|
|
184
|
+
label: "SMS Public Webhook URL",
|
|
185
|
+
help: "Public URL configured in Twilio for incoming messages. Must match Twilio's signed URL exactly."
|
|
186
|
+
},
|
|
187
|
+
webhookPath: {
|
|
188
|
+
label: "SMS Webhook Path",
|
|
189
|
+
help: "Gateway HTTP path that receives Twilio incoming-message webhooks. Use a distinct path per account."
|
|
190
|
+
},
|
|
191
|
+
dmPolicy: {
|
|
192
|
+
label: "SMS DM Policy",
|
|
193
|
+
help: "Direct SMS access control (\"pairing\" recommended). \"open\" requires channels.sms.allowFrom=[\"*\"]."
|
|
194
|
+
},
|
|
195
|
+
allowFrom: {
|
|
196
|
+
label: "SMS Allow From",
|
|
197
|
+
help: "Allowed sender phone numbers in E.164 format, or * when dmPolicy is open."
|
|
198
|
+
},
|
|
199
|
+
textChunkLimit: {
|
|
200
|
+
label: "SMS Text Chunk Limit",
|
|
201
|
+
help: "Maximum characters per outbound SMS chunk before OpenClaw splits long replies."
|
|
202
|
+
}
|
|
203
|
+
} });
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region extensions/sms/src/twilio.ts
|
|
206
|
+
const TWILIO_ACCOUNTS_URL = "https://api.twilio.com/2010-04-01/Accounts";
|
|
207
|
+
const TWILIO_MESSAGING_URL = "https://messaging.twilio.com/v1";
|
|
208
|
+
const TWILIO_API_HOSTNAME = "api.twilio.com";
|
|
209
|
+
const TWILIO_MESSAGING_HOSTNAME = "messaging.twilio.com";
|
|
210
|
+
const TWILIO_API_TIMEOUT_MS = 3e4;
|
|
211
|
+
const TWILIO_API_SUCCESS_BODY_LIMIT_BYTES = 1 * 1024 * 1024;
|
|
212
|
+
const TWILIO_API_ERROR_BODY_LIMIT_BYTES = 8 * 1024;
|
|
213
|
+
const TRUNCATED_RESPONSE_SUFFIX = "... [truncated]";
|
|
214
|
+
const WEBHOOK_BODY_LIMIT_BYTES = 32 * 1024;
|
|
215
|
+
const WEBHOOK_BODY_TIMEOUT_MS = 5e3;
|
|
216
|
+
function firstString(value) {
|
|
217
|
+
if (Array.isArray(value)) return firstString(value[0]);
|
|
218
|
+
return typeof value === "string" ? value : "";
|
|
219
|
+
}
|
|
220
|
+
function firstTrimmedString(value) {
|
|
221
|
+
return firstString(value).trim();
|
|
222
|
+
}
|
|
223
|
+
function firstStringish(value) {
|
|
224
|
+
const first = Array.isArray(value) ? value[0] : value;
|
|
225
|
+
if (typeof first === "string") return first;
|
|
226
|
+
return typeof first === "number" ? String(first) : "";
|
|
227
|
+
}
|
|
228
|
+
function parseTwilioApiError(text) {
|
|
229
|
+
try {
|
|
230
|
+
const parsed = JSON.parse(text);
|
|
231
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
232
|
+
const record = parsed;
|
|
233
|
+
return {
|
|
234
|
+
code: typeof record.code === "number" ? record.code : void 0,
|
|
235
|
+
message: typeof record.message === "string" ? record.message : void 0
|
|
236
|
+
};
|
|
237
|
+
} catch {
|
|
238
|
+
return {};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function parseTwilioSuccessPayload(text) {
|
|
242
|
+
if (!text.trim()) return {};
|
|
243
|
+
try {
|
|
244
|
+
const parsed = JSON.parse(text);
|
|
245
|
+
if (!parsed || typeof parsed !== "object") throw new Error("Twilio SMS send returned malformed JSON.");
|
|
246
|
+
const record = parsed;
|
|
247
|
+
return {
|
|
248
|
+
sid: typeof record.sid === "string" ? record.sid : void 0,
|
|
249
|
+
to: typeof record.to === "string" ? record.to : void 0,
|
|
250
|
+
from: typeof record.from === "string" ? record.from : void 0,
|
|
251
|
+
status: typeof record.status === "string" ? record.status : void 0
|
|
252
|
+
};
|
|
253
|
+
} catch (cause) {
|
|
254
|
+
if (cause instanceof Error && cause.message === "Twilio SMS send returned malformed JSON.") throw cause;
|
|
255
|
+
throw new Error("Twilio SMS send returned malformed JSON.", { cause });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function requestSearch(req) {
|
|
259
|
+
try {
|
|
260
|
+
return new URL(req.url ?? "/", "http://localhost").search;
|
|
261
|
+
} catch {
|
|
262
|
+
return "";
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function configuredUrlHasQuery(url) {
|
|
266
|
+
const hashIndex = url.indexOf("#");
|
|
267
|
+
return (hashIndex === -1 ? url : url.slice(0, hashIndex)).includes("?");
|
|
268
|
+
}
|
|
269
|
+
function resolveTwilioWebhookSignatureUrl(params) {
|
|
270
|
+
if (configuredUrlHasQuery(params.publicWebhookUrl)) return params.publicWebhookUrl;
|
|
271
|
+
const search = requestSearch(params.req);
|
|
272
|
+
if (!search) return params.publicWebhookUrl;
|
|
273
|
+
const hashIndex = params.publicWebhookUrl.indexOf("#");
|
|
274
|
+
if (hashIndex === -1) return `${params.publicWebhookUrl}${search}`;
|
|
275
|
+
return `${params.publicWebhookUrl.slice(0, hashIndex)}${search}${params.publicWebhookUrl.slice(hashIndex)}`;
|
|
276
|
+
}
|
|
277
|
+
var TwilioSmsApiError = class extends Error {
|
|
278
|
+
constructor(httpStatus, responseText, operation = "send") {
|
|
279
|
+
const parsed = parseTwilioApiError(responseText);
|
|
280
|
+
const detail = parsed.message ?? (responseText || "unknown");
|
|
281
|
+
super(`Twilio SMS ${operation} failed (${httpStatus}): ${detail}`);
|
|
282
|
+
this.name = "TwilioSmsApiError";
|
|
283
|
+
this.httpStatus = httpStatus;
|
|
284
|
+
this.responseText = responseText;
|
|
285
|
+
this.twilioCode = parsed.code;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
function parseTwilioFormBody(body) {
|
|
289
|
+
const parsed = querystring.parse(body);
|
|
290
|
+
const out = {};
|
|
291
|
+
for (const [key, value] of Object.entries(parsed)) out[key] = firstString(value);
|
|
292
|
+
return out;
|
|
293
|
+
}
|
|
294
|
+
function computeTwilioSignature(params) {
|
|
295
|
+
const data = params.url + Object.keys(params.form).toSorted().map((key) => `${key}${params.form[key] ?? ""}`).join("");
|
|
296
|
+
return createHmac("sha1", params.authToken).update(data).digest("base64");
|
|
297
|
+
}
|
|
298
|
+
function safeEqual(a, b) {
|
|
299
|
+
const left = Buffer.from(a);
|
|
300
|
+
const right = Buffer.from(b);
|
|
301
|
+
return left.length === right.length && timingSafeEqual(left, right);
|
|
302
|
+
}
|
|
303
|
+
function verifyTwilioSignature(params) {
|
|
304
|
+
if (!params.signature || !params.url || !params.authToken) return false;
|
|
305
|
+
return safeEqual(params.signature, computeTwilioSignature({
|
|
306
|
+
url: params.url,
|
|
307
|
+
authToken: params.authToken,
|
|
308
|
+
form: params.form
|
|
309
|
+
}));
|
|
310
|
+
}
|
|
311
|
+
function buildTwilioInboundMessage(form) {
|
|
312
|
+
const from = firstTrimmedString(form.From);
|
|
313
|
+
const to = firstTrimmedString(form.To);
|
|
314
|
+
const body = firstString(form.Body);
|
|
315
|
+
const accountSid = firstTrimmedString(form.AccountSid);
|
|
316
|
+
const messageSid = firstTrimmedString(form.MessageSid) || firstTrimmedString(form.SmsSid) || firstTrimmedString(form.SmsMessageSid);
|
|
317
|
+
if (!from || !to || !body || !messageSid) return null;
|
|
318
|
+
return {
|
|
319
|
+
accountSid,
|
|
320
|
+
from,
|
|
321
|
+
to,
|
|
322
|
+
body,
|
|
323
|
+
messageSid
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
async function readTwilioWebhookForm(req) {
|
|
327
|
+
return parseTwilioFormBody(await readRequestBodyWithLimit(req, {
|
|
328
|
+
maxBytes: WEBHOOK_BODY_LIMIT_BYTES,
|
|
329
|
+
timeoutMs: WEBHOOK_BODY_TIMEOUT_MS
|
|
330
|
+
}));
|
|
331
|
+
}
|
|
332
|
+
function respondTwiml(res, statusCode, body = "") {
|
|
333
|
+
res.statusCode = statusCode;
|
|
334
|
+
res.setHeader("content-type", "text/xml; charset=utf-8");
|
|
335
|
+
res.end(body || "<Response></Response>");
|
|
336
|
+
}
|
|
337
|
+
function twilioApiUrl(accountSid, path, query) {
|
|
338
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
339
|
+
const url = new URL(`${TWILIO_ACCOUNTS_URL}/${encodeURIComponent(accountSid)}${normalizedPath}`);
|
|
340
|
+
if (query) url.search = query.toString();
|
|
341
|
+
return url.toString();
|
|
342
|
+
}
|
|
343
|
+
function twilioMessagingUrl(path, query) {
|
|
344
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
345
|
+
const url = new URL(`${TWILIO_MESSAGING_URL}${normalizedPath}`);
|
|
346
|
+
if (query) url.search = query.toString();
|
|
347
|
+
return url.toString();
|
|
348
|
+
}
|
|
349
|
+
function basicAuthHeader(account) {
|
|
350
|
+
return `Basic ${Buffer.from(`${account.accountSid}:${account.authToken}`).toString("base64")}`;
|
|
351
|
+
}
|
|
352
|
+
function appendTruncatedResponseSuffix(text) {
|
|
353
|
+
return `${text.trimEnd()}${TRUNCATED_RESPONSE_SUFFIX}`;
|
|
354
|
+
}
|
|
355
|
+
async function readTwilioApiResponseText(response) {
|
|
356
|
+
if (!response.body) return "";
|
|
357
|
+
const maxBytes = response.ok ? TWILIO_API_SUCCESS_BODY_LIMIT_BYTES : TWILIO_API_ERROR_BODY_LIMIT_BYTES;
|
|
358
|
+
const truncateOnLimit = !response.ok;
|
|
359
|
+
const reader = response.body.getReader();
|
|
360
|
+
const decoder = new TextDecoder();
|
|
361
|
+
let totalBytes = 0;
|
|
362
|
+
let text = "";
|
|
363
|
+
try {
|
|
364
|
+
while (true) {
|
|
365
|
+
const { done, value } = await reader.read();
|
|
366
|
+
if (done) return text + decoder.decode();
|
|
367
|
+
if (!value?.byteLength) continue;
|
|
368
|
+
const remainingBytes = maxBytes - totalBytes;
|
|
369
|
+
if (value.byteLength > remainingBytes) {
|
|
370
|
+
const clipped = remainingBytes > 0 ? value.slice(0, remainingBytes) : void 0;
|
|
371
|
+
if (truncateOnLimit) {
|
|
372
|
+
if (clipped) text += decoder.decode(clipped, { stream: true });
|
|
373
|
+
await reader.cancel().catch(() => void 0);
|
|
374
|
+
return appendTruncatedResponseSuffix(text + decoder.decode());
|
|
375
|
+
}
|
|
376
|
+
await reader.cancel().catch(() => void 0);
|
|
377
|
+
throw new Error(`Twilio SMS API response body too large: ${totalBytes + value.byteLength} bytes (limit: ${maxBytes} bytes)`);
|
|
378
|
+
}
|
|
379
|
+
text += decoder.decode(value, { stream: true });
|
|
380
|
+
totalBytes += value.byteLength;
|
|
381
|
+
}
|
|
382
|
+
} finally {
|
|
383
|
+
try {
|
|
384
|
+
reader.releaseLock();
|
|
385
|
+
} catch {}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function normalizeRequestHeaders(headers) {
|
|
389
|
+
if (!headers) return {};
|
|
390
|
+
if (headers instanceof Headers) return Object.fromEntries(headers.entries());
|
|
391
|
+
if (Array.isArray(headers)) return Object.fromEntries(headers.map(([key, value]) => [key, value]));
|
|
392
|
+
return Object.fromEntries(Object.entries(headers));
|
|
393
|
+
}
|
|
394
|
+
async function requestTwilioApi(params) {
|
|
395
|
+
const init = {
|
|
396
|
+
...params.init,
|
|
397
|
+
headers: {
|
|
398
|
+
...normalizeRequestHeaders(params.init?.headers),
|
|
399
|
+
authorization: basicAuthHeader(params.account)
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
if (params.fetchImpl) {
|
|
403
|
+
const response = await params.fetchImpl(params.url, init);
|
|
404
|
+
return {
|
|
405
|
+
ok: response.ok,
|
|
406
|
+
status: response.status,
|
|
407
|
+
text: await readTwilioApiResponseText(response)
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
const guarded = await fetchWithSsrFGuard({
|
|
411
|
+
url: params.url,
|
|
412
|
+
init,
|
|
413
|
+
auditContext: "sms-twilio-api",
|
|
414
|
+
policy: { allowedHostnames: [params.allowedHostname] },
|
|
415
|
+
requireHttps: true,
|
|
416
|
+
timeoutMs: params.timeoutMs ?? TWILIO_API_TIMEOUT_MS
|
|
417
|
+
});
|
|
418
|
+
try {
|
|
419
|
+
return {
|
|
420
|
+
ok: guarded.response.ok,
|
|
421
|
+
status: guarded.response.status,
|
|
422
|
+
text: await readTwilioApiResponseText(guarded.response)
|
|
423
|
+
};
|
|
424
|
+
} finally {
|
|
425
|
+
await guarded.release();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function parseTwilioIncomingPhoneNumber(record) {
|
|
429
|
+
return {
|
|
430
|
+
sid: firstTrimmedString(record.sid),
|
|
431
|
+
phoneNumber: firstTrimmedString(record.phone_number ?? record.phoneNumber),
|
|
432
|
+
smsUrl: firstTrimmedString(record.sms_url ?? record.smsUrl),
|
|
433
|
+
smsMethod: firstTrimmedString(record.sms_method ?? record.smsMethod),
|
|
434
|
+
voiceUrl: firstTrimmedString(record.voice_url ?? record.voiceUrl)
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
function parseTwilioMessageLogEntry(record) {
|
|
438
|
+
return {
|
|
439
|
+
sid: firstTrimmedString(record.sid),
|
|
440
|
+
direction: firstTrimmedString(record.direction),
|
|
441
|
+
status: firstTrimmedString(record.status),
|
|
442
|
+
to: firstTrimmedString(record.to),
|
|
443
|
+
from: firstTrimmedString(record.from),
|
|
444
|
+
errorCode: firstStringish(record.error_code ?? record.errorCode).trim(),
|
|
445
|
+
body: firstString(record.body),
|
|
446
|
+
dateCreated: firstTrimmedString(record.date_created ?? record.dateCreated),
|
|
447
|
+
dateSent: firstTrimmedString(record.date_sent ?? record.dateSent)
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function parseTwilioMessagingService(record) {
|
|
451
|
+
return {
|
|
452
|
+
sid: firstTrimmedString(record.sid),
|
|
453
|
+
inboundRequestUrl: firstTrimmedString(record.inbound_request_url ?? record.inboundRequestUrl),
|
|
454
|
+
inboundMethod: firstTrimmedString(record.inbound_method ?? record.inboundMethod),
|
|
455
|
+
useInboundWebhookOnNumber: Boolean(record.use_inbound_webhook_on_number ?? record.useInboundWebhookOnNumber)
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
function parseTwilioListPayload(text, key, parseEntry) {
|
|
459
|
+
if (!text.trim()) return [];
|
|
460
|
+
const parsed = JSON.parse(text);
|
|
461
|
+
if (!parsed || typeof parsed !== "object") return [];
|
|
462
|
+
const items = parsed[key];
|
|
463
|
+
if (!Array.isArray(items)) return [];
|
|
464
|
+
return items.filter((item) => Boolean(item && typeof item === "object" && !Array.isArray(item))).map(parseEntry);
|
|
465
|
+
}
|
|
466
|
+
async function listTwilioIncomingPhoneNumbers(params) {
|
|
467
|
+
const query = new URLSearchParams();
|
|
468
|
+
if (params.phoneNumber) query.set("PhoneNumber", params.phoneNumber);
|
|
469
|
+
const response = await requestTwilioApi({
|
|
470
|
+
account: params.account,
|
|
471
|
+
url: twilioApiUrl(params.account.accountSid, "/IncomingPhoneNumbers.json", query),
|
|
472
|
+
allowedHostname: TWILIO_API_HOSTNAME,
|
|
473
|
+
fetchImpl: params.fetchImpl,
|
|
474
|
+
timeoutMs: params.timeoutMs
|
|
475
|
+
});
|
|
476
|
+
if (!response.ok) throw new TwilioSmsApiError(response.status, response.text, "phone-number lookup");
|
|
477
|
+
return parseTwilioListPayload(response.text, "incoming_phone_numbers", parseTwilioIncomingPhoneNumber);
|
|
478
|
+
}
|
|
479
|
+
async function retrieveTwilioMessagingService(params) {
|
|
480
|
+
const response = await requestTwilioApi({
|
|
481
|
+
account: params.account,
|
|
482
|
+
url: twilioMessagingUrl(`/Services/${encodeURIComponent(params.serviceSid)}`),
|
|
483
|
+
allowedHostname: TWILIO_MESSAGING_HOSTNAME,
|
|
484
|
+
fetchImpl: params.fetchImpl,
|
|
485
|
+
timeoutMs: params.timeoutMs
|
|
486
|
+
});
|
|
487
|
+
if (!response.ok) throw new TwilioSmsApiError(response.status, response.text, "messaging-service lookup");
|
|
488
|
+
const parsed = JSON.parse(response.text);
|
|
489
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Twilio Messaging Service lookup returned malformed JSON.");
|
|
490
|
+
return parseTwilioMessagingService(parsed);
|
|
491
|
+
}
|
|
492
|
+
async function listTwilioMessages(params) {
|
|
493
|
+
const query = new URLSearchParams();
|
|
494
|
+
if (params.to) query.set("To", params.to);
|
|
495
|
+
if (params.from) query.set("From", params.from);
|
|
496
|
+
query.set("PageSize", String(params.pageSize ?? 5));
|
|
497
|
+
const response = await requestTwilioApi({
|
|
498
|
+
account: params.account,
|
|
499
|
+
url: twilioApiUrl(params.account.accountSid, "/Messages.json", query),
|
|
500
|
+
allowedHostname: TWILIO_API_HOSTNAME,
|
|
501
|
+
fetchImpl: params.fetchImpl,
|
|
502
|
+
timeoutMs: params.timeoutMs
|
|
503
|
+
});
|
|
504
|
+
if (!response.ok) throw new TwilioSmsApiError(response.status, response.text, "message lookup");
|
|
505
|
+
return parseTwilioListPayload(response.text, "messages", parseTwilioMessageLogEntry);
|
|
506
|
+
}
|
|
507
|
+
async function sendSmsViaTwilio(params) {
|
|
508
|
+
if (!params.account.fromNumber && !params.account.messagingServiceSid) throw new Error("Twilio SMS send requires fromNumber or messagingServiceSid.");
|
|
509
|
+
const body = new URLSearchParams({
|
|
510
|
+
To: params.to,
|
|
511
|
+
Body: params.text
|
|
512
|
+
});
|
|
513
|
+
if (params.account.fromNumber) body.set("From", params.account.fromNumber);
|
|
514
|
+
else body.set("MessagingServiceSid", params.account.messagingServiceSid);
|
|
515
|
+
const init = {
|
|
516
|
+
method: "POST",
|
|
517
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
518
|
+
body
|
|
519
|
+
};
|
|
520
|
+
const response = await requestTwilioApi({
|
|
521
|
+
account: params.account,
|
|
522
|
+
url: twilioApiUrl(params.account.accountSid, "/Messages.json"),
|
|
523
|
+
allowedHostname: TWILIO_API_HOSTNAME,
|
|
524
|
+
init,
|
|
525
|
+
fetchImpl: params.fetchImpl
|
|
526
|
+
});
|
|
527
|
+
if (!response.ok) throw new TwilioSmsApiError(response.status, response.text);
|
|
528
|
+
const payload = parseTwilioSuccessPayload(response.text);
|
|
529
|
+
const sid = payload.sid?.trim();
|
|
530
|
+
if (!sid) throw new Error("Twilio SMS send response did not include a Message SID.");
|
|
531
|
+
return {
|
|
532
|
+
sid,
|
|
533
|
+
to: payload.to?.trim() || params.to,
|
|
534
|
+
...payload.from?.trim() ? { from: payload.from.trim() } : {},
|
|
535
|
+
...payload.status?.trim() ? { status: payload.status.trim() } : {}
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
//#endregion
|
|
539
|
+
//#region extensions/sms/src/send.ts
|
|
540
|
+
function toSmsPlainText(text) {
|
|
541
|
+
return stripMarkdown(text.replace(/```[^\n]*\n?([\s\S]*?)```/g, (_match, body) => body.trim()).replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g, (_match, label, url) => {
|
|
542
|
+
const cleanLabel = label.trim();
|
|
543
|
+
const cleanUrl = url.trim();
|
|
544
|
+
return cleanLabel && cleanLabel !== cleanUrl ? `${cleanLabel} (${cleanUrl})` : cleanUrl;
|
|
545
|
+
})).replace(/\r\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
546
|
+
}
|
|
547
|
+
async function sendSmsTextChunks(params) {
|
|
548
|
+
const text = toSmsPlainText(params.text);
|
|
549
|
+
if (!text) throw new Error("SMS send requires non-empty text.");
|
|
550
|
+
const chunks = chunkTextForOutbound(text, params.account.textChunkLimit).filter(Boolean);
|
|
551
|
+
const sendChunks = chunks.length ? chunks : [text];
|
|
552
|
+
const results = [];
|
|
553
|
+
for (const textLocal of sendChunks) results.push(await sendSmsViaTwilio({
|
|
554
|
+
account: params.account,
|
|
555
|
+
to: params.to,
|
|
556
|
+
text: textLocal
|
|
557
|
+
}));
|
|
558
|
+
return results;
|
|
559
|
+
}
|
|
560
|
+
//#endregion
|
|
561
|
+
//#region extensions/sms/src/inbound.ts
|
|
562
|
+
const CHANNEL_ID$2 = "sms";
|
|
563
|
+
async function authorizeSmsSender(params) {
|
|
564
|
+
return await resolveStableChannelMessageIngress({
|
|
565
|
+
channelId: CHANNEL_ID$2,
|
|
566
|
+
accountId: params.account.accountId,
|
|
567
|
+
cfg: params.cfg,
|
|
568
|
+
identity: {
|
|
569
|
+
key: "phone",
|
|
570
|
+
entryIdPrefix: "sms-entry"
|
|
571
|
+
},
|
|
572
|
+
readStoreAllowFrom: async () => await params.channelRuntime.pairing.readAllowFromStore({
|
|
573
|
+
channel: CHANNEL_ID$2,
|
|
574
|
+
accountId: params.account.accountId
|
|
575
|
+
}),
|
|
576
|
+
subject: { stableId: params.from },
|
|
577
|
+
conversation: {
|
|
578
|
+
kind: "direct",
|
|
579
|
+
id: "direct"
|
|
580
|
+
},
|
|
581
|
+
event: { mayPair: true },
|
|
582
|
+
dmPolicy: params.account.dmPolicy,
|
|
583
|
+
allowFrom: params.account.allowFrom
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
async function issueSmsPairingChallenge(params) {
|
|
587
|
+
await createChannelPairingChallengeIssuer({
|
|
588
|
+
channel: CHANNEL_ID$2,
|
|
589
|
+
upsertPairingRequest: async (input) => await params.channelRuntime.pairing.upsertPairingRequest({
|
|
590
|
+
channel: CHANNEL_ID$2,
|
|
591
|
+
accountId: params.account.accountId,
|
|
592
|
+
...input
|
|
593
|
+
})
|
|
594
|
+
})({
|
|
595
|
+
senderId: params.from,
|
|
596
|
+
senderIdLine: `Your SMS phone number: ${params.from}`,
|
|
597
|
+
sendPairingReply: async (text) => {
|
|
598
|
+
await sendSmsTextChunks({
|
|
599
|
+
account: params.account,
|
|
600
|
+
to: params.from,
|
|
601
|
+
text
|
|
602
|
+
});
|
|
603
|
+
},
|
|
604
|
+
onCreated: () => {
|
|
605
|
+
params.log?.info?.(`SMS pairing request created for ${params.from}`);
|
|
606
|
+
},
|
|
607
|
+
onReplyError: (err) => {
|
|
608
|
+
params.log?.warn?.(`SMS pairing reply failed for ${params.from}: ${String(err)}`);
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
async function dispatchSmsInboundEvent(params) {
|
|
613
|
+
const from = normalizeSmsPhoneNumber(params.msg.from);
|
|
614
|
+
const auth = await authorizeSmsSender({
|
|
615
|
+
cfg: params.cfg,
|
|
616
|
+
account: params.account,
|
|
617
|
+
channelRuntime: params.channelRuntime,
|
|
618
|
+
from
|
|
619
|
+
});
|
|
620
|
+
if (!auth.senderAccess.allowed) {
|
|
621
|
+
if (auth.senderAccess.decision === "pairing") {
|
|
622
|
+
await issueSmsPairingChallenge({
|
|
623
|
+
account: params.account,
|
|
624
|
+
channelRuntime: params.channelRuntime,
|
|
625
|
+
from,
|
|
626
|
+
log: params.log
|
|
627
|
+
});
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
params.log?.warn?.(`SMS sender ${from} is not authorized`);
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
const route = params.channelRuntime.routing.resolveAgentRoute({
|
|
634
|
+
cfg: params.cfg,
|
|
635
|
+
channel: CHANNEL_ID$2,
|
|
636
|
+
accountId: params.account.accountId,
|
|
637
|
+
peer: {
|
|
638
|
+
kind: "direct",
|
|
639
|
+
id: from
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
const sessionKey = route.sessionKey;
|
|
643
|
+
await params.channelRuntime.inbound.run({
|
|
644
|
+
channel: CHANNEL_ID$2,
|
|
645
|
+
accountId: params.account.accountId,
|
|
646
|
+
raw: params.msg,
|
|
647
|
+
adapter: {
|
|
648
|
+
ingest: (msg) => ({
|
|
649
|
+
id: msg.messageSid,
|
|
650
|
+
timestamp: Date.now(),
|
|
651
|
+
rawText: msg.body,
|
|
652
|
+
textForAgent: msg.body,
|
|
653
|
+
textForCommands: msg.body,
|
|
654
|
+
raw: msg
|
|
655
|
+
}),
|
|
656
|
+
resolveTurn: async (input) => {
|
|
657
|
+
const ctxPayload = params.channelRuntime.inbound.buildContext({
|
|
658
|
+
channel: CHANNEL_ID$2,
|
|
659
|
+
accountId: params.account.accountId,
|
|
660
|
+
timestamp: input.timestamp,
|
|
661
|
+
from: `sms:${from}`,
|
|
662
|
+
sender: {
|
|
663
|
+
id: from,
|
|
664
|
+
name: from
|
|
665
|
+
},
|
|
666
|
+
conversation: {
|
|
667
|
+
kind: "direct",
|
|
668
|
+
id: from,
|
|
669
|
+
label: from
|
|
670
|
+
},
|
|
671
|
+
route: {
|
|
672
|
+
agentId: route.agentId,
|
|
673
|
+
accountId: params.account.accountId,
|
|
674
|
+
routeSessionKey: sessionKey,
|
|
675
|
+
dispatchSessionKey: sessionKey
|
|
676
|
+
},
|
|
677
|
+
reply: { to: `sms:${from}` },
|
|
678
|
+
message: {
|
|
679
|
+
rawBody: input.rawText,
|
|
680
|
+
commandBody: input.textForCommands,
|
|
681
|
+
bodyForAgent: input.textForAgent
|
|
682
|
+
},
|
|
683
|
+
extra: {
|
|
684
|
+
MessageSid: params.msg.messageSid,
|
|
685
|
+
To: params.msg.to
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
const storePath = params.channelRuntime.session.resolveStorePath(params.cfg.session?.store, { agentId: route.agentId });
|
|
689
|
+
return {
|
|
690
|
+
cfg: params.cfg,
|
|
691
|
+
channel: CHANNEL_ID$2,
|
|
692
|
+
accountId: params.account.accountId,
|
|
693
|
+
agentId: route.agentId,
|
|
694
|
+
routeSessionKey: sessionKey,
|
|
695
|
+
storePath,
|
|
696
|
+
ctxPayload,
|
|
697
|
+
recordInboundSession: params.channelRuntime.session.recordInboundSession,
|
|
698
|
+
dispatchReplyWithBufferedBlockDispatcher: params.channelRuntime.reply.dispatchReplyWithBufferedBlockDispatcher,
|
|
699
|
+
delivery: {
|
|
700
|
+
durable: () => ({ to: from }),
|
|
701
|
+
deliver: async (payload) => {
|
|
702
|
+
const text = payload.text;
|
|
703
|
+
if (!text) return { visibleReplySent: false };
|
|
704
|
+
await sendSmsTextChunks({
|
|
705
|
+
account: params.account,
|
|
706
|
+
to: from,
|
|
707
|
+
text
|
|
708
|
+
});
|
|
709
|
+
return { visibleReplySent: true };
|
|
710
|
+
}
|
|
711
|
+
},
|
|
712
|
+
dispatcherOptions: { onReplyStart: () => {
|
|
713
|
+
params.log?.info?.(`SMS reply started for ${from}`);
|
|
714
|
+
} }
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
//#endregion
|
|
721
|
+
//#region extensions/sms/src/webhook.ts
|
|
722
|
+
const rateLimiter = createFixedWindowRateLimiter({
|
|
723
|
+
maxRequests: 30,
|
|
724
|
+
windowMs: 6e4,
|
|
725
|
+
maxTrackedKeys: 5e3
|
|
726
|
+
});
|
|
727
|
+
const REPLAY_CACHE_TTL_MS = 10 * 6e4;
|
|
728
|
+
const REPLAY_CACHE_MAX_KEYS = 1e4;
|
|
729
|
+
const replayCache = /* @__PURE__ */ new Map();
|
|
730
|
+
function headerValue(value) {
|
|
731
|
+
if (Array.isArray(value)) return value[0];
|
|
732
|
+
return value;
|
|
733
|
+
}
|
|
734
|
+
function rateLimitKey(req) {
|
|
735
|
+
return req.socket?.remoteAddress ?? "unknown";
|
|
736
|
+
}
|
|
737
|
+
function rememberWebhookMessage(params) {
|
|
738
|
+
const now = params.now ?? Date.now();
|
|
739
|
+
for (const [key, expiresAt] of replayCache) {
|
|
740
|
+
if (expiresAt > now && replayCache.size <= REPLAY_CACHE_MAX_KEYS) break;
|
|
741
|
+
replayCache.delete(key);
|
|
742
|
+
}
|
|
743
|
+
const key = `${params.accountId}:${params.messageSid}`;
|
|
744
|
+
if ((replayCache.get(key) ?? 0) > now) return false;
|
|
745
|
+
replayCache.set(key, now + REPLAY_CACHE_TTL_MS);
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
function createSmsWebhookHandler(params) {
|
|
749
|
+
return async (req, res) => {
|
|
750
|
+
if (req.method !== "POST") {
|
|
751
|
+
respondTwiml(res, 405, "Method not allowed");
|
|
752
|
+
return true;
|
|
753
|
+
}
|
|
754
|
+
const key = rateLimitKey(req);
|
|
755
|
+
if (rateLimiter.isRateLimited(key)) {
|
|
756
|
+
params.log?.warn?.(`SMS webhook rate limit exceeded for ${key}`);
|
|
757
|
+
respondTwiml(res, 429, "Rate limit exceeded");
|
|
758
|
+
return true;
|
|
759
|
+
}
|
|
760
|
+
let form;
|
|
761
|
+
try {
|
|
762
|
+
form = await readTwilioWebhookForm(req);
|
|
763
|
+
} catch {
|
|
764
|
+
respondTwiml(res, 400, "Invalid request body");
|
|
765
|
+
return true;
|
|
766
|
+
}
|
|
767
|
+
if (!params.account.dangerouslyDisableSignatureValidation) {
|
|
768
|
+
if (!verifyTwilioSignature({
|
|
769
|
+
signature: headerValue(req.headers["x-twilio-signature"]),
|
|
770
|
+
url: resolveTwilioWebhookSignatureUrl({
|
|
771
|
+
req,
|
|
772
|
+
publicWebhookUrl: params.account.publicWebhookUrl
|
|
773
|
+
}),
|
|
774
|
+
authToken: params.account.authToken,
|
|
775
|
+
form
|
|
776
|
+
})) {
|
|
777
|
+
params.log?.warn?.("SMS webhook rejected invalid Twilio signature");
|
|
778
|
+
respondTwiml(res, 403, "Invalid signature");
|
|
779
|
+
return true;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
const msg = buildTwilioInboundMessage(form);
|
|
783
|
+
if (!msg) {
|
|
784
|
+
respondTwiml(res, 400, "Missing SMS payload");
|
|
785
|
+
return true;
|
|
786
|
+
}
|
|
787
|
+
if (msg.accountSid && msg.accountSid !== params.account.accountSid) {
|
|
788
|
+
params.log?.warn?.("SMS webhook rejected mismatched Twilio AccountSid");
|
|
789
|
+
respondTwiml(res, 403, "Invalid account");
|
|
790
|
+
return true;
|
|
791
|
+
}
|
|
792
|
+
if (!rememberWebhookMessage({
|
|
793
|
+
accountId: params.account.accountId,
|
|
794
|
+
messageSid: msg.messageSid
|
|
795
|
+
})) {
|
|
796
|
+
params.log?.warn?.(`SMS webhook ignored replayed message ${msg.messageSid}`);
|
|
797
|
+
respondTwiml(res, 200);
|
|
798
|
+
return true;
|
|
799
|
+
}
|
|
800
|
+
dispatchSmsInboundEvent({
|
|
801
|
+
cfg: params.cfg,
|
|
802
|
+
account: params.account,
|
|
803
|
+
msg,
|
|
804
|
+
channelRuntime: params.channelRuntime,
|
|
805
|
+
log: params.log
|
|
806
|
+
}).catch((err) => {
|
|
807
|
+
params.log?.error?.(`SMS webhook dispatch failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
808
|
+
});
|
|
809
|
+
respondTwiml(res, 200);
|
|
810
|
+
return true;
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
//#endregion
|
|
814
|
+
//#region extensions/sms/src/gateway.ts
|
|
815
|
+
const CHANNEL_ID$1 = "sms";
|
|
816
|
+
const activeRoutes = /* @__PURE__ */ new Map();
|
|
817
|
+
const activeRoutePaths = /* @__PURE__ */ new Map();
|
|
818
|
+
function routeKey(account) {
|
|
819
|
+
return `${account.accountId}:${normalizeWebhookPath(account.webhookPath)}`;
|
|
820
|
+
}
|
|
821
|
+
function normalizeWebhookPath(path) {
|
|
822
|
+
const trimmed = path.trim();
|
|
823
|
+
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
824
|
+
}
|
|
825
|
+
function collectSmsStartupWarnings(account) {
|
|
826
|
+
const warnings = [];
|
|
827
|
+
if (!account.accountSid || !account.authToken || !account.fromNumber && !account.messagingServiceSid) warnings.push("- SMS: accountSid, authToken, and fromNumber or messagingServiceSid are required.");
|
|
828
|
+
if (!account.publicWebhookUrl && !account.dangerouslyDisableSignatureValidation) warnings.push("- SMS: publicWebhookUrl is required for Twilio signature validation. Set dangerouslyDisableSignatureValidation=true only for local testing.");
|
|
829
|
+
if (account.dmPolicy === "allowlist" && account.allowFrom.length === 0) warnings.push("- SMS: dmPolicy=allowlist with empty allowFrom rejects every sender.");
|
|
830
|
+
if (account.dmPolicy === "open" && !account.allowFrom.includes("*")) warnings.push("- SMS: dmPolicy=open should set allowFrom=[\"*\"] or explicit sender numbers.");
|
|
831
|
+
return warnings;
|
|
832
|
+
}
|
|
833
|
+
function registerSmsWebhookRoute(params) {
|
|
834
|
+
const key = routeKey(params.account);
|
|
835
|
+
const webhookPath = normalizeWebhookPath(params.account.webhookPath);
|
|
836
|
+
const currentPathOwner = activeRoutePaths.get(webhookPath);
|
|
837
|
+
if (currentPathOwner && currentPathOwner !== params.account.accountId) throw new Error(`SMS webhook path ${webhookPath} is already registered by account ${currentPathOwner}; configure a distinct webhookPath for account ${params.account.accountId}.`);
|
|
838
|
+
activeRoutes.get(key)?.();
|
|
839
|
+
activeRoutePaths.delete(webhookPath);
|
|
840
|
+
const unregister = registerPluginHttpRoute({
|
|
841
|
+
path: webhookPath,
|
|
842
|
+
auth: "plugin",
|
|
843
|
+
pluginId: CHANNEL_ID$1,
|
|
844
|
+
accountId: params.account.accountId,
|
|
845
|
+
log: (msg) => params.log?.info?.(msg),
|
|
846
|
+
handler: createSmsWebhookHandler(params)
|
|
847
|
+
});
|
|
848
|
+
activeRoutes.set(key, unregister);
|
|
849
|
+
activeRoutePaths.set(webhookPath, params.account.accountId);
|
|
850
|
+
return () => {
|
|
851
|
+
unregister();
|
|
852
|
+
activeRoutes.delete(key);
|
|
853
|
+
if (activeRoutePaths.get(webhookPath) === params.account.accountId) activeRoutePaths.delete(webhookPath);
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
async function startSmsGatewayAccount(params) {
|
|
857
|
+
if (!params.account.enabled) {
|
|
858
|
+
params.log?.info?.(`SMS account ${params.account.accountId} is disabled`);
|
|
859
|
+
return waitUntilAbort(params.abortSignal);
|
|
860
|
+
}
|
|
861
|
+
const warnings = collectSmsStartupWarnings(params.account);
|
|
862
|
+
if (warnings.some((warning) => warning.includes("required"))) {
|
|
863
|
+
for (const warning of warnings) params.log?.warn?.(warning);
|
|
864
|
+
return waitUntilAbort(params.abortSignal);
|
|
865
|
+
}
|
|
866
|
+
for (const warning of warnings) params.log?.warn?.(warning);
|
|
867
|
+
const unregister = registerSmsWebhookRoute(params);
|
|
868
|
+
params.log?.info?.(`Registered SMS webhook route ${params.account.webhookPath} for account ${params.account.accountId}`);
|
|
869
|
+
return waitUntilAbort(params.abortSignal, unregister);
|
|
870
|
+
}
|
|
871
|
+
//#endregion
|
|
872
|
+
//#region extensions/sms/src/status.ts
|
|
873
|
+
const TWILIO_ERROR_WEBHOOK_REACHABILITY = "11200";
|
|
874
|
+
function addTailscaleHint(account, hints) {
|
|
875
|
+
let host;
|
|
876
|
+
try {
|
|
877
|
+
host = new URL(account.publicWebhookUrl).hostname;
|
|
878
|
+
} catch {
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (!host.endsWith(".ts.net")) return;
|
|
882
|
+
hints.push(`Tailscale Funnel must expose the exact SMS path: tailscale funnel --bg --set-path ${account.webhookPath} http://127.0.0.1:<gateway-port>${account.webhookPath}`);
|
|
883
|
+
}
|
|
884
|
+
function compareTwilioWebhook(account, phoneNumber) {
|
|
885
|
+
if (!account.fromNumber) return {
|
|
886
|
+
status: "skipped",
|
|
887
|
+
reason: "Messaging Service senders do not have one phone-number SMS webhook to inspect."
|
|
888
|
+
};
|
|
889
|
+
if (!phoneNumber) return {
|
|
890
|
+
status: "number-not-found",
|
|
891
|
+
expectedNumber: account.fromNumber
|
|
892
|
+
};
|
|
893
|
+
const configuredMethod = phoneNumber.smsMethod.toUpperCase();
|
|
894
|
+
if (!phoneNumber.smsUrl) return {
|
|
895
|
+
status: "missing",
|
|
896
|
+
phoneNumber: phoneNumber.phoneNumber || account.fromNumber,
|
|
897
|
+
expectedUrl: account.publicWebhookUrl,
|
|
898
|
+
configuredMethod
|
|
899
|
+
};
|
|
900
|
+
if (configuredMethod && configuredMethod !== "POST") return {
|
|
901
|
+
status: "method-mismatch",
|
|
902
|
+
phoneNumber: phoneNumber.phoneNumber || account.fromNumber,
|
|
903
|
+
expectedUrl: account.publicWebhookUrl,
|
|
904
|
+
configuredUrl: phoneNumber.smsUrl,
|
|
905
|
+
configuredMethod
|
|
906
|
+
};
|
|
907
|
+
if (phoneNumber.smsUrl !== account.publicWebhookUrl) return {
|
|
908
|
+
status: "url-mismatch",
|
|
909
|
+
phoneNumber: phoneNumber.phoneNumber || account.fromNumber,
|
|
910
|
+
expectedUrl: account.publicWebhookUrl,
|
|
911
|
+
configuredUrl: phoneNumber.smsUrl,
|
|
912
|
+
configuredMethod
|
|
913
|
+
};
|
|
914
|
+
return {
|
|
915
|
+
status: "matches",
|
|
916
|
+
phoneNumber: phoneNumber.phoneNumber || account.fromNumber,
|
|
917
|
+
expectedUrl: account.publicWebhookUrl,
|
|
918
|
+
configuredUrl: phoneNumber.smsUrl,
|
|
919
|
+
configuredMethod,
|
|
920
|
+
voiceUrl: phoneNumber.voiceUrl
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
function compareTwilioMessagingService(account, service) {
|
|
924
|
+
if (service.useInboundWebhookOnNumber) return {
|
|
925
|
+
status: "unavailable",
|
|
926
|
+
reason: "Twilio Messaging Service defers inbound webhooks to sender phone numbers; configure fromNumber or disable defer-to-sender before probing."
|
|
927
|
+
};
|
|
928
|
+
const configuredMethod = service.inboundMethod.toUpperCase();
|
|
929
|
+
if (!service.inboundRequestUrl) return {
|
|
930
|
+
status: "messaging-service-missing",
|
|
931
|
+
serviceSid: service.sid || account.messagingServiceSid,
|
|
932
|
+
expectedUrl: account.publicWebhookUrl,
|
|
933
|
+
configuredMethod
|
|
934
|
+
};
|
|
935
|
+
if (configuredMethod && configuredMethod !== "POST") return {
|
|
936
|
+
status: "messaging-service-method-mismatch",
|
|
937
|
+
serviceSid: service.sid || account.messagingServiceSid,
|
|
938
|
+
expectedUrl: account.publicWebhookUrl,
|
|
939
|
+
configuredUrl: service.inboundRequestUrl,
|
|
940
|
+
configuredMethod
|
|
941
|
+
};
|
|
942
|
+
if (service.inboundRequestUrl !== account.publicWebhookUrl) return {
|
|
943
|
+
status: "messaging-service-url-mismatch",
|
|
944
|
+
serviceSid: service.sid || account.messagingServiceSid,
|
|
945
|
+
expectedUrl: account.publicWebhookUrl,
|
|
946
|
+
configuredUrl: service.inboundRequestUrl,
|
|
947
|
+
configuredMethod
|
|
948
|
+
};
|
|
949
|
+
return {
|
|
950
|
+
status: "messaging-service-matches",
|
|
951
|
+
serviceSid: service.sid || account.messagingServiceSid,
|
|
952
|
+
expectedUrl: account.publicWebhookUrl,
|
|
953
|
+
configuredUrl: service.inboundRequestUrl,
|
|
954
|
+
configuredMethod
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
function recentInboundSummary(messages) {
|
|
958
|
+
const message = messages[0];
|
|
959
|
+
if (!message) return;
|
|
960
|
+
return {
|
|
961
|
+
sid: message.sid,
|
|
962
|
+
direction: message.direction,
|
|
963
|
+
status: message.status,
|
|
964
|
+
errorCode: message.errorCode,
|
|
965
|
+
dateCreated: message.dateCreated,
|
|
966
|
+
dateSent: message.dateSent
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
function webhookError(probe) {
|
|
970
|
+
switch (probe.status) {
|
|
971
|
+
case "matches":
|
|
972
|
+
case "skipped": return;
|
|
973
|
+
case "unavailable": return probe.reason;
|
|
974
|
+
case "number-not-found": return `Twilio account does not list ${probe.expectedNumber} as an incoming phone number.`;
|
|
975
|
+
case "missing": return `Twilio number ${probe.phoneNumber} has no SMS webhook URL configured.`;
|
|
976
|
+
case "method-mismatch": return `Twilio number ${probe.phoneNumber} uses ${probe.configuredMethod || "an unknown method"} for SMS webhooks; use POST.`;
|
|
977
|
+
case "url-mismatch": return `Twilio number ${probe.phoneNumber} points SMS webhooks at ${probe.configuredUrl}; expected ${probe.expectedUrl}.`;
|
|
978
|
+
case "messaging-service-missing": return `Twilio Messaging Service ${probe.serviceSid} has no inbound request URL configured.`;
|
|
979
|
+
case "messaging-service-method-mismatch": return `Twilio Messaging Service ${probe.serviceSid} uses ${probe.configuredMethod || "an unknown method"} for inbound webhooks; use POST.`;
|
|
980
|
+
case "messaging-service-url-mismatch": return `Twilio Messaging Service ${probe.serviceSid} points inbound webhooks at ${probe.configuredUrl}; expected ${probe.expectedUrl}.`;
|
|
981
|
+
case "messaging-service-matches": return;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
async function probeSmsAccount(params) {
|
|
985
|
+
const hints = [];
|
|
986
|
+
addTailscaleHint(params.account, hints);
|
|
987
|
+
const webhook = params.account.fromNumber ? compareTwilioWebhook(params.account, (await listTwilioIncomingPhoneNumbers({
|
|
988
|
+
account: params.account,
|
|
989
|
+
phoneNumber: params.account.fromNumber,
|
|
990
|
+
fetchImpl: params.options?.fetchImpl,
|
|
991
|
+
timeoutMs: params.timeoutMs
|
|
992
|
+
}))[0]) : params.account.messagingServiceSid ? compareTwilioMessagingService(params.account, await retrieveTwilioMessagingService({
|
|
993
|
+
account: params.account,
|
|
994
|
+
serviceSid: params.account.messagingServiceSid,
|
|
995
|
+
fetchImpl: params.options?.fetchImpl,
|
|
996
|
+
timeoutMs: params.timeoutMs
|
|
997
|
+
})) : {
|
|
998
|
+
status: "unavailable",
|
|
999
|
+
reason: "Twilio SMS probe requires fromNumber or messagingServiceSid."
|
|
1000
|
+
};
|
|
1001
|
+
const recentInbound = recentInboundSummary(params.account.fromNumber ? await listTwilioMessages({
|
|
1002
|
+
account: params.account,
|
|
1003
|
+
to: params.account.fromNumber,
|
|
1004
|
+
pageSize: 3,
|
|
1005
|
+
fetchImpl: params.options?.fetchImpl,
|
|
1006
|
+
timeoutMs: params.timeoutMs
|
|
1007
|
+
}) : []);
|
|
1008
|
+
if (recentInbound?.errorCode === TWILIO_ERROR_WEBHOOK_REACHABILITY) hints.push("Twilio error 11200 means Twilio could not reach the SMS webhook. Check the public URL, tunnel/Funnel route, and Twilio Messaging webhook method.");
|
|
1009
|
+
const error = webhookError(webhook) ?? (recentInbound?.errorCode === TWILIO_ERROR_WEBHOOK_REACHABILITY ? `Recent inbound SMS ${recentInbound.sid} has Twilio error 11200.` : void 0);
|
|
1010
|
+
return {
|
|
1011
|
+
ok: !error,
|
|
1012
|
+
...error ? { error } : {},
|
|
1013
|
+
webhook,
|
|
1014
|
+
...recentInbound ? { recentInbound } : {},
|
|
1015
|
+
hints
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
function formatSmsProbeLines(probe) {
|
|
1019
|
+
if (!probe || typeof probe !== "object") return [];
|
|
1020
|
+
const smsProbe = probe;
|
|
1021
|
+
const lines = [];
|
|
1022
|
+
if (smsProbe.ok === true) lines.push({
|
|
1023
|
+
text: "Probe: ok",
|
|
1024
|
+
tone: "success"
|
|
1025
|
+
});
|
|
1026
|
+
else if (smsProbe.ok === false) lines.push({
|
|
1027
|
+
text: `Probe: failed${smsProbe.error ? ` (${smsProbe.error})` : ""}`,
|
|
1028
|
+
tone: "error"
|
|
1029
|
+
});
|
|
1030
|
+
if (smsProbe.webhook?.status === "matches" || smsProbe.webhook?.status === "messaging-service-matches") lines.push({ text: `Twilio SMS webhook: ${smsProbe.webhook.configuredUrl}` });
|
|
1031
|
+
else if (smsProbe.webhook?.status && smsProbe.webhook.status !== "skipped") lines.push({
|
|
1032
|
+
text: `Twilio SMS webhook: ${smsProbe.webhook.status}`,
|
|
1033
|
+
tone: "warn"
|
|
1034
|
+
});
|
|
1035
|
+
if (smsProbe.recentInbound?.sid) {
|
|
1036
|
+
const error = smsProbe.recentInbound.errorCode ? ` error=${smsProbe.recentInbound.errorCode}` : "";
|
|
1037
|
+
lines.push({
|
|
1038
|
+
text: `Recent inbound: ${smsProbe.recentInbound.status || "unknown"}${error}`,
|
|
1039
|
+
tone: smsProbe.recentInbound.errorCode ? "warn" : "muted"
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
for (const hint of smsProbe.hints ?? []) lines.push({
|
|
1043
|
+
text: hint,
|
|
1044
|
+
tone: "warn"
|
|
1045
|
+
});
|
|
1046
|
+
return lines;
|
|
1047
|
+
}
|
|
1048
|
+
//#endregion
|
|
1049
|
+
//#region extensions/sms/src/channel.ts
|
|
1050
|
+
const CHANNEL_ID = "sms";
|
|
1051
|
+
const smsConfigAdapter = createHybridChannelConfigAdapter({
|
|
1052
|
+
sectionKey: CHANNEL_ID,
|
|
1053
|
+
listAccountIds: listSmsAccountIds,
|
|
1054
|
+
resolveAccount: resolveSmsAccount,
|
|
1055
|
+
defaultAccountId: resolveDefaultSmsAccountId,
|
|
1056
|
+
clearBaseFields: [
|
|
1057
|
+
"accountSid",
|
|
1058
|
+
"authToken",
|
|
1059
|
+
"fromNumber",
|
|
1060
|
+
"messagingServiceSid",
|
|
1061
|
+
"defaultTo",
|
|
1062
|
+
"webhookPath",
|
|
1063
|
+
"publicWebhookUrl",
|
|
1064
|
+
"dangerouslyDisableSignatureValidation",
|
|
1065
|
+
"dmPolicy",
|
|
1066
|
+
"allowFrom",
|
|
1067
|
+
"textChunkLimit"
|
|
1068
|
+
],
|
|
1069
|
+
resolveAllowFrom: (account) => account.allowFrom,
|
|
1070
|
+
formatAllowFrom: (allowFrom) => normalizeStringEntries(allowFrom.map((entry) => normalizeSmsAllowFrom(String(entry)))),
|
|
1071
|
+
resolveDefaultTo: (account) => account.defaultTo
|
|
1072
|
+
});
|
|
1073
|
+
const resolveSmsDmPolicy = createScopedDmSecurityResolver({
|
|
1074
|
+
channelKey: CHANNEL_ID,
|
|
1075
|
+
resolvePolicy: (account) => account.dmPolicy,
|
|
1076
|
+
resolveAllowFrom: (account) => account.allowFrom,
|
|
1077
|
+
policyPathSuffix: "dmPolicy",
|
|
1078
|
+
defaultPolicy: "pairing",
|
|
1079
|
+
approveHint: "openclaw pairing approve sms <code>",
|
|
1080
|
+
normalizeEntry: normalizeSmsAllowFrom
|
|
1081
|
+
});
|
|
1082
|
+
const collectSmsSecurityWarnings = createConditionalWarningCollector((account) => account.dangerouslyDisableSignatureValidation && "- SMS: Twilio signature validation is disabled. Only use this for local testing.", (account) => account.dmPolicy === "open" && account.allowFrom.includes("*") && "- SMS: dmPolicy=\"open\" allows any phone number to message the bot.");
|
|
1083
|
+
function smsSetupPatch(input) {
|
|
1084
|
+
const patch = {};
|
|
1085
|
+
for (const key of [
|
|
1086
|
+
"accountSid",
|
|
1087
|
+
"authToken",
|
|
1088
|
+
"fromNumber",
|
|
1089
|
+
"messagingServiceSid",
|
|
1090
|
+
"defaultTo",
|
|
1091
|
+
"webhookPath",
|
|
1092
|
+
"publicWebhookUrl",
|
|
1093
|
+
"dmPolicy",
|
|
1094
|
+
"allowFrom"
|
|
1095
|
+
]) if (input[key] !== void 0) patch[key] = input[key];
|
|
1096
|
+
return patch;
|
|
1097
|
+
}
|
|
1098
|
+
function applySmsAccountConfig(params) {
|
|
1099
|
+
const patch = smsSetupPatch(params.input);
|
|
1100
|
+
const channels = { ...params.cfg.channels };
|
|
1101
|
+
const current = { ...channels[CHANNEL_ID] };
|
|
1102
|
+
if (params.accountId === DEFAULT_ACCOUNT_ID) {
|
|
1103
|
+
channels[CHANNEL_ID] = {
|
|
1104
|
+
...current,
|
|
1105
|
+
...patch
|
|
1106
|
+
};
|
|
1107
|
+
return {
|
|
1108
|
+
...params.cfg,
|
|
1109
|
+
channels
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
const accounts = { ...current.accounts };
|
|
1113
|
+
accounts[params.accountId] = {
|
|
1114
|
+
...accounts[params.accountId],
|
|
1115
|
+
...patch
|
|
1116
|
+
};
|
|
1117
|
+
channels[CHANNEL_ID] = {
|
|
1118
|
+
...current,
|
|
1119
|
+
accounts
|
|
1120
|
+
};
|
|
1121
|
+
return {
|
|
1122
|
+
...params.cfg,
|
|
1123
|
+
channels
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
function createSmsReceipt(params) {
|
|
1127
|
+
const first = params.results[0];
|
|
1128
|
+
if (!first) throw new Error("SMS send did not return a Twilio Message SID.");
|
|
1129
|
+
return {
|
|
1130
|
+
channel: CHANNEL_ID,
|
|
1131
|
+
messageId: first.sid,
|
|
1132
|
+
chatId: first.to,
|
|
1133
|
+
receipt: createMessageReceiptFromOutboundResults({
|
|
1134
|
+
results: params.results.map((result) => ({
|
|
1135
|
+
channel: CHANNEL_ID,
|
|
1136
|
+
messageId: result.sid,
|
|
1137
|
+
chatId: result.to,
|
|
1138
|
+
toJid: result.to,
|
|
1139
|
+
conversationId: result.to,
|
|
1140
|
+
meta: {
|
|
1141
|
+
...result.from ? { from: result.from } : {},
|
|
1142
|
+
...result.status ? { status: result.status } : {}
|
|
1143
|
+
}
|
|
1144
|
+
})),
|
|
1145
|
+
threadId: first.to,
|
|
1146
|
+
kind: params.kind
|
|
1147
|
+
})
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
function resolveSmsTextChunkLimit(params) {
|
|
1151
|
+
return resolveSmsAccount(params.cfg, params.accountId).textChunkLimit || params.fallbackLimit || 1500;
|
|
1152
|
+
}
|
|
1153
|
+
async function sendSmsText(ctx) {
|
|
1154
|
+
const account = resolveSmsAccount(ctx.cfg, ctx.accountId);
|
|
1155
|
+
const to = normalizeSmsPhoneNumber(ctx.to) || account.defaultTo;
|
|
1156
|
+
if (!looksLikeSmsPhoneNumber(to)) throw new Error(`Invalid SMS target: ${ctx.to}`);
|
|
1157
|
+
return createSmsReceipt({
|
|
1158
|
+
results: await sendSmsTextChunks({
|
|
1159
|
+
account,
|
|
1160
|
+
to,
|
|
1161
|
+
text: ctx.text
|
|
1162
|
+
}),
|
|
1163
|
+
kind: "text"
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
const smsMessageAdapter = defineChannelMessageAdapter({
|
|
1167
|
+
id: CHANNEL_ID,
|
|
1168
|
+
durableFinal: { capabilities: {
|
|
1169
|
+
text: true,
|
|
1170
|
+
media: false,
|
|
1171
|
+
messageSendingHooks: true
|
|
1172
|
+
} },
|
|
1173
|
+
send: { text: async (ctx) => await sendSmsText(ctx) }
|
|
1174
|
+
});
|
|
1175
|
+
const smsPlugin = createChatChannelPlugin({
|
|
1176
|
+
base: {
|
|
1177
|
+
id: CHANNEL_ID,
|
|
1178
|
+
meta: {
|
|
1179
|
+
id: CHANNEL_ID,
|
|
1180
|
+
label: "SMS",
|
|
1181
|
+
selectionLabel: "SMS (Twilio)",
|
|
1182
|
+
detailLabel: "Twilio SMS",
|
|
1183
|
+
docsPath: "/channels/sms",
|
|
1184
|
+
docsLabel: "sms",
|
|
1185
|
+
blurb: "Twilio-backed SMS with inbound webhooks and outbound replies.",
|
|
1186
|
+
order: 88
|
|
1187
|
+
},
|
|
1188
|
+
capabilities: {
|
|
1189
|
+
chatTypes: ["direct"],
|
|
1190
|
+
media: false,
|
|
1191
|
+
threads: false,
|
|
1192
|
+
reactions: false,
|
|
1193
|
+
edit: false,
|
|
1194
|
+
unsend: false,
|
|
1195
|
+
reply: false,
|
|
1196
|
+
effects: false,
|
|
1197
|
+
blockStreaming: false
|
|
1198
|
+
},
|
|
1199
|
+
reload: { configPrefixes: [`channels.${CHANNEL_ID}`] },
|
|
1200
|
+
configSchema: SmsChannelConfigSchema,
|
|
1201
|
+
setup: { applyAccountConfig: applySmsAccountConfig },
|
|
1202
|
+
config: {
|
|
1203
|
+
...smsConfigAdapter,
|
|
1204
|
+
inspectAccount: inspectSmsAccount,
|
|
1205
|
+
isConfigured: isSmsAccountConfigured,
|
|
1206
|
+
unconfiguredReason: () => "SMS requires accountSid, authToken, and fromNumber or messagingServiceSid.",
|
|
1207
|
+
describeAccount: (account) => ({
|
|
1208
|
+
accountId: account.accountId,
|
|
1209
|
+
name: account.fromNumber || account.messagingServiceSid || "SMS",
|
|
1210
|
+
configured: isSmsAccountConfigured(account),
|
|
1211
|
+
enabled: account.enabled
|
|
1212
|
+
})
|
|
1213
|
+
},
|
|
1214
|
+
messaging: {
|
|
1215
|
+
targetPrefixes: ["twilio-sms"],
|
|
1216
|
+
normalizeTarget: (target) => normalizeSmsPhoneNumber(target),
|
|
1217
|
+
targetResolver: {
|
|
1218
|
+
looksLikeId: looksLikeSmsPhoneNumber,
|
|
1219
|
+
hint: "<+15551234567>"
|
|
1220
|
+
}
|
|
1221
|
+
},
|
|
1222
|
+
directory: createEmptyChannelDirectoryAdapter(),
|
|
1223
|
+
gateway: { startAccount: async (ctx) => {
|
|
1224
|
+
if (!ctx.channelRuntime) {
|
|
1225
|
+
ctx.log?.warn?.("SMS channel runtime is not available; webhook route not started");
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
return await startSmsGatewayAccount({
|
|
1229
|
+
cfg: ctx.cfg,
|
|
1230
|
+
account: ctx.account,
|
|
1231
|
+
channelRuntime: ctx.channelRuntime,
|
|
1232
|
+
abortSignal: ctx.abortSignal,
|
|
1233
|
+
log: ctx.log
|
|
1234
|
+
});
|
|
1235
|
+
} },
|
|
1236
|
+
status: {
|
|
1237
|
+
buildAccountSnapshot: ({ account }) => {
|
|
1238
|
+
const configured = isSmsAccountConfigured(account);
|
|
1239
|
+
return {
|
|
1240
|
+
accountId: account.accountId,
|
|
1241
|
+
name: account.fromNumber || account.messagingServiceSid || "SMS",
|
|
1242
|
+
enabled: account.enabled,
|
|
1243
|
+
configured,
|
|
1244
|
+
statusState: !account.enabled ? "disabled" : configured ? "configured" : "unconfigured"
|
|
1245
|
+
};
|
|
1246
|
+
},
|
|
1247
|
+
probeAccount: async ({ account, timeoutMs }) => await probeSmsAccount({
|
|
1248
|
+
account,
|
|
1249
|
+
timeoutMs
|
|
1250
|
+
}),
|
|
1251
|
+
formatCapabilitiesProbe: ({ probe }) => formatSmsProbeLines(probe),
|
|
1252
|
+
buildCapabilitiesDiagnostics: async ({ account }) => ({ lines: collectSmsStartupWarnings(account).map((text) => ({
|
|
1253
|
+
text,
|
|
1254
|
+
tone: "warn"
|
|
1255
|
+
})) })
|
|
1256
|
+
},
|
|
1257
|
+
secrets: {
|
|
1258
|
+
secretTargetRegistryEntries,
|
|
1259
|
+
collectRuntimeConfigAssignments
|
|
1260
|
+
},
|
|
1261
|
+
agentPrompt: { messageToolHints: () => [
|
|
1262
|
+
"",
|
|
1263
|
+
"### SMS Formatting",
|
|
1264
|
+
"SMS is plain text only. Keep replies brief, avoid markdown tables, and split long details into short messages."
|
|
1265
|
+
] },
|
|
1266
|
+
message: smsMessageAdapter
|
|
1267
|
+
},
|
|
1268
|
+
pairing: { text: {
|
|
1269
|
+
idLabel: "phoneNumber",
|
|
1270
|
+
message: "OpenClaw: your SMS access has been approved.",
|
|
1271
|
+
normalizeAllowEntry: normalizeSmsAllowFrom,
|
|
1272
|
+
notify: async ({ cfg, id, message, accountId }) => {
|
|
1273
|
+
await sendSmsTextChunks({
|
|
1274
|
+
account: resolveSmsAccount(cfg, accountId),
|
|
1275
|
+
to: normalizeSmsPhoneNumber(id),
|
|
1276
|
+
text: message
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
} },
|
|
1280
|
+
security: {
|
|
1281
|
+
resolveDmPolicy: resolveSmsDmPolicy,
|
|
1282
|
+
collectWarnings: ({ account }) => collectSmsSecurityWarnings(account)
|
|
1283
|
+
},
|
|
1284
|
+
outbound: {
|
|
1285
|
+
deliveryMode: "gateway",
|
|
1286
|
+
chunker: chunkTextForOutbound,
|
|
1287
|
+
chunkerMode: "text",
|
|
1288
|
+
textChunkLimit: 1500,
|
|
1289
|
+
resolveEffectiveTextChunkLimit: resolveSmsTextChunkLimit,
|
|
1290
|
+
resolveTarget: ({ cfg, to, accountId }) => {
|
|
1291
|
+
const explicit = normalizeSmsPhoneNumber(to ?? "");
|
|
1292
|
+
if (explicit) return {
|
|
1293
|
+
ok: true,
|
|
1294
|
+
to: explicit
|
|
1295
|
+
};
|
|
1296
|
+
if (cfg) {
|
|
1297
|
+
const account = resolveSmsAccount(cfg, accountId);
|
|
1298
|
+
if (account.defaultTo) return {
|
|
1299
|
+
ok: true,
|
|
1300
|
+
to: account.defaultTo
|
|
1301
|
+
};
|
|
1302
|
+
}
|
|
1303
|
+
return {
|
|
1304
|
+
ok: false,
|
|
1305
|
+
error: /* @__PURE__ */ new Error("SMS target must be an E.164 phone number.")
|
|
1306
|
+
};
|
|
1307
|
+
},
|
|
1308
|
+
sanitizeText: ({ text }) => toSmsPlainText(text),
|
|
1309
|
+
sendText: sendSmsText
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
//#endregion
|
|
1313
|
+
export { smsPlugin };
|