/** * Company-vault object-transport selection, in one neutral module. * * Every caller that pushes or pulls a COMPANY vault (`cmp_*`) — the long-running * `hq-sync-runner`, AND the one-shot `share()` / `sync()` paths that hq-cli and * standalone `hq sync` drive — must make the same transport decision before it * resolves an entity context: company vaults use the presigned-URL transport, so * `resolveEntityContext` skips `POST /sts/vend` for them (HQ-59). This module is * the single home for that decision. * * It lives at the top of `src/` rather than under `src/bin/` on purpose: * `src/bin/sync-runner.ts` already imports `src/cli/share.ts`, so if `share.ts` * reached back into `sync-runner.ts` for the selection it would form an import * cycle. A neutral module both sides depend on avoids that. */ import { type ContextRefresherFactory, type ObjectIOFactory, type PresignTransportClient } from "./object-io.js"; import type { VaultServiceConfig } from "./types.js"; /** * Resolve the object-transport factory for this sync session. * * Company vaults (`cmp_*`) ALWAYS use the presigned-URL transport: the client * holds no raw AWS credentials (it fetches short-lived signed URLs) and every * read/write is authorized server-side per-file, so it never hits the 2048-char * STS session-policy ceiling that produced the HQ-59 lockout. The STS-direct-S3 * (`S3SdkObjectIO`) path for company vaults is RETIRED — there is no env * override or rollback lever that can route a company vault back to direct S3. * Personal vaults (`prs_*`) KEEP the direct-S3/STS path: the membership-gated * `list`/`presign` endpoints 403 for the membership-less vend-self model, and a * single-owner personal vault has no ACL-scale problem. That cmp_/prs_ split * lives inside {@link presignObjectIOFactory}. * * Returns `null` only when the client predates the presign methods (never in a * shipped build); the caller then resets to the SDK default factory. */ export declare function selectObjectIOFactory(client: Partial, refresherFor?: ContextRefresherFactory, forceRefresherFor?: ContextRefresherFactory): ObjectIOFactory | null; /** * Install the company-vault object transport for a caller and record the choice * on `vaultConfig.companyVaultUsesPresign`. * * This is the single supported way to select the company-vault transport. It * keeps two things that must always agree derived from ONE value: the installed * `ObjectIO` factory (how bytes move) and the `companyVaultUsesPresign` flag * (whether `resolveEntityContext` skips the `cmp_` STS vend). A presign-capable * client installs `PresignObjectIO` for `cmp_` and sets the flag `true`; a * pre-presign client installs the refresher-aware S3 factory and sets it * `false`, so company vaults keep vending. They can never disagree because both * come from the same `selectObjectIOFactory` result. * * The flag is also the record that a decision has already been made. The * sync-runner sets it — `true` or an explicit `false` — on the SAME * `vaultConfig` object reference it later hands down to `share()` / `sync()`, so * re-entry through those one-shot paths must be a strict no-op: it must not * override the runner's decision or install a second factory over the runner's. * `undefined` is therefore the only "decide now" signal, and it is exactly the * state a one-shot hq-cli caller (which never ran the runner's selection) * arrives in — which is the defect this closes (Sentry hq-cli 7711917661): the * one-shot company push kept vending STS write creds and aborted on the * `POLICY_WRITE_SCOPE_TRUNCATED` 422 instead of using presign. * * @param deps.createClient Inject the presign-capable client. The sync-runner * passes its already-built `VaultClient` so no second client is created; * tests stub it. Defaults to `new VaultClient(vaultConfig)`. */ export declare function ensureCompanyVaultTransport(vaultConfig: VaultServiceConfig, deps?: { createClient?: (config: VaultServiceConfig) => Partial; }): void; //# sourceMappingURL=company-vault-transport.d.ts.map