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.
Files changed (30) hide show
  1. package/.github/actions/checkout-restore-dependencies/action.yaml +13 -0
  2. package/.github/cli/apify-test-tools.mjs +1 -1
  3. package/.github/scripts/check-major-tag-refs.mjs +1 -1
  4. package/.github/scripts/mask-config-secrets.sh +17 -0
  5. package/.github/scripts/run-with-apify-tokens.mjs +36 -11
  6. package/.github/workflows/public_platform-tests-claude-investigate-and-fix.yaml +6 -2
  7. package/.github/workflows/public_platform-tests.yaml +23 -0
  8. package/.github/workflows/public_pr-build-test.yaml +30 -1
  9. package/.github/workflows/public_push-build-latest.yaml +20 -3
  10. package/CHANGELOG.md +1 -0
  11. package/CONTRIBUTING.md +99 -8
  12. package/README.md +218 -699
  13. package/bin/git.ts +1 -1
  14. package/dist/bin/git.js +1 -1
  15. package/dist/bin/git.js.map +1 -1
  16. package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts +2 -0
  17. package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts.map +1 -0
  18. package/dist/test/unit/github-scripts/mask-config-secrets.test.js +50 -0
  19. package/dist/test/unit/github-scripts/mask-config-secrets.test.js.map +1 -0
  20. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts +2 -0
  21. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts.map +1 -0
  22. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js +102 -0
  23. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js.map +1 -0
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/docs/cli.md +358 -0
  26. package/docs/lib.md +271 -0
  27. package/docs/workflows.md +366 -0
  28. package/package.json +1 -1
  29. package/test/unit/github-scripts/mask-config-secrets.test.ts +61 -0
  30. 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 README section "Releasing Actors".');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(`
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 ALL_SECRETS. The token names come from `tokenEnvVar` in
7
- // the repo's apify-test-tools.config.json, which is the same file apify-test-tools itself reads, so
8
- // the two can't drift. Everything else in the secrets map (npm, Slack, GitHub, anything else the
9
- // repo holds) is left out, and ALL_SECRETS itself is dropped, so the blob never reaches the CLI or
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 { ALL_SECRETS, ...baseEnv } = process.env;
32
- if (!ALL_SECRETS) fail('ALL_SECRETS is not set. Add `ALL_SECRETS: ${{ toJSON(secrets) }}` to the step env.');
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 secrets;
40
+ let workflowSecrets;
35
41
  try {
36
- secrets = JSON.parse(ALL_SECRETS);
42
+ workflowSecrets = JSON.parse(WORKFLOW_SECRETS);
37
43
  } catch (error) {
38
- fail(`ALL_SECRETS is not valid JSON: ${error.message}`);
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 if a build fails on a missing token.`,
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: inherit
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: inherit
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
- ALL_SECRETS: ${{ toJSON(secrets) }}
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 the README.
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
- ALL_SECRETS: ${{ toJSON(secrets) }}
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
- ALL_SECRETS: ${{ toJSON(secrets) }}
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.