/** * Shared zip utilities for solution packaging. * Uses fflate for in-process zip creation (no external zip CLI dependency). */ import type { IFileSystem } from "@uipath/filesystem"; /** * Directory names that are never part of a solution bundle. Skipped at walk * time so the bundle stays small and Studio Web doesn't receive * developer-local artifacts. * * .venv Python virtualenvs (per-agent under solution//.venv). * Each is hundreds of MB and contains binaries that won't * execute on the Studio Web side anyway. * node_modules Node dependency cache; same reasoning as .venv. * __pycache__ Python bytecode; regenerated on import. * .git VCS metadata; never belongs in an upload. * .local Studio's per-project NuGet restore cache. Studio Web * restores its own packages on import, so uploading this one * only costs bundle size and time. * * .flow-sdk The Maestro builder SDK's authoring work directory: the * `.flow.ts` source, its author-side `bindings.json` and the * generated connector modules. Studio Web reads none of them; * it gets the compiled `.flow` and `bindings_v2.json` beside * this folder. Excluded by name, not as "any dot-folder": * `.project` (IDE state) and `.agent-builder` (inline agents) * must still ship. * * Callers can extend this set per-walk via the `additionalExcludeDirs` option. * User-authored excludes come from `.uipignore` files and go through * `ignoreRules` instead (see {@link UipignoreRules}). */ export declare const DEFAULT_EXCLUDED_DIR_NAMES: ReadonlySet; /** * File-name patterns that are never part of a solution bundle. Skipped at walk * time so the bundle doesn't ship developer-local secrets to Studio Web. * * /^\.env($|\..+)/ Dotenv credential files: `.env`, `.env.local`, * `.env.production`, etc. These conventionally hold API * keys, database passwords, and OAuth client secrets and * must never leave the developer's machine. Does not * match `.envrc`, `.environment`, or `myenv.txt`. */ export declare const DEFAULT_EXCLUDED_FILE_PATTERNS: ReadonlyArray; /** True when `name` matches any of the default-excluded file patterns. */ export declare function isDefaultExcludedFileName(name: string): boolean; /** File name read by bundle-service to extend the default exclude set. */ export declare const UIPIGNORE_FILENAME = ".uipignore"; /** * Split a `.uipignore` file body into its patterns: one per line, skipping * blank lines and lines that start with `#`. Nothing else is interpreted here. * The patterns go to the `ignore` package as-is, so the syntax is plain * gitignore: globs (`*.log`), anchored paths (`/dist`, `src/generated/`), a * trailing `/` for directories only, `!` to re-include. `codedapp push` feeds * the same file to `ignore` raw, so the two commands read it identically. */ export declare function parseUipignore(body: string): string[]; /** * Parsed `.uipignore` patterns, matched against paths relative to `baseDir` * (the directory that holds the file). `ignores` takes a forward-slash path * relative to `baseDir`, with a trailing `/` for a directory. */ export interface UipignoreRules { baseDir: string; patterns: readonly string[]; ignores: (relativePath: string) => boolean; } /** Build matchable rules from `.uipignore` patterns rooted at `baseDir`. */ export declare function createUipignoreRules(baseDir: string, patterns: readonly string[]): UipignoreRules; /** * True when any of `rules` ignores `fullPath`. Each rule set only sees paths * under its own `baseDir`; paths outside it are never matched. */ export declare function isIgnoredByRules(fs: IFileSystem, rules: readonly UipignoreRules[] | undefined, fullPath: string, isDirectory: boolean): boolean; /** What {@link collectTree} skips on top of the built-in defaults. */ export interface CollectTreeOptions { /** Extra directory names to skip at any depth (caller-supplied). */ additionalExcludeDirs?: Iterable; /** Parsed `.uipignore` rules (gitignore syntax). */ ignoreRules?: readonly UipignoreRules[]; } /** * Recursively walk `dir`, returning every file path and every empty directory * path beneath it. An empty directory is a directory whose `readdir` returns * no entries; deeper empty chains are represented by their leaves only, since * fflate creates parent directory records implicitly when it sees `a/b/c/`. * * Skips DEFAULT_EXCLUDED_DIR_NAMES plus any `additionalExcludeDirs` the * caller provides. Directory exclusion is by exact directory name at any * depth. Files matching DEFAULT_EXCLUDED_FILE_PATTERNS (e.g. `.env`, * `.env.local`) are also skipped at any depth — they conventionally hold * credentials and must not be shipped in the bundle. Files and directories * matched by `ignoreRules` (parsed `.uipignore` files) are skipped as well. */ export declare function collectTree(fs: IFileSystem, dir: string, options?: CollectTreeOptions): Promise<{ files: string[]; emptyDirs: string[]; }>; /** * Recursively collect all file paths under a directory. */ export declare function collectFiles(fs: IFileSystem, dir: string, options?: CollectTreeOptions): Promise; /** * Collect all files (and empty directories) under `dir` and zip them using * fflate. Empty directories are written as standard zip directory records * (path keys ending with `/` mapped to a zero-length buffer) so they survive * the round-trip to Studio Web. * * Returns the zip as a Uint8Array. */ export declare function createZipFromDir(fs: IFileSystem, dir: string, options?: CollectTreeOptions): Promise; /** * Give an archive a zip64 tail once it holds more entries than the classic * end-of-central-directory record can count. * * fflate writes zip32 only. Its EOCD entry count is a 16-bit field, and its * byte writer stops at the first zero byte rather than clamping to the field * width, so an archive of 65,536 entries reports 0 and one of 70,000 reports * 4,464 - with no error raised. Readers that trust the count (fflate's own * `unzipSync` bails at `if (!c) return {}`; .NET's `ZipArchive` throws when the * walked central directory disagrees with it) then see an empty or corrupt * archive. That is how a solution bundle large enough to cross the ceiling * reaches Studio Web's import as "the project archive is corrupt or the * compression isn't supported" - a valid-looking file that strict readers * refuse. * * The fix is the one zip64 prescribes for a count-only overflow: keep the * central directory exactly as written, saturate the classic EOCD's count * fields, and put the true counts in a zip64 EOCD record plus its locator. Per- * entry zip64 extra fields are not involved, because no individual entry's size * or offset overflows here. * * @param zip - Archive as fflate produced it. * @returns The same archive, with a zip64 tail when one is needed. */ export declare function finalizeZip64(zip: Uint8Array): Uint8Array;