apify-test-tools 0.10.2-beta.8 β 0.10.2-beta.9
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/.github/actions/checkout-restore-dependencies/action.yaml +13 -0
- package/.github/cli/apify-test-tools.mjs +1 -1
- package/.github/scripts/check-major-tag-refs.mjs +1 -1
- package/.github/scripts/mask-config-secrets.sh +17 -0
- package/.github/scripts/run-with-apify-tokens.mjs +36 -11
- package/.github/workflows/public_platform-tests-claude-investigate-and-fix.yaml +6 -2
- package/.github/workflows/public_platform-tests.yaml +23 -0
- package/.github/workflows/public_pr-build-test.yaml +30 -1
- package/.github/workflows/public_push-build-latest.yaml +20 -3
- package/CHANGELOG.md +1 -0
- package/CONTRIBUTING.md +99 -8
- package/README.md +218 -699
- package/bin/git.ts +1 -1
- package/dist/bin/git.js +1 -1
- package/dist/bin/git.js.map +1 -1
- package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts +2 -0
- package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts.map +1 -0
- package/dist/test/unit/github-scripts/mask-config-secrets.test.js +50 -0
- package/dist/test/unit/github-scripts/mask-config-secrets.test.js.map +1 -0
- package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts +2 -0
- package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts.map +1 -0
- package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js +102 -0
- package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/cli.md +358 -0
- package/docs/lib.md +271 -0
- package/docs/workflows.md +366 -0
- package/package.json +1 -1
- package/test/unit/github-scripts/mask-config-secrets.test.ts +61 -0
- package/test/unit/github-scripts/run-with-apify-tokens.test.ts +115 -0
|
@@ -8,6 +8,11 @@ inputs:
|
|
|
8
8
|
generated .npmrc references), and only on the dependency install steps, so it
|
|
9
9
|
never reaches the build or test steps. Use a read-only token.
|
|
10
10
|
required: false
|
|
11
|
+
config-secrets:
|
|
12
|
+
description: >-
|
|
13
|
+
The CONFIG_SECRETS workflow secret, if the caller passed one. Every value inside it is
|
|
14
|
+
registered as a mask, see .github/scripts/mask-config-secrets.sh.
|
|
15
|
+
required: false
|
|
11
16
|
|
|
12
17
|
outputs:
|
|
13
18
|
scripts-path:
|
|
@@ -24,6 +29,14 @@ outputs:
|
|
|
24
29
|
runs:
|
|
25
30
|
using: 'composite'
|
|
26
31
|
steps:
|
|
32
|
+
# Runs before anything can use a packed secret, see the script for why.
|
|
33
|
+
- name: Mask config secrets
|
|
34
|
+
if: inputs.config-secrets != ''
|
|
35
|
+
shell: bash
|
|
36
|
+
env:
|
|
37
|
+
CONFIG_SECRETS: ${{ inputs.config-secrets }}
|
|
38
|
+
run: bash "${{ github.action_path }}/../../scripts/mask-config-secrets.sh"
|
|
39
|
+
|
|
27
40
|
- name: Checkout Repository
|
|
28
41
|
uses: actions/checkout@v5
|
|
29
42
|
with:
|
|
@@ -202,7 +202,7 @@ Git error: ${n}`),this.name="GitCommandError",this.args=[...A],this.gitError=n,t
|
|
|
202
202
|
`).map(M9).join(`
|
|
203
203
|
`)),i=e.parent;return r=>i.containsPath(r)?t.ignores(i.relativePathTo(r)):!1},$C=e=>{try{let A=e.joinFile(".dockerignore");return L9(A)}catch{return FA.warn(`[.dockerignore] not found in "${e}".`),()=>!1}};import{statSync as ph}from"node:fs";import T9 from"node:path";var{posix:Ia}=T9,RU=e=>{let A=e.slice(e.lastIndexOf("/")+1);if(A===""||A==="."||A==="..")throw new Error(`Expected a file path, got directory path "${e}".`)},VC=class{#A;constructor(A){if(Ia.isAbsolute(A))throw new Error(`Expected a relative path, got absolute path "${A}".`);let t=Ia.normalize(A);this.#A=t.endsWith("/")?t.slice(0,-1):t,this.assertNoEscape(A)}isEqualTo(A){return(this instanceof A.constructor||A instanceof this.constructor)&&this.#A===A.#A}get path(){return this.#A}toString(){return this.path}toJSON(){return this.path}assertNoEscape(A){if(this.#A===".."||this.#A.startsWith("../"))throw new Error(`Path "${A}" escapes the repo root.`)}},ca=class e extends VC{static ROOT=new e(".");isRoot(){return this.path===e.ROOT.path}joinDir(A){return new e(this.join(A))}joinFile(A){return RU(A),new jn(this.join(A))}relativePathTo(A){return Ia.relative(this.path,A)}containsPath(A){try{return this.contains(new e(A))}catch{return!1}}contains(A){return this.isRoot()?!0:this.isEqualTo(A)||A.path.startsWith(`${this.path}/`)}isStrictAncestorOf(A){return!this.isEqualTo(A)&&this.contains(A)}assertIsDir(){let A=ph(this.path,{throwIfNoEntry:!1});if(!A)throw new Error(`Expected directory "${this}" to exist.`);if(!A.isDirectory())throw new Error(`Expected "${this}" to be a directory.`);return this}join(A){if(Ia.isAbsolute(A))throw new Error(`Expected a relative path to join with "${this}", got absolute path "${A}".`);return Ia.join(this.path,A)}},WC=class e extends ca{constructor(A){super(A),this.assertIsDir()}static initialize(A){return new e(A.path)}},jn=class extends VC{constructor(A){RU(A),super(A)}get parent(){return new ca(Ia.dirname(this.path))}joinDir(A){return this.parent.joinDir(A)}joinFile(A){return this.parent.joinFile(A)}isWithin(A){return A.contains(this)}exists(){return ph(this.path,{throwIfNoEntry:!1})?.isFile()??!1}assertIsFile(){if(this.exists())return this;throw ph(this.path,{throwIfNoEntry:!1})?new Error(`Expected "${this}" to be a file.`):new Error(`Expected file "${this}" to exist.`)}},qn=class e extends jn{constructor(A){super(A),this.assertIsFile()}static initialize(A){return new e(A.path)}};var G9=[".vscode/",".gitignore",".husky/",".eslintrc","eslint.config.mjs",".prettierrc",".editorconfig"],O9=(e,A)=>{let t=A.relativePathTo(e.path).toLowerCase();return G9.some(i=>t.startsWith(i))},P9=async(e,A,t,i,r)=>{let n=e.path.toLowerCase();if(n.endsWith("changelog.md"))return{impact:"cosmetic",semanticallyVerified:!1};let o=A.contextPaths.find(u=>u.contains(e));if(!o)return{impact:"outside-context"};if(O9(e,o))return{impact:"ignored"};let s=A.actorJson.file.parent.contains(e);if(!s&&!r(e.path)&&i(e.path))return{impact:"ignored"};let a=e.isWithin(A.folder);return n.endsWith("readme.md")?a?{impact:"cosmetic",semanticallyVerified:!1}:{impact:"ignored"}:n.endsWith(".json")&&s&&await QU(t,e.path)?{impact:"cosmetic",semanticallyVerified:!0}:{impact:"functional"}},J9=(e,A,t)=>{let i=o=>!o.folder.isEqualTo(A.folder),r=o=>!o.folder.isRoot();return t.filter(i).filter(r).some(o=>e.isWithin(o.folder))},K9=e=>{let A=new Map;for(let{actorConfig:t,files:i}of e.values())for(let r of i){let n=A.get(r)??new Set;n.add(t.actorFullName),A.set(r,n)}return A},H9=e=>{let A=new Map;for(let[t,i]of e){let r=Array.from(i).sort(),n=r.join(","),o=A.get(n)??{actors:r,files:[]};o.files.push(t),A.set(n,o)}return Array.from(A.values()).sort((t,i)=>i.actors.length!==t.actors.length?i.actors.length-t.actors.length:t.actors.join(",").localeCompare(i.actors.join(",")))},Y9=e=>{for(let{actors:A,files:t}of e)A.length>1?FA.info(`[DIFF]: Shared changes for actors ${A.join(", ")}: ${t.join(", ")}`):FA.info(`[DIFF]: Changes specific to actor ${A[0]}: ${t.join(", ")}`)},_U=async({filepathsChanged:e,actorConfigs:A,range:t,testFilesGlob:i})=>{let r=new Map,n=new Set,o=i?(0,vU.default)(i,{nocase:!0,dot:!0}):()=>!1;for(let C of A){let l=$C(C.dockerContextDir);for(let I of e){let c=new jn(I);if(J9(c,C,A))continue;let E=await P9(c,C,t,l,o);if(E.impact!=="outside-context"&&o(I)&&n.add(I),E.impact==="ignored"||E.impact==="outside-context")continue;let B=r.get(C.folder.path)??{actorConfig:C,files:[],hasFunctionalChange:!1};B.files.push(I),B.hasFunctionalChange||=E.impact==="functional",r.set(C.folder.path,B)}}Y9(H9(K9(r)));for(let C of e.filter(l=>o(l)&&!n.has(l)))FA.warn(`[DIFF]: Test file ${C} is outside every Actor's context, so changing only it builds and tests nothing. Add its folder to "overrideActorContext" of the Actors it tests.`);let s=Array.from(r.values()),a=s.filter(C=>C.hasFunctionalChange).map(C=>C.actorConfig),u=s.filter(C=>!C.hasFunctionalChange).map(C=>C.actorConfig),g=C=>C.map(l=>l.actorFullName).join(", ")||"none";return FA.info(`[DIFF]: Actors with functional changes: ${g(a)}`),FA.info(`[DIFF]: Actors with only cosmetic changes: ${g(u)}`),{functional:a,cosmetic:u}};var bU="\xBB\xA6\xAB",j9=["%H","%aN<%aE>","%aD","%s"].join(bU),q9=["--name-only","--no-renames"],xU=async e=>{if(e.length===0)throw new Error("Cannot get changed files: the commit list is empty. This should never happen.");return hh(`${e[0].sha}~`,e[e.length-1].sha)},hh=async(e,A)=>{let i=(await jt(["diff",...q9,`${e}..${A}`],{operation:"get the list of changed files between commits"})).split(`
|
|
204
204
|
`).filter(Boolean);return FA.info(`Changed files (up to 50): ${i.slice(0,50).join(", ")}`),i},NU=async(e,A)=>jt(["merge-base",e,A],{operation:`find where ${A} forked from ${e}`}),kU=async e=>jt(["rev-parse","--verify","--quiet",`${e}^{commit}`],{operation:`look up ${e} in local Git history`}).catch(A=>{if(!(A instanceof Yn&&A.exitCode===1))throw A}),$9=/^[0-9a-f]{40}$/i,UU=e=>{if(!e)return;let A;if(e.startsWith("{")?A=JSON.parse(e).sha:A=e,!$9.test(A))throw new Error(`Invalid base commit SHA: "${A}". It should be a 40-character hexadecimal string, instead got input: "${e}".`);return A},Dh=async(e,A)=>{let i=(await jt(["log",`--pretty=format:${j9}`,`${e}..${A}`],{operation:"list commits reachable from the source ref but absent from the target ref"})).split(`
|
|
205
|
-
`).filter(Boolean).map(V9);return i.reverse(),i},zC=async({sourceBranch:e,targetBranch:A,baseCommit:t})=>{let i=UU(t),r=await Dh(A,e);if(r.length===0)throw new Error(`${e} has no commits that are not on ${A}.`);let n=r[r.length-1]?.sha;if(i!==void 0&&i===n)return FA.info(`Detected rerun with the same commit that we already validated. This usually means the user wants to rerun the Action from scratch, ignoring last validated commit ${i} and returning all commits`),FA.info(`Commits being returned: ${r.map(a=>a.sha).join(", ")}`),r;let o=r.findIndex(a=>a.sha===i);if(o!==-1){let a=r.slice(o+1);return FA.info(`Found base commit ${i} at index ${o}, returning ${a.length} commits after it`),FA.info(`Commits being returned: ${a.map(u=>u.sha).join(", ")}`),a}return FA.info(`Base commit ${i} not found in the commit range, returning all ${r.length} commits`),FA.info(`Commits being returned: ${r.map(a=>a.sha).join(", ")}`),r},V9=e=>{let A=e.split(bU);if(A.length!==4)throw new Error(`Failed to parse commit string: ${e}`);let[t,i,r,n]=A;return{sha:t,author:i,date:r,message:n}},MU=async()=>{let e=await jt(["rev-parse","--abbrev-ref","HEAD"],{operation:"determine the checked-out branch"});if(e==="HEAD")throw new Error("Cannot determine the branch to build from: HEAD is detached. Check out the branch you want to build.");return e},LU=async e=>jt(["rev-parse","--verify",`${e}^{commit}`],{operation:`resolve ${e} to a commit`}),W9=async()=>(await jt(["remote","get-url","origin"],{operation:"read the origin repository URL"})).replace(/^https:\/\/github\.com\//,"git@github.com:"),ZC=async e=>({repoUrl:e??await W9(),shouldVerifyRepoUrl:e===void 0}),XC=e=>e.trim().split("#")[0].replace(/^[a-z+]+:\/\//i,"").replace(/^[^@/]+@/,"").replace(":","/").replace(/\/+$/,"").replace(/\.git$/,"").toLowerCase(),TU=e=>XC(e).split("/").pop(),z9=/^0{40}$/,GU=async(e,A="HEAD")=>{let t=UU(e);if(!t)throw new Error('A base commit is required for release. See the
|
|
205
|
+
`).filter(Boolean).map(V9);return i.reverse(),i},zC=async({sourceBranch:e,targetBranch:A,baseCommit:t})=>{let i=UU(t),r=await Dh(A,e);if(r.length===0)throw new Error(`${e} has no commits that are not on ${A}.`);let n=r[r.length-1]?.sha;if(i!==void 0&&i===n)return FA.info(`Detected rerun with the same commit that we already validated. This usually means the user wants to rerun the Action from scratch, ignoring last validated commit ${i} and returning all commits`),FA.info(`Commits being returned: ${r.map(a=>a.sha).join(", ")}`),r;let o=r.findIndex(a=>a.sha===i);if(o!==-1){let a=r.slice(o+1);return FA.info(`Found base commit ${i} at index ${o}, returning ${a.length} commits after it`),FA.info(`Commits being returned: ${a.map(u=>u.sha).join(", ")}`),a}return FA.info(`Base commit ${i} not found in the commit range, returning all ${r.length} commits`),FA.info(`Commits being returned: ${r.map(a=>a.sha).join(", ")}`),r},V9=e=>{let A=e.split(bU);if(A.length!==4)throw new Error(`Failed to parse commit string: ${e}`);let[t,i,r,n]=A;return{sha:t,author:i,date:r,message:n}},MU=async()=>{let e=await jt(["rev-parse","--abbrev-ref","HEAD"],{operation:"determine the checked-out branch"});if(e==="HEAD")throw new Error("Cannot determine the branch to build from: HEAD is detached. Check out the branch you want to build.");return e},LU=async e=>jt(["rev-parse","--verify",`${e}^{commit}`],{operation:`resolve ${e} to a commit`}),W9=async()=>(await jt(["remote","get-url","origin"],{operation:"read the origin repository URL"})).replace(/^https:\/\/github\.com\//,"git@github.com:"),ZC=async e=>({repoUrl:e??await W9(),shouldVerifyRepoUrl:e===void 0}),XC=e=>e.trim().split("#")[0].replace(/^[a-z+]+:\/\//i,"").replace(/^[^@/]+@/,"").replace(":","/").replace(/\/+$/,"").replace(/\.git$/,"").toLowerCase(),TU=e=>XC(e).split("/").pop(),z9=/^0{40}$/,GU=async(e,A="HEAD")=>{let t=UU(e);if(!t)throw new Error('A base commit is required for release. See the "Releasing Actors" section of docs/cli.md.');if(z9.test(t))throw new Error(`Base commit is ${t}, which means the branch was just created and there is no previous release to diff against. Rerun with the base commit set to the last commit before the changes you want to release.`);let i=await jt(["rev-parse","--verify","--quiet",`${t}^{commit}`],{operation:"verify the release base commit in local Git history"}).catch(n=>{if(n instanceof Yn&&n.exitCode===1)return"";throw n});if(!i)throw new Error(`Base commit ${t} is not in the local git history. Either the checkout is shallow (fetch the full history, e.g. fetch-depth: 0 in actions/checkout) or the branch was force-pushed.`);if(await jt(["merge-base",i,A],{operation:`check whether the release base commit is an ancestor of ${A}`}).catch(n=>{if(n instanceof Yn&&n.exitCode===1)return"";throw n})!==t)throw new Error(`Base commit ${t} is not an ancestor of ${A}, most likely because the branch was force-pushed. The changed files cannot be determined reliably. Rerun with the base commit set to an ancestor of ${A} from before the changes you want to release.`);return t},fh="CHANGELOG.md",OU=async(e,A,t)=>{if(!t.includes(fh))return null;let i=await jt(["diff",e,A,"--",fh],{operation:"read changelog changes since the last release"}),r=[],n=!1;for(let o of i.split(`
|
|
206
206
|
`)){if(o.startsWith("+++")&&o.toLowerCase().includes(fh.toLowerCase())){n=!0;continue}if(n){if(o.startsWith("diff"))break;o.startsWith("+")&&r.push(o.slice(1).trim())}}return r.join(`
|
|
207
207
|
`).trim()};function PU({actors:e,ignore:A},t){let i=t.map(o=>o.actorFullName),r=[...e,...A].filter(o=>!i.includes(o));if(r.length>0)throw new Error(`The following actors from the filter config do not exist: ${r.join(", ")}`);return(e.length?t.filter(o=>e.includes(o.actorFullName)):t).filter(o=>!A.includes(o.actorFullName))}import{readFileSync as Z9}from"node:fs";var $u=(e,A)=>({success:!1,reason:e,failure:new Error(A)});function Al(e){let A;try{A=Z9(e.path,"utf8")}catch{return $u("unreadable",`Expected ${e} to exist or be readable`)}let t;try{t=JSON.parse(A)}catch(i){return $u("invalid-json",`Failed to parse ${e}: ${i}`)}return t===null?$u("not-an-object",`Expected ${e} to be a JSON object, not null`):Array.isArray(t)?$u("not-an-object",`Expected ${e} to be a JSON object, not an array`):typeof t!="object"?$u("not-an-object",`Expected ${e} to be a JSON object`):{success:!0,contents:t}}import{readdirSync as OeA}from"node:fs";import PeA from"node:path";var JA={};Or(JA,{$brand:()=>Mh,$input:()=>oy,$output:()=>ny,INVALID:()=>ui,NEVER:()=>Uh,TimePrecision:()=>Qy,ZodAny:()=>rw,ZodArray:()=>aw,ZodBase64:()=>zE,ZodBase64URL:()=>ZE,ZodBigInt:()=>Va,ZodBigIntFormat:()=>eB,ZodBoolean:()=>$a,ZodCIDRv4:()=>VE,ZodCIDRv6:()=>WE,ZodCUID:()=>JE,ZodCUID2:()=>KE,ZodCatch:()=>vw,ZodCodec:()=>JI,ZodCompileAsyncError:()=>Fr,ZodCompileUnsupportedError:()=>Qe,ZodCreditCard:()=>W0,ZodCustom:()=>KI,ZodCustomStringFormat:()=>Is,ZodDate:()=>MI,ZodDefault:()=>mw,ZodDiscriminatedUnion:()=>uw,ZodE164:()=>XE,ZodEmail:()=>TE,ZodEmoji:()=>OE,ZodEnum:()=>Ya,ZodError:()=>leA,ZodExactOptional:()=>nB,ZodFile:()=>pw,ZodFirstPartyTypeKind:()=>Kw,ZodFunction:()=>Gw,ZodGUID:()=>GE,ZodIBAN:()=>z0,ZodIPv4:()=>qE,ZodIPv6:()=>$E,ZodISODate:()=>io,ZodISODateTime:()=>to,ZodISODuration:()=>no,ZodISOTime:()=>ro,ZodInstanceOf:()=>Jw,ZodIntersection:()=>Iw,ZodIssueCode:()=>QeA,ZodJWT:()=>AB,ZodKSUID:()=>jE,ZodLazy:()=>Mw,ZodLiteral:()=>dw,ZodMAC:()=>V0,ZodMap:()=>Bw,ZodNaN:()=>bw,ZodNanoID:()=>PE,ZodNever:()=>ow,ZodNonOptional:()=>oB,ZodNull:()=>tw,ZodNullable:()=>Dw,ZodNumber:()=>qa,ZodNumberFormat:()=>cs,ZodObject:()=>TI,ZodOptional:()=>OI,ZodPipe:()=>PI,ZodPrefault:()=>ww,ZodPreprocess:()=>xw,ZodPromise:()=>Tw,ZodReadonly:()=>Nw,ZodRealError:()=>Ri,ZodRecord:()=>Ha,ZodSet:()=>Qw,ZodString:()=>ja,ZodStringFormat:()=>Te,ZodSuccess:()=>Rw,ZodSymbol:()=>Aw,ZodTemplateLiteral:()=>Uw,ZodTransform:()=>fw,ZodTuple:()=>Cw,ZodType:()=>ge,ZodULID:()=>HE,ZodURL:()=>UI,ZodUUID:()=>jr,ZodUndefined:()=>ew,ZodUnion:()=>GI,ZodUnknown:()=>nw,ZodVoid:()=>sw,ZodXID:()=>YE,ZodXor:()=>gw,_ZodString:()=>LE,_default:()=>yw,_function:()=>hG,any:()=>ZT,array:()=>LI,base64:()=>xT,base64url:()=>NT,bigint:()=>qT,boolean:()=>X0,catch:()=>_w,check:()=>DG,cidrv4:()=>_T,cidrv6:()=>bT,clone:()=>ke,codec:()=>QG,coerce:()=>Yw,compile:()=>uy,config:()=>nt,core:()=>Bn,creditCard:()=>UT,cuid:()=>DT,cuid2:()=>mT,currencyCode:()=>PT,custom:()=>mG,date:()=>AG,decode:()=>J0,decodeAsync:()=>H0,deepPartial:()=>MG,describe:()=>yG,discriminatedUnion:()=>oG,e164:()=>kT,email:()=>cT,emoji:()=>fT,encode:()=>P0,encodeAsync:()=>K0,endsWith:()=>Na,enum:()=>iB,exactOptional:()=>hw,file:()=>CG,flattenError:()=>rI,float32:()=>KT,float64:()=>HT,formatError:()=>nI,fromJSONSchema:()=>kG,function:()=>hG,getDiscriminatedOption:()=>Nm,getErrorMap:()=>peA,globalRegistry:()=>Ot,gt:()=>Hr,gte:()=>Hi,guid:()=>CT,hash:()=>JT,hex:()=>OT,hostname:()=>GT,httpUrl:()=>pT,iban:()=>MT,includes:()=>ba,input:()=>TG,instanceof:()=>SG,int:()=>UE,int32:()=>YT,int64:()=>$T,intersection:()=>cw,invertCodec:()=>dG,ipv4:()=>FT,ipv6:()=>vT,iso:()=>HI,json:()=>RG,jwt:()=>LT,keyof:()=>eG,ksuid:()=>ST,lazy:()=>Lw,length:()=>os,literal:()=>cG,locales:()=>wI,looseObject:()=>rG,looseRecord:()=>aG,lowercase:()=>va,lt:()=>Kr,lte:()=>Ki,mac:()=>RT,map:()=>gG,maxLength:()=>ns,maxSize:()=>Zn,memoizer:()=>mI,meta:()=>wG,mime:()=>Ua,minLength:()=>En,minSize:()=>Yr,multipleOf:()=>zn,nan:()=>BG,nanoid:()=>hT,nativeEnum:()=>IG,negative:()=>yE,never:()=>tB,nonnegative:()=>SE,nonoptional:()=>Fw,nonpositive:()=>wE,normalize:()=>Ma,null:()=>iw,nullable:()=>kI,nullish:()=>lG,number:()=>Z0,object:()=>tG,optional:()=>gs,output:()=>GG,overwrite:()=>Rr,parse:()=>L0,parseAsync:()=>T0,partialRecord:()=>sG,pipe:()=>ME,positive:()=>mE,prefault:()=>Sw,preprocess:()=>vG,prettifyError:()=>Wo,promise:()=>fG,properties:()=>ka,property:()=>FE,readonly:()=>kw,record:()=>Ew,refine:()=>Ow,regex:()=>Ra,regexes:()=>or,registry:()=>Zl,safeDecode:()=>j0,safeDecodeAsync:()=>$0,safeEncode:()=>Y0,safeEncodeAsync:()=>q0,safeParse:()=>G0,safeParseAsync:()=>O0,set:()=>uG,setErrorMap:()=>deA,size:()=>rs,slugify:()=>Oa,startsWith:()=>xa,strictObject:()=>iG,string:()=>NI,stringFormat:()=>TT,stringbool:()=>FG,success:()=>EG,superRefine:()=>Pw,symbol:()=>WT,templateLiteral:()=>pG,toJSONSchema:()=>bE,toLowerCase:()=>Ta,toUpperCase:()=>Ga,toZod:()=>Vu,transform:()=>rB,treeifyError:()=>Oh,trim:()=>La,tuple:()=>lw,uint32:()=>jT,uint64:()=>VT,ulid:()=>yT,undefined:()=>zT,union:()=>Wa,unknown:()=>as,uppercase:()=>_a,url:()=>dT,util:()=>aA,uuid:()=>lT,uuidv4:()=>ET,uuidv6:()=>BT,uuidv7:()=>QT,validate:()=>oI,validateAsync:()=>sI,void:()=>XT,withParser:()=>Xl,xid:()=>wT,xor:()=>nG});var Bn={};Or(Bn,{$ZodAny:()=>wm,$ZodArray:()=>_m,$ZodAsyncError:()=>Si,$ZodBase64:()=>Cm,$ZodBase64URL:()=>lm,$ZodBigInt:()=>Tl,$ZodBigIntFormat:()=>hm,$ZodBoolean:()=>QI,$ZodCIDRv4:()=>Im,$ZodCIDRv6:()=>cm,$ZodCUID:()=>XD,$ZodCUID2:()=>Am,$ZodCatch:()=>Vm,$ZodCheck:()=>Pe,$ZodCheckBigIntFormat:()=>SD,$ZodCheckEndsWith:()=>TD,$ZodCheckGreaterThan:()=>Dl,$ZodCheckIncludes:()=>MD,$ZodCheckLengthEquals:()=>xD,$ZodCheckLessThan:()=>hl,$ZodCheckLowerCase:()=>kD,$ZodCheckMaxLength:()=>_D,$ZodCheckMaxSize:()=>FD,$ZodCheckMimeType:()=>PD,$ZodCheckMinLength:()=>bD,$ZodCheckMinSize:()=>RD,$ZodCheckMultipleOf:()=>yD,$ZodCheckNumberFormat:()=>wD,$ZodCheckOverwrite:()=>JD,$ZodCheckProperties:()=>OD,$ZodCheckProperty:()=>GD,$ZodCheckRegex:()=>ND,$ZodCheckSizeEquals:()=>vD,$ZodCheckStartsWith:()=>LD,$ZodCheckStringFormat:()=>ma,$ZodCheckUpperCase:()=>UD,$ZodCodec:()=>pI,$ZodCreditCard:()=>Bm,$ZodCustom:()=>ty,$ZodCustomStringFormat:()=>pm,$ZodCyclicError:()=>Yl,$ZodDate:()=>vm,$ZodDefault:()=>Ym,$ZodDiscriminatedUnion:()=>km,$ZodE164:()=>Em,$ZodEmail:()=>qD,$ZodEmoji:()=>zD,$ZodEncodeError:()=>Wn,$ZodEnum:()=>Gm,$ZodError:()=>Gh,$ZodExactOptional:()=>Km,$ZodFile:()=>Pm,$ZodFunction:()=>Ay,$ZodGUID:()=>YD,$ZodIBAN:()=>Qm,$ZodIPv4:()=>am,$ZodIPv6:()=>gm,$ZodISODate:()=>nm,$ZodISODateTime:()=>rm,$ZodISODuration:()=>sm,$ZodISOTime:()=>om,$ZodIntersection:()=>Um,$ZodJWT:()=>dm,$ZodKSUID:()=>im,$ZodLazy:()=>fI,$ZodLiteral:()=>Om,$ZodMAC:()=>um,$ZodMap:()=>Lm,$ZodNaN:()=>Wm,$ZodNanoID:()=>ZD,$ZodNever:()=>Fm,$ZodNonOptional:()=>qm,$ZodNull:()=>ym,$ZodNullable:()=>Hm,$ZodNumber:()=>Ll,$ZodNumberFormat:()=>fm,$ZodObject:()=>DM,$ZodObjectJIT:()=>bm,$ZodOptional:()=>Ol,$ZodPipe:()=>Pl,$ZodPrefault:()=>jm,$ZodPreprocess:()=>zm,$ZodPromise:()=>ey,$ZodReadonly:()=>Zm,$ZodRealError:()=>Fi,$ZodRecord:()=>Mm,$ZodRegistry:()=>zl,$ZodSet:()=>Tm,$ZodString:()=>Xo,$ZodStringFormat:()=>Ue,$ZodSuccess:()=>$m,$ZodSymbol:()=>Dm,$ZodTemplateLiteral:()=>Xm,$ZodTransform:()=>Jm,$ZodTuple:()=>Gl,$ZodType:()=>ne,$ZodULID:()=>em,$ZodURL:()=>WD,$ZodUUID:()=>jD,$ZodUndefined:()=>mm,$ZodUnion:()=>dI,$ZodUnknown:()=>Sm,$ZodVoid:()=>Rm,$ZodXID:()=>tm,$ZodXor:()=>xm,$brand:()=>Mh,$constructor:()=>H,$input:()=>oy,$output:()=>ny,Doc:()=>Zo,INVALID:()=>ui,JSONSchema:()=>gT,JSONSchemaGenerator:()=>xE,NEVER:()=>Uh,TimePrecision:()=>Qy,URL_BAD_FORMAT:()=>$D,URL_UNPARSEABLE:()=>cI,ZodCompileAsyncError:()=>Fr,ZodCompileUnsupportedError:()=>Qe,_any:()=>ky,_array:()=>Py,_base64:()=>pE,_base64url:()=>fE,_bigint:()=>Fy,_boolean:()=>wy,_catch:()=>teA,_check:()=>qL,_cidrv4:()=>QE,_cidrv6:()=>dE,_coercedBigint:()=>Ry,_coercedBoolean:()=>Sy,_coercedDate:()=>Gy,_coercedNumber:()=>py,_coercedString:()=>Cy,_creditCard:()=>Ey,_cuid:()=>uE,_cuid2:()=>IE,_custom:()=>Ky,_date:()=>Ty,_decode:()=>ul,_decodeAsync:()=>cl,_default:()=>XAA,_discriminatedUnion:()=>PAA,_e164:()=>hE,_email:()=>tE,_emoji:()=>aE,_encode:()=>gl,_encodeAsync:()=>Il,_endsWith:()=>Na,_enum:()=>qAA,_file:()=>Jy,_float32:()=>hy,_float64:()=>Dy,_gt:()=>Hr,_gte:()=>Hi,_guid:()=>iE,_iban:()=>By,_includes:()=>ba,_int:()=>fy,_int32:()=>my,_int64:()=>vy,_intersection:()=>JAA,_ipv4:()=>EE,_ipv6:()=>BE,_isoDate:()=>RI,_isoDateTime:()=>FI,_isoDuration:()=>_I,_isoTime:()=>vI,_jwt:()=>DE,_ksuid:()=>lE,_lazy:()=>oeA,_length:()=>os,_literal:()=>VAA,_lowercase:()=>va,_lt:()=>Kr,_lte:()=>Ki,_mac:()=>ly,_map:()=>YAA,_max:()=>Ki,_maxLength:()=>ns,_maxSize:()=>Zn,_mime:()=>Ua,_min:()=>Hi,_minLength:()=>En,_minSize:()=>Yr,_multipleOf:()=>zn,_nan:()=>Oy,_nanoid:()=>gE,_nativeEnum:()=>$AA,_negative:()=>yE,_never:()=>My,_nonnegative:()=>SE,_nonoptional:()=>AeA,_nonpositive:()=>wE,_normalize:()=>Ma,_null:()=>Ny,_nullable:()=>ZAA,_number:()=>dy,_optional:()=>zAA,_overwrite:()=>Rr,_parse:()=>pa,_parseAsync:()=>fa,_pipe:()=>ieA,_positive:()=>mE,_promise:()=>seA,_properties:()=>ka,_property:()=>FE,_readonly:()=>reA,_record:()=>HAA,_refine:()=>Hy,_regex:()=>Ra,_safeDecode:()=>ll,_safeDecodeAsync:()=>Bl,_safeEncode:()=>Cl,_safeEncodeAsync:()=>El,_safeParse:()=>ha,_safeParseAsync:()=>Da,_set:()=>jAA,_size:()=>rs,_slugify:()=>Oa,_startsWith:()=>xa,_string:()=>cy,_stringFormat:()=>ss,_stringbool:()=>$y,_success:()=>eeA,_superRefine:()=>Yy,_symbol:()=>by,_templateLiteral:()=>neA,_toLowerCase:()=>Ta,_toUpperCase:()=>Ga,_transform:()=>WAA,_trim:()=>La,_tuple:()=>KAA,_uint32:()=>yy,_uint64:()=>_y,_ulid:()=>cE,_undefined:()=>xy,_union:()=>GAA,_unknown:()=>Uy,_uppercase:()=>_a,_url:()=>SI,_uuid:()=>rE,_uuidv4:()=>nE,_uuidv6:()=>oE,_uuidv7:()=>sE,_void:()=>Ly,_xid:()=>CE,_xor:()=>OAA,base64Charset:()=>xl,base64urlCharset:()=>BI,canParseURL:()=>VD,clone:()=>ke,compile:()=>uy,compileFn:()=>AE,config:()=>nt,createStandardJSONSchemaMethod:()=>Pa,createToJSONSchemaMethod:()=>Wy,decode:()=>KX,decodeAsync:()=>YX,describe:()=>jy,encode:()=>JX,encodeAsync:()=>HX,extractDefs:()=>Ao,finalize:()=>eo,flattenError:()=>rI,formatError:()=>nI,getDiscriminatedOption:()=>Nm,globalConfig:()=>bt,globalRegistry:()=>Ot,handleUnrepresentable:()=>mt,initializeContext:()=>Xn,isBackEdge:()=>ql,isRecursiveSchema:()=>jl,isValidBase64:()=>EI,isValidBase64URL:()=>Nl,isValidCIDRv6:()=>bl,isValidCreditCard:()=>kl,isValidIBAN:()=>Ul,isValidIPv6:()=>lI,isValidJWT:()=>Ml,locales:()=>wI,memoizer:()=>mI,mergeValues:()=>ya,meta:()=>qy,parse:()=>sl,parseAsync:()=>al,parseURLObject:()=>pM,prettifyError:()=>Wo,process:()=>Me,processSchema:()=>Me,regexes:()=>or,registry:()=>Zl,safeDecode:()=>qX,safeDecodeAsync:()=>VX,safeEncode:()=>jX,safeEncodeAsync:()=>$X,safeParse:()=>LX,safeParseAsync:()=>TX,standardProps:()=>Fl,stripTabAndNewline:()=>CI,toDotPath:()=>ZU,toJSONSchema:()=>bE,toZod:()=>Vu,treeifyError:()=>Oh,urlHostnameOk:()=>vl,urlProtocolOk:()=>_l,util:()=>aA,validate:()=>oI,validateAsync:()=>sI,validateURL:()=>Rl,version:()=>KD,withParser:()=>Xl});var aA={};Or(aA,{BIGINT_FORMAT_RANGES:()=>AI,CONSTANT_CATCH:()=>nl,Class:()=>wh,NUMBER_FORMAT_RANGES:()=>Xu,aborted:()=>gi,allowsEval:()=>Rh,assert:()=>iX,assertEqual:()=>X9,assertIs:()=>eX,assertNever:()=>tX,assertNotEqual:()=>AX,assignProp:()=>Gt,attachSchema:()=>rl,base64ToUint8Array:()=>jU,base64urlToUint8Array:()=>DX,cached:()=>Ba,captureStackTrace:()=>tl,cleanEnum:()=>hX,cleanRegex:()=>Cn,clone:()=>ke,cloneDef:()=>oX,codePointLength:()=>Vo,constantCatch:()=>Nh,createTransparentProxy:()=>cX,defineLazy:()=>Sh,defineLazyInternal:()=>ce,derived:()=>SX,esc:()=>ai,escapeRegex:()=>nr,explicitlyAborted:()=>bh,extend:()=>EX,finalizeIssue:()=>wi,floatSafeRemainder:()=>Wu,getElementAtPath:()=>sX,getEnumValues:()=>la,getLengthableOrigin:()=>tI,getParsedType:()=>IX,getSizableOrigin:()=>eI,hexToUint8Array:()=>yX,hide:()=>iI,installLazyProp:()=>_X,isObject:()=>$o,isPlainObject:()=>rr,issue:()=>da,joinValues:()=>Y,jsonStringifyReplacer:()=>Ea,members:()=>xh,merge:()=>QX,mergeDefs:()=>Sr,normalizeParams:()=>mA,nullish:()=>el,numKeys:()=>uX,objectClone:()=>rX,omit:()=>lX,optionalKeys:()=>_h,own:()=>Vn,parsedType:()=>uA,partial:()=>dX,pick:()=>CX,prefixIssues:()=>yi,primitiveTypes:()=>vh,promiseAllObject:()=>aX,propertyKeyTypes:()=>Zu,randomString:()=>gX,rawShape:()=>Qa,required:()=>pX,safeExtend:()=>BX,shallowClone:()=>zu,slugify:()=>Fh,stringifyPrimitive:()=>gA,toZod:()=>Vu,uint8ArrayToBase64:()=>qU,uint8ArrayToBase64url:()=>mX,uint8ArrayToHex:()=>wX,unwrapMessage:()=>Ca});function X9(e){return e}function AX(e){return e}function Vu(){return e=>e}function eX(e){}function tX(e){throw new Error("Unexpected value in exhaustive check")}function iX(e){}function la(e){let A=Object.values(e).filter(i=>typeof i=="number");return Object.entries(e).filter(([i,r])=>A.indexOf(+i)===-1).map(([i,r])=>r)}function Y(e,A="|"){return e.map(t=>gA(t)).join(A)}function Ea(e,A){return typeof A=="bigint"?A.toString():A}var yh=class{constructor(A){this._getter=A,this._value=void 0}get value(){let A=this._getter;return A!==void 0&&(this._value=A(),this._getter=void 0),this._value}};function Ba(e){return new yh(e)}function el(e){return e==null}function Cn(e){let A=e.startsWith("^")?1:0,t=e.endsWith("$")?e.length-1:e.length;return e.slice(A,t)}function Wu(e,A){let t=e/A,i=Math.round(t),r=4*Number.EPSILON*Math.max(Math.abs(t),1);return Math.abs(t-i)<r?0:t-i}var JU=Symbol("evaluating");function Sh(e,A,t){let i;Object.defineProperty(e,A,{get(){if(i!==JU)return i===void 0&&(i=JU,i=t()),i},set(r){Object.defineProperty(e,A,{value:r})},configurable:!0})}function rX(e){return Object.create(Object.getPrototypeOf(e),Object.getOwnPropertyDescriptors(e))}function Gt(e,A,t){Object.defineProperty(e,A,{value:t,writable:!0,enumerable:!0,configurable:!0})}function Qa(e){let A=Object.getOwnPropertyDescriptor(e,"shape");return A?.get?A.get.raw:A?.value}function cn(e){return Qa(e._zod.def)??e._zod.def.shape}function KU(e,A,t){Object.defineProperty(e,A,{get(){let i=t();return Gt(this,A,i),i},enumerable:!0,configurable:!0})}function HU(e,A,t){A in e?Gt(e,A,t):e[A]=t}function qo(e,A,t,i){let r=cn(A);for(let n of t){let o=Object.getOwnPropertyDescriptor(r,n);o.enumerable&&(o.get?KU(e,n,()=>{let s=A._zod.def.shape[n];return i?i(s,n):s}):HU(e,n,i?i(o.value,n):o.value))}}function nX(e,A){for(let t of Reflect.ownKeys(A)){let i=Object.getOwnPropertyDescriptor(A,t);i.enumerable&&(i.get?KU(e,t,()=>A[t]):HU(e,t,i.value))}}function Sr(...e){let A={};for(let t of e){let i=Object.getOwnPropertyDescriptors(t);Object.assign(A,i)}return Object.defineProperties({},A)}function oX(e){return Sr(e._zod.def)}function sX(e,A){return A?A.reduce((t,i)=>t?.[i],e):e}function aX(e){let A=Object.keys(e),t=A.map(i=>e[i]);return Promise.all(t).then(i=>{let r={};for(let n=0;n<A.length;n++)r[A[n]]=i[n];return r})}function gX(e=10){let A="abcdefghijklmnopqrstuvwxyz",t="";for(let i=0;i<e;i++)t+=A[Math.floor(Math.random()*A.length)];return t}function ai(e){return JSON.stringify(e)}function Fh(e){return e.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_-]+/g,"-").replace(/^-+|-+$/g,"")}var tl="captureStackTrace"in Error?Error.captureStackTrace:(...e)=>{};function $o(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}var Rh=Ba(()=>{if(bt.jitless||typeof navigator<"u"&&navigator?.userAgent?.includes("Cloudflare"))return!1;try{let e=Function;return new e(""),!0}catch{return!1}});function rr(e){if($o(e)===!1)return!1;let A=e.constructor;if(A===void 0||typeof A!="function")return!0;let t=A.prototype;return!($o(t)===!1||Object.prototype.hasOwnProperty.call(t,"isPrototypeOf")===!1)}function zu(e){return rr(e)?{...e}:Array.isArray(e)?[...e]:e instanceof Map?new Map(e):e instanceof Set?new Set(e):e}function uX(e){let A=0;for(let t in e)Object.prototype.hasOwnProperty.call(e,t)&&A++;return A}var IX=e=>{let A=typeof e;switch(A){case"undefined":return"undefined";case"string":return"string";case"number":return Number.isNaN(e)?"nan":"number";case"boolean":return"boolean";case"function":return"function";case"bigint":return"bigint";case"symbol":return"symbol";case"object":return Array.isArray(e)?"array":e===null?"null":e.then&&typeof e.then=="function"&&e.catch&&typeof e.catch=="function"?"promise":typeof Map<"u"&&e instanceof Map?"map":typeof Set<"u"&&e instanceof Set?"set":typeof Date<"u"&&e instanceof Date?"date":typeof File<"u"&&e instanceof File?"file":"object";default:throw new Error(`Unknown data type: ${A}`)}},Zu=new Set(["string","number","symbol"]),vh=new Set(["string","number","bigint","boolean","symbol","undefined"]);function nr(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function ke(e,A,t){let i=new e._zod.constr(A??e._zod.def);return(!A||t?.parent)&&(i._zod.parent=e),i}function mA(e){let A=e;if(!A)return{};if(typeof A=="string")return{error:()=>A};if(A?.message!==void 0){if(A?.error!==void 0)throw new Error("Cannot specify both `message` and `error` params");A.error=A.message}return delete A.message,typeof A.error=="string"?{...A,error:()=>A.error}:A}function cX(e){let A;return new Proxy({},{get(t,i,r){return A??(A=e()),Reflect.get(A,i,r)},set(t,i,r,n){return A??(A=e()),Reflect.set(A,i,r,n)},has(t,i){return A??(A=e()),Reflect.has(A,i)},deleteProperty(t,i){return A??(A=e()),Reflect.deleteProperty(A,i)},ownKeys(t){return A??(A=e()),Reflect.ownKeys(A)},getOwnPropertyDescriptor(t,i){return A??(A=e()),Reflect.getOwnPropertyDescriptor(A,i)},defineProperty(t,i,r){return A??(A=e()),Reflect.defineProperty(A,i,r)}})}function gA(e){return typeof e=="bigint"?e.toString()+"n":typeof e=="string"?`"${e}"`:`${e}`}function _h(e){return Object.keys(e).filter(A=>e[A]._zod.optin!==void 0&&e[A]._zod.optout==="optional")}var Xu={safeint:[Number.MIN_SAFE_INTEGER,Number.MAX_SAFE_INTEGER],int32:[-2147483648,2147483647],uint32:[0,4294967295],float32:[-34028234663852886e22,34028234663852886e22],float64:[-Number.MAX_VALUE,Number.MAX_VALUE]},AI={int64:[BigInt("-9223372036854775808"),BigInt("9223372036854775807")],uint64:[BigInt(0),BigInt("18446744073709551615")]};function CX(e,A){let t=e._zod.def,i=t.checks;if(i&&i.length>0)throw new Error(".pick() cannot be used on object schemas containing refinements");let n={};return qo(n,e,il(e,A)),ke(e,Sr(t,{shape:n,checks:[]}))}function il(e,A){let t=cn(e),i=[];for(let r of Reflect.ownKeys(A)){if(!Object.getOwnPropertyDescriptor(t,r)?.enumerable)throw new Error(`Unrecognized key: "${String(r)}"`);A[r]&&i.push(r)}return i}function lX(e,A){let t=e._zod.def,i=t.checks;if(i&&i.length>0)throw new Error(".omit() cannot be used on object schemas containing refinements");let n=new Set(il(e,A)),o={};return qo(o,e,Reflect.ownKeys(cn(e)).filter(s=>!n.has(s))),ke(e,Sr(t,{shape:o,checks:[]}))}function EX(e,A){if(!rr(A))throw new Error("Invalid input to extend: expected a plain object");let t=e._zod.def.checks;if(t&&t.length>0){let r=cn(e);for(let n of Reflect.ownKeys(A))if(Object.getOwnPropertyDescriptor(r,n)!==void 0)throw new Error("Cannot overwrite keys on object schemas containing refinements. Use `.safeExtend()` instead.")}return ke(e,Sr(e._zod.def,{shape:YU(e,A)}))}function YU(e,A){let t={};return qo(t,e,Reflect.ownKeys(cn(e))),nX(t,A),t}function BX(e,A){if(!rr(A))throw new Error("Invalid input to safeExtend: expected a plain object");return ke(e,Sr(e._zod.def,{shape:YU(e,A)}))}function QX(e,A){if(!A?._zod?.def)throw new Error("Invalid input to merge: expected an object schema. To merge a plain shape, use `.extend()`.");if(e._zod.def.checks?.length)throw new Error(".merge() cannot be used on object schemas containing refinements. Use .safeExtend() instead.");let t={};qo(t,e,Reflect.ownKeys(cn(e))),qo(t,A,Reflect.ownKeys(cn(A)));let i=Sr(e._zod.def,{shape:t,get catchall(){return A._zod.def.catchall},checks:A._zod.def.checks??[]});return ke(e,i)}function dX(e,A,t,i="partial"){let n=A._zod.def.checks;if(n&&n.length>0)throw new Error(`.${i}() cannot be used on object schemas containing refinements`);let s=t?new Set(il(A,t)):void 0,a={};return qo(a,A,Reflect.ownKeys(cn(A)),e&&((u,g)=>s&&!s.has(g)?u:new e({type:"optional",innerType:u}))),ke(A,Sr(A._zod.def,{shape:a,checks:[]}))}function pX(e,A,t){let i=t?new Set(il(A,t)):void 0,r={};return qo(r,A,Reflect.ownKeys(cn(A)),(n,o)=>i&&!i.has(o)?n:new e({type:"nonoptional",innerType:n})),ke(A,Sr(A._zod.def,{shape:r}))}function gi(e,A=0){if(e.aborted===!0)return!0;for(let t=A;t<e.issues.length;t++)if(e.issues[t]?.continue!==!0)return!0;return!1}function bh(e,A=0){if(e.aborted===!0)return!0;for(let t=A;t<e.issues.length;t++)if(e.issues[t]?.continue===!1)return!0;return!1}function yi(e,A){return A.map(t=>{var i;return(i=t).path??(i.path=[]),t.path.unshift(e),t})}function Ca(e){return typeof e=="string"?e:e?.message}function rl(e,A,t){var i;for(let r=A;r<e.length;r++)(i=e[r]).schema??(i.schema=t)}function wi(e,A,t){var i;let r=e.inst?._zod?.traits;r?.has("$ZodType")&&(r.has("$ZodCheck")?(i=e).schema??(i.schema=e.inst):e.schema=e.inst);let n=e.schema!==e.inst?e.schema?._zod.def?.error:void 0,o=e.message?e.message:Ca(e.inst?._zod.def?.error?.(e))??Ca(n?.(e))??Ca(A?.error?.(e))??Ca(t.customError?.(e))??Ca(t.localeError?.(e))??"Invalid input",s={};for(let a of Object.keys(e))a==="inst"||a==="schema"||a==="continue"||a==="input"||a==="__proto__"||(s[a]=e[a]);return s.path??(s.path=[]),s.message=o,A?.reportInput&&(s.input=e.input),s}function eI(e){return e instanceof Set?"set":e instanceof Map?"map":e instanceof File?"file":"unknown"}var fX=/[\uD800-\uDBFF]/;function Vo(e){let A=e.length;if(!fX.test(e))return A;let t=A;for(let i=0;i<A-1;i++)(e.charCodeAt(i)&64512)===55296&&(e.charCodeAt(i+1)&64512)===56320&&(t--,i++);return t}function tI(e){return Array.isArray(e)?"array":typeof e=="string"?"string":"unknown"}function uA(e){let A=typeof e;switch(A){case"number":return Number.isNaN(e)?"nan":"number";case"object":{if(e===null)return"null";if(Array.isArray(e))return"array";let t=e;if(t&&Object.getPrototypeOf(t)!==Object.prototype&&"constructor"in t&&t.constructor)return t.constructor.name}}return A}function da(...e){let[A,t,i]=e;return typeof A=="string"?{message:A,code:"custom",input:t,inst:i}:{...A}}function hX(e){return Object.entries(e).filter(([A,t])=>Number.isNaN(Number.parseInt(A,10))).map(A=>A[1])}function jU(e){let A=atob(e),t=new Uint8Array(A.length);for(let i=0;i<A.length;i++)t[i]=A.charCodeAt(i);return t}function qU(e){let A="";for(let t=0;t<e.length;t++)A+=String.fromCharCode(e[t]);return btoa(A)}function DX(e){let A=e.replace(/-/g,"+").replace(/_/g,"/"),t="=".repeat((4-A.length%4)%4);return jU(A+t)}function mX(e){return qU(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function yX(e){let A=e.replace(/^0x/,"");if(A.length%2!==0)throw new Error("Invalid hex string length");let t=new Uint8Array(A.length/2);for(let i=0;i<A.length;i+=2)t[i/2]=Number.parseInt(A.slice(i,i+2),16);return t}function wX(e){return Array.from(e).map(A=>A.toString(16).padStart(2,"0")).join("")}var wh=class{constructor(...A){}};function xh(e,A){for(let t in A){let i=Object.getOwnPropertyDescriptor(A,t);i.get?Object.defineProperty(e,t,{...i,enumerable:!1}):FX(e,t,i.value)}}function Vn(e,A,t,i=!0){return Object.defineProperty(e,A,{configurable:!0,writable:!0,enumerable:i,value:t}),t}function iI(e,A,t){return Vn(e,A,t,!1)}function SX(e,A){for(let t in e){let i=e[t];Object.defineProperty(A,t,{configurable:!0,enumerable:!0,get(){return Vn(this,t,i(this))},set(r){Vn(this,t,r)}})}return A}function FX(e,A,t){Object.defineProperty(e,A,{configurable:!0,get(){return this==null?t:Vn(this,A,t.bind(this))},set(i){Vn(this,A,i)}})}function RX(e,A){let t=Object.getPrototypeOf(e);return A in t?void 0:t}var mh,$n=!1,vX={configurable:!0,get(){$n=!0}};function ce(e,A,t){let i=Object.getPrototypeOf(e._zod);if(A in i&&mh!==e._zod){mh=void 0;return}mh=e._zod,Object.defineProperty(i,A,{configurable:!0,get(){Object.defineProperty(this,A,vX);let r=$n;$n=!1;try{let n=t(this);return $n?delete this[A]:Object.defineProperty(this,A,{configurable:!0,writable:!0,value:n}),$n=$n||r,n}catch(n){throw delete this[A],$n=$n||r,n}},set(r){Object.defineProperty(this,A,{configurable:!0,writable:!0,value:r})}})}function _X(e,A,t,i){let r=RX(e,A);r&&Object.defineProperty(r,A,{configurable:!0,get(){let n={configurable:!0,writable:!0,enumerable:i,value:void 0};return Object.defineProperty(this,A,n),n.value=t(this),Object.defineProperty(this,A,n),n.value},set(n){Object.defineProperty(this,A,{configurable:!0,writable:!0,enumerable:i,value:n})}})}var nl="~constantCatch";function Nh(e){let A=()=>e;return A[nl]=!0,A}var $U,Uh=Object.freeze({status:"aborted"}),kh={value:void 0,enumerable:!1},VU="captureStackTrace"in Error?Error:null;function bX(e){let A=VU;if(A){let t=A.stackTraceLimit;if(typeof t=="number"){try{A.stackTraceLimit=0}catch{return VU=null,new e}try{return new e}finally{A.stackTraceLimit=t}}}return new e}function H(e,A,t,i){let r={};function n(l){this.def=l,this.constr=C,this.traits=new Set}n.prototype=r;let o=t,s=o&&new WeakSet;function a(l,I){if(l._zod){if(l._zod.traits.has(e))return}else{kh.value=new n(I);try{Object.defineProperty(l,"_zod",kh)}finally{kh.value=void 0}}if(l._zod.traits.add(e),A(l,I),s){let E=Object.getPrototypeOf(l),B=l._zod.constr.prototype,Q=E;for(;Q&&Q!==B;)Q=Object.getPrototypeOf(Q);let p=Q??E;s.has(p)||(s.add(p),xh(p,o))}let c=C.prototype;for(let E in c)Object.prototype.hasOwnProperty.call(c,E)&&(E in l||(l[E]=c[E].bind(l)))}let u=i?.Parent??Object;class g extends u{}Object.defineProperty(g,"name",{value:e});function C(l){let I=i?.Parent?bX(g):this;a(I,l);let c=I._zod.deferred;if(c){for(let B of c)B();I._zod.deferred=void 0}let E=globalThis.__zod_globalConfig?.postProcessor;return E&&E(I),I}return Object.defineProperty(C,"init",{value:a}),Object.defineProperty(C,Symbol.hasInstance,{value:l=>i?.Parent&&l instanceof i.Parent?!0:l?._zod?.traits?.has(e)}),Object.defineProperty(C,"name",{value:e}),C}var Mh=Symbol("zod_brand"),Si=class extends Error{constructor(){super("Encountered Promise during synchronous parse. Use .parseAsync() instead.")}},Wn=class extends Error{constructor(A){super(`Encountered unidirectional transform during encode: ${A}`),this.name="ZodEncodeError"}};($U=globalThis).__zod_globalConfig??($U.__zod_globalConfig={});var bt=globalThis.__zod_globalConfig;function nt(e){return e&&Object.assign(bt,e),bt}function xX(){let e=this._zod;return e.message??(e.message=JSON.stringify(e.def,Ea,2)),e.message}function NX(e){this._zod.message=e}var kX={get:xX,set:NX,enumerable:!0,configurable:!0},Th={value:void 0,enumerable:!1},WU=new WeakSet([Object.prototype,Error.prototype]),zU=(e,A)=>{e.name="$ZodError",Th.value=A,Object.defineProperty(e,"issues",Th),Th.value=void 0,Object.defineProperty(e,"message",kX);let t=Object.getPrototypeOf(e);WU.has(t)||(WU.add(t),Object.defineProperty(t,"toString",{configurable:!0,enumerable:!1,get(){let i=()=>this.message;return Object.defineProperty(this,"toString",{value:i,configurable:!0,writable:!0}),i},set(i){Object.defineProperty(this,"toString",{value:i,configurable:!0,writable:!0})}}))},Gh=H("$ZodError",zU),Fi=H("$ZodError",zU,void 0,{Parent:Error});function UX(e,A,t){return Object.prototype.hasOwnProperty.call(e,A)||(A==="__proto__"?Object.defineProperty(e,A,{value:t(),writable:!0,enumerable:!0,configurable:!0}):e[A]=t()),e[A]}function rI(e,A=t=>t.message){let t={},i=[];for(let r of e.issues)r.path.length>0?UX(t,r.path[0],()=>[]).push(A(r)):i.push(A(r));return{formErrors:i,fieldErrors:t}}function nI(e,A=t=>t.message){let t={_errors:[]},i=(r,n=[])=>{for(let o of r.issues)if(o.code==="invalid_union"&&o.errors.length)o.errors.map(s=>i({issues:s},[...n,...o.path]));else if(o.code==="invalid_key")i({issues:o.issues},[...n,...o.path]);else if(o.code==="invalid_element")i({issues:o.issues},[...n,...o.path]);else{let s=[...n,...o.path];if(s.length===0)t._errors.push(A(o));else{let a=t,u=0;for(;u<s.length;){let g=s[u],C=u===s.length-1;if(g==="_errors"){C&&a._errors.push(A(o)),u++;continue}Object.prototype.hasOwnProperty.call(a,g)||Object.defineProperty(a,g,{value:{_errors:[]},enumerable:!0,writable:!0,configurable:!0});let l=a[g];C&&l._errors.push(A(o)),a=l,u++}}}};return i(e),t}function Oh(e,A=t=>t.message){let t={errors:[]},i=(r,n=[])=>{var o;for(let s of r.issues)if(s.code==="invalid_union"&&s.errors.length)s.errors.map(a=>i({issues:a},[...n,...s.path]));else if(s.code==="invalid_key")i({issues:s.issues},[...n,...s.path]);else if(s.code==="invalid_element")i({issues:s.issues},[...n,...s.path]);else{let a=[...n,...s.path];if(a.length===0){t.errors.push(A(s));continue}let u=t,g=0;for(;g<a.length;){let C=a[g],l=g===a.length-1;typeof C=="string"?(u.properties??(u.properties={}),Object.prototype.hasOwnProperty.call(u.properties,C)||Object.defineProperty(u.properties,C,{value:{errors:[]},enumerable:!0,writable:!0,configurable:!0}),u=u.properties[C]):(u.items??(u.items=[]),(o=u.items)[C]??(o[C]={errors:[]}),u=u.items[C]),l&&u.errors.push(A(s)),g++}}};return i(e),t}function ZU(e){let A=[],t=e.map(i=>typeof i=="object"?i.key:i);for(let i of t)typeof i=="number"?A.push(`[${i}]`):typeof i=="symbol"?A.push(`[${JSON.stringify(String(i))}]`):/[^\w$]/.test(i)?A.push(`[${JSON.stringify(i)}]`):(A.length&&A.push("."),A.push(i));return A.join("")}function Wo(e){let A=[],t=[...e.issues].sort((i,r)=>(i.path??[]).length-(r.path??[]).length);for(let i of t)A.push(`\u2716 ${i.message}`),i.path?.length&&A.push(` \u2192 at ${ZU(i.path)}`);return A.join(`
|
|
208
208
|
`)}function ol(e,A){return{callee:A?.callee??e,Err:A?.Err}}var pa=e=>{let A=(t,i,r,n)=>{let o=r?{...r,async:!1}:{async:!1},s=t._zod.run({value:i,issues:[]},o);if(s instanceof Promise)throw new Si;if(s.issues.length){let a=new(n?.Err??e)(s.issues.map(u=>wi(u,o,nt())));throw tl(a,n?.callee??A),a}return s.value};return A},sl=pa(Fi),fa=e=>{let A=async(t,i,r,n)=>{let o=r?{...r,async:!0}:{async:!0},s=t._zod.run({value:i,issues:[]},o);if(s instanceof Promise&&(s=await s),s.issues.length){let a=new(n?.Err??e)(s.issues.map(u=>wi(u,o,nt())));throw tl(a,n?.callee??A),a}return s.value};return A},al=fa(Fi),ha=e=>(A,t,i)=>{let r=i?{...i,async:!1}:{async:!1},n=A._zod.run({value:t,issues:[]},r);if(n instanceof Promise)throw new Si;return n.issues.length?XU(e,n.issues,r):{success:!0,data:n.value}},LX=ha(Fi);function XU(e,A,t){let i;return{success:!1,get error(){return i||(i=new e(A.map(r=>wi(r,t,nt()))),A=void 0,t=void 0),i},set error(r){i=r,A=void 0,t=void 0}}}var Da=e=>async(A,t,i)=>{let r=i?{...i,async:!0}:{async:!0},n=A._zod.run({value:t,issues:[]},r);return n instanceof Promise&&(n=await n),n.issues.length?XU(e,n.issues,r):{success:!0,data:n.value}},TX=Da(Fi),GX=Symbol.for("zod.compile.invalid"),OX=Symbol.for("zod.compile.fallback"),oI=((e,A,t)=>{let i=e._zod.bag.validator;if(i!==void 0){if(i(A)!==GX)return!0;if(i.definite===!0&&t===void 0)return!1}return PX(e,A,t)});function PX(e,A,t){let i=t?{...t,async:!1,abortEarly:!0}:{async:!1,abortEarly:!0},r=e._zod.bag.fallbackRun,n;if(r?(i[OX]=!0,n=r({value:A,issues:[]},i)):n=e._zod.run({value:A,issues:[]},i),n instanceof Promise)throw new Si;return n.issues.length===0}var sI=async(e,A,t)=>{let i=t?{...t,async:!0,abortEarly:!0}:{async:!0,abortEarly:!0},r=e._zod.run({value:A,issues:[]},i);return r instanceof Promise&&(r=await r),r.issues.length===0},gl=e=>{let A=pa(e),t=(i,r,n,o)=>{let s=n?{...n,direction:"backward"}:{direction:"backward"};return A(i,r,s,ol(t,o))};return t},JX=gl(Fi),ul=e=>{let A=pa(e),t=(i,r,n,o)=>A(i,r,n,ol(t,o));return t},KX=ul(Fi),Il=e=>{let A=fa(e),t=async(i,r,n,o)=>{let s=n?{...n,direction:"backward"}:{direction:"backward"};return await A(i,r,s,ol(t,o))};return t},HX=Il(Fi),cl=e=>{let A=fa(e),t=async(i,r,n,o)=>await A(i,r,n,ol(t,o));return t},YX=cl(Fi),Cl=e=>(A,t,i)=>{let r=i?{...i,direction:"backward"}:{direction:"backward"};return ha(e)(A,t,r)},jX=Cl(Fi),ll=e=>(A,t,i)=>ha(e)(A,t,i),qX=ll(Fi),El=e=>async(A,t,i)=>{let r=i?{...i,direction:"backward"}:{direction:"backward"};return Da(e)(A,t,r)},$X=El(Fi),Bl=e=>async(A,t,i)=>Da(e)(A,t,i),VX=Bl(Fi);var or={};Or(or,{anyString:()=>CD,base64:()=>rD,base64url:()=>nD,bigint:()=>ED,boolean:()=>BD,browserEmail:()=>i5,cidrv4:()=>tD,cidrv6:()=>iD,creditCard:()=>Ql,cuid:()=>Jh,cuid2:()=>Kh,currencyCode:()=>gD,date:()=>uD,datetime:()=>cD,domain:()=>sD,duration:()=>Vh,e164:()=>aD,email:()=>zh,emoji:()=>Zh,extendedDuration:()=>WX,guid:()=>Wh,hex:()=>hD,hostname:()=>oD,html5Email:()=>A5,httpProtocol:()=>aI,iban:()=>dl,idnEmail:()=>t5,integer:()=>gI,ipv4:()=>Xh,ipv6:()=>AD,ksuid:()=>jh,lowercase:()=>pD,mac:()=>eD,md5_base64:()=>s5,md5_base64url:()=>a5,md5_hex:()=>o5,nanoid:()=>qh,nanoidOfLength:()=>$h,null:()=>QD,number:()=>ln,rfc5322Email:()=>e5,sha1_base64:()=>u5,sha1_base64url:()=>I5,sha1_hex:()=>g5,sha256_base64:()=>C5,sha256_base64url:()=>l5,sha256_hex:()=>c5,sha384_base64:()=>B5,sha384_base64url:()=>Q5,sha384_hex:()=>E5,sha512_base64:()=>p5,sha512_base64url:()=>f5,sha512_hex:()=>d5,string:()=>lD,time:()=>ID,ulid:()=>Hh,undefined:()=>dD,unicodeEmail:()=>AM,uppercase:()=>fD,uuid:()=>zo,uuid4:()=>zX,uuid6:()=>ZX,uuid7:()=>XX,xid:()=>Yh});var Jh=/^[cC][0-9a-z]{6,}$/,Kh=/^[0-9a-z]+$/,Hh=/^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$/,Yh=/^[0-9a-vA-V]{20}$/,jh=/^[A-Za-z0-9]{27}$/,qh=/^[a-zA-Z0-9_-]{21}$/;function $h(e){return new RegExp(`^[a-zA-Z0-9_-]{${e}}$`)}var Vh=/^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/,WX=/^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/,Wh=/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/,zo=e=>e?new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${e}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`):/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/,zX=zo(4),ZX=zo(6),XX=zo(7),zh=/^(?:[A-Za-z0-9_'+\-]+\.)*[A-Za-z0-9_'+\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/,A5=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,e5=/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,AM=/^[^\s@"]{1,64}@[^\s@]{1,255}$/u,t5=AM,i5=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,r5="^(?=[\\s\\S]*[\\p{Extended_Pictographic}\\p{Regional_Indicator}\\u20E3])[\\p{Extended_Pictographic}\\p{Emoji_Component}]+$";function Zh(){return new RegExp(r5,"u")}var Xh=/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,AD=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/,eD=e=>{let A=nr(e??":");return new RegExp(`^(?:[0-9A-F]{2}${A}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${A}){5}[0-9a-f]{2}$`)},tD=/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/,iD=/^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,rD=/^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/,nD=/^(?:[A-Za-z0-9_-]{4})*(?:[A-Za-z0-9_-]{2,3})?$/,oD=/^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/,sD=/^(?=.{1,253}$)([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}$/,aI=/^https?$/,aD=/^\+[1-9]\d{6,14}$/,Ql=/^\d(?:[ -]?\d){11,18}$/,gD=/^(?:AED|AFN|ALL|AMD|AOA|ARS|AUD|AWG|AZN|BAM|BBD|BDT|BHD|BIF|BMD|BND|BOB|BOV|BRL|BSD|BTN|BWP|BYN|BZD|CAD|CDF|CHE|CHF|CHW|CLF|CLP|CNY|COP|COU|CRC|CUP|CVE|CZK|DJF|DKK|DOP|DZD|EGP|ERN|ETB|EUR|FJD|FKP|GBP|GEL|GHS|GIP|GMD|GNF|GTQ|GYD|HKD|HNL|HTG|HUF|IDR|ILS|INR|IQD|IRR|ISK|JMD|JOD|JPY|KES|KGS|KHR|KMF|KPW|KRW|KWD|KYD|KZT|LAK|LBP|LKR|LRD|LSL|LYD|MAD|MDL|MGA|MKD|MMK|MNT|MOP|MRU|MUR|MVR|MWK|MXN|MXV|MYR|MZN|NAD|NGN|NIO|NOK|NPR|NZD|OMR|PAB|PEN|PGK|PHP|PKR|PLN|PYG|QAR|RON|RSD|RUB|RWF|SAR|SBD|SCR|SDG|SEK|SGD|SHP|SLE|SOS|SRD|SSP|STN|SVC|SYP|SZL|THB|TJS|TMT|TND|TOP|TRY|TTD|TWD|TZS|UAH|UGX|USD|USN|UYI|UYU|UYW|UZS|VED|VES|VND|VUV|WST|XAD|XAF|XAG|XAU|XBA|XBB|XBC|XBD|XCD|XCG|XDR|XOF|XPD|XPF|XPT|XSU|XTS|XUA|XXX|YER|ZAR|ZMW|ZWG)$/,dl=/^[A-Z]{2}(?!00|01|99)\d{2}[A-Z0-9]{11,30}$/,eM="(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))";function n5(e){return new RegExp(`^${e}$`)}var uD=n5(eM);function Ph(e){let A="(?:[01]\\d|2[0-3]):[0-5]\\d";return typeof e.precision=="number"?e.precision===-1?`${A}`:e.precision===0?`${A}:[0-5]\\d`:`${A}:[0-5]\\d\\.\\d{${e.precision}}`:e.seconds?`${A}:[0-5]\\d(?:\\.\\d+)?`:`${A}(?::[0-5]\\d(?:\\.\\d+)?)?`}function ID(e){return new RegExp(`^${Ph(e)}$`)}function cD(e){let A=["Z"];e.offset&&A.push("([+-](?:[01]\\d|2[0-3]):[0-5]\\d)");let t=`${Ph({precision:e.precision,seconds:!0})}(?:${A.join("|")})`,i=e.local?`${t}|${Ph({precision:e.precision})}`:t;return new RegExp(`^${eM}T(?:${i})$`)}var CD=/^[\s\S]{0,}$/,lD=e=>{let A=e?`[\\s\\S]{${e?.minimum??0},${e?.maximum??""}}`:"[\\s\\S]*";return new RegExp(`^${A}$`)},ED=/^-?\d+n?$/,gI=/^-?\d+$/,ln=/^-?\d+(?:\.\d+)?$/,BD=/^(?:true|false)$/i,QD=/^null$/i;var dD=/^undefined$/i;var pD=/^[^A-Z]*$/,fD=/^[^a-z]*$/,hD=/^[0-9a-fA-F]*$/;function uI(e,A){return new RegExp(`^[A-Za-z0-9+/]{${e}}${A}$`)}function II(e){return new RegExp(`^[A-Za-z0-9_-]{${e}}$`)}var o5=/^[0-9a-fA-F]{32}$/,s5=uI(22,"=="),a5=II(22),g5=/^[0-9a-fA-F]{40}$/,u5=uI(27,"="),I5=II(27),c5=/^[0-9a-fA-F]{64}$/,C5=uI(43,"="),l5=II(43),E5=/^[0-9a-fA-F]{96}$/,B5=uI(64,""),Q5=II(64),d5=/^[0-9a-fA-F]{128}$/,p5=uI(86,"=="),f5=II(86);var Pe=H("$ZodCheck",(e,A)=>{var t;e._zod??(e._zod={}),e._zod.def=A,(t=e._zod).onattach??(t.onattach=[])}),DD=e=>{let A=e.value;return!el(A)&&A.size!==void 0},mD=e=>{let A=e.value;return!el(A)&&A.length!==void 0},pl={number:"number",bigint:"bigint",object:"date"},hl=H("$ZodCheckLessThan",(e,A)=>{Pe.init(e,A);let t=pl[typeof A.value];e._zod.check=i=>{(A.inclusive?i.value<=A.value:i.value<A.value)||i.issues.push({origin:pl[typeof i.value]??t,code:"too_big",maximum:typeof A.value=="object"?A.value.getTime():A.value,input:i.value,inclusive:A.inclusive,inst:e,continue:!A.abort})}}),Dl=H("$ZodCheckGreaterThan",(e,A)=>{Pe.init(e,A);let t=pl[typeof A.value];e._zod.check=i=>{(A.inclusive?i.value>=A.value:i.value>A.value)||i.issues.push({origin:pl[typeof i.value]??t,code:"too_small",minimum:typeof A.value=="object"?A.value.getTime():A.value,input:i.value,inclusive:A.inclusive,inst:e,continue:!A.abort})}}),yD=H("$ZodCheckMultipleOf",(e,A)=>{Pe.init(e,A),e._zod.check=t=>{if(typeof t.value!=typeof A.value)throw new Error("Cannot mix number and bigint in multiple_of check.");(typeof t.value=="bigint"?A.value!==BigInt(0)&&t.value%A.value===BigInt(0):Wu(t.value,A.value)===0)||t.issues.push({origin:typeof t.value,code:"not_multiple_of",divisor:A.value,input:t.value,inst:e,continue:!A.abort})}}),wD=H("$ZodCheckNumberFormat",(e,A)=>{Pe.init(e,A),A.format=A.format||"float64";let t=A.format?.includes("int"),i=t?"int":"number",[r,n]=Xu[A.format];e._zod.check=o=>{let s=o.value;if(t){if(!Number.isInteger(s)){o.issues.push({expected:i,format:A.format,code:"invalid_type",continue:!1,input:s,inst:e});return}if(!Number.isSafeInteger(s)){s>0?o.issues.push({input:s,code:"too_big",maximum:Number.MAX_SAFE_INTEGER,note:"Integers must be within the safe integer range.",inst:e,origin:i,inclusive:!0,continue:!A.abort}):o.issues.push({input:s,code:"too_small",minimum:Number.MIN_SAFE_INTEGER,note:"Integers must be within the safe integer range.",inst:e,origin:i,inclusive:!0,continue:!A.abort});return}}s<r&&o.issues.push({origin:"number",input:s,code:"too_small",minimum:r,inclusive:!0,inst:e,continue:!A.abort}),s>n&&o.issues.push({origin:"number",input:s,code:"too_big",maximum:n,inclusive:!0,inst:e,continue:!A.abort})}}),SD=H("$ZodCheckBigIntFormat",(e,A)=>{Pe.init(e,A);let[t,i]=AI[A.format];e._zod.check=r=>{let n=r.value;n<t&&r.issues.push({origin:"bigint",input:n,code:"too_small",minimum:t,inclusive:!0,inst:e,continue:!A.abort}),n>i&&r.issues.push({origin:"bigint",input:n,code:"too_big",maximum:i,inclusive:!0,inst:e,continue:!A.abort})}}),FD=H("$ZodCheckMaxSize",(e,A)=>{var t;Pe.init(e,A),(t=e._zod.def).when??(t.when=DD),e._zod.check=i=>{let r=i.value;r.size<=A.maximum||i.issues.push({origin:eI(r),code:"too_big",maximum:A.maximum,inclusive:!0,input:r,inst:e,continue:!A.abort})}}),RD=H("$ZodCheckMinSize",(e,A)=>{var t;Pe.init(e,A),(t=e._zod.def).when??(t.when=DD),e._zod.check=i=>{let r=i.value;r.size>=A.minimum||i.issues.push({origin:eI(r),code:"too_small",minimum:A.minimum,inclusive:!0,input:r,inst:e,continue:!A.abort})}}),vD=H("$ZodCheckSizeEquals",(e,A)=>{var t;Pe.init(e,A),(t=e._zod.def).when??(t.when=DD),e._zod.check=i=>{let r=i.value,n=r.size;if(n===A.size)return;let o=n>A.size;i.issues.push({origin:eI(r),...o?{code:"too_big",maximum:A.size}:{code:"too_small",minimum:A.size},inclusive:!0,exact:!0,input:i.value,inst:e,continue:!A.abort})}}),_D=H("$ZodCheckMaxLength",(e,A)=>{var t;Pe.init(e,A),(t=e._zod.def).when??(t.when=mD),e._zod.check=i=>{let r=i.value,n=r.length;if((typeof r=="string"&&n>A.maximum?Vo(r):n)<=A.maximum)return;let s=tI(r);i.issues.push({origin:s,code:"too_big",maximum:A.maximum,inclusive:!0,input:r,inst:e,continue:!A.abort})}}),bD=H("$ZodCheckMinLength",(e,A)=>{var t;Pe.init(e,A),(t=e._zod.def).when??(t.when=mD),e._zod.check=i=>{let r=i.value,n=r.length;if((typeof r=="string"&&n>=A.minimum&&n<A.minimum*2?Vo(r):n)>=A.minimum)return;let s=tI(r);i.issues.push({origin:s,code:"too_small",minimum:A.minimum,inclusive:!0,input:r,inst:e,continue:!A.abort})}}),xD=H("$ZodCheckLengthEquals",(e,A)=>{var t;Pe.init(e,A),(t=e._zod.def).when??(t.when=mD),e._zod.check=i=>{let r=i.value,n=r.length,o=typeof r=="string"&&n>=A.length&&n<=A.length*2?Vo(r):n;if(o===A.length)return;let s=tI(r),a=o>A.length;i.issues.push({origin:s,...a?{code:"too_big",maximum:A.length}:{code:"too_small",minimum:A.length},inclusive:!0,exact:!0,input:i.value,inst:e,continue:!A.abort})}}),ma=H("$ZodCheckStringFormat",(e,A)=>{var t,i;Pe.init(e,A),A.pattern?(t=e._zod).check??(t.check=r=>{A.pattern.lastIndex=0,!A.pattern.test(r.value)&&r.issues.push({origin:"string",code:"invalid_format",format:A.format,input:r.value,...A.pattern?{pattern:A.pattern.toString()}:{},inst:e,continue:!A.abort})}):(i=e._zod).check??(i.check=()=>{})}),ND=H("$ZodCheckRegex",(e,A)=>{ma.init(e,A),e._zod.check=t=>{A.pattern.lastIndex=0,!A.pattern.test(t.value)&&t.issues.push({origin:"string",code:"invalid_format",format:"regex",input:t.value,pattern:A.pattern.toString(),inst:e,continue:!A.abort})}}),kD=H("$ZodCheckLowerCase",(e,A)=>{A.pattern??(A.pattern=pD),ma.init(e,A)}),UD=H("$ZodCheckUpperCase",(e,A)=>{A.pattern??(A.pattern=fD),ma.init(e,A)}),MD=H("$ZodCheckIncludes",(e,A)=>{Pe.init(e,A);let t=nr(A.includes),i=new RegExp(typeof A.position=="number"?`^.{${A.position},}${t}`:t);A.pattern=i,e._zod.check=r=>{r.value.includes(A.includes,A.position)||r.issues.push({origin:"string",code:"invalid_format",format:"includes",includes:A.includes,input:r.value,inst:e,continue:!A.abort})}}),LD=H("$ZodCheckStartsWith",(e,A)=>{Pe.init(e,A);let t=new RegExp(`^${nr(A.prefix)}.*`);A.pattern??(A.pattern=t),e._zod.check=i=>{i.value.startsWith(A.prefix)||i.issues.push({origin:"string",code:"invalid_format",format:"starts_with",prefix:A.prefix,input:i.value,inst:e,continue:!A.abort})}}),TD=H("$ZodCheckEndsWith",(e,A)=>{Pe.init(e,A);let t=new RegExp(`.*${nr(A.suffix)}$`);A.pattern??(A.pattern=t),e._zod.check=i=>{i.value.endsWith(A.suffix)||i.issues.push({origin:"string",code:"invalid_format",format:"ends_with",suffix:A.suffix,input:i.value,inst:e,continue:!A.abort})}});function fl(e,A,t){e.issues.length&&A.issues.push(...yi(t,e.issues))}var GD=H("$ZodCheckProperty",(e,A)=>{Pe.init(e,A),e._zod.check=t=>{let i=A.schema._zod.run({value:t.value[A.property],issues:[]},{});if(i instanceof Promise)return i.then(r=>fl(r,t,A.property));fl(i,t,A.property)}}),OD=H("$ZodCheckProperties",(e,A)=>{Pe.init(e,A),iI(e,Symbol.iterator,function*(){yield e});let t;e._zod.check=i=>{if(i.value==null){i.issues.push({expected:"object",code:"invalid_type",input:i.value,inst:e});return}t??(t=Reflect.ownKeys(A.shape).map(o=>[o,A.shape[o]]));let r=i.value,n;for(let[o,s]of t){let a=s._zod.run({value:r[o],issues:[]},{});a instanceof Promise?(n??(n=[]),n.push(a.then(u=>fl(u,i,o)))):fl(a,i,o)}if(n)return Promise.all(n).then(()=>{})}}),PD=H("$ZodCheckMimeType",(e,A)=>{Pe.init(e,A);let t=new Set(A.mime);e._zod.check=i=>{t.has(i.value.type)||i.issues.push({code:"invalid_value",values:A.mime,input:i.value.type,inst:e,continue:!A.abort})}}),JD=H("$ZodCheckOverwrite",(e,A)=>{Pe.init(e,A),e._zod.check=t=>{t.value=A.tx(t.value)}});var Zo=class{constructor(A=[],t={}){this.content=[],this.indent=0,this.args=A,this.closed=t}indented(A){this.indent+=1;try{A(this)}finally{this.indent-=1}}write(A){if(typeof A=="function"){A(this,{execution:"sync"}),A(this,{execution:"async"});return}let i=A.split(`
|
|
@@ -18,7 +18,7 @@ const TAG_SOURCE = '.github/workflows/_move_major_tag.yaml';
|
|
|
18
18
|
const REVIEW_WORKFLOW = '.github/workflows/public_review.yaml';
|
|
19
19
|
|
|
20
20
|
// Every place a ref into this repo can appear: live `uses:`, commented examples, README snippets.
|
|
21
|
-
const SEARCH_PATHS = ['.github', 'README.md', 'CONTRIBUTING.md'];
|
|
21
|
+
const SEARCH_PATHS = ['.github', 'README.md', 'CONTRIBUTING.md', 'docs'];
|
|
22
22
|
|
|
23
23
|
const read = (rel) => fs.readFileSync(path.join(ROOT, rel), 'utf8');
|
|
24
24
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Registers every value inside the CONFIG_SECRETS secret as a mask.
|
|
3
|
+
#
|
|
4
|
+
# CONFIG_SECRETS=... bash .github/scripts/mask-config-secrets.sh
|
|
5
|
+
#
|
|
6
|
+
# The runner masks a secret by its exact value, so a value packed inside a JSON secret is only
|
|
7
|
+
# masked as part of that whole blob. Once a step takes it out, it would print in clear.
|
|
8
|
+
# Multi-line values are registered line by line, the way the runner registers secrets.
|
|
9
|
+
# CONFIG_SECRETS may be empty or unset.
|
|
10
|
+
|
|
11
|
+
set -uo pipefail
|
|
12
|
+
|
|
13
|
+
[ -n "${CONFIG_SECRETS:-}" ] || exit 0
|
|
14
|
+
|
|
15
|
+
# jq's errors can quote the input, so they are dropped for our own message
|
|
16
|
+
jq -r 'if type != "object" then error else . end | to_entries[] | .value | strings | split("\n")[] | select(. != "") | "::add-mask::" + .' <<< "$CONFIG_SECRETS" 2>/dev/null \
|
|
17
|
+
|| { echo "::error::The CONFIG_SECRETS secret must be a JSON object."; exit 1; }
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
//
|
|
4
4
|
// jq ... | node .github/scripts/run-with-apify-tokens.mjs apify-test-tools build --version-number 0.99
|
|
5
5
|
//
|
|
6
|
-
// The step passes the whole secrets map as
|
|
7
|
-
// the repo's apify-test-tools.config.json, which is the same file
|
|
8
|
-
// the two can't drift. Everything else in the secrets map (npm,
|
|
9
|
-
// repo holds) is left out, and
|
|
10
|
-
// anything under node_modules.
|
|
6
|
+
// The step passes the reusable workflow's whole secrets map as WORKFLOW_SECRETS. The token names
|
|
7
|
+
// come from `tokenEnvVar` in the repo's apify-test-tools.config.json, which is the same file
|
|
8
|
+
// apify-test-tools itself reads, so the two can't drift. Everything else in the secrets map (npm,
|
|
9
|
+
// Slack, GitHub, anything else the repo holds) is left out, and WORKFLOW_SECRETS itself is dropped,
|
|
10
|
+
// so the blob never reaches the CLI or anything under node_modules.
|
|
11
|
+
//
|
|
12
|
+
// Each token is looked up in the CONFIG_SECRETS secret first, a JSON object of secret name -> value,
|
|
13
|
+
// and then among the top-level secrets, which is where `secrets: inherit` puts them. The secrets the
|
|
14
|
+
// workflows read by name (NPM_TOKEN, TESTER_APIFY_TOKEN, ...) never come from CONFIG_SECRETS.
|
|
11
15
|
//
|
|
12
16
|
// The command runs without a shell, so branch names and other interpolated arguments are passed
|
|
13
17
|
// through as literal argv entries.
|
|
@@ -28,16 +32,36 @@ const fail = (message) => {
|
|
|
28
32
|
const [command, ...args] = process.argv.slice(2);
|
|
29
33
|
if (!command) fail('Usage: run-with-apify-tokens.mjs <command> [args...]');
|
|
30
34
|
|
|
31
|
-
const {
|
|
32
|
-
if (!
|
|
35
|
+
const { WORKFLOW_SECRETS, ...baseEnv } = process.env;
|
|
36
|
+
if (!WORKFLOW_SECRETS) {
|
|
37
|
+
fail('WORKFLOW_SECRETS is not set. Add `WORKFLOW_SECRETS: ${{ toJSON(secrets) }}` to the step env.');
|
|
38
|
+
}
|
|
33
39
|
|
|
34
|
-
let
|
|
40
|
+
let workflowSecrets;
|
|
35
41
|
try {
|
|
36
|
-
|
|
42
|
+
workflowSecrets = JSON.parse(WORKFLOW_SECRETS);
|
|
37
43
|
} catch (error) {
|
|
38
|
-
fail(`
|
|
44
|
+
fail(`WORKFLOW_SECRETS is not valid JSON: ${error.message}`);
|
|
39
45
|
}
|
|
40
46
|
|
|
47
|
+
// Never includes the parse error: Node quotes the input in it, and the input is a secret.
|
|
48
|
+
const unpackConfigSecrets = () => {
|
|
49
|
+
const packed = workflowSecrets.CONFIG_SECRETS;
|
|
50
|
+
if (!packed) return {};
|
|
51
|
+
let value;
|
|
52
|
+
try {
|
|
53
|
+
value = JSON.parse(packed);
|
|
54
|
+
} catch {
|
|
55
|
+
fail('The CONFIG_SECRETS secret is not valid JSON.');
|
|
56
|
+
}
|
|
57
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
58
|
+
fail('The CONFIG_SECRETS secret must be a JSON object.');
|
|
59
|
+
}
|
|
60
|
+
return value;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const secrets = { ...workflowSecrets, ...unpackConfigSecrets() };
|
|
64
|
+
|
|
41
65
|
const configPath = path.resolve(process.cwd(), CONFIG_FILE_NAME);
|
|
42
66
|
let config;
|
|
43
67
|
try {
|
|
@@ -78,7 +102,8 @@ const missing = tokenNames.filter((name) => !(name in secrets));
|
|
|
78
102
|
if (missing.length > 0) {
|
|
79
103
|
console.error(
|
|
80
104
|
`Warning: ${CONFIG_FILE_NAME} declares ${missing.join(', ')}, but no such secret was passed ` +
|
|
81
|
-
`to this workflow. Check the repository secrets
|
|
105
|
+
`to this workflow, neither inside CONFIG_SECRETS nor inherited. Check the repository secrets ` +
|
|
106
|
+
`and the workflow's \`secrets:\` if a build fails on a missing token.`,
|
|
82
107
|
);
|
|
83
108
|
}
|
|
84
109
|
|
|
@@ -23,13 +23,17 @@ name: 'Platform tests: Claude failure investigation and fix'
|
|
|
23
23
|
# uses: apify/apify-test-tools/.github/workflows/public_platform-tests.yaml@workflows-v0
|
|
24
24
|
# with:
|
|
25
25
|
# subtest: core
|
|
26
|
-
# secrets:
|
|
26
|
+
# secrets:
|
|
27
|
+
# TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
|
|
28
|
+
# SLACK_TOKEN_TESTS_BOT: ${{ secrets.SLACK_TOKEN_TESTS_BOT }}
|
|
27
29
|
#
|
|
28
30
|
# handle-failure:
|
|
29
31
|
# needs: platformTestsCore
|
|
30
32
|
# if: ${{ failure() }}
|
|
31
33
|
# uses: apify/apify-test-tools/.github/workflows/public_platform-tests-claude-investigate-and-fix.yaml@workflows-v0
|
|
32
|
-
# secrets:
|
|
34
|
+
# secrets:
|
|
35
|
+
# ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
36
|
+
# TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
|
|
33
37
|
|
|
34
38
|
on:
|
|
35
39
|
workflow_call:
|
|
@@ -18,6 +18,17 @@ on:
|
|
|
18
18
|
type: string
|
|
19
19
|
default: ''
|
|
20
20
|
required: false
|
|
21
|
+
# Only TESTER_APIFY_TOKEN is required, every test needs it. See the Secrets section of docs/workflows.md.
|
|
22
|
+
secrets:
|
|
23
|
+
NPM_TOKEN:
|
|
24
|
+
required: false
|
|
25
|
+
description: Read-only token for installing private npm packages.
|
|
26
|
+
TESTER_APIFY_TOKEN:
|
|
27
|
+
required: true
|
|
28
|
+
description: Apify token the platform tests run Actors with.
|
|
29
|
+
SLACK_TOKEN_TESTS_BOT:
|
|
30
|
+
required: false
|
|
31
|
+
description: Slack token for reporting test results.
|
|
21
32
|
|
|
22
33
|
jobs:
|
|
23
34
|
scheduledPlatformTests:
|
|
@@ -31,6 +42,18 @@ jobs:
|
|
|
31
42
|
with:
|
|
32
43
|
npm-token: ${{ secrets.NPM_TOKEN }}
|
|
33
44
|
|
|
45
|
+
# Fails here with a clear message rather than deep in vitest. `required: true` alone doesn't
|
|
46
|
+
# catch it: a caller can list the secret while the repo doesn't have it, and PRs from forks
|
|
47
|
+
# never get secrets.
|
|
48
|
+
- name: Check TESTER_APIFY_TOKEN
|
|
49
|
+
env:
|
|
50
|
+
TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
|
|
51
|
+
run: |
|
|
52
|
+
if [ -z "$TESTER_APIFY_TOKEN" ]; then
|
|
53
|
+
echo "::error::TESTER_APIFY_TOKEN is empty. Pass it in the secrets: block of the job that calls this workflow."
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
34
57
|
- name: Test
|
|
35
58
|
env:
|
|
36
59
|
TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
|
|
@@ -12,6 +12,22 @@ on:
|
|
|
12
12
|
type: string
|
|
13
13
|
default: ''
|
|
14
14
|
required: false
|
|
15
|
+
# Every secret is optional. The ones this workflow reads are declared by name. The secrets that
|
|
16
|
+
# apify-test-tools.config.json names (e.g. each Actor's `tokenEnvVar`) differ per repo, so they
|
|
17
|
+
# come packed in CONFIG_SECRETS. See the Secrets section of docs/workflows.md.
|
|
18
|
+
secrets:
|
|
19
|
+
NPM_TOKEN:
|
|
20
|
+
required: false
|
|
21
|
+
description: Read-only token for installing private npm packages.
|
|
22
|
+
TESTER_APIFY_TOKEN:
|
|
23
|
+
required: false
|
|
24
|
+
description: Apify token the platform tests run Actors with.
|
|
25
|
+
CONFIG_SECRETS:
|
|
26
|
+
required: false
|
|
27
|
+
description: >-
|
|
28
|
+
JSON object of the secrets apify-test-tools.config.json names, secret name -> value.
|
|
29
|
+
Today that is each Actor's `tokenEnvVar`. Passing `toJSON(secrets)` works too, only
|
|
30
|
+
the names the config declares are used.
|
|
15
31
|
|
|
16
32
|
concurrency:
|
|
17
33
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
@@ -29,6 +45,19 @@ jobs:
|
|
|
29
45
|
with:
|
|
30
46
|
# Some repos use private npm packages, they need to pass NPM_TOKEN secret to this workflow
|
|
31
47
|
npm-token: ${{ secrets.NPM_TOKEN }}
|
|
48
|
+
config-secrets: ${{ secrets.CONFIG_SECRETS }}
|
|
49
|
+
|
|
50
|
+
# Fails here with a clear message rather than deep in vitest. `required: true` alone doesn't
|
|
51
|
+
# catch it: a caller can list the secret while the repo doesn't have it, and PRs from forks
|
|
52
|
+
# never get secrets.
|
|
53
|
+
- name: Check TESTER_APIFY_TOKEN
|
|
54
|
+
env:
|
|
55
|
+
TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
|
|
56
|
+
run: |
|
|
57
|
+
if [ -z "$TESTER_APIFY_TOKEN" ]; then
|
|
58
|
+
echo "::error::TESTER_APIFY_TOKEN is empty. Pass it in the secrets: block of the job that calls this workflow."
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
32
61
|
|
|
33
62
|
- name: Pick last validated commit from cache
|
|
34
63
|
id: base_commit
|
|
@@ -69,7 +98,7 @@ jobs:
|
|
|
69
98
|
# bash rather than the default shell, for pipefail
|
|
70
99
|
shell: bash
|
|
71
100
|
env:
|
|
72
|
-
|
|
101
|
+
WORKFLOW_SECRETS: ${{ toJSON(secrets) }}
|
|
73
102
|
SCRIPTS_PATH: ${{ steps.setup.outputs.scripts-path }}
|
|
74
103
|
run: |
|
|
75
104
|
actor_builds=$(jq '{ actors: .functionallyChangedActors }' affected.json \
|
|
@@ -8,6 +8,22 @@ on:
|
|
|
8
8
|
type: string
|
|
9
9
|
default: ''
|
|
10
10
|
required: false
|
|
11
|
+
# Every secret is optional. The ones this workflow reads are declared by name. The secrets that
|
|
12
|
+
# apify-test-tools.config.json names (e.g. each Actor's `tokenEnvVar`) differ per repo, so they
|
|
13
|
+
# come packed in CONFIG_SECRETS. See the Secrets section of docs/workflows.md.
|
|
14
|
+
secrets:
|
|
15
|
+
NPM_TOKEN:
|
|
16
|
+
required: false
|
|
17
|
+
description: Read-only token for installing private npm packages.
|
|
18
|
+
SLACK_TOKEN_RELEASES_BOT:
|
|
19
|
+
required: false
|
|
20
|
+
description: Slack token for announcing releases.
|
|
21
|
+
CONFIG_SECRETS:
|
|
22
|
+
required: false
|
|
23
|
+
description: >-
|
|
24
|
+
JSON object of the secrets apify-test-tools.config.json names, secret name -> value.
|
|
25
|
+
Today that is each Actor's `tokenEnvVar`. Passing `toJSON(secrets)` works too, only
|
|
26
|
+
the names the config declares are used.
|
|
11
27
|
|
|
12
28
|
jobs:
|
|
13
29
|
pushBuildLatest:
|
|
@@ -24,9 +40,10 @@ jobs:
|
|
|
24
40
|
uses: apify/apify-test-tools/.github/actions/checkout-restore-dependencies@workflows-v0
|
|
25
41
|
with:
|
|
26
42
|
npm-token: ${{ secrets.NPM_TOKEN }}
|
|
43
|
+
config-secrets: ${{ secrets.CONFIG_SECRETS }}
|
|
27
44
|
|
|
28
45
|
# --since is the last commit that is already released: the push's "before" commit.
|
|
29
|
-
# Everything after it up to HEAD gets released. See the "Releasing Actors" section of
|
|
46
|
+
# Everything after it up to HEAD gets released. See the "Releasing Actors" section of docs/cli.md.
|
|
30
47
|
# Needs no tokens, it only reads git and apify-test-tools.config.json.
|
|
31
48
|
- name: Find changes since the last release
|
|
32
49
|
run: |
|
|
@@ -41,7 +58,7 @@ jobs:
|
|
|
41
58
|
# bash rather than the default shell, for pipefail
|
|
42
59
|
shell: bash
|
|
43
60
|
env:
|
|
44
|
-
|
|
61
|
+
WORKFLOW_SECRETS: ${{ toJSON(secrets) }}
|
|
45
62
|
run: |
|
|
46
63
|
jq '{ actors: (.functionallyChangedActors + .cosmeticallyChangedActors) }' affected.json \
|
|
47
64
|
| node "${{ steps.setup.outputs.scripts-path }}/run-with-apify-tokens.mjs" \
|
|
@@ -56,7 +73,7 @@ jobs:
|
|
|
56
73
|
|
|
57
74
|
- name: Delete old builds
|
|
58
75
|
env:
|
|
59
|
-
|
|
76
|
+
WORKFLOW_SECRETS: ${{ toJSON(secrets) }}
|
|
60
77
|
run: |
|
|
61
78
|
node "${{ steps.setup.outputs.scripts-path }}/run-with-apify-tokens.mjs" \
|
|
62
79
|
apify-test-tools delete-old-builds
|
package/CHANGELOG.md
CHANGED
|
@@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file.
|
|
|
13
13
|
- **get-affected-actors:** Three-dot diff, narrowed per Actor with --since ([#204](https://github.com/apify/apify-test-tools/pull/204)) ([fa9a0e7](https://github.com/apify/apify-test-tools/commit/fa9a0e7518764dd4722ec9ecbf67b2a26a5a062e)) by [@metalwarrior665](https://github.com/metalwarrior665)
|
|
14
14
|
- Add effort input to Claude investigate-and-fix workflow ([#221](https://github.com/apify/apify-test-tools/pull/221)) ([c2ac078](https://github.com/apify/apify-test-tools/commit/c2ac078aec9ef02337af0e5c06db1b947b6c969b)) by [@foxt451](https://github.com/foxt451)
|
|
15
15
|
- **ci:** Support pnpm ([#214](https://github.com/apify/apify-test-tools/pull/214)) ([ee7d734](https://github.com/apify/apify-test-tools/commit/ee7d7340564c5b8657a8a1f0cf920d67b40ae013)) by [@ruocco-l](https://github.com/ruocco-l)
|
|
16
|
+
- Support flexible secret passing methods in workflows ([#225](https://github.com/apify/apify-test-tools/pull/225)) ([22f7e80](https://github.com/apify/apify-test-tools/commit/22f7e807ca3949656c15b79f848a192d71b15946)) by [@metalwarrior665](https://github.com/metalwarrior665), closes [#205](https://github.com/apify/apify-test-tools/issues/205)
|
|
16
17
|
|
|
17
18
|
### π Bug Fixes
|
|
18
19
|
|
package/CONTRIBUTING.md
CHANGED
|
@@ -56,6 +56,8 @@ npx tsx /path/to/apify-test-tools/bin/main.ts --help
|
|
|
56
56
|
npx tsx /path/to/apify-test-tools/bin/main.ts get-commits --target-branch master --source-branch feat/testing-feature-branch
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
Or clone a test repo into `local-clone/` inside this repo and run `npm run start:dev -- <command>`.
|
|
60
|
+
|
|
59
61
|
#### Working on the library
|
|
60
62
|
|
|
61
63
|
You need to istall the local version of `apify-test-tools` in your cloned `testing-repo-for-github-actions`:
|
|
@@ -85,15 +87,8 @@ The tag is not semver, so `git-cliff` would abort on it. It is skipped only beca
|
|
|
85
87
|
The action's "Nothing to release" guard resolves to this tag and no longer fires, so an empty stable
|
|
86
88
|
release fails at `npm publish` instead of erroring cleanly.
|
|
87
89
|
|
|
88
|
-
Consumers pin `@workflows-v0`, not `@master`. See
|
|
89
|
-
[Versioning and releases](./README.md#versioning-and-releases) in the README for how the tag and the
|
|
90
|
-
npm release relate β the short version:
|
|
90
|
+
Consumers pin `@workflows-v0`, not `@master`. See [Versioning and releases](#versioning-and-releases) below.
|
|
91
91
|
|
|
92
|
-
- the workflows and the CLI ship together on every master push, through the tag; no npm release needed
|
|
93
|
-
- the lib ships through a stable npm release
|
|
94
|
-
- the CLI runs from `.github/cli/apify-test-tools.mjs`, a bundle the pre-commit hook rebuilds with
|
|
95
|
-
`npm run bundle`. If you commit with `--no-verify`, run it yourself: the `CLI bundle` check fails
|
|
96
|
-
on a stale bundle, and a stale bundle would hold the tag.
|
|
97
92
|
- `npm test` covers the bundle without network (`test/bundle/`). `npm run test:e2e` runs it against
|
|
98
93
|
dummy Actors in an isolated sandbox account (`test/e2e/`) and skips itself unless
|
|
99
94
|
`E2E_TEST_APIFY_TOKEN_DBYPODOIHUZABNQTR` is set. CI passes that secret only to the `E2E tests` job.
|
|
@@ -108,3 +103,99 @@ pushing workflow changes.
|
|
|
108
103
|
reusable workflow runs with the caller's repo checked out and never gets its own. Its `prompt-ref`
|
|
109
104
|
input defaults to `workflows-v0` so the instructions come from the same release as the workflow β leaving it
|
|
110
105
|
at `master` would run released workflows against unreleased instructions.
|
|
106
|
+
|
|
107
|
+
## Versioning and releases
|
|
108
|
+
|
|
109
|
+
The workflows and the npm package live in one repo but ship on their own schedules:
|
|
110
|
+
|
|
111
|
+
| What | Consumers get it through | Ships when |
|
|
112
|
+
| -------------------------------------------- | ------------------------------------------ | ----------------------- |
|
|
113
|
+
| the workflows and the CLI they call | the `@workflows-v0` tag in `uses:` | every master push |
|
|
114
|
+
| the lib (`testActor`, `describe`, matchersβ¦) | `apify-test-tools` in their `package.json` | a stable release on npm |
|
|
115
|
+
|
|
116
|
+
The CLI is bundled with its dependencies into `.github/cli/apify-test-tools.mjs` (`npm run bundle`, run by the
|
|
117
|
+
pre-commit hook and checked in CI), and the setup action runs it from there. Nothing is installed for it, so a tag is
|
|
118
|
+
a complete statement: these workflows and this CLI, with the exact dependency versions from `package-lock.json` at
|
|
119
|
+
that commit. The consumer's own `node_modules` is left alone, so their tests keep the lib version they locked.
|
|
120
|
+
|
|
121
|
+
- **Workflow or CLI change** β merge it. `workflows-v0` moves once checks and tests pass, and it goes live. No
|
|
122
|
+
release needed, even when a workflow starts using a new CLI feature: both are in the same commit.
|
|
123
|
+
- **Lib change** β merge it, then cut a release when you want it out. Consumers pick it up when they update
|
|
124
|
+
`apify-test-tools`.
|
|
125
|
+
|
|
126
|
+
The CLI and the lib in one job can be different versions now, so the formats between them are a contract: the
|
|
127
|
+
`ACTOR_BUILDS` JSON that `build` writes and the lib reads, and the vitest JSON report `report-tests` reads. Add
|
|
128
|
+
fields freely; renaming or removing one needs a new major tag.
|
|
129
|
+
|
|
130
|
+
`workflows-v0` moving on every master push means `@workflows-v0` is as live as `@master` was β there's no staging
|
|
131
|
+
step. What the tag buys you is a `workflows-v1` for breaking workflow changes, so repos migrate one at a time instead
|
|
132
|
+
of all at once, and a way to roll back by pointing the tag at an earlier commit (**Move major version tag**
|
|
133
|
+
workflow). Bump `MAJOR_TAG` in `.github/workflows/_move_major_tag.yaml` to cut the next major; the old tag then
|
|
134
|
+
freezes where it is and keeps working, CLI included, since the bundle is part of the frozen commit.
|
|
135
|
+
|
|
136
|
+
The tag tracks the **workflows'** contract, not the npm package version. They move independently on purpose, so
|
|
137
|
+
`@workflows-v0` is expected to stay `@workflows-v0` after the package reaches 1.0 β bump it when a workflow breaks
|
|
138
|
+
its callers, not when the package does. Because `uses:` cannot take an expression, every ref into this repo repeats
|
|
139
|
+
the tag literally; `check-major-tag-refs.mjs` fails the build if `MAJOR_TAG` and those refs disagree, which is the
|
|
140
|
+
mistake that would otherwise ship silently during a bump.
|
|
141
|
+
|
|
142
|
+
## Testing workflow changes
|
|
143
|
+
|
|
144
|
+
- Point [testing-repo-for-github-actions](https://github.com/apify-store/testing-repo-for-github-actions) at your
|
|
145
|
+
branch (`uses: ...@your-branch`). It has real attached Actors and tests. The branch carries its own CLI bundle, so
|
|
146
|
+
one branch tests the workflows and the CLI together.
|
|
147
|
+
- To change the composite action itself, repoint the `uses:` refs inside the reusable workflows at your branch as
|
|
148
|
+
well, and change them back before merging.
|
|
149
|
+
- Make sure the shell code actually works on your laptop first.
|
|
150
|
+
- After merging, watch the workflow on a real project before moving on.
|
|
151
|
+
|
|
152
|
+
## How the workflows scope secrets
|
|
153
|
+
|
|
154
|
+
The public side of this is the [Secrets](./docs/workflows.md#secrets) table.
|
|
155
|
+
|
|
156
|
+
The Actor tokens are the one set that cannot be listed in the workflow, because each Actor names its own token via
|
|
157
|
+
`tokenEnvVar` in `apify-test-tools.config.json`, and a reusable workflow only accepts secrets it declares by name.
|
|
158
|
+
Callers pack them into the `CONFIG_SECRETS` secret. Those steps pass `${{ toJSON(secrets) }}` as `WORKFLOW_SECRETS`
|
|
159
|
+
and run the command through `.github/scripts/run-with-apify-tokens.mjs`, which reads that same config file to decide
|
|
160
|
+
which secrets to pass on. It looks each one up in `CONFIG_SECRETS` first, then among the secrets `secrets: inherit`
|
|
161
|
+
brought:
|
|
162
|
+
|
|
163
|
+
```yaml
|
|
164
|
+
- name: Build
|
|
165
|
+
shell: bash
|
|
166
|
+
env:
|
|
167
|
+
WORKFLOW_SECRETS: ${{ toJSON(secrets) }}
|
|
168
|
+
run: |
|
|
169
|
+
jq '{ actors: .functionallyChangedActors }' affected.json \
|
|
170
|
+
| node "${{ steps.setup.outputs.scripts-path }}/run-with-apify-tokens.mjs" \
|
|
171
|
+
apify-test-tools build --version-number 0.99
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The wrapper passes only the tokens the config declares and drops `WORKFLOW_SECRETS`, so neither the CLI nor anything
|
|
175
|
+
under `node_modules` sees the blob. Nothing is written to `$GITHUB_ENV`, so the tokens stay inside that one command
|
|
176
|
+
rather than leaking into later steps. Reading the same file `apify-test-tools` reads means the two can't drift, and a
|
|
177
|
+
secret that merely looks like an Actor token is not passed just because of its name.
|
|
178
|
+
|
|
179
|
+
A token the config declares but the repo hasn't set is a warning, not a failure: a repo can carry an Actor whose
|
|
180
|
+
token isn't configured and still build fine as long as that Actor never changes, and `apify-test-tools` raises a
|
|
181
|
+
precise error naming the Actor at the point it actually needs the token.
|
|
182
|
+
|
|
183
|
+
The runner masks a secret by its exact value, so it only knows `CONFIG_SECRETS` as a whole blob. The setup action
|
|
184
|
+
runs `.github/scripts/mask-config-secrets.sh` first, which registers each value inside it with `::add-mask::`, so a
|
|
185
|
+
token taken out of the blob is masked too.
|
|
186
|
+
|
|
187
|
+
`scripts-path` comes from the setup action (give the step `id: setup`) and points at this repo's `.github/scripts/`
|
|
188
|
+
directory inside the runner's action checkout, so workflows can run these helpers without checking this repo out
|
|
189
|
+
again. The caller's workspace holds the caller's repo, not this one.
|
|
190
|
+
|
|
191
|
+
Two tidier-looking alternatives don't work, so don't reach for them:
|
|
192
|
+
|
|
193
|
+
- **Exporting to `$GITHUB_ENV`** would let the steps call the CLI directly with no wrapper, but `$GITHUB_ENV`
|
|
194
|
+
applies to every later step in the job. In `pr-build-test` the vitest step runs after the build, so it would
|
|
195
|
+
inherit Actor tokens it has no use for.
|
|
196
|
+
- **Returning the tokens as a step output** would be scoped correctly, but the runner refuses to set an output whose
|
|
197
|
+
value contains a registered secret. It logs `Skip output <name> since it may contain secret` and leaves the output
|
|
198
|
+
empty, so anything reading it downstream gets nothing.
|
|
199
|
+
|
|
200
|
+
The `unitTest` job runs static checks and needs `NPM_TOKEN` only. No job runs `npm ci` or `pnpm install` with Apify
|
|
201
|
+
or Slack credentials in scope, so a postinstall script in the dependency tree cannot read them.
|