@gigadrive/sdk 0.8.6 → 0.9.1

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/auth/credential-provider.ts","../src/auth/token-manager.ts","../src/http-client.ts","../src/streaming.ts","../src/resources/base-resource.ts","../src/resources/ai-gateway/index.ts","../src/resources/api-keys.ts","../src/resources/application-env-vars.ts","../src/resources/application-requests.ts","../src/upload/checksum.ts","../src/upload/content-type.ts","../src/upload/source.ts","../src/upload/transport.ts","../src/resources/storage-context.ts","../src/resources/storage-buckets.ts","../src/resources/storage-objects.ts","../src/resources/storage-trash.ts","../src/resources/storage-upload-sessions.ts","../src/resources/application-storage.ts","../src/resources/applications.ts","../src/resources/deployments.ts","../src/resources/image-optimization.ts","../src/resources/organization-ai-gateway.ts","../src/resources/organization-env-vars.ts","../src/resources/organization-members.ts","../src/resources/organization-products.ts","../src/resources/organizations.ts","../src/resources/sticky-sessions.ts","../src/client.ts","../src/pagination.ts"],"sourcesContent":["/**\n * Base error class for all Gigadrive SDK errors. Every error thrown by the SDK\n * extends this class, so you can catch all SDK errors with a single check.\n *\n * @example\n * ```ts\n * try {\n * await client.organizations.list();\n * } catch (err) {\n * if (err instanceof GigadriveError) {\n * console.error('SDK error:', err.message);\n * }\n * }\n * ```\n */\nexport class GigadriveError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'GigadriveError';\n }\n}\n\n/**\n * Thrown when authentication fails. This includes missing or invalid credentials,\n * expired tokens, failed token refresh attempts, and failed token exchanges.\n *\n * Common causes:\n * - No credentials provided and no environment variables set\n * - Invalid `clientId`/`clientSecret` pair\n * - Expired or revoked refresh token\n * - API returned 401 even after an automatic token refresh retry\n *\n * @example\n * ```ts\n * try {\n * const client = new GigadriveClient(); // no credentials\n * } catch (err) {\n * if (err instanceof AuthenticationError) {\n * console.error('Auth failed:', err.message);\n * }\n * }\n * ```\n */\nexport class AuthenticationError extends GigadriveError {\n constructor(message: string) {\n super(message);\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Thrown when an SDK operation requires local configuration that could not be\n * resolved before making an API request.\n *\n * Storage operations use this error when neither an explicit application ID,\n * `GigadriveClientConfig.applicationId`, nor the workload-provided\n * `GIGADRIVE_APPLICATION_ID` environment variable is available.\n */\nexport class ConfigurationError extends GigadriveError {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigurationError';\n }\n}\n\n/**\n * Thrown when the Gigadrive API returns a non-2xx HTTP response.\n *\n * Contains the HTTP {@link status} code and an optional machine-readable\n * {@link code} parsed from the response body.\n *\n * @example\n * ```ts\n * try {\n * await client.deployments.get('non-existent-id');\n * } catch (err) {\n * if (err instanceof ApiError) {\n * console.error(`API error ${err.status}: ${err.message}`);\n * // err.code may contain a machine-readable error code\n * }\n * }\n * ```\n */\nexport class ApiError extends GigadriveError {\n /** The HTTP status code of the failed response (e.g. 404, 500). */\n readonly status: number;\n /** An optional machine-readable error code from the API response body. */\n readonly code: string | undefined;\n\n constructor(message: string, status: number, code?: string) {\n super(message);\n this.name = 'ApiError';\n this.status = status;\n this.code = code;\n }\n}\n\n/**\n * Thrown when a file upload fails. The original cause (e.g. a network error or a\n * transport-level error from the resumable upload) is preserved on\n * {@link cause} for inspection.\n *\n * @example\n * ```ts\n * try {\n * await client.storage.upload({ bucket: 'assets', key, data });\n * } catch (err) {\n * if (err instanceof UploadError) {\n * console.error('Upload failed:', err.message, err.cause);\n * }\n * }\n * ```\n */\nexport class UploadError extends GigadriveError {\n /** The underlying error that caused the upload to fail, if any. */\n override readonly cause: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'UploadError';\n this.cause = cause;\n }\n}\n\n/**\n * Thrown when an upload cannot complete because its session (and the short-lived\n * upload URL it was issued with) expired. Create a new upload to retry.\n *\n * The upload URL is only valid until `session.expiresAt`; very large uploads on\n * slow connections can exceed that window.\n */\nexport class UploadSessionExpiredError extends UploadError {\n constructor(\n message = 'The upload session expired before the upload completed. Start a new upload to retry.',\n cause?: unknown\n ) {\n super(message, cause);\n this.name = 'UploadSessionExpiredError';\n }\n}\n","import { AuthenticationError } from '../errors';\n\nconst DEFAULT_SCOPE = 'offline_access openid profile email';\nconst TOKEN_EXPIRY_MARGIN_SECONDS = 30;\n\n/**\n * Compute the absolute expiry (epoch ms) for a token, applying a safety margin\n * so the SDK refreshes proactively. The margin is clamped to never exceed half\n * the token lifetime, so very short-lived tokens are not treated as already\n * expired (which would refresh on every request).\n */\nconst computeExpiresAt = (expiresInSeconds: number | undefined): number => {\n const ttl = expiresInSeconds ?? 3600;\n const margin = Math.min(TOKEN_EXPIRY_MARGIN_SECONDS, ttl / 2);\n return Date.now() + (ttl - margin) * 1000;\n};\n\n/**\n * Read an environment variable safely. Returns `undefined` when `process` is\n * unavailable (e.g. browsers / some edge runtimes) instead of throwing.\n *\n * @internal\n */\nexport const readEnv = (name: string): string | undefined => {\n if (typeof process === 'undefined' || !process.env) return undefined;\n return process.env[name];\n};\n\ninterface RawTokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n}\n\n/**\n * Validate and normalize a token-endpoint JSON response, guarding against\n * malformed payloads that would otherwise yield `Authorization: Bearer undefined`.\n */\nconst parseTokenResponse = (payload: unknown): RawTokenResponse => {\n const data = payload as { access_token?: unknown; refresh_token?: unknown; expires_in?: unknown };\n if (typeof data.access_token !== 'string' || data.access_token.length === 0) {\n throw new AuthenticationError('Token endpoint returned no access_token');\n }\n return {\n access_token: data.access_token,\n refresh_token: typeof data.refresh_token === 'string' ? data.refresh_token : undefined,\n expires_in: typeof data.expires_in === 'number' ? data.expires_in : undefined,\n };\n};\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** The result of a credential provider's token fetch. */\nexport interface TokenResult {\n /** The access token to use in API requests. */\n accessToken: string;\n /** Epoch milliseconds when the token expires, or `null` for tokens that never expire (e.g. static bearer tokens). */\n expiresAt: number | null;\n /** A refresh token for obtaining new access tokens, if the provider supports token rotation. */\n refreshToken?: string;\n}\n\n/**\n * A strategy for obtaining access tokens. The SDK ships with four built-in\n * providers (see {@link resolveCredentialProvider} for automatic selection),\n * but you can implement this interface for custom auth flows.\n */\nexport interface CredentialProvider {\n /** A string identifying the provider type (e.g. `\"oauth2-client-credentials\"`, `\"bearer\"`). */\n readonly type: string;\n /** Fetch a new access token. May perform network requests (e.g. OAuth2 token exchange). */\n getToken(): Promise<TokenResult>;\n}\n\ninterface OidcDiscoveryDocument {\n token_endpoint?: string;\n authorization_endpoint?: string;\n userinfo_endpoint?: string;\n}\n\n// ---------------------------------------------------------------------------\n// OIDC Discovery\n// ---------------------------------------------------------------------------\n\nconst discoverOidc = async (issuerUrl: string, fetchFn: typeof globalThis.fetch): Promise<OidcDiscoveryDocument> => {\n const discoveryUrl = `${issuerUrl.replace(/\\/$/, '')}/.well-known/openid-configuration`;\n const response = await fetchFn(discoveryUrl);\n\n if (!response.ok) {\n throw new AuthenticationError(`OIDC discovery failed: ${response.status} ${response.statusText}`);\n }\n\n return (await response.json()) as OidcDiscoveryDocument;\n};\n\n// ---------------------------------------------------------------------------\n// PKCE helpers\n// ---------------------------------------------------------------------------\n\nconst base64UrlEncode = (buffer: Uint8Array): string => {\n let binary = '';\n for (let i = 0; i < buffer.byteLength; i++) {\n binary += String.fromCharCode(buffer[i]);\n }\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n};\n\nconst generatePkce = async (): Promise<{ codeVerifier: string; codeChallenge: string }> => {\n const randomBytes = new Uint8Array(64);\n crypto.getRandomValues(randomBytes);\n const codeVerifier = base64UrlEncode(randomBytes);\n\n const encoder = new TextEncoder();\n const data = encoder.encode(codeVerifier);\n const digest = await crypto.subtle.digest('SHA-256', data);\n const codeChallenge = base64UrlEncode(new Uint8Array(digest));\n\n return { codeVerifier, codeChallenge };\n};\n\nconst generateState = (): string => {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n};\n\n// ---------------------------------------------------------------------------\n// OAuth2 Client Credentials Provider (Network API keys)\n// ---------------------------------------------------------------------------\n\n/**\n * Authenticates using the OAuth2 client credentials grant. Exchanges an\n * API key (client ID + secret) for a short-lived access token via the\n * Gigadrive Network token endpoint.\n *\n * Tokens are valid for 5 minutes. A 30-second safety margin is applied so\n * the SDK refreshes proactively before the token actually expires.\n *\n * This is the most common provider for server-to-server (machine-to-machine)\n * use cases.\n */\nexport class OAuth2ClientCredentialProvider implements CredentialProvider {\n readonly type = 'oauth2-client-credentials';\n\n constructor(\n private readonly clientId: string,\n private readonly clientSecret: string,\n private readonly tokenUrl: string,\n private readonly fetchFn: typeof globalThis.fetch\n ) {}\n\n async getToken(): Promise<TokenResult> {\n const credentials = btoa(`${this.clientId}:${this.clientSecret}`);\n\n const response = await this.fetchFn(this.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Basic ${credentials}`,\n },\n body: new URLSearchParams({ grant_type: 'client_credentials' }).toString(),\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n throw new AuthenticationError(`OAuth2 token request failed (${response.status}): ${body}`);\n }\n\n const data = parseTokenResponse(await response.json());\n\n return {\n accessToken: data.access_token,\n expiresAt: computeExpiresAt(data.expires_in),\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// OAuth2 Authorization Code Provider (IDP, PKCE, no local server)\n// ---------------------------------------------------------------------------\n\n/**\n * Authenticates using the OAuth2 authorization code grant with PKCE. This\n * provider is designed for interactive flows where a user authorizes the\n * application via a browser.\n *\n * The SDK generates the PKCE challenge, builds the authorization URL, and\n * passes it to your `onAuthorizationUrl` callback. Your callback is\n * responsible for presenting the URL to the user and returning the result\n * (either the full redirect URL or just the authorization code).\n *\n * The provider performs OIDC discovery to locate the authorization and token\n * endpoints automatically.\n */\nexport class OAuth2AuthorizationCodeProvider implements CredentialProvider {\n readonly type = 'oauth2-authorization-code';\n private currentRefreshToken: string | null = null;\n\n constructor(\n private readonly clientId: string,\n private readonly issuerUrl: string,\n private readonly redirectUri: string,\n private readonly onAuthorizationUrl: (url: string) => Promise<string>,\n private readonly fetchFn: typeof globalThis.fetch,\n private readonly scope: string = DEFAULT_SCOPE\n ) {}\n\n async getToken(): Promise<TokenResult> {\n const oidc = await discoverOidc(this.issuerUrl, this.fetchFn);\n\n if (!oidc.token_endpoint) {\n throw new AuthenticationError('OIDC discovery returned no token endpoint');\n }\n\n // After the first interactive exchange, refresh silently rather than\n // re-prompting the user. Only fall back to a fresh authorization when the\n // refresh token is actually rejected — transient errors are surfaced.\n if (this.currentRefreshToken) {\n const refreshed = await this.tryRefresh(oidc.token_endpoint, this.currentRefreshToken);\n if (refreshed) return refreshed;\n this.currentRefreshToken = null;\n }\n\n if (!oidc.authorization_endpoint) {\n throw new AuthenticationError('OIDC discovery returned incomplete endpoints');\n }\n\n const { codeVerifier, codeChallenge } = await generatePkce();\n const state = generateState();\n\n const authUrl = new URL(oidc.authorization_endpoint);\n authUrl.searchParams.set('client_id', this.clientId);\n authUrl.searchParams.set('redirect_uri', this.redirectUri);\n authUrl.searchParams.set('response_type', 'code');\n authUrl.searchParams.set('scope', this.scope);\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n authUrl.searchParams.set('state', state);\n\n const result = await this.onAuthorizationUrl(authUrl.toString());\n\n // Extract the authorization code — accept either a full URL or just the code\n let code: string;\n let returnedState: string | null = null;\n\n try {\n const callbackUrl = new URL(result);\n code = callbackUrl.searchParams.get('code') ?? '';\n returnedState = callbackUrl.searchParams.get('state');\n\n const error = callbackUrl.searchParams.get('error');\n if (error) {\n const description = callbackUrl.searchParams.get('error_description') ?? error;\n throw new AuthenticationError(`Authorization failed: ${description}`);\n }\n } catch (e) {\n if (e instanceof AuthenticationError) throw e;\n // Not a valid URL — treat the entire result as the code\n code = result;\n }\n\n if (!code) {\n throw new AuthenticationError('No authorization code received');\n }\n\n if (returnedState !== null && returnedState !== state) {\n throw new AuthenticationError('State mismatch — possible CSRF attack');\n }\n\n // Exchange code for tokens\n const response = await this.fetchFn(oidc.token_endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: this.clientId,\n code,\n redirect_uri: this.redirectUri,\n code_verifier: codeVerifier,\n }).toString(),\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n throw new AuthenticationError(`Token exchange failed (${response.status}): ${body}`);\n }\n\n const data = parseTokenResponse(await response.json());\n\n this.currentRefreshToken = data.refresh_token ?? null;\n\n return {\n accessToken: data.access_token,\n expiresAt: computeExpiresAt(data.expires_in),\n refreshToken: data.refresh_token,\n };\n }\n\n /**\n * Try to exchange the stored refresh token for a new access token. Returns the\n * token on success, `null` when the refresh token is definitively rejected\n * (a 4xx — caller should re-authenticate), and throws on transient failures.\n */\n private async tryRefresh(tokenEndpoint: string, refreshToken: string): Promise<TokenResult | null> {\n const response = await this.fetchFn(tokenEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.clientId,\n refresh_token: refreshToken,\n }).toString(),\n });\n\n if (!response.ok) {\n // A 4xx means the refresh token is invalid/expired — re-authenticate.\n if (response.status >= 400 && response.status < 500) return null;\n // Transient (network/5xx) failures surface instead of forcing a re-prompt.\n const body = await response.text().catch(() => '');\n throw new AuthenticationError(`Token refresh failed (${response.status}): ${body}`);\n }\n\n const data = parseTokenResponse(await response.json());\n\n if (data.refresh_token) {\n this.currentRefreshToken = data.refresh_token;\n }\n\n return {\n accessToken: data.access_token,\n expiresAt: computeExpiresAt(data.expires_in),\n refreshToken: data.refresh_token ?? this.currentRefreshToken ?? undefined,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// OAuth2 Refresh Token Provider (IDP)\n// ---------------------------------------------------------------------------\n\n/**\n * Authenticates using an IDP refresh token. Exchanges the refresh token for\n * a short-lived access token via the IDP's token endpoint (discovered via\n * OIDC). Handles refresh-token rotation automatically — if the IDP issues\n * a new refresh token, it is stored internally for subsequent refreshes.\n *\n * This provider is typically used when a user has previously logged in\n * (e.g. via the CLI) and you have a stored refresh token.\n */\nexport class OAuth2RefreshTokenProvider implements CredentialProvider {\n readonly type = 'oauth2-refresh-token';\n private currentRefreshToken: string;\n\n constructor(\n private readonly clientId: string,\n refreshToken: string,\n private readonly issuerUrl: string,\n private readonly fetchFn: typeof globalThis.fetch\n ) {\n this.currentRefreshToken = refreshToken;\n }\n\n async getToken(): Promise<TokenResult> {\n const oidc = await discoverOidc(this.issuerUrl, this.fetchFn);\n\n if (!oidc.token_endpoint) {\n throw new AuthenticationError('OIDC discovery returned no token endpoint');\n }\n\n const response = await this.fetchFn(oidc.token_endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.clientId,\n refresh_token: this.currentRefreshToken,\n }).toString(),\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n if (response.status === 400) {\n throw new AuthenticationError('Refresh token is invalid or expired. Please re-authenticate.');\n }\n throw new AuthenticationError(`Token refresh failed (${response.status}): ${body}`);\n }\n\n const data = parseTokenResponse(await response.json());\n\n // Handle refresh token rotation\n if (data.refresh_token) {\n this.currentRefreshToken = data.refresh_token;\n }\n\n return {\n accessToken: data.access_token,\n expiresAt: computeExpiresAt(data.expires_in),\n refreshToken: data.refresh_token ?? this.currentRefreshToken,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Bearer Token Provider (static)\n// ---------------------------------------------------------------------------\n\n/**\n * Uses a static, pre-obtained bearer token. The token is never refreshed —\n * if it expires, API requests will fail with an {@link AuthenticationError}.\n *\n * This is the simplest provider and is used when the caller already has a\n * valid access token (e.g. from an external auth flow or a long-lived token).\n */\nexport class BearerTokenProvider implements CredentialProvider {\n readonly type = 'bearer';\n\n constructor(private readonly token: string) {}\n\n getToken(): Promise<TokenResult> {\n return Promise.resolve({ accessToken: this.token, expiresAt: null });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Credential resolution\n// ---------------------------------------------------------------------------\n\nexport interface CredentialResolverConfig {\n clientId?: string;\n clientSecret?: string;\n bearerToken?: string;\n refreshToken?: string;\n idpIssuerUrl?: string;\n onAuthorizationUrl?: (url: string) => Promise<string>;\n redirectUri?: string;\n baseUrl?: string;\n fetch?: typeof globalThis.fetch;\n /** OAuth scopes to request in the authorization-code flow (in addition to identity scopes). */\n scopes?: string[];\n}\n\nconst DEFAULT_IDP_ISSUER_URL = 'https://idp.gigadrive.de';\nconst DEFAULT_BASE_URL = 'https://api.gigadrive.network';\n\n/**\n * Resolves a `CredentialProvider` from explicit config or environment variables.\n *\n * Resolution order:\n * 1. Explicit `bearerToken` → BearerTokenProvider\n * 2. Explicit `clientId` + `clientSecret` → OAuth2ClientCredentialProvider\n * 3. Explicit `refreshToken` + `clientId` → OAuth2RefreshTokenProvider\n * 4. Explicit `onAuthorizationUrl` + `clientId` → OAuth2AuthorizationCodeProvider\n * 5. `GIGADRIVE_BEARER_TOKEN` env var → BearerTokenProvider\n * 6. `GIGADRIVE_CLIENT_ID` + `GIGADRIVE_CLIENT_SECRET` → OAuth2ClientCredentialProvider\n * 7. `GIGADRIVE_REFRESH_TOKEN` + `GIGADRIVE_CLIENT_ID` → OAuth2RefreshTokenProvider\n * 8. Throws AuthenticationError\n */\nexport const resolveCredentialProvider = (config: CredentialResolverConfig): CredentialProvider => {\n // Bind the default fetch to globalThis so calling it as `this.fetchFn(...)`\n // does not throw \"Illegal invocation\" in runtimes that require a bound receiver.\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n const baseUrl = config.baseUrl ?? readEnv('GIGADRIVE_API_BASE_URL') ?? DEFAULT_BASE_URL;\n const idpIssuerUrl = config.idpIssuerUrl ?? readEnv('GIGADRIVE_IDP_ISSUER_URL') ?? DEFAULT_IDP_ISSUER_URL;\n const tokenUrl = `${baseUrl}/oauth2/token`;\n\n // 1. Explicit bearer token\n if (config.bearerToken) {\n return new BearerTokenProvider(config.bearerToken);\n }\n\n // 2. Explicit client credentials\n if (config.clientId && config.clientSecret) {\n return new OAuth2ClientCredentialProvider(config.clientId, config.clientSecret, tokenUrl, fetchFn);\n }\n\n // 3. Explicit refresh token\n if (config.refreshToken && config.clientId) {\n return new OAuth2RefreshTokenProvider(config.clientId, config.refreshToken, idpIssuerUrl, fetchFn);\n }\n\n // 4. Explicit authorization code callback\n if (config.onAuthorizationUrl && config.clientId) {\n const redirectUri = config.redirectUri ?? 'urn:ietf:wg:oauth:2.0:oob';\n const scope = config.scopes && config.scopes.length > 0 ? config.scopes.join(' ') : DEFAULT_SCOPE;\n return new OAuth2AuthorizationCodeProvider(\n config.clientId,\n idpIssuerUrl,\n redirectUri,\n config.onAuthorizationUrl,\n fetchFn,\n scope\n );\n }\n\n // 5. GIGADRIVE_BEARER_TOKEN env var\n const envBearerToken = readEnv('GIGADRIVE_BEARER_TOKEN');\n if (envBearerToken) {\n return new BearerTokenProvider(envBearerToken);\n }\n\n // 6. GIGADRIVE_CLIENT_ID + GIGADRIVE_CLIENT_SECRET env vars\n const envClientId = readEnv('GIGADRIVE_CLIENT_ID');\n const envClientSecret = readEnv('GIGADRIVE_CLIENT_SECRET');\n if (envClientId && envClientSecret) {\n return new OAuth2ClientCredentialProvider(envClientId, envClientSecret, tokenUrl, fetchFn);\n }\n\n // 7. GIGADRIVE_REFRESH_TOKEN + GIGADRIVE_CLIENT_ID env vars\n const envRefreshToken = readEnv('GIGADRIVE_REFRESH_TOKEN');\n if (envRefreshToken && envClientId) {\n return new OAuth2RefreshTokenProvider(envClientId, envRefreshToken, idpIssuerUrl, fetchFn);\n }\n\n // 8. No credentials found\n throw new AuthenticationError(\n 'No credentials provided. Set one of:\\n' +\n ' - GIGADRIVE_BEARER_TOKEN\\n' +\n ' - GIGADRIVE_CLIENT_ID + GIGADRIVE_CLIENT_SECRET\\n' +\n ' - GIGADRIVE_REFRESH_TOKEN + GIGADRIVE_CLIENT_ID\\n' +\n 'Or pass credentials directly to the GigadriveClient constructor.'\n );\n};\n","import type { CredentialProvider } from './credential-provider';\n\n/**\n * Manages the access-token lifecycle: caching, automatic expiry detection,\n * proactive refresh, and concurrent-call deduplication.\n *\n * When multiple API requests fire simultaneously with an expired token, only\n * a single refresh call is made — all concurrent callers await the same\n * pending Promise. This prevents a \"thundering herd\" of token requests.\n *\n * @internal Used internally by {@link HttpClient}. Not part of the public API.\n */\nexport class TokenManager {\n private cachedToken: string | null = null;\n private expiresAt: number | null = null;\n private pendingRefresh: Promise<string> | null = null;\n\n constructor(private readonly provider: CredentialProvider) {}\n\n /**\n * Returns a valid access token. Uses the cached token if still valid,\n * otherwise fetches a new one from the credential provider.\n *\n * Concurrent calls are deduplicated — only one refresh runs at a time.\n */\n async getToken(): Promise<string> {\n if (this.cachedToken && (this.expiresAt === null || Date.now() < this.expiresAt)) {\n return this.cachedToken;\n }\n\n // Deduplicate concurrent refresh calls\n if (this.pendingRefresh) {\n return this.pendingRefresh;\n }\n\n this.pendingRefresh = this.refresh();\n\n try {\n return await this.pendingRefresh;\n } finally {\n this.pendingRefresh = null;\n }\n }\n\n /**\n * Invalidates the cached token. The next `getToken()` call will trigger a refresh.\n */\n invalidate(): void {\n this.cachedToken = null;\n this.expiresAt = null;\n }\n\n private async refresh(): Promise<string> {\n const result = await this.provider.getToken();\n this.cachedToken = result.accessToken;\n this.expiresAt = result.expiresAt;\n return result.accessToken;\n }\n}\n","import type { TokenManager } from './auth/token-manager';\nimport { ApiError, AuthenticationError } from './errors';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * A paginated API response. List endpoints return this shape.\n *\n * @typeParam T - The type of each item in the list.\n */\nexport interface Paginated<T> {\n /** The items on the current page. */\n items: T[];\n /** The total number of items across all pages. */\n total: number;\n /** An opaque cursor for the next page, present on cursor-paginated endpoints when more items remain. */\n nextCursor?: string;\n}\n\n/** A value that can be serialized into a query-string parameter. `undefined` values are omitted. */\nexport type QueryValue = string | number | boolean | undefined;\n\n/** Common pagination query parameters accepted by list endpoints. */\nexport interface ListQuery {\n /** 1-indexed page number (for page/`perPage`-style pagination). */\n page?: number;\n /** Maximum number of items per page. */\n perPage?: number;\n /** Opaque cursor for cursor-based pagination (from a previous response's `nextCursor`). */\n cursor?: string;\n}\n\n/** @internal */\nexport interface RequestOptions {\n query?: Record<string, QueryValue>;\n body?: unknown;\n headers?: Record<string, string>;\n /** Abort signal to cancel the request (and any 401-refresh retry). */\n signal?: AbortSignal;\n}\n\nconst isRawBody = (body: unknown): boolean =>\n typeof body === 'string' ||\n body instanceof ArrayBuffer ||\n (typeof Uint8Array !== 'undefined' && body instanceof Uint8Array) ||\n (typeof Blob !== 'undefined' && body instanceof Blob) ||\n (typeof FormData !== 'undefined' && body instanceof FormData) ||\n (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream);\n\nconst hasHeader = (headers: Record<string, string>, name: string): boolean =>\n Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase());\n\n// ---------------------------------------------------------------------------\n// HTTP Client\n// ---------------------------------------------------------------------------\n\n/**\n * Low-level HTTP client used internally by all resource classes. Handles\n * authentication header injection, JSON serialization, error mapping, and\n * automatic retry on 401 responses.\n *\n * You do not need to use this class directly — interact with the API through\n * the resource properties on {@link GigadriveClient} instead.\n *\n * @internal\n */\nexport class HttpClient {\n constructor(\n private readonly baseUrl: string,\n private readonly tokenManager: TokenManager,\n private readonly fetchFn: typeof globalThis.fetch\n ) {}\n\n /** @internal */\n async get<T>(path: string, options?: Pick<RequestOptions, 'query' | 'signal'>): Promise<T> {\n return this.request<T>('GET', path, options);\n }\n\n /** @internal */\n async post<T>(\n path: string,\n body?: unknown,\n options?: Pick<RequestOptions, 'headers' | 'query' | 'signal'>\n ): Promise<T> {\n return this.request<T>('POST', path, { body, ...options });\n }\n\n /** @internal */\n async put<T>(\n path: string,\n body?: unknown,\n options?: Pick<RequestOptions, 'headers' | 'query' | 'signal'>\n ): Promise<T> {\n return this.request<T>('PUT', path, { body, ...options });\n }\n\n /** @internal */\n async patch<T>(\n path: string,\n body?: unknown,\n options?: Pick<RequestOptions, 'headers' | 'query' | 'signal'>\n ): Promise<T> {\n return this.request<T>('PATCH', path, { body, ...options });\n }\n\n /** @internal */\n async delete<T>(path: string, options?: Pick<RequestOptions, 'query' | 'signal'>): Promise<T> {\n return this.request<T>('DELETE', path, options);\n }\n\n /** @internal */\n async postRaw<T>(\n path: string,\n body: string | ArrayBuffer | Uint8Array | ReadableStream | Blob | FormData,\n headers?: Record<string, string>\n ): Promise<T> {\n return this.request<T>('POST', path, { body, headers });\n }\n\n /**\n * Make an authenticated request and return the raw `Response` without parsing\n * the body. Used for streamed (SSE) and binary responses.\n *\n * @throws {@link ApiError} if the response status is not OK.\n * @internal\n */\n async requestStream(method: string, path: string, options?: RequestOptions): Promise<Response> {\n const response = await this.fetchWithAuth(method, path, options);\n if (!response.ok) {\n throw await this.toApiError(response);\n }\n return response;\n }\n\n /**\n * Make a raw fetch request to an arbitrary URL (e.g. presigned upload URLs\n * or resumable upload endpoints). No auth header is injected and the base URL\n * is not prepended.\n *\n * @param url - The full URL to fetch.\n * @param init - Standard `RequestInit` options.\n * @returns The raw `Response` object.\n * @throws {@link ApiError} if the response status is not OK.\n *\n * @internal\n */\n async fetchRaw(url: string, init: RequestInit): Promise<Response> {\n const response = await this.fetchFn(url, init);\n if (!response.ok) {\n throw new ApiError(response.statusText, response.status);\n }\n return response;\n }\n\n private async request<T>(method: string, path: string, options?: RequestOptions): Promise<T> {\n const response = await this.fetchWithAuth(method, path, options);\n return this.handleResponse<T>(response);\n }\n\n /** Perform the request with auth injection and a single 401 refresh-retry. */\n private async fetchWithAuth(method: string, path: string, options?: RequestOptions): Promise<Response> {\n const url = this.buildUrl(path, options?.query);\n const token = await this.tokenManager.getToken();\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n ...options?.headers,\n };\n\n let requestBody: RequestInit['body'] = null;\n if (options?.body !== undefined) {\n if (isRawBody(options.body)) {\n // Raw bodies (FormData/Blob/bytes/streams) set their own Content-Type.\n requestBody = options.body as RequestInit['body'];\n } else {\n requestBody = JSON.stringify(options.body);\n if (!hasHeader(headers, 'Content-Type')) {\n headers['Content-Type'] = 'application/json';\n }\n }\n }\n\n const signal = options?.signal;\n const response = await this.fetchFn(url, { method, headers, body: requestBody, signal });\n\n // A streamed body is consumed by the first fetch and cannot be replayed, so\n // we cannot transparently retry it after a token refresh.\n const bodyIsOneShot = typeof ReadableStream !== 'undefined' && requestBody instanceof ReadableStream;\n\n // Retry once on 401 after refreshing the token.\n if (response.status === 401 && !bodyIsOneShot) {\n this.tokenManager.invalidate();\n const retryToken = await this.tokenManager.getToken();\n headers.Authorization = `Bearer ${retryToken}`;\n\n const retryResponse = await this.fetchFn(url, { method, headers, body: requestBody, signal });\n if (retryResponse.status === 401) {\n throw new AuthenticationError('Authentication failed after token refresh');\n }\n return retryResponse;\n }\n\n return response;\n }\n\n private async handleResponse<T>(response: Response): Promise<T> {\n if (response.ok) {\n // Handle empty responses (204 No Content, or responses with no body)\n if (response.status === 204) {\n return undefined as T;\n }\n\n const text = await response.text();\n if (!text) {\n return undefined as T;\n }\n\n return JSON.parse(text) as T;\n }\n\n throw await this.toApiError(response);\n }\n\n private async toApiError(response: Response): Promise<ApiError> {\n let message: string;\n let code: string | undefined;\n\n try {\n const body = (await response.json()) as { error?: string | { message?: string; code?: string } };\n if (typeof body.error === 'string') {\n message = body.error;\n } else if (body.error && typeof body.error === 'object') {\n message = body.error.message ?? response.statusText;\n code = body.error.code;\n } else {\n message = response.statusText;\n }\n } catch {\n message = response.statusText;\n }\n\n return new ApiError(message, response.status, code);\n }\n\n private buildUrl(path: string, query?: Record<string, QueryValue>): string {\n const url = `${this.baseUrl}${path}`;\n\n if (!query) return url;\n\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined) {\n params.set(key, String(value));\n }\n }\n\n const qs = params.toString();\n return qs ? `${url}?${qs}` : url;\n }\n}\n","/**\n * Server-Sent Events (SSE) parsing for streamed API responses (e.g. streamed\n * chat completions). Works in browsers and Node.js 18+ where `Response.body` is\n * a web `ReadableStream`.\n *\n * @internal\n */\n\n/** Extract and concatenate the `data:` payload(s) from a single SSE event block. */\nconst extractData = (rawEvent: string): string | null => {\n const dataLines = rawEvent\n .split('\\n')\n .filter((line) => line.startsWith('data:'))\n .map((line) => line.slice('data:'.length).replace(/^ /, ''));\n if (dataLines.length === 0) return null;\n const joined = dataLines.join('\\n');\n // Treat whitespace-only events (e.g. keep-alive comments or a truncated final\n // \"data:\" line) as \"no data\" so we never call JSON.parse on an empty string.\n return joined.trim().length === 0 ? null : joined;\n};\n\nconst parseEvent = <T>(data: string): T => {\n try {\n return JSON.parse(data) as T;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to parse streamed SSE data as JSON: ${message}`);\n }\n};\n\n/**\n * Parse an SSE stream, yielding each event's `data` payload parsed as JSON.\n * The `[DONE]` sentinel and empty keep-alive events are skipped; iteration ends\n * when the underlying stream closes.\n *\n * @typeParam T - The shape of each streamed JSON chunk.\n * @param response - A streaming `fetch` response.\n */\nexport async function* parseSSEStream<T = unknown>(response: Response): AsyncGenerator<T> {\n const body = response.body as ReadableStream<Uint8Array> | null;\n if (!body) {\n throw new Error('The response has no readable body to stream.');\n }\n\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n const drain = function* (flush: boolean): Generator<T> {\n // SSE events are separated by a blank line; CRLF is normalised on read.\n let separator = buffer.indexOf('\\n\\n');\n while (separator !== -1) {\n const rawEvent = buffer.slice(0, separator);\n buffer = buffer.slice(separator + 2);\n const data = extractData(rawEvent);\n if (data !== null && data !== '[DONE]') {\n yield parseEvent<T>(data);\n }\n separator = buffer.indexOf('\\n\\n');\n }\n if (flush) {\n const data = extractData(buffer);\n buffer = '';\n if (data !== null && data !== '[DONE]') {\n yield parseEvent<T>(data);\n }\n }\n };\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n // Normalise CRLF on the whole buffer so a separator split across two reads\n // (a trailing \"\\r\" then a leading \"\\n\") is still collapsed correctly.\n buffer = (buffer + decoder.decode(value, { stream: true })).replace(/\\r\\n/g, '\\n');\n yield* drain(false);\n }\n yield* drain(true);\n } finally {\n // Cancel (not just release the lock) so breaking out of the consumer's\n // `for await` early stops the underlying HTTP body instead of leaking it.\n await reader.cancel().catch(() => undefined);\n }\n}\n","import type { HttpClient } from '../http-client';\n\n/**\n * Base class for all API resource classes. Provides access to the shared\n * HTTP client for making authenticated API requests.\n *\n * @internal\n */\nexport class BaseResource {\n constructor(protected readonly httpClient: HttpClient) {}\n}\n","import type { HttpClient, Paginated } from '../../http-client';\nimport { parseSSEStream } from '../../streaming';\nimport { BaseResource } from '../base-resource';\nimport type {\n AiModel,\n ChatCompletionChunk,\n ChatCompletionRequest,\n ChatCompletionResponse,\n GatewayRequestOptions,\n GatewayResult,\n ResponsesRequest,\n ResponsesResponse,\n SpeechRequest,\n TranscriptionRequest,\n TranscriptionResponse,\n VideoGenerationRequest,\n VideoGenerationResponse,\n VideoModelList,\n} from './types';\n\nexport type * from './types';\n\nconst BASE = '/ai/v1';\n\nconst toBlob = (file: Blob | Uint8Array | ArrayBuffer): Blob => {\n if (file instanceof Uint8Array) return new Blob([file]);\n if (typeof Blob !== 'undefined' && file instanceof Blob) return file;\n return new Blob([new Uint8Array(file as ArrayBuffer)]);\n};\n\n/** Text-to-speech and speech-to-text endpoints. */\nexport class AiGatewayAudioResource extends BaseResource {\n /**\n * Synthesize speech from text. Returns the raw audio bytes.\n *\n * @returns The audio content as an `ArrayBuffer` (format per `response_format`).\n */\n async speech(data: SpeechRequest, options?: GatewayRequestOptions): Promise<ArrayBuffer> {\n const response = await this.httpClient.requestStream('POST', `${BASE}/audio/speech`, {\n body: data,\n headers: options?.headers,\n });\n return response.arrayBuffer();\n }\n\n /**\n * Transcribe an audio file to text. The file is sent as multipart form data.\n */\n async transcriptions(data: TranscriptionRequest, options?: GatewayRequestOptions): Promise<TranscriptionResponse> {\n const form = new FormData();\n const { file, filename, ...rest } = data;\n form.set('file', toBlob(file), filename ?? 'audio');\n for (const [key, value] of Object.entries(rest)) {\n if (value === undefined || value === null) continue;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- narrows to primitive so no-base-to-string is satisfied\n form.set(key, typeof value === 'object' ? JSON.stringify(value) : String(value as string | number | boolean));\n }\n return this.httpClient.postRaw(`${BASE}/audio/transcriptions`, form, options?.headers);\n }\n}\n\n/** Video generation endpoints. */\nexport class AiGatewayVideosResource extends BaseResource {\n /** Generate a video from a prompt. */\n async generations(data: VideoGenerationRequest, options?: GatewayRequestOptions): Promise<VideoGenerationResponse> {\n return this.httpClient.post(`${BASE}/videos`, data, { headers: options?.headers });\n }\n\n /** List the video models available through the gateway. */\n async listModels(): Promise<VideoModelList> {\n return this.httpClient.get(`${BASE}/videos/models`);\n }\n}\n\n/**\n * Interact with the Gigadrive AI Gateway — an OpenAI-compatible API that routes\n * requests to multiple AI providers. Accessed via {@link GigadriveClient.aiGateway}.\n *\n * @example\n * ```ts\n * // Chat completion\n * const res = await client.aiGateway.chatCompletions({\n * model: 'openai/gpt-4o',\n * messages: [{ role: 'user', content: 'Hello!' }],\n * });\n * console.log(res.choices[0].message.content);\n *\n * // Streamed chat completion\n * for await (const chunk of client.aiGateway.chatCompletionsStream({\n * model: 'openai/gpt-4o',\n * messages: [{ role: 'user', content: 'Write a haiku.' }],\n * })) {\n * process.stdout.write(chunk.choices[0]?.delta.content ?? '');\n * }\n * ```\n */\nexport class AiGatewayResource extends BaseResource {\n /** Text-to-speech and speech-to-text. */\n readonly audio: AiGatewayAudioResource;\n /** Video generation. */\n readonly videos: AiGatewayVideosResource;\n\n constructor(httpClient: HttpClient) {\n super(httpClient);\n this.audio = new AiGatewayAudioResource(httpClient);\n this.videos = new AiGatewayVideosResource(httpClient);\n }\n\n /**\n * Create a chat completion using the OpenAI-compatible endpoint.\n *\n * @param data - The chat completion request (model, messages, options, provider routing).\n * @param options - Custom headers (e.g. `X-Gigadrive-Application-Id`).\n */\n async chatCompletions(data: ChatCompletionRequest, options?: GatewayRequestOptions): Promise<ChatCompletionResponse> {\n return this.httpClient.post(`${BASE}/chat/completions`, { ...data, stream: false }, { headers: options?.headers });\n }\n\n /**\n * Like {@link chatCompletions}, but also returns the raw response and the\n * gateway request-id / cost headers.\n */\n async chatCompletionsWithResponse(\n data: ChatCompletionRequest,\n options?: GatewayRequestOptions\n ): Promise<GatewayResult<ChatCompletionResponse>> {\n const response = await this.httpClient.requestStream('POST', `${BASE}/chat/completions`, {\n body: { ...data, stream: false },\n headers: options?.headers,\n });\n const body = (await response.json()) as ChatCompletionResponse;\n const cost = response.headers.get('X-Gigadrive-Cost-Micros');\n const costMicros = cost !== null ? Number(cost) : NaN;\n return {\n data: body,\n response,\n requestId: response.headers.get('X-Gigadrive-Request-Id') ?? undefined,\n costMicros: Number.isFinite(costMicros) ? costMicros : undefined,\n };\n }\n\n /**\n * Stream a chat completion as Server-Sent Events. Yields each chunk as it\n * arrives and ends when the gateway closes the stream.\n */\n async *chatCompletionsStream(\n data: ChatCompletionRequest,\n options?: GatewayRequestOptions\n ): AsyncGenerator<ChatCompletionChunk> {\n const response = await this.httpClient.requestStream('POST', `${BASE}/chat/completions`, {\n body: { ...data, stream: true },\n headers: options?.headers,\n });\n yield* parseSSEStream<ChatCompletionChunk>(response);\n }\n\n /**\n * Create a response using the Open Responses-compatible endpoint.\n */\n async responses(data: ResponsesRequest, options?: GatewayRequestOptions): Promise<ResponsesResponse> {\n return this.httpClient.post(`${BASE}/responses`, { ...data, stream: false }, { headers: options?.headers });\n }\n\n /**\n * Stream a response using the Open Responses-compatible endpoint.\n */\n async *responsesStream(data: ResponsesRequest, options?: GatewayRequestOptions): AsyncGenerator<unknown> {\n const response = await this.httpClient.requestStream('POST', `${BASE}/responses`, {\n body: { ...data, stream: true },\n headers: options?.headers,\n });\n yield* parseSSEStream(response);\n }\n\n /**\n * List all AI models available through the gateway.\n */\n async listModels(): Promise<Paginated<AiModel>> {\n return this.httpClient.get(`${BASE}/models`);\n }\n\n /**\n * Get details for a specific AI model by its ID.\n *\n * @param modelId - The model identifier (e.g. `\"openai/gpt-4o\"`).\n */\n async getModel(modelId: string): Promise<AiModel> {\n return this.httpClient.get(`${BASE}/models/${encodeURIComponent(modelId)}`);\n }\n}\n","import type { Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n/** An application-scoped API key. The secret is never returned after creation. */\nexport interface ApiKey {\n /** Unique identifier (UUID). Used as the OAuth client ID. */\n id: string;\n /** Human-readable label. */\n name: string;\n /** Application this key is scoped to. */\n applicationId: string | null;\n /** API capability scopes granted to the key. */\n scopes: string[];\n /** ISO 8601 expiry, or `null` if the key never expires. */\n expiresAt: string | null;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Input for creating an application-scoped API key. */\nexport interface CreateApiKeyInput {\n /** Human-readable label for the key. */\n name: string;\n /** Application to scope the key to. The key can only act on this application. */\n applicationId: string;\n /**\n * API capability scopes to grant. Each must be a subset of your own access and\n * cannot include API key management. Defaults to a minimal read-only set.\n */\n scopes?: string[];\n /** Optional ISO 8601 expiry. Defaults to 90 days when omitted. */\n expiresAt?: string;\n}\n\n/**\n * The result of creating an API key. Includes the plaintext {@link secret},\n * which is returned only once and cannot be retrieved again.\n */\nexport interface CreateApiKeyResult extends ApiKey {\n /** The plaintext client secret. Store it now — it cannot be retrieved again. */\n secret: string;\n}\n\n/** Query for {@link ApiKeysResource.list}. */\nexport interface ListApiKeysQuery {\n /** Application whose keys should be listed. */\n applicationId: string;\n}\n\n/**\n * Manage application-scoped API keys. Accessed via {@link GigadriveClient.apiKeys}.\n *\n * @example\n * ```ts\n * const key = await client.apiKeys.create({ name: 'ci', applicationId: 'app-id' });\n * // Use key.id + key.secret as OAuth client credentials. Store the secret now.\n * ```\n */\nexport class ApiKeysResource extends BaseResource {\n /**\n * Provision a new application-scoped API key. The plaintext secret is returned\n * exactly once — store it immediately.\n *\n * @param data - The key name, target application, and optional scopes/expiry.\n * @returns The created key including its one-time plaintext secret.\n */\n async create(data: CreateApiKeyInput): Promise<CreateApiKeyResult> {\n return this.httpClient.post('/api-keys', data);\n }\n\n /**\n * List the API keys scoped to an application. Secrets are never returned.\n *\n * @param query - The application whose keys should be listed.\n * @returns A paginated list of API key metadata.\n */\n async list(query: ListApiKeysQuery): Promise<Paginated<ApiKey>> {\n return this.httpClient.get('/api-keys', {\n query: query as unknown as Record<string, string | number | undefined>,\n });\n }\n\n /**\n * Permanently revoke an API key.\n *\n * @param apiKeyId - The API key ID (UUID).\n */\n async delete(apiKeyId: string): Promise<void> {\n return this.httpClient.delete(`/api-keys/${apiKeyId}`);\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport type { CreateEnvVarInput, EnvVar, PullEnvVarsQuery, PullEnvVarsResult, UpdateEnvVarInput } from './env-vars';\n\n/**\n * Manage environment variables scoped to an application.\n * Accessed via `client.applications.envVars`.\n */\nexport class ApplicationEnvVarsResource extends BaseResource {\n /**\n * List all environment variables for an application.\n *\n * @param applicationId - The application ID (UUID).\n * @returns A paginated list of environment variables.\n *\n * @example\n * ```ts\n * const { items } = await client.applications.envVars.list('app-id');\n * for (const v of items) {\n * console.log(`${v.key}=${v.sensitive ? '***' : v.value}`);\n * }\n * ```\n */\n async list(applicationId: string, query?: ListQuery): Promise<Paginated<EnvVar>> {\n return this.httpClient.get(`/applications/${applicationId}/env-vars`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Pull the environment variables that apply to an application for local\n * development. Merges organization-wide, application-wide, and (optionally)\n * environment-specific overrides, returning only non-sensitive values — ready\n * to write to a local `.env` file.\n *\n * @param applicationId - The application ID (UUID).\n * @param query - Optional environment targeting.\n * @returns The resolved non-sensitive variables plus the count of omitted secrets.\n *\n * @example\n * ```ts\n * const { items } = await client.applications.envVars.pull('app-id');\n * const dotenv = items.map((v) => `${v.key}=${v.value}`).join('\\n');\n * ```\n */\n async pull(applicationId: string, query?: PullEnvVarsQuery): Promise<PullEnvVarsResult> {\n return this.httpClient.get(`/applications/${applicationId}/env-vars/pull`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Create a new environment variable for an application.\n *\n * @param applicationId - The application ID (UUID).\n * @param data - The variable key, value, and optional settings.\n * @returns The newly created environment variable.\n *\n * @example\n * ```ts\n * const envVar = await client.applications.envVars.create('app-id', {\n * key: 'DATABASE_URL',\n * value: 'postgres://...',\n * sensitive: true,\n * });\n * ```\n */\n async create(applicationId: string, data: CreateEnvVarInput): Promise<EnvVar> {\n return this.httpClient.post(`/applications/${applicationId}/env-vars`, data);\n }\n\n /**\n * Update an existing environment variable. Only the fields you provide\n * will be changed; omitted fields are left unchanged.\n *\n * @param applicationId - The application ID (UUID).\n * @param envVarId - The environment variable ID (UUID).\n * @param data - The fields to update.\n * @returns The updated environment variable.\n *\n * @example\n * ```ts\n * await client.applications.envVars.update('app-id', 'var-id', {\n * value: 'postgres://new-host/db',\n * });\n * ```\n */\n async update(applicationId: string, envVarId: string, data: UpdateEnvVarInput): Promise<EnvVar> {\n return this.httpClient.patch(`/applications/${applicationId}/env-vars/${envVarId}`, data);\n }\n\n /**\n * Permanently delete an environment variable.\n *\n * @param applicationId - The application ID (UUID).\n * @param envVarId - The environment variable ID (UUID).\n *\n * @example\n * ```ts\n * await client.applications.envVars.delete('app-id', 'var-id');\n * ```\n */\n async delete(applicationId: string, envVarId: string): Promise<void> {\n return this.httpClient.delete(`/applications/${applicationId}/env-vars/${envVarId}`);\n }\n}\n","import type { Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n/** A nested reference to the application that served a request. */\nexport interface NetworkRequestApplicationRef {\n id: string;\n name: string;\n}\n\n/** A nested reference to the deployment that served a request. */\nexport interface NetworkRequestDeploymentRef {\n id: string;\n status: string;\n}\n\n/** A nested reference to the function route that handled a request. */\nexport interface NetworkRequestFunctionRef {\n id: string;\n name: string | null;\n path: string;\n region: string | null;\n}\n\n/** A nested reference to the static asset that served a request. */\nexport interface NetworkRequestAssetRef {\n id: string;\n path: string;\n objectKey: string;\n}\n\n/** A nested reference to the storage bucket involved in a request. */\nexport interface NetworkRequestBucketRef {\n id: string;\n name: string;\n slug: string;\n}\n\n/** A nested reference to the storage object involved in a request. */\nexport interface NetworkRequestObjectRef {\n id: string;\n key: string;\n contentType: string | null;\n}\n\n/** The HTTP request details captured for a network request. */\nexport interface NetworkRequestDetails {\n method: string;\n hostname: string;\n path: string;\n query: string | null;\n protocol: string | null;\n country: string | null;\n userAgent: string | null;\n referer: string | null;\n}\n\n/** The HTTP response details captured for a network request. */\nexport interface NetworkResponseDetails {\n status: number | null;\n cacheStatus: 'hit' | 'miss' | 'bypass' | 'revalidated' | 'stale' | 'updating' | null;\n cacheHit: boolean | null;\n region: string | null;\n edgeLocation: string | null;\n}\n\n/** Byte and timing metrics for a network request. */\nexport interface NetworkRequestMetrics {\n requestBodyBytes: number | null;\n responseBodyBytes: number | null;\n bytesSent: number | null;\n durationMs: number | null;\n}\n\n/** A single observed request served through the Gigadrive Network edge (summary form). */\nexport interface NetworkRequestSummary {\n id: string;\n application: NetworkRequestApplicationRef;\n deployment: NetworkRequestDeploymentRef | null;\n deploymentFunction: NetworkRequestFunctionRef | null;\n deploymentAsset: NetworkRequestAssetRef | null;\n storageBucket: NetworkRequestBucketRef | null;\n storageObject: NetworkRequestObjectRef | null;\n request: NetworkRequestDetails;\n response: NetworkResponseDetails;\n metrics: NetworkRequestMetrics;\n startedAt: string;\n completedAt: string | null;\n}\n\n/** A full network request record, including sanitized request/response headers. */\nexport interface NetworkRequest extends NetworkRequestSummary {\n /** Sanitized request headers captured for debugging. */\n requestHeaders: Record<string, string>;\n /** Sanitized response headers captured for debugging. */\n responseHeaders: Record<string, string>;\n}\n\n/** Query filters for listing application requests. All fields are optional. */\nexport interface ListRequestsQuery {\n /** Filter to requests served by one deployment. */\n deploymentId?: string;\n /** Filter to requests served by one function route. */\n deploymentFunctionId?: string;\n /** Filter to requests served by one static asset route. */\n deploymentAssetId?: string;\n /** Filter to storage delivery requests for one bucket. */\n storageBucketId?: string;\n /** Filter to storage delivery requests for one object. */\n storageObjectId?: string;\n /** Only include requests that started at or after this ISO 8601 timestamp. */\n from?: string;\n /** Only include requests that started before or at this ISO 8601 timestamp. */\n to?: string;\n /** Maximum number of records to return. */\n limit?: number;\n /** Opaque cursor from a previous response's `nextCursor`. */\n cursor?: string;\n /** Filter by HTTP method (e.g. `\"GET\"`). */\n method?: string;\n /** Filter by exact HTTP status code. */\n status?: number;\n /** Filter by status family (`2`, `3`, `4`, or `5`). */\n statusFamily?: number;\n /** Filter by request hostname. */\n hostname?: string;\n /** Filter to requests whose path starts with this prefix. */\n pathPrefix?: string;\n /** Filter by ISO 3166-1 alpha-2 country code. */\n country?: string;\n /** Filter by origin region. */\n region?: string;\n /** Filter by edge location. */\n edgeLocation?: string;\n /** Filter by CDN cache state. */\n cacheStatus?: string;\n /** Filter by whether the response was served from cache. */\n cacheHit?: boolean;\n}\n\n/**\n * Read observed traffic (request logs) for an application. Accessed via\n * `client.applications.requests`.\n *\n * @example\n * ```ts\n * // Recent 5xx responses for a deployment\n * const { items } = await client.applications.requests.list('app-id', {\n * deploymentId: 'dep-id',\n * statusFamily: 5,\n * limit: 100,\n * });\n * ```\n */\nexport class ApplicationRequestsResource extends BaseResource {\n /**\n * List requests for an application, with rich filtering and cursor pagination.\n *\n * @param applicationId - The application ID (UUID).\n * @param query - Optional filters and pagination.\n * @returns A page of request summaries.\n */\n async list(applicationId: string, query?: ListRequestsQuery): Promise<Paginated<NetworkRequestSummary>> {\n return this.httpClient.get(`/applications/${applicationId}/requests`, {\n query: query as Record<string, string | number | boolean | undefined> | undefined,\n });\n }\n\n /**\n * Get a single request by ID, including sanitized request/response headers.\n *\n * @param applicationId - The application ID (UUID).\n * @param requestId - The request record ID (UUID).\n * @returns The full request record.\n */\n async get(applicationId: string, requestId: string): Promise<NetworkRequest> {\n return this.httpClient.get(`/applications/${applicationId}/requests/${requestId}`);\n }\n}\n","/**\n * Checksum helpers used to satisfy the storage upload contract, which requires\n * a SHA-256 of the object content (SHA-1 and MD5 are optional integrity hints).\n *\n * SHA-256 and SHA-1 are computed with the Web Crypto API (`crypto.subtle`),\n * which is available in modern browsers and Node.js 18+. MD5 is not provided by\n * Web Crypto, so it is computed with Node's `crypto` module and is therefore\n * Node-only — pass `checksumMd5` explicitly if you need it in the browser.\n *\n * @internal\n */\n\n/** A set of computed content checksums (lowercase hex). */\nexport interface Checksums {\n /** SHA-256 checksum. Always computed. */\n sha256: string;\n /** SHA-1 checksum, when requested. */\n sha1?: string;\n /** MD5 checksum, when requested (Node.js only). */\n md5?: string;\n}\n\n/** Which optional checksums to compute alongside the always-required SHA-256. */\nexport interface ChecksumRequest {\n /** Also compute a SHA-1 checksum. */\n sha1?: boolean;\n /** Also compute an MD5 checksum (Node.js only). */\n md5?: boolean;\n}\n\nconst toHex = (buffer: ArrayBuffer): string => {\n const bytes = new Uint8Array(buffer);\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += bytes[i].toString(16).padStart(2, '0');\n }\n return hex;\n};\n\nconst subtleDigest = async (algorithm: 'SHA-256' | 'SHA-1', bytes: Uint8Array): Promise<string> =>\n toHex(await crypto.subtle.digest(algorithm, bytes));\n\nconst importNodeCrypto = async (): Promise<typeof import('node:crypto') | null> => {\n if (typeof process === 'undefined' || !process.versions?.node) return null;\n try {\n return await import('node:crypto');\n } catch {\n return null;\n }\n};\n\nconst md5Hex = async (bytes: Uint8Array): Promise<string> => {\n const nodeCrypto = await importNodeCrypto();\n if (!nodeCrypto) {\n throw new Error('MD5 checksums are only supported in Node.js. Provide checksumMd5 explicitly in the browser.');\n }\n return nodeCrypto.createHash('md5').update(bytes).digest('hex');\n};\n\n/**\n * Compute checksums for an in-memory byte buffer.\n *\n * @param bytes - The content bytes.\n * @param request - Which optional checksums to compute (SHA-256 is always computed).\n */\nexport const computeChecksums = async (bytes: Uint8Array, request: ChecksumRequest = {}): Promise<Checksums> => {\n const checksums: Checksums = { sha256: await subtleDigest('SHA-256', bytes) };\n if (request.sha1) checksums.sha1 = await subtleDigest('SHA-1', bytes);\n if (request.md5) checksums.md5 = await md5Hex(bytes);\n return checksums;\n};\n\n/**\n * Compute checksums for a file on disk by streaming it through Node's hashing\n * primitives — avoids loading the whole file into memory. Node.js only.\n *\n * @param path - Filesystem path to hash.\n * @param request - Which optional checksums to compute (SHA-256 is always computed).\n */\nexport const hashNodeFile = async (path: string, request: ChecksumRequest = {}): Promise<Checksums> => {\n const [fs, nodeCrypto] = await Promise.all([import('node:fs'), import('node:crypto')]);\n const sha256 = nodeCrypto.createHash('sha256');\n const sha1 = request.sha1 ? nodeCrypto.createHash('sha1') : null;\n const md5 = request.md5 ? nodeCrypto.createHash('md5') : null;\n\n await new Promise<void>((resolve, reject) => {\n const stream = fs.createReadStream(path);\n stream.on('data', (chunk) => {\n sha256.update(chunk);\n sha1?.update(chunk);\n md5?.update(chunk);\n });\n stream.on('end', () => resolve());\n stream.on('error', reject);\n });\n\n const checksums: Checksums = { sha256: sha256.digest('hex') };\n if (sha1) checksums.sha1 = sha1.digest('hex');\n if (md5) checksums.md5 = md5.digest('hex');\n return checksums;\n};\n","/**\n * Minimal filename → MIME type inference used to populate an upload's content\n * type when the caller does not provide one. Intentionally dependency-free and\n * covers the most common web/asset types; callers can always pass an explicit\n * `contentType` to override.\n *\n * @internal\n */\n\nconst MIME_TYPES: Record<string, string> = {\n // Text & code\n txt: 'text/plain',\n csv: 'text/csv',\n html: 'text/html',\n htm: 'text/html',\n css: 'text/css',\n js: 'text/javascript',\n mjs: 'text/javascript',\n json: 'application/json',\n xml: 'application/xml',\n md: 'text/markdown',\n // Images\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n avif: 'image/avif',\n ico: 'image/x-icon',\n bmp: 'image/bmp',\n tiff: 'image/tiff',\n heic: 'image/heic',\n // Audio\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n oga: 'audio/ogg',\n flac: 'audio/flac',\n aac: 'audio/aac',\n m4a: 'audio/mp4',\n // Video\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n // Documents\n pdf: 'application/pdf',\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n // Archives & binaries\n zip: 'application/zip',\n gz: 'application/gzip',\n tar: 'application/x-tar',\n br: 'application/x-brotli',\n wasm: 'application/wasm',\n // Fonts\n woff: 'font/woff',\n woff2: 'font/woff2',\n ttf: 'font/ttf',\n otf: 'font/otf',\n};\n\n/**\n * Infer a MIME type from a filename or object key by its extension.\n *\n * @param nameOrKey - A filename or object key (e.g. `\"images/photo.jpg\"`).\n * @returns The inferred MIME type, or `undefined` if the extension is unknown.\n */\nexport const inferContentType = (nameOrKey: string): string | undefined => {\n const lastDot = nameOrKey.lastIndexOf('.');\n if (lastDot === -1 || lastDot === nameOrKey.length - 1) return undefined;\n const ext = nameOrKey.slice(lastDot + 1).toLowerCase();\n return MIME_TYPES[ext];\n};\n","/**\n * Resolves the various accepted upload inputs (in-memory bytes, a Node.js file\n * path, or a Node.js readable stream) into the concrete values the upload flow\n * needs: the object tus-js-client consumes, the byte size, an inferred content\n * type, and the required checksums.\n *\n * @internal\n */\n\nimport { computeChecksums, hashNodeFile, type Checksums } from './checksum';\nimport { inferContentType } from './content-type';\n\n/** A minimal Node.js `Readable`-like shape (avoids depending on `node:stream` types). */\nexport interface NodeReadableLike {\n on(event: string, listener: (...args: unknown[]) => void): unknown;\n pipe?: unknown;\n read?: unknown;\n}\n\n/** In-memory data accepted by the upload helpers. `Buffer` is a `Uint8Array`. */\nexport type UploadData = Blob | ArrayBuffer | Uint8Array;\n\n/** The tus-js-client file input union. */\nexport type TusFile = File | Blob | Uint8Array | NodeReadableLike;\n\n/** Input describing what to upload and any pre-supplied metadata. */\nexport interface UploadSourceInput {\n /** The object key/path the upload targets — used to infer content type. */\n key: string;\n /** In-memory data (browser `File`/`Blob`, Node `Buffer`, `Uint8Array`, `ArrayBuffer`). */\n data?: UploadData;\n /** A filesystem path to stream from (Node.js only). */\n path?: string;\n /** A readable stream (Node.js only). Requires `contentLength` and `checksumSha256`. */\n stream?: NodeReadableLike;\n /** Explicit content type. Inferred from `key` when omitted. */\n contentType?: string;\n /** Explicit byte size. Required for `stream`; computed otherwise. */\n contentLength?: number;\n /** Pre-computed SHA-256 (skips hashing). Required for `stream`. */\n checksumSha256?: string;\n /** Pre-computed SHA-1. */\n checksumSha1?: string;\n /** Pre-computed MD5. */\n checksumMd5?: string;\n}\n\n/** The fully resolved upload source. */\nexport interface ResolvedUploadSource {\n /** The value handed to tus-js-client. */\n tusFile: TusFile;\n /** Total upload size in bytes. */\n size: number;\n /** Resolved content type, if known. */\n contentType?: string;\n /** Checksums (always includes SHA-256). */\n checksums: Checksums;\n /** Whether a finite chunk size is required (true for streamed/file-path inputs). */\n requiresFiniteChunkSize: boolean;\n}\n\nconst isNode = (): boolean => typeof process !== 'undefined' && !!process.versions?.node;\n\nconst toBytes = async (data: UploadData): Promise<Uint8Array> => {\n if (typeof Blob !== 'undefined' && data instanceof Blob) return new Uint8Array(await data.arrayBuffer());\n if (data instanceof Uint8Array) return data;\n if (data instanceof ArrayBuffer) return new Uint8Array(data);\n throw new Error('Unsupported upload data type. Pass a File, Blob, Buffer, Uint8Array, or ArrayBuffer.');\n};\n\nconst sizeOf = (data: UploadData): number => {\n if (typeof Blob !== 'undefined' && data instanceof Blob) return data.size;\n if (data instanceof Uint8Array) return data.byteLength;\n if (data instanceof ArrayBuffer) return data.byteLength;\n throw new Error('Cannot determine upload size. Pass a File, Blob, Buffer, Uint8Array, or ArrayBuffer.');\n};\n\n/** Convert in-memory data into a value tus-js-client accepts in the current runtime. */\nconst toTusFile = async (data: UploadData): Promise<TusFile> => {\n if (!isNode()) {\n if (typeof Blob !== 'undefined' && data instanceof Blob) return data;\n const bytes = data instanceof Uint8Array ? data : new Uint8Array(data as ArrayBuffer);\n return new Blob([bytes]);\n }\n\n const { Buffer } = await import('node:buffer');\n const bytes =\n typeof Blob !== 'undefined' && data instanceof Blob\n ? new Uint8Array(await data.arrayBuffer())\n : data instanceof Uint8Array\n ? data\n : new Uint8Array(data as ArrayBuffer);\n return Buffer.isBuffer(data) ? data : Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n};\n\n/**\n * Build the checksum set, always honoring caller-supplied SHA-1/MD5 (they are\n * passed through, never recomputed). Only SHA-256 is ever computed by the SDK.\n */\nconst buildChecksums = (input: UploadSourceInput, sha256: string): Checksums => {\n const checksums: Checksums = { sha256 };\n if (input.checksumSha1) checksums.sha1 = input.checksumSha1;\n if (input.checksumMd5) checksums.md5 = input.checksumMd5;\n return checksums;\n};\n\n/**\n * Resolve an {@link UploadSourceInput} into a {@link ResolvedUploadSource},\n * computing size, content type, and the SHA-256 as needed.\n *\n * @param input - The upload source description. Exactly one of `data`, `path`,\n * or `stream` must be provided.\n * @param options - Set `hash: false` to skip SHA-256 computation (e.g. when\n * uploading to an already-authorized URL, where checksums are not needed).\n */\nexport const resolveUploadSource = async (\n input: UploadSourceInput,\n options: { hash?: boolean } = {}\n): Promise<ResolvedUploadSource> => {\n const sourceCount = [input.data !== undefined, input.path !== undefined, input.stream !== undefined].filter(\n Boolean\n ).length;\n if (sourceCount > 1) {\n throw new Error('Provide only one upload source: data, path, or stream.');\n }\n\n const hash = options.hash !== false;\n const contentType = input.contentType ?? inferContentType(input.key);\n\n if (input.data !== undefined) {\n const size = input.contentLength ?? sizeOf(input.data);\n const sha256 = input.checksumSha256 ?? (hash ? (await computeChecksums(await toBytes(input.data))).sha256 : '');\n return {\n tusFile: await toTusFile(input.data),\n size,\n contentType,\n checksums: buildChecksums(input, sha256),\n requiresFiniteChunkSize: false,\n };\n }\n\n if (input.path !== undefined) {\n if (!isNode()) throw new Error('Uploading from a file path is only supported in Node.js.');\n const fs = await import('node:fs');\n const size = input.contentLength ?? fs.statSync(input.path).size;\n const sha256 = input.checksumSha256 ?? (hash ? (await hashNodeFile(input.path)).sha256 : '');\n // A fresh read stream is handed to tus for the byte upload.\n const tusFile = fs.createReadStream(input.path) as unknown as NodeReadableLike;\n return { tusFile, size, contentType, checksums: buildChecksums(input, sha256), requiresFiniteChunkSize: true };\n }\n\n if (input.stream !== undefined) {\n if (input.contentLength === undefined) {\n throw new Error('Uploading from a stream requires contentLength to be provided.');\n }\n if (hash && !input.checksumSha256) {\n throw new Error('Uploading from a stream requires checksumSha256 to be provided.');\n }\n return {\n tusFile: input.stream,\n size: input.contentLength,\n contentType,\n checksums: buildChecksums(input, input.checksumSha256 ?? ''),\n requiresFiniteChunkSize: true,\n };\n }\n\n throw new Error('No upload source provided. Pass one of: data, path, or stream.');\n};\n","/**\n * Thin, injectable wrapper around `tus-js-client` that performs the resumable\n * byte upload. Isolated here so the upload flow can be unit-tested with a fake\n * transport (no real network I/O) and so abort/resume behaviour lives in one\n * place.\n *\n * @internal\n */\n\nimport * as tus from 'tus-js-client';\nimport { UploadError, UploadSessionExpiredError } from '../errors';\nimport type { ResolvedUploadSource, TusFile } from './source';\n\n/** Default chunk size for streamed/file-path uploads, which require a finite chunk size. */\nexport const DEFAULT_STREAM_CHUNK_SIZE = 50 * 1024 * 1024;\n\n/** A persistence backend for resumable upload fingerprints (matches tus-js-client's `UrlStorage`). */\nexport interface UploadUrlStorage {\n findAllUploads(): Promise<unknown[]>;\n findUploadsByFingerprint(fingerprint: string): Promise<unknown[]>;\n removeUpload(urlStorageKey: string): Promise<void>;\n addUpload(fingerprint: string, upload: unknown): Promise<string>;\n}\n\n/** Parameters for a single byte upload. */\nexport interface TusUploadParams {\n /** The file/data passed to tus-js-client. */\n data: TusFile;\n /** Signed upload URL (already includes the short-lived upload token). */\n uploadUrl: string;\n /** Total upload size in bytes. */\n uploadSize: number;\n /** Headers issued with the upload session. */\n headers: Record<string, string>;\n /** Maximum chunk size in bytes. Required for streamed inputs. */\n chunkSize?: number;\n /** Retry backoff in milliseconds. `null`/`[]` disables retries. */\n retryDelays?: number[] | null;\n /** Progress callback. */\n onProgress?: (bytesSent: number, bytesTotal: number) => void;\n /** Abort signal to cancel the upload. */\n signal?: AbortSignal;\n /** Persist a resumable fingerprint so the upload can resume later. */\n resume?: boolean;\n /** Custom storage for resumable fingerprints (defaults to the tus-js-client default for the runtime). */\n urlStorage?: UploadUrlStorage;\n}\n\n/** Performs a single resumable byte upload. Resolves on success, rejects on error/abort. */\nexport type UploadTransport = (params: TusUploadParams) => Promise<void>;\n\nconst DEFAULT_RETRY_DELAYS = [0, 1000, 3000, 5000];\n\n/** An `AbortError`-named error, consistent with the Fetch/DOM cancellation convention. */\nexport const createAbortError = (): Error => {\n const error = new Error('The upload was aborted.');\n error.name = 'AbortError';\n return error;\n};\n\n/** The default upload transport, backed by `tus-js-client`. */\nexport const tusUploadTransport: UploadTransport = (params) =>\n new Promise<void>((resolve, reject) => {\n if (params.signal?.aborted) {\n reject(createAbortError());\n return;\n }\n\n let settled = false;\n const cleanup = () => {\n if (params.signal) params.signal.removeEventListener('abort', onAbort);\n };\n const finish = (fn: () => void) => {\n if (settled) return;\n settled = true;\n cleanup();\n fn();\n };\n\n const headers = Object.fromEntries(\n Object.entries(params.headers).filter(([name]) => name.toLowerCase() !== 'tus-resumable')\n );\n\n const upload = new tus.Upload(params.data as tus.Upload['file'], {\n uploadUrl: params.uploadUrl,\n uploadSize: params.uploadSize,\n // tus-js-client sets Tus-Resumable itself. In browsers, forwarding the\n // session's copy makes XMLHttpRequest combine both values and produces\n // an invalid `1.0.0, 1.0.0` protocol header.\n headers,\n chunkSize: params.chunkSize ?? Infinity,\n retryDelays: params.retryDelays === undefined ? DEFAULT_RETRY_DELAYS : params.retryDelays,\n storeFingerprintForResuming: params.resume ?? false,\n removeFingerprintOnSuccess: true,\n ...(params.urlStorage ? { urlStorage: params.urlStorage as never } : {}),\n onProgress: params.onProgress ?? null,\n onError: (error) => finish(() => reject(error)),\n onSuccess: () => finish(() => resolve()),\n });\n\n const onAbort = () => {\n void upload.abort();\n finish(() => reject(createAbortError()));\n };\n // `once` ensures the listener detaches after firing, even if `finish` (and\n // thus `cleanup`) never runs because the upload hangs without settling.\n if (params.signal) params.signal.addEventListener('abort', onAbort, { once: true });\n\n upload.start();\n });\n\n/** Options shared by the high-level upload entry points. */\nexport interface RunUploadOptions {\n /** Maximum chunk size in bytes. */\n chunkSize?: number;\n /** Retry backoff in milliseconds. `null`/`[]` disables retries. */\n retryDelays?: number[] | null;\n /** Progress callback. */\n onProgress?: (bytesSent: number, bytesTotal: number) => void;\n /** Abort signal to cancel the upload. */\n signal?: AbortSignal;\n /** Persist a resumable fingerprint so the upload can resume later. */\n resume?: boolean;\n /** Custom storage for resumable fingerprints. */\n urlStorage?: UploadUrlStorage;\n}\n\n/** Run a resolved upload through the given transport, applying sensible chunk-size defaults. */\nexport const runResolvedUpload = (\n transport: UploadTransport,\n uploadUrl: string,\n resolved: ResolvedUploadSource,\n options: RunUploadOptions = {},\n headers: Record<string, string> = { 'Tus-Resumable': '1.0.0' }\n): Promise<void> =>\n transport({\n data: resolved.tusFile,\n uploadUrl,\n uploadSize: resolved.size,\n headers,\n chunkSize: options.chunkSize ?? (resolved.requiresFiniteChunkSize ? DEFAULT_STREAM_CHUNK_SIZE : undefined),\n retryDelays: options.retryDelays,\n onProgress: options.onProgress,\n signal: options.signal,\n resume: options.resume,\n urlStorage: options.urlStorage,\n });\n\nconst tusStatus = (error: unknown): number | undefined => {\n const response = (error as tus.DetailedError | undefined)?.originalResponse;\n return response ? response.getStatus() : undefined;\n};\n\n/**\n * Normalise a transport-layer error into an SDK error. Aborts are re-thrown\n * as-is; auth/expiry statuses become {@link UploadSessionExpiredError}; anything\n * else becomes a generic {@link UploadError}.\n */\nexport const toUploadError = (error: unknown): never => {\n if (error instanceof Error && error.name === 'AbortError') throw error;\n const status = tusStatus(error);\n if (status === 401 || status === 403 || status === 410) {\n throw new UploadSessionExpiredError(undefined, error);\n }\n throw new UploadError(error instanceof Error ? error.message : 'The upload failed.', error);\n};\n","import { ConfigurationError } from '../errors';\n\n/**\n * Canonical environment-scoped bucket name or a deprecated bucket UUID.\n *\n * REST callers should use the immutable bucket `name`. UUID values remain\n * accepted while existing integrations migrate. Global delivery/S3 slugs are\n * not valid REST bucket references.\n */\nexport type StorageBucketReference = string;\n\n/** Selects an application environment by slug or UUID for management calls. */\nexport interface StorageEnvironmentOptions {\n /**\n * Environment slug or UUID. Deployed workloads normally omit this because\n * their credential determines the authoritative environment.\n */\n environment?: string;\n}\n\n/** @internal */\nexport const resolveStorageApplicationId = (\n defaultApplicationId: string | undefined,\n explicitApplicationId?: string\n): string => {\n const applicationId = explicitApplicationId ?? defaultApplicationId;\n if (applicationId) return applicationId;\n\n throw new ConfigurationError(\n 'No application context is configured. Pass an application ID to this call, set GigadriveClientConfig.applicationId, or run inside a Gigadrive deployment with GIGADRIVE_APPLICATION_ID.'\n );\n};\n\n/** @internal */\nexport const resolveStorageBucketReference = (input: {\n bucket?: string;\n bucketId?: string;\n}): StorageBucketReference => {\n const hasBucket = typeof input.bucket === 'string';\n const hasBucketId = typeof input.bucketId === 'string';\n\n if (hasBucket === hasBucketId) {\n throw new ConfigurationError(\n 'Provide exactly one storage bucket reference using `bucket` or deprecated `bucketId`.'\n );\n }\n\n return hasBucket ? (input.bucket as string) : (input.bucketId as string);\n};\n\n/** @internal */\nexport const encodeStorageBucketReference = (bucketRef: StorageBucketReference): string =>\n encodeURIComponent(bucketRef);\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport {\n encodeStorageBucketReference,\n resolveStorageApplicationId,\n type StorageBucketReference,\n type StorageEnvironmentOptions,\n} from './storage-context';\n\n/** A storage bucket belonging to one application environment. */\nexport interface StorageBucket {\n /**\n * Internal bucket UUID. New REST calls should use {@link name} instead.\n * @deprecated Use the environment-scoped bucket `name` for API addressing.\n */\n id: string;\n /** The application this bucket belongs to. */\n applicationId: string;\n /** Canonical immutable API/IaC identifier, unique within {@link environmentId}. */\n name: string;\n /** Global CDN/S3 identifier. This is not the bucket reference used by REST methods. */\n slug: string;\n /** `\"public\"` buckets use stable CDN URLs; `\"private\"` buckets require signed access URLs. */\n visibility: 'public' | 'private';\n /** Hostname used to serve public objects or signed private-object URLs. */\n cdnHostname: string;\n /** The application environment this bucket is scoped to. */\n environmentId: string;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\ninterface CreateStorageBucketBase {\n /**\n * Immutable lowercase URL-safe identifier. The API accepts 3–63 ASCII\n * letters, numbers, and internal hyphens and does not normalize the value.\n */\n name: string;\n /** Bucket visibility. Defaults to `\"private\"`. */\n visibility?: 'public' | 'private';\n /**\n * Explicit global delivery/S3 slug.\n * @deprecated Omit this field and let the API generate the global slug.\n */\n slug?: string;\n}\n\n/** Input for creating an environment-scoped storage bucket. */\nexport type CreateStorageBucketInput = CreateStorageBucketBase &\n (\n | {\n /** Canonical environment slug or UUID. */\n environment: string;\n /**\n * Deprecated compatibility selector. When both fields are supplied,\n * they must resolve to the same environment.\n * @deprecated Use {@link environment}.\n */\n environmentId?: string;\n }\n | {\n environment?: undefined;\n /**\n * Application environment UUID.\n * @deprecated Use `environment` with an environment slug or UUID.\n */\n environmentId: string;\n }\n );\n\n/** Query parameters for listing storage buckets. */\nexport interface ListStorageBucketsQuery extends ListQuery, StorageEnvironmentOptions {}\n\n/**\n * Manages storage buckets for an application.\n *\n * Methods accept an application ID as their first argument for compatibility.\n * When the client has an application context, callers can omit it and address\n * buckets directly by their environment-scoped names.\n */\nexport class StorageBucketsResource extends BaseResource {\n constructor(\n httpClient: ConstructorParameters<typeof BaseResource>[0],\n private readonly defaultApplicationId?: string\n ) {\n super(httpClient);\n }\n\n /** Lists buckets, optionally restricted to an environment slug or UUID. */\n async list(query?: ListStorageBucketsQuery): Promise<Paginated<StorageBucket>>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async list(applicationId: string, query?: ListStorageBucketsQuery): Promise<Paginated<StorageBucket>>;\n async list(\n applicationIdOrQuery?: string | ListStorageBucketsQuery,\n legacyQuery?: ListStorageBucketsQuery\n ): Promise<Paginated<StorageBucket>> {\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n typeof applicationIdOrQuery === 'string' ? applicationIdOrQuery : undefined\n );\n const query = typeof applicationIdOrQuery === 'string' ? legacyQuery : applicationIdOrQuery;\n return this.httpClient.get(`/applications/${applicationId}/storage/buckets`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /** Creates a bucket with an immutable environment-scoped name. */\n async create(data: CreateStorageBucketInput): Promise<StorageBucket>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async create(applicationId: string, data: CreateStorageBucketInput): Promise<StorageBucket>;\n async create(\n applicationIdOrData: string | CreateStorageBucketInput,\n legacyData?: CreateStorageBucketInput\n ): Promise<StorageBucket> {\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n typeof applicationIdOrData === 'string' ? applicationIdOrData : undefined\n );\n const data = typeof applicationIdOrData === 'string' ? legacyData! : applicationIdOrData;\n return this.httpClient.post(`/applications/${applicationId}/storage/buckets`, data);\n }\n\n /** Gets a bucket by canonical environment-scoped name or deprecated UUID. */\n async get(bucketRef: StorageBucketReference, options?: StorageEnvironmentOptions): Promise<StorageBucket>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async get(\n applicationId: string,\n bucketRef: StorageBucketReference,\n options?: StorageEnvironmentOptions\n ): Promise<StorageBucket>;\n async get(\n applicationIdOrBucketRef: string,\n bucketRefOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<StorageBucket> {\n const explicitApplication = typeof bucketRefOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrOptions : applicationIdOrBucketRef;\n const options = explicitApplication ? legacyOptions : bucketRefOrOptions;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}`,\n {\n query: { environment: options?.environment },\n }\n );\n }\n\n /** Permanently deletes a bucket and all of its live and trashed objects. */\n async delete(bucketRef: StorageBucketReference, options?: StorageEnvironmentOptions): Promise<void>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async delete(\n applicationId: string,\n bucketRef: StorageBucketReference,\n options?: StorageEnvironmentOptions\n ): Promise<void>;\n async delete(\n applicationIdOrBucketRef: string,\n bucketRefOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<void> {\n const explicitApplication = typeof bucketRefOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrOptions : applicationIdOrBucketRef;\n const options = explicitApplication ? legacyOptions : bucketRefOrOptions;\n return this.httpClient.delete(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}`,\n { query: { environment: options?.environment } }\n );\n }\n}\n","import type { Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport {\n encodeStorageBucketReference,\n resolveStorageApplicationId,\n type StorageBucketReference,\n type StorageEnvironmentOptions,\n} from './storage-context';\n\n/** A file stored in a storage bucket. */\nexport interface StorageObject {\n /** Unique object identifier (UUID). */\n id: string;\n /** Internal UUID of the bucket containing this object. */\n bucketId: string;\n /** The application this object belongs to. */\n applicationId: string;\n /** The upload session that created this object, or `null` for imported objects. */\n uploadSessionId: string | null;\n /** The object key within the bucket, such as `\"images/photo.jpg\"`. */\n key: string;\n /** MIME content type, or `null` when none was recorded. */\n contentType: string | null;\n /** File size in bytes. */\n contentLength: number;\n /** SHA-1 checksum, if available. */\n checksumSha1: string | null;\n /** SHA-256 checksum, if available. */\n checksumSha256: string | null;\n /** MD5 checksum, if available. */\n checksumMd5: string | null;\n /** ISO 8601 timestamp of upload finalization. */\n uploadedAt: string;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Access URL details for a public or private storage object. */\nexport interface StorageObjectAccess {\n /** `\"public\"` for stable CDN URLs or `\"signed\"` for expiring URLs. */\n accessType: 'public' | 'signed';\n /** URL used to read the object. */\n url: string;\n /** ISO 8601 expiry for signed URLs, or `null` for public URLs. */\n expiresAt: string | null;\n}\n\n/** Query parameters for listing objects in a bucket. */\nexport interface ListStorageObjectsQuery extends StorageEnvironmentOptions {\n /** Only return objects whose key starts with this prefix. */\n prefix?: string;\n /** Group keys by this delimiter into virtual folders. Defaults to `\"/\"`. */\n delimiter?: string;\n /** Opaque cursor from a previous response. */\n cursor?: string;\n /** Maximum objects to return, from 1 through 1000. */\n limit?: number;\n}\n\n/** Options for creating an object access URL. */\nexport interface StorageObjectAccessOptions extends StorageEnvironmentOptions {\n /** Signed URL lifetime in seconds, from 60 through 86,400. */\n expiresInSeconds?: number;\n}\n\n/** A page of storage objects, including any common virtual-folder prefixes. */\nexport interface StorageObjectList extends Paginated<StorageObject> {\n commonPrefixes: string[];\n}\n\n/**\n * Reads and soft-deletes objects and creates access URLs.\n *\n * The context-bound overloads use the application configured on the client.\n * Explicit application overloads remain available for management tools and\n * compatibility. Bucket references should be canonical names; UUIDs remain a\n * deprecated server-side fallback.\n */\nexport class StorageObjectsResource extends BaseResource {\n constructor(\n httpClient: ConstructorParameters<typeof BaseResource>[0],\n private readonly defaultApplicationId?: string\n ) {\n super(httpClient);\n }\n\n /** Lists objects in a bucket. */\n async list(bucketRef: StorageBucketReference, query?: ListStorageObjectsQuery): Promise<StorageObjectList>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async list(\n applicationId: string,\n bucketRef: StorageBucketReference,\n query?: ListStorageObjectsQuery\n ): Promise<StorageObjectList>;\n async list(\n applicationIdOrBucketRef: string,\n bucketRefOrQuery?: string | ListStorageObjectsQuery,\n legacyQuery?: ListStorageObjectsQuery\n ): Promise<StorageObjectList> {\n const explicitApplication = typeof bucketRefOrQuery === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrQuery : applicationIdOrBucketRef;\n const query = explicitApplication ? legacyQuery : bucketRefOrQuery;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/objects`,\n {\n query: query as Record<string, string | number | undefined> | undefined,\n }\n );\n }\n\n /** Gets object metadata by object UUID. */\n async get(\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async get(\n applicationId: string,\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject>;\n async get(\n applicationIdOrBucketRef: string,\n bucketRefOrObjectId: string,\n objectIdOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<StorageObject> {\n const explicitApplication = typeof objectIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrObjectId : applicationIdOrBucketRef;\n const objectId = explicitApplication ? objectIdOrOptions : bucketRefOrObjectId;\n const options = explicitApplication ? legacyOptions : objectIdOrOptions;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/objects/${objectId}`,\n { query: { environment: options?.environment } }\n );\n }\n\n /**\n * Resolves an object by exact key by paging a prefix listing.\n *\n * The API has no get-by-key endpoint. This helper preserves the same\n * application, bucket, and environment across every page.\n */\n async getByKey(\n bucketRef: StorageBucketReference,\n key: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject | null>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async getByKey(\n applicationId: string,\n bucketRef: StorageBucketReference,\n key: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject | null>;\n async getByKey(\n applicationIdOrBucketRef: string,\n bucketRefOrKey: string,\n keyOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<StorageObject | null> {\n const explicitApplication = typeof keyOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrKey : applicationIdOrBucketRef;\n const key = explicitApplication ? keyOrOptions : bucketRefOrKey;\n const options = explicitApplication ? legacyOptions : keyOrOptions;\n\n let cursor: string | undefined;\n do {\n const page = await this.list(applicationId, bucketRef, {\n environment: options?.environment,\n prefix: key,\n cursor,\n });\n const match = page.items.find((object) => object.key === key);\n if (match) return match;\n cursor = page.nextCursor;\n } while (cursor);\n return null;\n }\n\n /** Moves a live object into the bucket trash. */\n async delete(bucketRef: StorageBucketReference, objectId: string, options?: StorageEnvironmentOptions): Promise<void>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async delete(\n applicationId: string,\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<void>;\n async delete(\n applicationIdOrBucketRef: string,\n bucketRefOrObjectId: string,\n objectIdOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<void> {\n const explicitApplication = typeof objectIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrObjectId : applicationIdOrBucketRef;\n const objectId = explicitApplication ? objectIdOrOptions : bucketRefOrObjectId;\n const options = explicitApplication ? legacyOptions : objectIdOrOptions;\n return this.httpClient.delete(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/objects/${objectId}`,\n { query: { environment: options?.environment } }\n );\n }\n\n /** Creates a stable public or time-limited signed object URL. */\n async getAccessUrl(\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageObjectAccessOptions\n ): Promise<StorageObjectAccess>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async getAccessUrl(\n applicationId: string,\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageObjectAccessOptions\n ): Promise<StorageObjectAccess>;\n async getAccessUrl(\n applicationIdOrBucketRef: string,\n bucketRefOrObjectId: string,\n objectIdOrOptions?: string | StorageObjectAccessOptions,\n legacyOptions?: StorageObjectAccessOptions\n ): Promise<StorageObjectAccess> {\n const explicitApplication = typeof objectIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrObjectId : applicationIdOrBucketRef;\n const objectId = explicitApplication ? objectIdOrOptions : bucketRefOrObjectId;\n const options = explicitApplication ? legacyOptions : objectIdOrOptions;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/objects/${objectId}/access-url`,\n { query: { environment: options?.environment, expiresInSeconds: options?.expiresInSeconds } }\n );\n }\n}\n","import type { Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport {\n encodeStorageBucketReference,\n resolveStorageApplicationId,\n type StorageBucketReference,\n type StorageEnvironmentOptions,\n} from './storage-context';\nimport type { StorageObject } from './storage-objects';\n\n/** A soft-deleted storage object returned by a bucket trash listing. */\nexport interface TrashedStorageObject extends StorageObject {\n /** ISO 8601 timestamp when the object was moved to trash. */\n deletedAt: string;\n}\n\n/** Query parameters for listing a bucket's trashed objects. */\nexport interface ListStorageTrashQuery extends StorageEnvironmentOptions {\n /** Only return trashed objects whose keys start with this prefix. */\n prefix?: string;\n /** Opaque cursor returned by a previous trash listing. */\n cursor?: string;\n /** Maximum objects to return, from 1 through 1000. */\n limit?: number;\n}\n\n/** A page of soft-deleted objects. */\nexport type StorageTrashList = Paginated<TrashedStorageObject>;\n\n/** Result returned after permanently deleting every object in a bucket's trash. */\nexport interface EmptyStorageTrashResult {\n /** Number of trashed objects permanently deleted. */\n purgedCount: number;\n}\n\n/**\n * Manages the lifecycle of soft-deleted storage objects.\n *\n * Restoring can fail with HTTP 409 when a live object already uses the same\n * key. Purge and empty operations are irreversible.\n */\nexport class StorageTrashResource extends BaseResource {\n constructor(\n httpClient: ConstructorParameters<typeof BaseResource>[0],\n private readonly defaultApplicationId?: string\n ) {\n super(httpClient);\n }\n\n /** Lists soft-deleted objects in a bucket. */\n async list(bucketRef: StorageBucketReference, query?: ListStorageTrashQuery): Promise<StorageTrashList>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async list(\n applicationId: string,\n bucketRef: StorageBucketReference,\n query?: ListStorageTrashQuery\n ): Promise<StorageTrashList>;\n async list(\n applicationIdOrBucketRef: string,\n bucketRefOrQuery?: string | ListStorageTrashQuery,\n legacyQuery?: ListStorageTrashQuery\n ): Promise<StorageTrashList> {\n const explicitApplication = typeof bucketRefOrQuery === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrQuery : applicationIdOrBucketRef;\n const query = explicitApplication ? legacyQuery : bucketRefOrQuery;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/trash`,\n { query: query as Record<string, string | number | undefined> | undefined }\n );\n }\n\n /** Restores a soft-deleted object to its original key. */\n async restore(\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async restore(\n applicationId: string,\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject>;\n async restore(\n applicationIdOrBucketRef: string,\n bucketRefOrObjectId: string,\n objectIdOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<StorageObject> {\n const explicitApplication = typeof objectIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrObjectId : applicationIdOrBucketRef;\n const objectId = explicitApplication ? objectIdOrOptions : bucketRefOrObjectId;\n const options = explicitApplication ? legacyOptions : objectIdOrOptions;\n return this.httpClient.post(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/trash/${objectId}/restore`,\n undefined,\n { query: { environment: options?.environment } }\n );\n }\n\n /** Permanently deletes one object from bucket trash. */\n async purge(bucketRef: StorageBucketReference, objectId: string, options?: StorageEnvironmentOptions): Promise<void>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async purge(\n applicationId: string,\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<void>;\n async purge(\n applicationIdOrBucketRef: string,\n bucketRefOrObjectId: string,\n objectIdOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<void> {\n const explicitApplication = typeof objectIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrObjectId : applicationIdOrBucketRef;\n const objectId = explicitApplication ? objectIdOrOptions : bucketRefOrObjectId;\n const options = explicitApplication ? legacyOptions : objectIdOrOptions;\n return this.httpClient.delete(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/trash/${objectId}`,\n { query: { environment: options?.environment } }\n );\n }\n\n /** Permanently deletes every object in a bucket's trash. */\n async empty(bucketRef: StorageBucketReference, options?: StorageEnvironmentOptions): Promise<EmptyStorageTrashResult>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async empty(\n applicationId: string,\n bucketRef: StorageBucketReference,\n options?: StorageEnvironmentOptions\n ): Promise<EmptyStorageTrashResult>;\n async empty(\n applicationIdOrBucketRef: string,\n bucketRefOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<EmptyStorageTrashResult> {\n const explicitApplication = typeof bucketRefOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrOptions : applicationIdOrBucketRef;\n const options = explicitApplication ? legacyOptions : bucketRefOrOptions;\n return this.httpClient.delete(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/trash`,\n { query: { environment: options?.environment } }\n );\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { resolveUploadSource, type NodeReadableLike, type UploadData } from '../upload/source';\nimport {\n runResolvedUpload,\n toUploadError,\n tusUploadTransport,\n type RunUploadOptions,\n type UploadTransport,\n} from '../upload/transport';\nimport { BaseResource } from './base-resource';\nimport {\n encodeStorageBucketReference,\n resolveStorageApplicationId,\n type StorageBucketReference,\n type StorageEnvironmentOptions,\n} from './storage-context';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Represents an upload session for a storage object. Upload sessions track the\n * lifecycle of a file upload from creation through completion.\n */\nexport interface StorageUploadSession {\n /** Unique identifier (UUID). */\n id: string;\n /** The bucket this upload targets. */\n bucketId: string;\n /** The application this upload belongs to. */\n applicationId: string;\n /** The object key/path the file will be stored at (e.g. `\"images/photo.jpg\"`). */\n key: string;\n /** MIME content type declared at creation, or `null` if not specified. */\n contentType: string | null;\n /** Expected file size in bytes declared at creation, or `null`. */\n contentLength: number | null;\n /** SHA-1 checksum for server-side verification, if provided. */\n checksumSha1: string | null;\n /** SHA-256 checksum for server-side verification, if provided. */\n checksumSha256: string | null;\n /** MD5 checksum for server-side verification, if provided. */\n checksumMd5: string | null;\n /**\n * Current session state:\n * - `\"pending\"` — Session created, awaiting the first bytes.\n * - `\"ready\"` — Receiving file data.\n * - `\"completed\"` — Upload verified and storage object created.\n * - `\"failed\"` — Upload failed or was rejected.\n * - `\"expired\"` — Session exceeded its expiration time.\n */\n state: 'pending' | 'ready' | 'completed' | 'failed' | 'expired';\n /** ISO 8601 timestamp when this session (and its upload URL) expires. */\n expiresAt: string;\n /** ISO 8601 timestamp when the upload was finalized, or `null`. */\n uploadedAt: string | null;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Input for creating a new upload session. */\nexport interface CreateUploadSessionInput {\n /** The object key/path the file will be stored at (e.g. `\"images/photo.jpg\"`). 1–1024 characters. */\n key: string;\n /** File size in bytes. Required. */\n contentLength: number;\n /** Lowercase hex SHA-256 checksum (64 chars) of the content. Required for server-side verification. */\n checksumSha256: string;\n /** MIME content type of the file (e.g. `\"image/jpeg\"`). */\n contentType?: string;\n /** Optional lowercase hex SHA-1 checksum (40 chars). */\n checksumSha1?: string;\n /** Optional lowercase hex MD5 checksum (32 chars). */\n checksumMd5?: string;\n}\n\n/** Query parameters for listing upload sessions in a bucket. */\nexport interface ListStorageUploadSessionsQuery extends ListQuery, StorageEnvironmentOptions {}\n\n/**\n * Response from creating an upload session. Contains both the session metadata\n * and the resumable upload instructions (signed URL + headers).\n */\nexport interface CreateUploadSessionResponse {\n /** The created upload session. */\n session: StorageUploadSession;\n /** Resumable upload instructions — use these to send the file data. */\n upload: {\n /** The HTTP method for the byte upload (resumable upload protocol). */\n method: 'PATCH';\n /** Signed upload URL. Send your file data here. */\n url: string;\n /** Required headers to include with the upload request. */\n headers: Record<string, string>;\n /** The URL where the object will be accessible after upload (CDN URL for public buckets). */\n publicObjectUrl: string;\n };\n}\n\n/** A byte source for uploading directly to a known signed URL. */\nexport interface UploadByteSource {\n /** In-memory data (`File`/`Blob`/`Buffer`/`Uint8Array`/`ArrayBuffer`). */\n data?: UploadData;\n /** A filesystem path to stream from (Node.js only). */\n path?: string;\n /** A readable stream (Node.js only). Requires `contentLength`. */\n stream?: NodeReadableLike;\n /** Byte size — required for `stream` inputs, computed otherwise. */\n contentLength?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Resource\n// ---------------------------------------------------------------------------\n\n/**\n * Manage upload sessions and upload bytes to a signed upload URL using the\n * resumable upload protocol. Accessed via `client.storage.uploadSessions`.\n *\n * For most use cases, prefer the high-level `client.storage.upload()`\n * which creates the session, computes the required checksum, uploads the bytes,\n * and returns the public URL.\n */\nexport class StorageUploadSessionsResource extends BaseResource {\n constructor(\n httpClient: ConstructorParameters<typeof BaseResource>[0],\n private readonly transport: UploadTransport = tusUploadTransport,\n private readonly defaultApplicationId?: string\n ) {\n super(httpClient);\n }\n\n /**\n * List upload sessions for a bucket.\n *\n * @param bucketRef - Canonical bucket name or deprecated UUID fallback.\n * @param query - Optional pagination parameters.\n * @returns A paginated list of upload sessions.\n */\n async list(\n bucketRef: StorageBucketReference,\n query?: ListStorageUploadSessionsQuery\n ): Promise<Paginated<StorageUploadSession>>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async list(\n applicationId: string,\n bucketRef: StorageBucketReference,\n query?: ListStorageUploadSessionsQuery\n ): Promise<Paginated<StorageUploadSession>>;\n async list(\n applicationIdOrBucketRef: string,\n bucketRefOrQuery?: string | ListStorageUploadSessionsQuery,\n legacyQuery?: ListStorageUploadSessionsQuery\n ): Promise<Paginated<StorageUploadSession>> {\n const explicitApplication = typeof bucketRefOrQuery === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrQuery : applicationIdOrBucketRef;\n const query = explicitApplication ? legacyQuery : bucketRefOrQuery;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/uploads`,\n { query: query as Record<string, string | number | undefined> | undefined }\n );\n }\n\n /**\n * Create an upload session. Returns the session metadata and a signed upload\n * URL for sending file data. This is the low-level method — for most use\n * cases prefer `client.storage.upload()` which also computes the\n * required SHA-256 checksum for you.\n *\n * @param bucketRef - Canonical bucket name or deprecated UUID fallback.\n * @param data - Object key, content length, SHA-256 checksum, and optional content type / extra checksums.\n * @returns The session and resumable upload instructions (URL, method, headers).\n */\n async create(\n bucketRef: StorageBucketReference,\n data: CreateUploadSessionInput,\n options?: StorageEnvironmentOptions\n ): Promise<CreateUploadSessionResponse>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async create(\n applicationId: string,\n bucketRef: StorageBucketReference,\n data: CreateUploadSessionInput,\n options?: StorageEnvironmentOptions\n ): Promise<CreateUploadSessionResponse>;\n async create(\n applicationIdOrBucketRef: string,\n bucketRefOrData: string | CreateUploadSessionInput,\n dataOrOptions?: CreateUploadSessionInput | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<CreateUploadSessionResponse> {\n const explicitApplication = typeof bucketRefOrData === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrData : applicationIdOrBucketRef;\n const data = explicitApplication ? (dataOrOptions as CreateUploadSessionInput) : bucketRefOrData;\n const options = explicitApplication ? legacyOptions : (dataOrOptions as StorageEnvironmentOptions | undefined);\n return this.httpClient.post(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/uploads`,\n data,\n { query: { environment: options?.environment } }\n );\n }\n\n /**\n * Get an upload session by ID. Use this to track server-side processing after\n * an upload (poll until `state === 'completed'`).\n *\n * @param bucketRef - Canonical bucket name or deprecated UUID fallback.\n * @param sessionId - The upload session ID (UUID).\n * @returns The current session state.\n */\n async get(\n bucketRef: StorageBucketReference,\n sessionId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageUploadSession>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async get(\n applicationId: string,\n bucketRef: StorageBucketReference,\n sessionId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageUploadSession>;\n async get(\n applicationIdOrBucketRef: string,\n bucketRefOrSessionId: string,\n sessionIdOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<StorageUploadSession> {\n const explicitApplication = typeof sessionIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrSessionId : applicationIdOrBucketRef;\n const sessionId = explicitApplication ? sessionIdOrOptions : bucketRefOrSessionId;\n const options = explicitApplication ? legacyOptions : sessionIdOrOptions;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/uploads/${sessionId}`,\n { query: { environment: options?.environment } }\n );\n }\n\n /**\n * Upload bytes directly to a pre-existing signed upload URL — for example, a\n * URL returned by {@link create} or handed to your client by a backend. Skips\n * session creation and checksum computation.\n *\n * @param url - A signed upload URL.\n * @param source - The bytes to upload.\n * @param options - Chunk size, retry config, progress, abort signal, resume,\n * and any required `headers` returned with the upload session.\n * @throws {@link UploadError} if the upload fails after all retries.\n */\n async uploadToUrl(\n url: string,\n source: UploadByteSource,\n options?: RunUploadOptions & { headers?: Record<string, string> }\n ): Promise<void> {\n const resolved = await resolveUploadSource({ key: '', ...source }, { hash: false });\n const headers = { 'Tus-Resumable': '1.0.0', ...options?.headers };\n await runResolvedUpload(this.transport, url, resolved, options, headers).catch(toUploadError);\n }\n\n /**\n * Resume an interrupted upload to a previously issued signed upload URL. The\n * resumable protocol negotiates the current offset and continues from there.\n *\n * @param url - The signed upload URL from the original {@link create} call.\n * @param source - The full bytes to upload (the same content as the original).\n * @param options - Chunk size, retry config, progress, abort signal.\n */\n async resumeFromUrl(\n url: string,\n source: UploadByteSource,\n options?: RunUploadOptions & { headers?: Record<string, string> }\n ): Promise<void> {\n return this.uploadToUrl(url, source, { ...options, resume: true });\n }\n}\n","import { UploadError } from '../errors';\nimport type { HttpClient } from '../http-client';\nimport { resolveUploadSource, type NodeReadableLike, type UploadData } from '../upload/source';\nimport {\n runResolvedUpload,\n toUploadError,\n tusUploadTransport,\n type UploadTransport,\n type UploadUrlStorage,\n} from '../upload/transport';\nimport { StorageBucketsResource } from './storage-buckets';\nimport {\n resolveStorageApplicationId,\n resolveStorageBucketReference,\n type StorageBucketReference,\n type StorageEnvironmentOptions,\n} from './storage-context';\nimport { StorageObjectsResource, type StorageObject } from './storage-objects';\nimport { StorageTrashResource } from './storage-trash';\nimport { StorageUploadSessionsResource, type StorageUploadSession } from './storage-upload-sessions';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Options controlling whether and how to wait for an upload to finalize server-side. */\nexport interface WaitForCompletionOptions extends StorageEnvironmentOptions {\n /** Maximum time to wait in milliseconds. Default: 60000. */\n timeoutMs?: number;\n /** How often to poll the session state, in milliseconds. Default: 1000. */\n pollIntervalMs?: number;\n}\n\ninterface UploadFileOptions {\n /**\n * Explicit application UUID. Omit this when the client was configured with\n * `applicationId` or is running with `GIGADRIVE_APPLICATION_ID`.\n * @deprecated Configure `GigadriveClientConfig.applicationId` or use workload context.\n */\n applicationId?: string;\n /**\n * Environment slug or UUID. Workloads normally omit this because the API\n * infers and enforces the deployment environment from their credential. If\n * completion options also specify an environment, this top-level value takes\n * precedence for the entire upload lifecycle.\n */\n environment?: string;\n /** The object key/path in the bucket (e.g. `\"images/logo.png\"`). */\n key: string;\n /** In-memory data (browser `File`/`Blob`, Node `Buffer`, `Uint8Array`, `ArrayBuffer`). */\n data?: UploadData;\n /** A filesystem path to upload from (Node.js only). Size, checksum, and content type are derived automatically. */\n path?: string;\n /** A readable stream to upload from (Node.js only). Requires `contentLength` and `checksumSha256`. */\n stream?: NodeReadableLike;\n /** MIME content type. Inferred from `key` when omitted. */\n contentType?: string;\n /** Byte size. Required for `stream`; computed otherwise. */\n contentLength?: number;\n /** Pre-computed SHA-256 (skips hashing). Required for `stream`. */\n checksumSha256?: string;\n /** Also send a SHA-1 checksum. */\n checksumSha1?: string;\n /** Also send an MD5 checksum (Node.js only unless provided). */\n checksumMd5?: string;\n /** Maximum chunk size in bytes (for very large files / streams). */\n chunkSize?: number;\n /** Retry backoff in milliseconds; `null`/`[]` disables retries. */\n retryDelays?: number[] | null;\n /** Progress callback invoked during the byte upload. */\n onProgress?: (bytesSent: number, bytesTotal: number) => void;\n /** Abort signal to cancel the upload. */\n signal?: AbortSignal;\n /** Persist a resumable fingerprint so the upload can be resumed later. */\n resume?: boolean;\n /** Custom storage backend for resumable fingerprints. */\n urlStorage?: UploadUrlStorage;\n /** Wait until the object is finalized server-side before resolving. Pass options to tune polling. */\n waitForCompletion?: boolean | WaitForCompletionOptions;\n}\n\n/** Input for the high-level {@link ApplicationStorageResource.upload | upload()} method. */\nexport type UploadFileInput = UploadFileOptions &\n (\n | {\n /** Canonical environment-scoped bucket name, or a deprecated UUID fallback. */\n bucket: StorageBucketReference;\n bucketId?: never;\n }\n | {\n bucket?: never;\n /**\n * Internal bucket UUID.\n * @deprecated Use `bucket` with the canonical environment-scoped name.\n */\n bucketId: string;\n }\n );\n\n/** Result of a successful upload. */\nexport interface UploadFileResult {\n /** The upload session. When `waitForCompletion` was set, `state` is `\"completed\"`. */\n session: StorageUploadSession;\n /** The public/CDN URL of the uploaded object. */\n url: string;\n /** The finalized storage object — present only when `waitForCompletion` was set. */\n object?: StorageObject;\n}\n\n/** Options for {@link ApplicationStorageResource.uploadBatch | uploadBatch()}. */\nexport interface UploadBatchOptions {\n /** Maximum number of concurrent uploads. Default: 4. */\n concurrency?: number;\n /** Called after each file settles, with the number completed and the total. */\n onProgress?: (completed: number, total: number) => void;\n}\n\n/** The outcome of one file within a batch upload. Errors are isolated per file. */\nexport interface UploadBatchItemResult {\n /** The input that produced this result. */\n input: UploadFileInput;\n /** The successful result, if the upload succeeded. */\n result?: UploadFileResult;\n /** The error, if this upload failed. */\n error?: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Resource\n// ---------------------------------------------------------------------------\n\nconst delay = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Namespace for all storage operations on an application: bucket management,\n * object listing/access, low-level upload sessions, and the high-level\n * {@link upload} / {@link uploadBatch} helpers.\n *\n * Accessed canonically via `client.storage`. `client.applications.storage`\n * references the same resource for compatibility.\n *\n * @example\n * ```ts\n * // High-level upload (Node.js, from a path — checksum/size/content-type inferred)\n * const { url } = await client.storage.upload({\n * bucket: 'photos',\n * key: 'photos/cat.jpg',\n * path: './cat.jpg',\n * });\n *\n * // Browser upload from a file input, with progress and abort\n * const controller = new AbortController();\n * const { url } = await client.storage.upload({\n * bucket: 'uploads',\n * key: `uploads/${file.name}`,\n * data: file,\n * onProgress: (sent, total) => console.log(`${Math.round((sent / total) * 100)}%`),\n * signal: controller.signal,\n * });\n * ```\n */\nexport class ApplicationStorageResource {\n /** Create, list, get, and delete storage buckets. */\n readonly buckets: StorageBucketsResource;\n /** List, get, delete objects, and generate access URLs. */\n readonly objects: StorageObjectsResource;\n /** Low-level upload sessions and direct-to-URL byte uploads. */\n readonly uploadSessions: StorageUploadSessionsResource;\n /** Lists, restores, and permanently purges soft-deleted objects. */\n readonly trash: StorageTrashResource;\n\n private readonly transport: UploadTransport;\n\n constructor(\n httpClient: HttpClient,\n transport: UploadTransport = tusUploadTransport,\n private readonly defaultApplicationId?: string\n ) {\n this.transport = transport;\n this.buckets = new StorageBucketsResource(httpClient, defaultApplicationId);\n this.objects = new StorageObjectsResource(httpClient, defaultApplicationId);\n this.uploadSessions = new StorageUploadSessionsResource(httpClient, transport, defaultApplicationId);\n this.trash = new StorageTrashResource(httpClient, defaultApplicationId);\n }\n\n /**\n * Upload a file to a storage bucket. Handles the full flow: computes the\n * required SHA-256 checksum, creates an upload session, uploads the bytes with\n * automatic retries (and optional progress/abort/resume), and returns the\n * public URL.\n *\n * Accepts browser `File`/`Blob`, Node `Buffer`/`Uint8Array`/`ArrayBuffer`, a\n * Node filesystem `path`, or a Node readable `stream` (with `contentLength`\n * and `checksumSha256`). The content type is inferred from `key` when omitted.\n *\n * @param input - What and where to upload, plus optional transfer options.\n * @returns The upload session and public object URL (and the finalized object when `waitForCompletion` is set).\n * @throws {@link UploadError} if the byte upload fails.\n * @throws {@link UploadSessionExpiredError} if the session expires mid-upload.\n *\n * @example\n * ```ts\n * const { session, url, object } = await client.storage.upload({\n * bucket: 'reports', key: 'q1.pdf', path: './q1.pdf',\n * waitForCompletion: true,\n * });\n * console.log(object?.contentLength, 'bytes available at', url);\n * ```\n */\n async upload(input: UploadFileInput): Promise<UploadFileResult> {\n const applicationId = resolveStorageApplicationId(this.defaultApplicationId, input.applicationId);\n const bucketRef = resolveStorageBucketReference(input);\n const completionOptions = typeof input.waitForCompletion === 'object' ? input.waitForCompletion : undefined;\n const environment = input.environment ?? completionOptions?.environment;\n const resolved = await resolveUploadSource({\n key: input.key,\n data: input.data,\n path: input.path,\n stream: input.stream,\n contentType: input.contentType,\n contentLength: input.contentLength,\n checksumSha256: input.checksumSha256,\n checksumSha1: input.checksumSha1,\n checksumMd5: input.checksumMd5,\n });\n\n const { session, upload } = await this.uploadSessions.create(\n applicationId,\n bucketRef,\n {\n key: input.key,\n contentLength: resolved.size,\n checksumSha256: resolved.checksums.sha256,\n contentType: resolved.contentType,\n checksumSha1: resolved.checksums.sha1,\n checksumMd5: resolved.checksums.md5,\n },\n { environment }\n );\n\n await runResolvedUpload(\n this.transport,\n upload.url,\n resolved,\n {\n chunkSize: input.chunkSize,\n retryDelays: input.retryDelays,\n onProgress: input.onProgress,\n signal: input.signal,\n resume: input.resume,\n urlStorage: input.urlStorage,\n },\n // Forward any required headers the API issued with the session.\n { 'Tus-Resumable': '1.0.0', ...upload.headers }\n ).catch(toUploadError);\n\n if (input.waitForCompletion) {\n const options = completionOptions ?? {};\n const completed = await this.waitForCompletion(applicationId, bucketRef, session.id, {\n ...options,\n environment,\n });\n const object = (await this.objects.getByKey(applicationId, bucketRef, input.key, { environment })) ?? undefined;\n return { session: completed, url: upload.publicObjectUrl, object };\n }\n\n return { session, url: upload.publicObjectUrl };\n }\n\n /**\n * Upload many files concurrently. Each file is uploaded independently; a\n * failure for one file does not abort the others — inspect each item's\n * `error`/`result`.\n *\n * @param inputs - The files to upload.\n * @param options - Concurrency limit and an aggregated progress callback.\n * @returns One result per input, in the same order.\n *\n * @example\n * ```ts\n * const results = await client.storage.uploadBatch(\n * files.map((f) => ({ bucket: 'uploads', key: f.name, data: f })),\n * { concurrency: 6, onProgress: (done, total) => console.log(`${done}/${total}`) },\n * );\n * const failed = results.filter((r) => r.error);\n * ```\n */\n async uploadBatch(inputs: UploadFileInput[], options?: UploadBatchOptions): Promise<UploadBatchItemResult[]> {\n const concurrency = Math.max(1, options?.concurrency ?? 4);\n const results: UploadBatchItemResult[] = new Array(inputs.length);\n let completed = 0;\n let next = 0;\n\n const worker = async (): Promise<void> => {\n for (;;) {\n const index = next++;\n if (index >= inputs.length) return;\n try {\n results[index] = { input: inputs[index], result: await this.upload(inputs[index]) };\n } catch (error) {\n results[index] = { input: inputs[index], error };\n }\n completed++;\n options?.onProgress?.(completed, inputs.length);\n }\n };\n\n await Promise.all(Array.from({ length: Math.min(concurrency, inputs.length) }, () => worker()));\n return results;\n }\n\n /**\n * Poll an upload session until the object is finalized server-side.\n *\n * @param bucketRef - Canonical bucket name or deprecated UUID fallback.\n * @param sessionId - The upload session ID (UUID).\n * @param options - Timeout and polling interval.\n * @returns The completed session.\n * @throws {@link UploadError} if the session fails, expires, or the timeout elapses.\n */\n async waitForCompletion(\n bucketRef: StorageBucketReference,\n sessionId: string,\n options?: WaitForCompletionOptions\n ): Promise<StorageUploadSession>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async waitForCompletion(\n applicationId: string,\n bucketRef: StorageBucketReference,\n sessionId: string,\n options?: WaitForCompletionOptions\n ): Promise<StorageUploadSession>;\n async waitForCompletion(\n applicationIdOrBucketRef: string,\n bucketRefOrSessionId: string,\n sessionIdOrOptions?: string | WaitForCompletionOptions,\n legacyOptions?: WaitForCompletionOptions\n ): Promise<StorageUploadSession> {\n const explicitApplication = typeof sessionIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrSessionId : applicationIdOrBucketRef;\n const sessionId = explicitApplication ? sessionIdOrOptions : bucketRefOrSessionId;\n const options = explicitApplication ? legacyOptions : sessionIdOrOptions;\n const timeoutMs = options?.timeoutMs ?? 60_000;\n const pollIntervalMs = options?.pollIntervalMs ?? 1000;\n const deadline = Date.now() + timeoutMs;\n\n for (;;) {\n const session = await this.uploadSessions.get(applicationId, bucketRef, sessionId, {\n environment: options?.environment,\n });\n if (session.state === 'completed') return session;\n if (session.state === 'failed' || session.state === 'expired') {\n throw new UploadError(`Upload session ${session.state}.`);\n }\n if (Date.now() >= deadline) {\n throw new UploadError('Timed out waiting for the upload to complete.');\n }\n await delay(pollIntervalMs);\n }\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { ApplicationEnvVarsResource } from './application-env-vars';\nimport { ApplicationRequestsResource } from './application-requests';\nimport { ApplicationStorageResource } from './application-storage';\nimport { BaseResource } from './base-resource';\nimport type { ApplicationHostnameList, HostnameAvailability, SetProductionHostnameResult } from './hostnames';\nimport type { Organization } from './organizations';\n\n/** A Gigadrive Network application, belonging to an {@link Organization}. */\nexport interface Application {\n /** Unique identifier (UUID). */\n id: string;\n /** The organization this application belongs to. */\n organization: Organization;\n /** Display name of the application. */\n name: string;\n /** Avatar / logo URL. */\n imageUrl: string;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Input accepted when creating a Gigadrive Network application. */\nexport interface CreateApplicationInput {\n /** Organization that will own the application. */\n organizationId: string;\n /** Display name. Surrounding whitespace is removed by the API. */\n name: string;\n /** Optional lowercase slug. Generated from {@link name} when omitted. */\n slug?: string;\n /**\n * Project directory relative to the repository root. The API normalizes\n * redundant separators and rejects absolute paths and traversal segments.\n */\n rootDirectory?: string;\n}\n\n/**\n * Application creation result used to start the first deployment without an\n * additional lookup.\n */\nexport interface CreatedApplication {\n /** Stable application UUID. */\n id: string;\n /** Owning organization UUID. */\n organizationId: string;\n /** Normalized display name. */\n name: string;\n /** Generated or caller-supplied application slug. */\n slug: string;\n /** Application icon URL. */\n imageUrl: string;\n /** Normalized project directory, or `null` for the repository root. */\n rootDirectory: string | null;\n /** Production environment slug to use for the first deployment. */\n defaultEnvironmentSlug: string;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Query filters for listing applications. */\nexport interface ListApplicationsQuery extends ListQuery {\n /** Only return applications belonging to this organization. */\n organizationId?: string;\n}\n\n/**\n * Manage applications. Accessed via {@link GigadriveClient.applications}.\n *\n * @example\n * ```ts\n * const { items: apps } = await client.applications.list();\n * console.log(apps.map((a) => `${a.name} (${a.organization.name})`));\n * ```\n */\nexport class ApplicationsResource extends BaseResource {\n /**\n * Manage environment variables scoped to an application.\n *\n * @example\n * ```ts\n * await client.applications.envVars.create('app-id', {\n * key: 'DATABASE_URL',\n * value: 'postgres://...',\n * sensitive: true,\n * });\n * ```\n */\n readonly envVars: ApplicationEnvVarsResource;\n\n /**\n * Manage storage buckets, objects, and file uploads for an application.\n *\n * @example\n * ```ts\n * // Upload a file\n * const { url } = await client.storage.upload({\n * bucket: 'assets',\n * key: 'images/logo.png',\n * data: fileData,\n * });\n *\n * // List objects in a bucket\n * const { items } = await client.storage.objects.list('assets');\n * ```\n */\n readonly storage: ApplicationStorageResource;\n\n /**\n * Read observed traffic (request logs) for an application.\n *\n * @example\n * ```ts\n * const { items } = await client.applications.requests.list('app-id', { statusFamily: 5 });\n * ```\n */\n readonly requests: ApplicationRequestsResource;\n\n constructor(httpClient: ConstructorParameters<typeof BaseResource>[0], defaultApplicationId?: string) {\n super(httpClient);\n this.envVars = new ApplicationEnvVarsResource(this.httpClient);\n this.storage = new ApplicationStorageResource(this.httpClient, undefined, defaultApplicationId);\n this.requests = new ApplicationRequestsResource(this.httpClient);\n }\n\n /**\n * List applications the authenticated actor has access to.\n *\n * Requires the `network:applications:read` scope.\n *\n * @param query - Optional organization filter and pagination.\n * @returns A paginated list of applications.\n *\n * @example\n * ```ts\n * const { items, total } = await client.applications.list({ organizationId: 'org-id' });\n * console.log(`Found ${total} applications`);\n * ```\n */\n async list(query?: ListApplicationsQuery): Promise<Paginated<Application>> {\n return this.httpClient.get('/applications', {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Creates an application with production and preview environments.\n *\n * Requires the `network:applications:write` scope and access to the owning\n * organization. Application-, deployment-, and function-scoped tokens cannot\n * create applications.\n *\n * @param input - Ownership, display name, and optional repository layout.\n * @returns The persisted application plus the default production environment\n * slug, ready for an immediate deployment request.\n *\n * @example\n * ```ts\n * const app = await client.applications.create({\n * organizationId: 'org-id',\n * name: 'Next.js Storefront',\n * });\n * console.log(app.id, app.defaultEnvironmentSlug);\n * ```\n */\n async create(input: CreateApplicationInput): Promise<CreatedApplication> {\n return this.httpClient.post('/applications', input);\n }\n\n /**\n * List the `*.gigadrive.app` hostnames for an application (production alias\n * and per-branch aliases).\n *\n * @param applicationId - The application ID (UUID).\n * @returns The hostnames plus the production hostname `label`.\n *\n * @example\n * ```ts\n * const { items, label } = await client.applications.hostnames('app-id');\n * console.log(`Production: ${label}.gigadrive.app`);\n * ```\n */\n async hostnames(applicationId: string): Promise<ApplicationHostnameList> {\n return this.httpClient.get(`/applications/${applicationId}/hostnames`);\n }\n\n /**\n * Check whether a candidate production hostname label is allowed and globally\n * available before setting it with {@link setProductionHostname}.\n *\n * Requires the `network:applications:read` scope.\n *\n * @param applicationId - The application ID (UUID).\n * @param label - The candidate production hostname label (e.g. `\"my-app\"`).\n * @returns Whether the label is available, plus a `reason` when it is not.\n *\n * @example\n * ```ts\n * const { available, reason } = await client.applications.checkHostnameAvailability('app-id', 'my-app');\n * if (!available) console.log(`Unavailable: ${reason}`);\n * ```\n */\n async checkHostnameAvailability(applicationId: string, label: string): Promise<HostnameAvailability> {\n return this.httpClient.get(`/applications/${applicationId}/hostname/availability`, {\n query: { label },\n });\n }\n\n /**\n * Set the application's production hostname. The production alias\n * `{label}.gigadrive.app` is re-pointed to the latest production deployment.\n *\n * Requires the `network:applications:write` scope. Deployment- and\n * function-scoped tokens cannot change the production hostname.\n *\n * @param applicationId - The application ID (UUID).\n * @param label - The production hostname label (e.g. `\"my-app\"`). It is\n * normalized (slugified) server-side.\n * @returns The saved label, the resulting hostname, and whether it is live yet.\n *\n * @example\n * ```ts\n * const { hostname, live } = await client.applications.setProductionHostname('app-id', 'my-app');\n * console.log(live ? `Live at ${hostname}` : `Reserved ${hostname} (deploy to go live)`);\n * ```\n */\n async setProductionHostname(applicationId: string, label: string): Promise<SetProductionHostnameResult> {\n return this.httpClient.put(`/applications/${applicationId}/hostname`, { label });\n }\n}\n","import type { Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport type { Hostname } from './hostnames';\n\n/**\n * The lifecycle status of a deployment.\n * - `\"PENDING\"` — Created, waiting for artifact upload.\n * - `\"QUEUED\"` — Queued for processing.\n * - `\"STARTING\"` — Processing is starting.\n * - `\"BUILDING\"` — Build pipeline is running.\n * - `\"PROVISIONING\"` — Infrastructure is being provisioned.\n * - `\"ACTIVE\"` — Successfully deployed and serving traffic.\n * - `\"FAILED\"` — Build or provisioning failed.\n */\nexport type DeploymentStatus = 'PENDING' | 'QUEUED' | 'STARTING' | 'BUILDING' | 'PROVISIONING' | 'ACTIVE' | 'FAILED';\n\n/** The severity level of a deployment log entry. */\nexport type DeploymentLogType = 'INFO' | 'ERROR' | 'WARN' | 'DEBUG';\n\n/** A deployment of an application to the Gigadrive Network. */\nexport interface Deployment {\n /** Unique identifier (UUID). */\n id: string;\n /** The application this deployment belongs to. */\n applicationId: string;\n /** Current lifecycle status. */\n status: DeploymentStatus;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** A single log entry from a deployment's build or provisioning pipeline. */\nexport interface DeploymentLog {\n /** Unique identifier. */\n id: string;\n /** The log message text. */\n message: string;\n /** Severity level: `\"INFO\"`, `\"ERROR\"`, `\"WARN\"`, or `\"DEBUG\"`. */\n type: DeploymentLogType;\n /** ISO 8601 timestamp of when this log entry was created. */\n createdAt: string;\n}\n\n/** A paginated page of deployment log entries. */\nexport interface DeploymentLogPage {\n /** Total number of log entries for this deployment. */\n totalItems: number;\n /** Maximum number of entries per page. */\n limit: number;\n /** Number of entries skipped (for pagination). */\n offset: number;\n /** The log entries on this page. */\n items: DeploymentLog[];\n}\n\n/** Input for creating a new deployment. */\nexport interface CreateDeploymentInput {\n /** The application to deploy. */\n applicationId: string;\n /** Optional git source for the deployment. When omitted, the deployment expects an artifact upload. */\n gitSource?: {\n /** The git ref to deploy (e.g. `\"main\"`, `\"v1.0.0\"`). */\n ref: string;\n /** A specific commit SHA to deploy. If omitted, the HEAD of the ref is used. */\n sha?: string;\n };\n}\n\n/** Query filters for listing deployments. All fields are optional. */\nexport interface ListDeploymentsQuery {\n /** Filter by organization ID. */\n organizationId?: string;\n /** Filter by application ID. */\n applicationId?: string;\n /** Filter by deployment status. */\n status?: DeploymentStatus;\n}\n\n/** Query parameters for fetching deployment logs. */\nexport interface ListDeploymentLogsQuery {\n /** Number of log entries to skip (for pagination). */\n offset?: number;\n /** Maximum number of log entries to return per page. */\n limit?: number;\n /** Only return log entries created after this ISO 8601 timestamp. Useful for tailing logs. */\n 'createdAt[gt]'?: string;\n}\n\n/** Result from starting a multipart deployment upload. */\nexport interface StartUploadResult {\n /** The multipart upload ID. Pass this to subsequent `getPresignedUrl` and `completeUpload` calls. */\n uploadId: string;\n}\n\n/** A presigned URL for uploading a single part of a multipart deployment upload. */\nexport interface PresignedUrlResult {\n /** The presigned URL to PUT the part data to. */\n url: string;\n}\n\n/** A successfully uploaded part, used to complete the multipart upload. */\nexport interface UploadPart {\n /** The 1-based part number. */\n partNumber: number;\n /** The ETag returned by the storage provider after uploading this part. */\n etag: string;\n}\n\n/**\n * Manage deployments — create, monitor, upload artifacts, and read logs.\n * Accessed via {@link GigadriveClient.deployments}.\n *\n * ## Deployment lifecycle\n *\n * 1. **Create** a deployment with {@link create}.\n * 2. **Upload** build artifacts using the multipart upload flow\n * ({@link startUpload} → {@link getPresignedUrl} → {@link uploadPart} → {@link completeUpload}).\n * 3. **Monitor** the build with {@link get} and {@link getLogs}.\n *\n * @example\n * ```ts\n * // Create a deployment\n * const deployment = await client.deployments.create({ applicationId: 'app-id' });\n *\n * // Check status\n * const updated = await client.deployments.get(deployment.id);\n * console.log(`Status: ${updated.status}`);\n *\n * // Read build logs\n * const logs = await client.deployments.getLogs(deployment.id, { limit: 50 });\n * for (const entry of logs.items) {\n * console.log(`[${entry.type}] ${entry.message}`);\n * }\n * ```\n */\nexport class DeploymentsResource extends BaseResource {\n /**\n * List deployments, optionally filtered by organization, application, or status.\n *\n * Requires the `network:deployments:read` scope.\n *\n * @param query - Optional filters.\n * @returns A paginated list of deployments.\n *\n * @example\n * ```ts\n * // All deployments for an application\n * const { items } = await client.deployments.list({ applicationId: 'app-id' });\n *\n * // Only active deployments\n * const { items } = await client.deployments.list({ status: 'ACTIVE' });\n * ```\n */\n async list(query?: ListDeploymentsQuery): Promise<Paginated<Deployment>> {\n return this.httpClient.get('/deployments', {\n query: query as Record<string, string | undefined> | undefined,\n });\n }\n\n /**\n * Get a deployment by ID, including its current status.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @returns The deployment with its current status.\n *\n * @example\n * ```ts\n * const deployment = await client.deployments.get('deployment-id');\n * if (deployment.status === 'ACTIVE') {\n * console.log('Deployment is live!');\n * }\n * ```\n */\n async get(deploymentId: string): Promise<Deployment> {\n return this.httpClient.get(`/deployments/${deploymentId}`);\n }\n\n /**\n * Create a new deployment. The deployment starts in `\"PENDING\"` status,\n * waiting for artifact upload. Use the multipart upload methods\n * ({@link startUpload}, {@link getPresignedUrl}, {@link uploadPart},\n * {@link completeUpload}) to upload build artifacts.\n *\n * Requires the `network:deployments:trigger` scope.\n *\n * @param data - The application ID and optional git source.\n * @returns The newly created deployment.\n *\n * @example\n * ```ts\n * const deployment = await client.deployments.create({\n * applicationId: 'app-id',\n * });\n * console.log(`Created deployment ${deployment.id} (${deployment.status})`);\n * ```\n */\n async create(data: CreateDeploymentInput): Promise<Deployment> {\n return this.httpClient.post('/deployments', data);\n }\n\n /**\n * Start a multipart upload for deployment artifacts. This initiates a new\n * multipart upload and returns an upload ID for subsequent part uploads.\n *\n * The deployment must be in `\"PENDING\"` status.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @returns An object containing the `uploadId` for subsequent calls.\n *\n * @example\n * ```ts\n * const { uploadId } = await client.deployments.startUpload('deployment-id');\n * ```\n */\n async startUpload(deploymentId: string): Promise<StartUploadResult> {\n return this.httpClient.post(`/deployments/${deploymentId}/upload/start`);\n }\n\n /**\n * Get a presigned URL for uploading a single part of a multipart upload.\n * The URL is temporary and should be used immediately with {@link uploadPart}.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @param uploadId - The multipart upload ID from {@link startUpload}.\n * @param partNumber - The 1-based part number.\n * @returns An object containing the presigned `url` to PUT the part data to.\n *\n * @example\n * ```ts\n * const { url } = await client.deployments.getPresignedUrl(\n * 'deployment-id', uploadId, 1,\n * );\n * ```\n */\n async getPresignedUrl(deploymentId: string, uploadId: string, partNumber: number): Promise<PresignedUrlResult> {\n if (!Number.isInteger(partNumber) || partNumber < 1) {\n throw new Error(`partNumber must be a positive integer, received ${partNumber}`);\n }\n return this.httpClient.post(`/deployments/${deploymentId}/upload/part`, { uploadId, partNumber });\n }\n\n /**\n * Upload a part to a presigned URL obtained from {@link getPresignedUrl}.\n * This sends the chunk data directly to the backend storage service, not\n * to the Gigadrive API. The returned `etag` is needed for\n * {@link completeUpload}.\n *\n * @param presignedUrl - The presigned URL from {@link getPresignedUrl}.\n * @param data - The chunk data to upload.\n * @param partNumber - The 1-based part number (used for error messages).\n * @returns The part number and ETag. Collect these for {@link completeUpload}.\n * @throws {@link ApiError} if the PUT request fails.\n * @throws Error if the storage provider does not return an ETag header.\n *\n * @example\n * ```ts\n * const chunk = fileBuffer.subarray(0, 10 * 1024 * 1024); // 10 MB\n * const part = await client.deployments.uploadPart(presignedUrl, chunk, 1);\n * // part = { partNumber: 1, etag: '\"abc123...\"' }\n * ```\n */\n async uploadPart(\n presignedUrl: string,\n data: ArrayBuffer | Uint8Array | Blob,\n partNumber: number\n ): Promise<UploadPart> {\n if (!Number.isInteger(partNumber) || partNumber < 1) {\n throw new Error(`partNumber must be a positive integer, received ${partNumber}`);\n }\n const response = await this.httpClient.fetchRaw(presignedUrl, {\n method: 'PUT',\n headers: {\n // Deployment artifacts are always ZIP archives.\n 'Content-Type': 'application/zip',\n 'Content-Length': String(data instanceof Blob ? data.size : data.byteLength),\n },\n body: data,\n });\n\n const etag = response.headers.get('ETag');\n if (!etag) {\n throw new Error(`No ETag received for part ${partNumber}`);\n }\n\n return { partNumber, etag };\n }\n\n /**\n * Complete a multipart upload after all parts have been uploaded via\n * {@link uploadPart}. This signals the storage provider to assemble the\n * parts into a single object and triggers the deployment build pipeline.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @param uploadId - The multipart upload ID from {@link startUpload}.\n * @param parts - Array of `{ partNumber, etag }` from each {@link uploadPart} call.\n *\n * @example\n * ```ts\n * await client.deployments.completeUpload(deploymentId, uploadId, [\n * { partNumber: 1, etag: '\"abc...\"' },\n * { partNumber: 2, etag: '\"def...\"' },\n * ]);\n * ```\n */\n async completeUpload(deploymentId: string, uploadId: string, parts: UploadPart[]): Promise<void> {\n return this.httpClient.post(`/deployments/${deploymentId}/upload/complete`, { uploadId, parts });\n }\n\n /**\n * Fetch deployment logs. Supports pagination and filtering by timestamp\n * for incremental log tailing.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @param query - Optional pagination and filter parameters.\n * @returns A page of log entries with total count.\n *\n * @example\n * ```ts\n * // Get the first page of logs\n * const page = await client.deployments.getLogs('deployment-id', {\n * offset: 0,\n * limit: 100,\n * });\n *\n * for (const entry of page.items) {\n * const prefix = entry.type === 'ERROR' ? 'ERR' : entry.type === 'WARN' ? 'WRN' : 'INF';\n * console.log(`[${prefix}] ${entry.message}`);\n * }\n *\n * // Tail new logs since last fetch\n * const newLogs = await client.deployments.getLogs('deployment-id', {\n * 'createdAt[gt]': lastEntry.createdAt,\n * });\n * ```\n */\n async getLogs(deploymentId: string, query?: ListDeploymentLogsQuery): Promise<DeploymentLogPage> {\n return this.httpClient.get(`/deployments/${deploymentId}/logs`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * List the immutable `*.gigadrive.app` hostnames assigned to a deployment.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @returns A paginated list of hostnames.\n *\n * @example\n * ```ts\n * const { items } = await client.deployments.getHostnames('deployment-id');\n * console.log(items.map((h) => h.hostname));\n * ```\n */\n async getHostnames(deploymentId: string): Promise<Paginated<Hostname>> {\n return this.httpClient.get(`/deployments/${deploymentId}/hostnames`);\n }\n}\n","import type { NormalizedImagePolicy } from '@gigadrive/network-config';\n\nimport { BaseResource } from './base-resource';\n\nexport interface ImageCacheInspection {\n enabled: boolean;\n deploymentTag: string;\n sourceTag: string | null;\n policy: NormalizedImagePolicy | null;\n}\n\nexport interface ImageCachePurgeResult {\n purged: true;\n tag: string;\n}\n\nexport interface ManagedImageUrlOptions {\n /** Deployment or custom application origin, for example `https://app.gigadrive.app`. */\n origin: string;\n /** Local application path or approved absolute remote URL. */\n source: string;\n filename?: string;\n width?: number;\n height?: number;\n quality?: number;\n format?: 'avif' | 'webp' | 'jpeg' | 'png';\n fit?: 'contain' | 'cover' | 'fill' | 'inside' | 'outside';\n variant?: string;\n}\n\n/** Creates the stable, framework-neutral managed image URL served on an application hostname. */\nexport const createManagedImageUrl = (options: ManagedImageUrlOptions): string => {\n const inferredFilename = options.source.split('/').filter(Boolean).at(-1)?.split('?')[0] || 'image.image';\n const filename = (options.filename ?? inferredFilename).replace(/[^A-Za-z0-9._-]/g, '_') || 'image.image';\n const url = new URL(\n `/_gigadrive/image/${encodeURIComponent(options.source)}/${encodeURIComponent(filename)}`,\n options.origin\n );\n for (const [name, value] of Object.entries({\n width: options.width,\n height: options.height,\n quality: options.quality,\n format: options.format,\n fit: options.fit,\n variant: options.variant,\n })) {\n if (value !== undefined) url.searchParams.set(name, String(value));\n }\n return url.toString();\n};\n\n/** Managed image optimization cache inspection and source/deployment purge operations. */\nexport class ImageOptimizationResource extends BaseResource {\n /** Create a managed image URL without making an API request. */\n url(options: ManagedImageUrlOptions): string {\n return createManagedImageUrl(options);\n }\n\n /** Inspect the immutable deployment policy and Bunny cache tags used for a source. */\n inspect(deploymentId: string, source?: string): Promise<ImageCacheInspection> {\n return this.httpClient.get(`/deployments/${deploymentId}/image-cache`, {\n query: { source },\n });\n }\n\n /** Purge all variants for one source, or every optimized image in the deployment when omitted. */\n purge(deploymentId: string, source?: string): Promise<ImageCachePurgeResult> {\n return this.httpClient.delete(`/deployments/${deploymentId}/image-cache`, {\n query: { source },\n });\n }\n}\n","import type { HttpClient, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** One bucket of an AI Gateway usage breakdown (by model, provider, or user). */\nexport interface AiGatewayUsageBreakdown {\n /** Bucket label (a model, provider, or user identifier). */\n label: string;\n /** Number of requests in this bucket. */\n requests: number;\n /** Total tokens in this bucket. */\n tokens: number;\n /** Input tokens in this bucket. */\n inputTokens: number;\n /** Output tokens in this bucket. */\n outputTokens: number;\n /** Billable cost in micros of USD for this bucket. */\n costMicros: number;\n}\n\n/** Aggregated AI Gateway usage over a time range, with breakdowns. */\nexport interface AiGatewayUsageSummary {\n summary: {\n requestCount: number;\n successCount: number;\n errorCount: number;\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n billableCostMicros: number;\n avgLatencyMs: number;\n };\n byModel: AiGatewayUsageBreakdown[];\n byProvider: AiGatewayUsageBreakdown[];\n byUser: AiGatewayUsageBreakdown[];\n}\n\n/** One provider attempt recorded while routing an AI Gateway request. */\nexport interface AiGatewayProviderAttempt {\n provider: string;\n error?: string;\n statusCode?: number;\n tag?: string;\n}\n\n/** A single AI Gateway request event with full telemetry. */\nexport interface AiGatewayRequestEvent {\n id: string;\n requestId: string;\n traceId: string | null;\n billingSubjectType: 'organization' | 'application';\n organizationId: string;\n applicationId: string | null;\n actorId: string | null;\n actorType: string;\n apiKeyId: string | null;\n authenticatedUserId: string | null;\n callerEndUserId: string | null;\n modelRequested: string;\n modelServed: string | null;\n provider: string | null;\n providerAttempts: AiGatewayProviderAttempt[] | null;\n status: 'pending' | 'success' | 'error' | 'cancelled';\n errorCode: string | null;\n errorType: string | null;\n inputTokens: number;\n outputTokens: number;\n cachedInputTokens: number;\n totalTokens: number;\n usageSource: 'provider' | 'estimated' | 'none';\n providerCostMicros: number;\n billableCostMicros: number;\n streaming: boolean;\n latencyMs: number | null;\n metadata: Record<string, string> | null;\n startedAt: string;\n completedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** An AI Gateway spend/usage budget. */\nexport interface AiGatewayBudget {\n id: string;\n organizationId: string;\n /** Application-specific target, or `null` for organization-wide. */\n applicationId: string | null;\n /** User-specific target, or `null` for all users. */\n userId: string | null;\n period: 'day' | 'month';\n maxCostMicros: number | null;\n maxRequests: number | null;\n maxTokens: number | null;\n maxRequestCostMicros: number | null;\n enabled: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Input for one budget when replacing the budget set. */\nexport interface AiGatewayBudgetInput {\n applicationId?: string;\n userId?: string;\n period?: 'day' | 'month';\n maxCostMicros?: number | null;\n maxRequests?: number | null;\n maxTokens?: number | null;\n maxRequestCostMicros?: number | null;\n enabled?: boolean;\n}\n\n/** An AI Gateway governance policy. */\nexport interface AiGatewayPolicy {\n id: string;\n organizationId: string;\n /** Application-specific target, or `null` for organization-wide. */\n applicationId: string | null;\n /** Allowed model IDs, or `null` to allow all. */\n allowedModels: string[] | null;\n /** Allowed provider IDs, or `null` to allow all. */\n allowedProviders: string[] | null;\n requireZdr: boolean;\n allowFallbacks: boolean;\n maxOutputTokens: number | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Input for creating or updating an AI Gateway policy. */\nexport interface AiGatewayPolicyInput {\n applicationId?: string;\n allowedModels?: string[] | null;\n allowedProviders?: string[] | null;\n requireZdr?: boolean;\n allowFallbacks?: boolean;\n maxOutputTokens?: number | null;\n}\n\n/** Query for usage summary. */\nexport interface AiGatewayUsageQuery {\n /** Only include usage at or after this ISO 8601 timestamp. */\n from?: string;\n /** Only include usage before or at this ISO 8601 timestamp. */\n to?: string;\n /** Restrict to one application. */\n applicationId?: string;\n}\n\n/** Query for the request-event log and CSV export. */\nexport interface AiGatewayRequestsQuery extends AiGatewayUsageQuery {\n model?: string;\n provider?: string;\n status?: 'pending' | 'success' | 'error' | 'cancelled';\n requestId?: string;\n authenticatedUserId?: string;\n callerEndUserId?: string;\n limit?: number;\n cursor?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Sub-resources\n// ---------------------------------------------------------------------------\n\n/** AI Gateway usage analytics for an organization. */\nexport class AiGatewayUsageResource extends BaseResource {\n /** Get an aggregated usage summary with breakdowns by model, provider, and user. */\n async summary(organizationId: string, query?: AiGatewayUsageQuery): Promise<AiGatewayUsageSummary> {\n return this.httpClient.get(`/organizations/${organizationId}/ai-gateway/usage/summary`, {\n query: query as Record<string, string | undefined> | undefined,\n });\n }\n\n /** List request-level usage events. */\n async requests(organizationId: string, query?: AiGatewayRequestsQuery): Promise<Paginated<AiGatewayRequestEvent>> {\n return this.httpClient.get(`/organizations/${organizationId}/ai-gateway/usage/requests`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /** Export request-level usage events as CSV text. */\n async export(organizationId: string, query?: AiGatewayRequestsQuery): Promise<string> {\n const response = await this.httpClient.requestStream(\n 'GET',\n `/organizations/${organizationId}/ai-gateway/usage/export`,\n { query: query as Record<string, string | number | undefined> | undefined }\n );\n return response.text();\n }\n}\n\n/** AI Gateway budgets for an organization. */\nexport class AiGatewayBudgetsResource extends BaseResource {\n /** List all budgets for an organization. */\n async list(organizationId: string): Promise<{ items: AiGatewayBudget[] }> {\n return this.httpClient.get(`/organizations/${organizationId}/ai-gateway/budgets`);\n }\n\n /**\n * Replace the organization's entire budget set. Pass an empty array to clear\n * all budgets.\n */\n async replace(organizationId: string, budgets: AiGatewayBudgetInput[]): Promise<{ items: AiGatewayBudget[] }> {\n return this.httpClient.put(`/organizations/${organizationId}/ai-gateway/budgets`, { budgets });\n }\n}\n\n/** AI Gateway governance policies for an organization. */\nexport class AiGatewayPoliciesResource extends BaseResource {\n /**\n * Get the governance policy for an organization, or for a specific\n * application when `applicationId` is provided. Returns `null` if no policy is set.\n */\n async get(organizationId: string, options?: { applicationId?: string }): Promise<AiGatewayPolicy | null> {\n const { policy } = await this.httpClient.get<{ policy: AiGatewayPolicy | null }>(\n `/organizations/${organizationId}/ai-gateway/policies`,\n { query: { applicationId: options?.applicationId } }\n );\n return policy;\n }\n\n /** Create or update an AI Gateway policy. */\n async put(organizationId: string, data: AiGatewayPolicyInput): Promise<AiGatewayPolicy> {\n const { policy } = await this.httpClient.put<{ policy: AiGatewayPolicy }>(\n `/organizations/${organizationId}/ai-gateway/policies`,\n data\n );\n return policy;\n }\n}\n\n/**\n * Organization-scoped AI Gateway governance: usage analytics, budgets, and\n * model/provider policies. Accessed via `client.organizations.aiGateway`.\n */\nexport class OrganizationAiGatewayResource {\n /** Usage analytics (summary, request log, CSV export). */\n readonly usage: AiGatewayUsageResource;\n /** Spend/usage budgets. */\n readonly budgets: AiGatewayBudgetsResource;\n /** Model/provider governance policies. */\n readonly policies: AiGatewayPoliciesResource;\n\n constructor(httpClient: HttpClient) {\n this.usage = new AiGatewayUsageResource(httpClient);\n this.budgets = new AiGatewayBudgetsResource(httpClient);\n this.policies = new AiGatewayPoliciesResource(httpClient);\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport type { CreateEnvVarInput, EnvVar, UpdateEnvVarInput } from './env-vars';\n\n/**\n * Manage environment variables scoped to an organization.\n * Accessed via `client.organizations.envVars`.\n */\nexport class OrganizationEnvVarsResource extends BaseResource {\n /**\n * List all environment variables for an organization.\n *\n * @param organizationId - The organization ID (UUID).\n * @returns A paginated list of environment variables.\n *\n * @example\n * ```ts\n * const { items } = await client.organizations.envVars.list('org-id');\n * for (const v of items) {\n * console.log(`${v.key}=${v.sensitive ? '***' : v.value}`);\n * }\n * ```\n */\n async list(organizationId: string, query?: ListQuery): Promise<Paginated<EnvVar>> {\n return this.httpClient.get(`/organizations/${organizationId}/env-vars`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Create a new environment variable for an organization.\n *\n * @param organizationId - The organization ID (UUID).\n * @param data - The variable key, value, and optional settings.\n * @returns The newly created environment variable.\n *\n * @example\n * ```ts\n * const envVar = await client.organizations.envVars.create('org-id', {\n * key: 'STRIPE_SECRET',\n * value: 'sk_live_...',\n * sensitive: true,\n * });\n * ```\n */\n async create(organizationId: string, data: CreateEnvVarInput): Promise<EnvVar> {\n return this.httpClient.post(`/organizations/${organizationId}/env-vars`, data);\n }\n\n /**\n * Update an existing environment variable. Only the fields you provide\n * will be changed; omitted fields are left unchanged.\n *\n * @param organizationId - The organization ID (UUID).\n * @param envVarId - The environment variable ID (UUID).\n * @param data - The fields to update.\n * @returns The updated environment variable.\n *\n * @example\n * ```ts\n * await client.organizations.envVars.update('org-id', 'var-id', {\n * value: 'new-value',\n * });\n * ```\n */\n async update(organizationId: string, envVarId: string, data: UpdateEnvVarInput): Promise<EnvVar> {\n return this.httpClient.patch(`/organizations/${organizationId}/env-vars/${envVarId}`, data);\n }\n\n /**\n * Permanently delete an environment variable.\n *\n * @param organizationId - The organization ID (UUID).\n * @param envVarId - The environment variable ID (UUID).\n *\n * @example\n * ```ts\n * await client.organizations.envVars.delete('org-id', 'var-id');\n * ```\n */\n async delete(organizationId: string, envVarId: string): Promise<void> {\n return this.httpClient.delete(`/organizations/${organizationId}/env-vars/${envVarId}`);\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n/** Organization membership role used for administration privileges. */\nexport type OrganizationMembershipRole = 'OWNER' | 'ADMIN' | 'MEMBER';\n\n/** A user membership in a Gigadrive organization. */\nexport interface OrganizationMember {\n /** Unique membership identifier (UUID). */\n membershipId: string;\n /** Organization that owns this membership. */\n organizationId: string;\n /** User who belongs to the organization. */\n userId: string;\n /** Email address of the organization member. */\n email: string;\n /** Given name of the organization member, or null when unset. */\n givenName: string | null;\n /** Family name of the organization member, or null when unset. */\n familyName: string | null;\n /** Avatar URL for the organization member, or null when unset. */\n imageUrl: string | null;\n /** Organization membership role. */\n role: OrganizationMembershipRole;\n /** ISO 8601 timestamp when the user joined the organization. */\n joinedAt: string;\n}\n\n/**\n * List organization members. Accessed via {@link OrganizationsResource.members}.\n *\n * @example\n * ```ts\n * const { items } = await client.organizations.members.list('org-id');\n * console.log(items.map((m) => `${m.email} (${m.role})`));\n * ```\n */\nexport class OrganizationMembersResource extends BaseResource {\n /**\n * List the users who belong to an organization.\n *\n * @param organizationId - Organization whose members should be listed.\n * @param query - Optional pagination.\n * @returns A paginated list of organization members.\n *\n * @example\n * ```ts\n * const { items, total } = await client.organizations.members.list('org-id');\n * console.log(`Found ${total} members`);\n * ```\n */\n async list(organizationId: string, query?: ListQuery): Promise<Paginated<OrganizationMember>> {\n return this.httpClient.get(`/organizations/${organizationId}/members`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n/** Product access mode from the code-defined product registry. */\nexport type ProductAccessMode = 'organization' | 'user';\n\n/** Fallback access policy when no explicit entitlement override exists. */\nexport type ProductDefaultAccessPolicy = 'granted' | 'explicit_entitlement_required';\n\n/** Lifecycle status of an explicit product entitlement override. */\nexport type ProductEntitlementStatus = 'ACTIVE' | 'SUSPENDED' | 'REVOKED';\n\n/** Lifecycle status of a local organization product subscription. */\nexport type ProductSubscriptionStatus = 'ACTIVE' | 'CANCELED';\n\n/** Whether effective access was resolved from an override or the registry default. */\nexport type ProductAccessResolutionSource = 'explicit' | 'default';\n\n/** A plan defined for a product in the product registry. */\nexport interface ProductPlan {\n /** Stable plan slug. */\n slug: string;\n /** Human-readable plan name. */\n displayName: string;\n /** Short description of the plan. */\n description: string;\n}\n\n/** Product metadata from the code-defined product registry. */\nexport interface ProductDefinition {\n /** Stable product slug (e.g. `network`, `office`). */\n slug: string;\n /** Human-readable product name. */\n displayName: string;\n /** Whether the product is granted to organizations or directly to users. */\n accessMode: ProductAccessMode;\n /** Fallback access policy when no explicit entitlement override exists. */\n defaultAccessPolicy: ProductDefaultAccessPolicy;\n /** Locally activatable plans for the product. */\n plans: ProductPlan[];\n}\n\n/** Explicit organization product entitlement override. */\nexport interface OrganizationProductEntitlement {\n /** Unique identifier (UUID). */\n id: string;\n /** Product slug this entitlement applies to. */\n product: string;\n /** Lifecycle status of the override. */\n status: ProductEntitlementStatus;\n /** User who last granted or updated the override, if known. */\n grantedByUserId: string | null;\n /** ISO 8601 timestamp when the entitlement was revoked, if revoked. */\n revokedAt: string | null;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Local organization product subscription / plan selection. */\nexport interface OrganizationProductSubscription {\n /** Unique identifier (UUID). */\n id: string;\n /** Product slug this subscription applies to. */\n product: string;\n /** Currently selected plan slug. */\n plan: string;\n /** Local subscription lifecycle status. */\n status: ProductSubscriptionStatus;\n /** User who activated the current plan, if known. */\n activatedByUserId: string | null;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Effective product access summary for an organization-scoped product. */\nexport interface OrganizationProductAccess {\n /** Product metadata from the registry. */\n product: ProductDefinition;\n /** Whether the organization currently has effective access. */\n hasAccess: boolean;\n /** Whether access was resolved from an explicit override or the default policy. */\n resolutionSource: ProductAccessResolutionSource;\n /** Explicit entitlement override when one exists. */\n explicitEntitlement: OrganizationProductEntitlement | null;\n /** Local product subscription when one exists. */\n subscription: OrganizationProductSubscription | null;\n}\n\n/** Compact yes/no entitlement check for an organization product. */\nexport interface OrganizationProductEntitlementCheck {\n /** Organization that was checked. */\n organizationId: string;\n /** Product slug that was checked. */\n product: string;\n /** Whether the organization currently has effective access. */\n hasAccess: boolean;\n}\n\n/**\n * Inspect organization product access / entitlements.\n *\n * Accessed via {@link OrganizationsResource.products}.\n *\n * Subscriptions are read-only through the public API — plan changes happen in\n * Gigadrive product surfaces, not via the SDK.\n *\n * @example\n * ```ts\n * const { items } = await client.organizations.products.list('org-id');\n * const check = await client.organizations.products.checkEntitlement('org-id', 'office');\n * console.log(check.hasAccess);\n * ```\n */\nexport class OrganizationProductsResource extends BaseResource {\n /**\n * List effective product access for every organization-scoped product.\n *\n * @param organizationId - Organization whose product access should be listed.\n * @param query - Optional pagination.\n * @returns A paginated list of product access summaries.\n *\n * @example\n * ```ts\n * const { items } = await client.organizations.products.list('org-id');\n * for (const item of items) {\n * console.log(item.product.slug, item.hasAccess);\n * }\n * ```\n */\n async list(organizationId: string, query?: ListQuery): Promise<Paginated<OrganizationProductAccess>> {\n return this.httpClient.get(`/organizations/${organizationId}/products`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Get effective access for one organization-scoped product.\n *\n * @param organizationId - Organization to inspect.\n * @param product - Product slug from the product registry.\n * @returns Product access summary including entitlement and subscription state.\n *\n * @example\n * ```ts\n * const access = await client.organizations.products.get('org-id', 'office');\n * console.log(access.hasAccess, access.subscription?.plan);\n * ```\n */\n async get(organizationId: string, product: string): Promise<OrganizationProductAccess> {\n return this.httpClient.get(`/organizations/${organizationId}/products/${product}`);\n }\n\n /**\n * Check whether an organization currently has access to a product.\n *\n * @param organizationId - Organization to check.\n * @param product - Product slug from the product registry.\n * @returns Compact entitlement check result.\n *\n * @example\n * ```ts\n * const { hasAccess } = await client.organizations.products.checkEntitlement('org-id', 'network');\n * ```\n */\n async checkEntitlement(organizationId: string, product: string): Promise<OrganizationProductEntitlementCheck> {\n return this.httpClient.get(`/organizations/${organizationId}/products/${product}/entitlement`);\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport { OrganizationAiGatewayResource } from './organization-ai-gateway';\nimport { OrganizationEnvVarsResource } from './organization-env-vars';\nimport { OrganizationMembersResource } from './organization-members';\nimport { OrganizationProductsResource } from './organization-products';\n\n/** A Gigadrive Network organization. */\nexport interface Organization {\n /** Unique identifier (UUID). */\n id: string;\n /** Display name of the organization. */\n name: string;\n /** URL-safe slug (e.g. `gigadrive`). */\n slug: string;\n /** Avatar / logo URL. */\n imageUrl: string;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Input for creating an organization. */\nexport interface CreateOrganizationInput {\n /** Display name for the new organization. */\n name: string;\n /** Optional URL-safe slug. Generated from the name when omitted. */\n slug?: string;\n}\n\n/**\n * Manage organizations. Accessed via {@link GigadriveClient.organizations}.\n *\n * @example\n * ```ts\n * const { items: orgs } = await client.organizations.list();\n * console.log(orgs.map((o) => o.name));\n * ```\n */\nexport class OrganizationsResource extends BaseResource {\n /**\n * Manage environment variables scoped to an organization.\n *\n * @example\n * ```ts\n * // List all env vars for an organization\n * const { items } = await client.organizations.envVars.list('org-id');\n *\n * // Create a new env var\n * await client.organizations.envVars.create('org-id', {\n * key: 'ANALYTICS_KEY',\n * value: 'ak_live_...',\n * sensitive: true,\n * });\n * ```\n */\n readonly envVars: OrganizationEnvVarsResource;\n\n /**\n * AI Gateway governance for an organization: usage analytics, budgets, and\n * model/provider policies.\n *\n * @example\n * ```ts\n * const usage = await client.organizations.aiGateway.usage.summary('org-id', { from: '2026-06-01' });\n * console.log(usage.summary.totalTokens);\n * ```\n */\n readonly aiGateway: OrganizationAiGatewayResource;\n\n /**\n * List organization members and membership roles.\n *\n * @example\n * ```ts\n * const { items } = await client.organizations.members.list('org-id');\n * ```\n */\n readonly members: OrganizationMembersResource;\n\n /**\n * Inspect organization product entitlements. Read-only through the public\n * API — plan changes happen in Gigadrive product surfaces, not via the SDK.\n *\n * @example\n * ```ts\n * const check = await client.organizations.products.checkEntitlement('org-id', 'office');\n * ```\n */\n readonly products: OrganizationProductsResource;\n\n constructor(...args: ConstructorParameters<typeof BaseResource>) {\n super(...args);\n this.envVars = new OrganizationEnvVarsResource(this.httpClient);\n this.aiGateway = new OrganizationAiGatewayResource(this.httpClient);\n this.members = new OrganizationMembersResource(this.httpClient);\n this.products = new OrganizationProductsResource(this.httpClient);\n }\n\n /**\n * List organizations the authenticated actor has access to.\n *\n * @param query - Optional pagination.\n * @returns A paginated list of organizations.\n *\n * @example\n * ```ts\n * const { items, total } = await client.organizations.list();\n * console.log(`Found ${total} organizations`);\n * ```\n */\n async list(query?: ListQuery): Promise<Paginated<Organization>> {\n return this.httpClient.get('/organizations', {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Get a single organization by ID.\n *\n * @param organizationId - Organization to retrieve.\n * @returns The organization.\n *\n * @example\n * ```ts\n * const org = await client.organizations.get('org-id');\n * console.log(org.name, org.slug);\n * ```\n */\n async get(organizationId: string): Promise<Organization> {\n return this.httpClient.get(`/organizations/${organizationId}`);\n }\n\n /**\n * Create a new organization.\n *\n * Requires a user-backed token with the `platform:organizations:write` scope.\n * The authenticated user becomes the organization owner.\n *\n * @param input - Organization creation input.\n * @returns The created organization.\n *\n * @example\n * ```ts\n * const org = await client.organizations.create({ name: 'Acme Corp' });\n * console.log(org.id, org.slug);\n * ```\n */\n async create(input: CreateOrganizationInput): Promise<Organization> {\n return this.httpClient.post('/organizations', input);\n }\n}\n","import { BaseResource } from './base-resource';\n\n/** Input for minting a routing-only sticky session URL. */\nexport interface CreateStickySessionUrlInput {\n /** Opaque application key shared by callers that must reach the same instance. */\n key: string;\n /** Relative deployment route, including any application query parameters. */\n endpoint: string;\n /** HTTP method used to resolve the target route. Defaults to `GET`. */\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'PATCH';\n /** URL lifetime in seconds. Defaults to four hours; accepted range is 60–86,400. */\n expiresInSeconds?: number;\n}\n\n/** A signed sticky URL and its absolute ISO 8601 expiration time. */\nexport interface CreateStickySessionUrlResult {\n url: string;\n expiresAt: string;\n}\n\n/**\n * Creates protocol-independent sticky routing URLs for MicroVM functions.\n *\n * The URL selects an instance but does not authenticate an application user or\n * store application state. Reusing the same key and unexpired URL keeps HTTP,\n * streaming, and WebSocket traffic on the same function instance.\n */\nexport class StickySessionsResource extends BaseResource {\n /**\n * Mints a signed URL for an opaque application key.\n *\n * Deployed Gigadrive workloads can call this with a zero-config\n * `GigadriveClient`; the platform injects `GIGADRIVE_CLIENT_ID` and\n * `GIGADRIVE_CLIENT_SECRET` using the SDK's existing credential chain.\n */\n async createUrl(input: CreateStickySessionUrlInput): Promise<CreateStickySessionUrlResult> {\n return this.httpClient.post('/sticky-sessions/urls', {\n ...input,\n method: input.method ?? 'GET',\n });\n }\n}\n","import { readEnv, resolveCredentialProvider } from './auth/credential-provider';\nimport { TokenManager } from './auth/token-manager';\nimport { HttpClient } from './http-client';\nimport { AiGatewayResource } from './resources/ai-gateway';\nimport { ApiKeysResource } from './resources/api-keys';\nimport type { ApplicationStorageResource } from './resources/application-storage';\nimport { ApplicationsResource } from './resources/applications';\nimport { DeploymentsResource } from './resources/deployments';\nimport { ImageOptimizationResource } from './resources/image-optimization';\nimport { OrganizationsResource } from './resources/organizations';\nimport { StickySessionsResource } from './resources/sticky-sessions';\n\nconst DEFAULT_BASE_URL = 'https://api.gigadrive.network';\n\n/**\n * Configuration for the {@link GigadriveClient}.\n *\n * Credentials are resolved in priority order: explicit config fields first,\n * then environment variables. See {@link GigadriveClient} for the full\n * resolution chain.\n */\nexport interface GigadriveClientConfig {\n /**\n * Default application UUID for context-bound storage calls.\n *\n * Falls back to `GIGADRIVE_APPLICATION_ID`, which the platform injects into\n * deployed workloads. Explicit application IDs supplied to compatibility\n * overloads take precedence over this value.\n */\n applicationId?: string;\n\n /**\n * OAuth2 client ID (the API key ID from the Gigadrive dashboard).\n * Used for both client-credentials and refresh-token flows.\n * Falls back to the `GIGADRIVE_CLIENT_ID` environment variable.\n */\n clientId?: string;\n\n /**\n * OAuth2 client secret (the API key secret from the Gigadrive dashboard).\n * Used together with {@link clientId} for the client-credentials grant.\n * Falls back to the `GIGADRIVE_CLIENT_SECRET` environment variable.\n */\n clientSecret?: string;\n\n /**\n * A pre-obtained bearer token (either an IDP or Network token).\n * When set, the SDK sends this token directly without any OAuth exchange.\n * The token is never refreshed — if it expires, requests will fail.\n * Falls back to the `GIGADRIVE_BEARER_TOKEN` environment variable.\n */\n bearerToken?: string;\n\n /**\n * An IDP refresh token for automatic access-token renewal. Used together\n * with {@link clientId}. The SDK will exchange this for short-lived access\n * tokens and handle refresh-token rotation automatically.\n * Falls back to the `GIGADRIVE_REFRESH_TOKEN` environment variable.\n */\n refreshToken?: string;\n\n /**\n * The IDP issuer URL used for OIDC discovery (fetching the\n * `.well-known/openid-configuration`). Only needed for refresh-token and\n * authorization-code flows.\n * Falls back to `GIGADRIVE_IDP_ISSUER_URL`, default: `https://idp.gigadrive.de`.\n */\n idpIssuerUrl?: string;\n\n /**\n * Callback for the OAuth2 authorization code flow with PKCE. The SDK\n * builds the authorization URL and passes it to this callback. Your code\n * must present the URL to the user (e.g. open a browser), then return\n * either the full redirect URL or just the authorization code.\n *\n * Requires {@link clientId} to be set.\n *\n * @param url - The authorization URL the user should visit.\n * @returns The full redirect URL (including `?code=...&state=...`) or the\n * bare authorization code.\n *\n * @example\n * ```ts\n * const client = new GigadriveClient({\n * clientId: 'my-app',\n * onAuthorizationUrl: async (url) => {\n * console.log('Visit:', url);\n * return await readline.question('Paste the redirect URL: ');\n * },\n * });\n * ```\n */\n onAuthorizationUrl?: (url: string) => Promise<string>;\n\n /**\n * Redirect URI for the authorization code flow.\n * Default: `urn:ietf:wg:oauth:2.0:oob` (out-of-band / manual copy-paste).\n */\n redirectUri?: string;\n\n /**\n * OAuth scopes to request during the authorization-code flow, in addition to\n * the default identity scopes (`openid profile email offline_access`). Use\n * this to request API capability scopes (e.g. `network:applications:read`) so\n * the resulting token can call the corresponding endpoints.\n */\n scopes?: string[];\n\n /**\n * Base URL of the Gigadrive Network API.\n * Falls back to `GIGADRIVE_API_BASE_URL`, default: `https://api.gigadrive.network`.\n */\n baseUrl?: string;\n\n /**\n * Custom `fetch` implementation. Useful for testing (injectable mock) or\n * non-standard runtimes like Cloudflare Workers that provide their own\n * `fetch`. Defaults to `globalThis.fetch`.\n */\n fetch?: typeof globalThis.fetch;\n}\n\n/**\n * The main entry point for the Gigadrive Network SDK.\n *\n * Create an instance to interact with organizations, applications, deployments,\n * storage, and the AI gateway. Authentication is handled automatically —\n * tokens are obtained, cached, and refreshed behind the scenes.\n *\n * ## Credential resolution order\n *\n * The client resolves credentials in the following order, using the first\n * match it finds:\n *\n * 1. Explicit `bearerToken` in config\n * 2. Explicit `clientId` + `clientSecret` in config\n * 3. Explicit `clientId` + `refreshToken` in config\n * 4. Explicit `clientId` + `onAuthorizationUrl` callback in config\n * 5. `GIGADRIVE_BEARER_TOKEN` environment variable\n * 6. `GIGADRIVE_CLIENT_ID` + `GIGADRIVE_CLIENT_SECRET` environment variables\n * 7. `GIGADRIVE_CLIENT_ID` + `GIGADRIVE_REFRESH_TOKEN` environment variables\n *\n * If no credentials are found, the constructor throws an\n * {@link AuthenticationError}.\n *\n * @example\n * ```ts\n * // Credentials auto-detected from environment variables\n * const client = new GigadriveClient();\n *\n * // Explicit API key (client credentials)\n * const client = new GigadriveClient({\n * clientId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',\n * clientSecret: 'sk_live_...',\n * });\n *\n * // Pre-obtained bearer token\n * const client = new GigadriveClient({ bearerToken: 'eyJ...' });\n *\n * // IDP refresh token — access tokens are renewed automatically\n * const client = new GigadriveClient({\n * clientId: 'my-app',\n * refreshToken: 'rt_...',\n * });\n *\n * // Use the client\n * const orgs = await client.organizations.list();\n * const deployment = await client.deployments.create({ applicationId: 'app-1' });\n * ```\n *\n * @throws {@link AuthenticationError} if no valid credentials are found.\n */\nexport class GigadriveClient {\n /** Organization management (list, environment variables). */\n readonly organizations: OrganizationsResource;\n /** Application management (list, environment variables, storage). */\n readonly applications: ApplicationsResource;\n /**\n * Context-bound file storage operations.\n *\n * Deployed workloads receive their application context through\n * `GIGADRIVE_APPLICATION_ID`; management clients can set\n * {@link GigadriveClientConfig.applicationId}. This is the same resource as\n * {@link applications}.storage.\n */\n readonly storage: ApplicationStorageResource;\n /** Deployment lifecycle (create, upload, status, logs). */\n readonly deployments: DeploymentsResource;\n /** AI Gateway — OpenAI-compatible chat completions and model listing. */\n readonly aiGateway: AiGatewayResource;\n /** Application-scoped API key management (create, list, revoke). */\n readonly apiKeys: ApiKeysResource;\n /** Signed URLs that keep related requests on one MicroVM instance. */\n readonly stickySessions: StickySessionsResource;\n /** Managed image optimization inspection and cache purge operations. */\n readonly imageOptimization: ImageOptimizationResource;\n\n constructor(config: GigadriveClientConfig = {}) {\n const baseUrl = config.baseUrl ?? readEnv('GIGADRIVE_API_BASE_URL') ?? DEFAULT_BASE_URL;\n const applicationId = config.applicationId ?? readEnv('GIGADRIVE_APPLICATION_ID');\n // Bind the default fetch to globalThis so it can be invoked as a method on\n // the HTTP client without throwing \"Illegal invocation\" in some runtimes.\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n\n const credentialProvider = resolveCredentialProvider({ ...config, baseUrl, fetch: fetchFn });\n const tokenManager = new TokenManager(credentialProvider);\n const httpClient = new HttpClient(baseUrl, tokenManager, fetchFn);\n\n this.organizations = new OrganizationsResource(httpClient);\n this.applications = new ApplicationsResource(httpClient, applicationId);\n this.storage = this.applications.storage;\n this.deployments = new DeploymentsResource(httpClient);\n this.aiGateway = new AiGatewayResource(httpClient);\n this.apiKeys = new ApiKeysResource(httpClient);\n this.stickySessions = new StickySessionsResource(httpClient);\n this.imageOptimization = new ImageOptimizationResource(httpClient);\n }\n}\n","import type { Paginated } from './http-client';\n\n/**\n * Lazily iterate every item across all pages of a cursor-paginated endpoint.\n * Pass a function that fetches one page for a given cursor; iteration stops when\n * the API stops returning a `nextCursor`.\n *\n * @typeParam T - The item type.\n * @param fetchPage - Fetches a single page for the given cursor (`undefined` for the first page).\n *\n * @example\n * ```ts\n * for await (const object of paginate((cursor) =>\n * client.applications.storage.objects.list('app-id', 'bucket-id', { cursor }),\n * )) {\n * console.log(object.key);\n * }\n * ```\n */\nexport async function* paginate<T>(\n fetchPage: (cursor: string | undefined) => Promise<Paginated<T>>\n): AsyncGenerator<T> {\n let cursor: string | undefined;\n do {\n const page = await fetchPage(cursor);\n for (const item of page.items) {\n yield item;\n }\n cursor = page.nextCursor;\n } while (cursor);\n}\n"],"mappings":"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","names":["bytes","DEFAULT_BASE_URL"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/auth/credential-provider.ts","../src/auth/token-manager.ts","../src/http-client.ts","../src/streaming.ts","../src/resources/base-resource.ts","../src/resources/ai-gateway/index.ts","../src/resources/api-keys.ts","../src/resources/application-env-vars.ts","../src/resources/application-requests.ts","../src/upload/checksum.ts","../src/upload/content-type.ts","../src/upload/source.ts","../src/upload/transport.ts","../src/resources/storage-context.ts","../src/resources/storage-buckets.ts","../src/resources/storage-objects.ts","../src/resources/storage-trash.ts","../src/resources/storage-upload-sessions.ts","../src/resources/application-storage.ts","../src/resources/domains.ts","../src/resources/applications.ts","../src/resources/deployments.ts","../src/resources/image-optimization.ts","../src/resources/organization-ai-gateway.ts","../src/resources/organization-env-vars.ts","../src/resources/organization-members.ts","../src/resources/organization-products.ts","../src/resources/organizations.ts","../src/queues/encoding.ts","../src/queues/errors.ts","../src/queues/signature.ts","../src/queues/queue.ts","../src/resources/queues.ts","../src/resources/sticky-sessions.ts","../src/client.ts","../src/pagination.ts","../src/queues/default-client.ts","../src/queues/workflow.ts"],"sourcesContent":["/**\n * Base error class for all Gigadrive SDK errors. Every error thrown by the SDK\n * extends this class, so you can catch all SDK errors with a single check.\n *\n * @example\n * ```ts\n * try {\n * await client.organizations.list();\n * } catch (err) {\n * if (err instanceof GigadriveError) {\n * console.error('SDK error:', err.message);\n * }\n * }\n * ```\n */\nexport class GigadriveError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'GigadriveError';\n }\n}\n\n/**\n * Thrown when authentication fails. This includes missing or invalid credentials,\n * expired tokens, failed token refresh attempts, and failed token exchanges.\n *\n * Common causes:\n * - No credentials provided and no environment variables set\n * - Invalid `clientId`/`clientSecret` pair\n * - Expired or revoked refresh token\n * - API returned 401 even after an automatic token refresh retry\n *\n * @example\n * ```ts\n * try {\n * const client = new GigadriveClient(); // no credentials\n * } catch (err) {\n * if (err instanceof AuthenticationError) {\n * console.error('Auth failed:', err.message);\n * }\n * }\n * ```\n */\nexport class AuthenticationError extends GigadriveError {\n constructor(message: string) {\n super(message);\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Thrown when an SDK operation requires local configuration that could not be\n * resolved before making an API request.\n *\n * Storage operations use this error when neither an explicit application ID,\n * `GigadriveClientConfig.applicationId`, nor the workload-provided\n * `GIGADRIVE_APPLICATION_ID` environment variable is available.\n */\nexport class ConfigurationError extends GigadriveError {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigurationError';\n }\n}\n\n/**\n * Thrown when the Gigadrive API returns a non-2xx HTTP response.\n *\n * Contains the HTTP {@link status} code and an optional machine-readable\n * {@link code} parsed from the response body.\n *\n * @example\n * ```ts\n * try {\n * await client.deployments.get('non-existent-id');\n * } catch (err) {\n * if (err instanceof ApiError) {\n * console.error(`API error ${err.status}: ${err.message}`);\n * // err.code may contain a machine-readable error code\n * }\n * }\n * ```\n */\nexport class ApiError extends GigadriveError {\n /** The HTTP status code of the failed response (e.g. 404, 500). */\n readonly status: number;\n /** An optional machine-readable error code from the API response body. */\n readonly code: string | undefined;\n /**\n * An optional finer-grained reason next to {@link code}, for example `daily_add_limit` with\n * `quota_exceeded`, or `other_organization` with `domain_in_use`.\n */\n readonly reason: string | undefined;\n\n constructor(message: string, status: number, code?: string, reason?: string) {\n super(message);\n this.name = 'ApiError';\n this.status = status;\n this.code = code;\n this.reason = reason;\n }\n}\n\n/**\n * Thrown when a file upload fails. The original cause (e.g. a network error or a\n * transport-level error from the resumable upload) is preserved on\n * {@link cause} for inspection.\n *\n * @example\n * ```ts\n * try {\n * await client.storage.upload({ bucket: 'assets', key, data });\n * } catch (err) {\n * if (err instanceof UploadError) {\n * console.error('Upload failed:', err.message, err.cause);\n * }\n * }\n * ```\n */\nexport class UploadError extends GigadriveError {\n /** The underlying error that caused the upload to fail, if any. */\n override readonly cause: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'UploadError';\n this.cause = cause;\n }\n}\n\n/**\n * Thrown when an upload cannot complete because its session (and the short-lived\n * upload URL it was issued with) expired. Create a new upload to retry.\n *\n * The upload URL is only valid until `session.expiresAt`; very large uploads on\n * slow connections can exceed that window.\n */\nexport class UploadSessionExpiredError extends UploadError {\n constructor(\n message = 'The upload session expired before the upload completed. Start a new upload to retry.',\n cause?: unknown\n ) {\n super(message, cause);\n this.name = 'UploadSessionExpiredError';\n }\n}\n","import { AuthenticationError } from '../errors';\n\nconst DEFAULT_SCOPE = 'offline_access openid profile email';\nconst TOKEN_EXPIRY_MARGIN_SECONDS = 30;\n\n/**\n * Compute the absolute expiry (epoch ms) for a token, applying a safety margin\n * so the SDK refreshes proactively. The margin is clamped to never exceed half\n * the token lifetime, so very short-lived tokens are not treated as already\n * expired (which would refresh on every request).\n */\nconst computeExpiresAt = (expiresInSeconds: number | undefined): number => {\n const ttl = expiresInSeconds ?? 3600;\n const margin = Math.min(TOKEN_EXPIRY_MARGIN_SECONDS, ttl / 2);\n return Date.now() + (ttl - margin) * 1000;\n};\n\n/**\n * Read an environment variable safely. Returns `undefined` when `process` is\n * unavailable (e.g. browsers / some edge runtimes) instead of throwing.\n *\n * @internal\n */\nexport const readEnv = (name: string): string | undefined => {\n if (typeof process === 'undefined' || !process.env) return undefined;\n return process.env[name];\n};\n\ninterface RawTokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n}\n\n/**\n * Validate and normalize a token-endpoint JSON response, guarding against\n * malformed payloads that would otherwise yield `Authorization: Bearer undefined`.\n */\nconst parseTokenResponse = (payload: unknown): RawTokenResponse => {\n const data = payload as { access_token?: unknown; refresh_token?: unknown; expires_in?: unknown };\n if (typeof data.access_token !== 'string' || data.access_token.length === 0) {\n throw new AuthenticationError('Token endpoint returned no access_token');\n }\n return {\n access_token: data.access_token,\n refresh_token: typeof data.refresh_token === 'string' ? data.refresh_token : undefined,\n expires_in: typeof data.expires_in === 'number' ? data.expires_in : undefined,\n };\n};\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** The result of a credential provider's token fetch. */\nexport interface TokenResult {\n /** The access token to use in API requests. */\n accessToken: string;\n /** Epoch milliseconds when the token expires, or `null` for tokens that never expire (e.g. static bearer tokens). */\n expiresAt: number | null;\n /** A refresh token for obtaining new access tokens, if the provider supports token rotation. */\n refreshToken?: string;\n}\n\n/**\n * A strategy for obtaining access tokens. The SDK ships with four built-in\n * providers (see {@link resolveCredentialProvider} for automatic selection),\n * but you can implement this interface for custom auth flows.\n */\nexport interface CredentialProvider {\n /** A string identifying the provider type (e.g. `\"oauth2-client-credentials\"`, `\"bearer\"`). */\n readonly type: string;\n /** Fetch a new access token. May perform network requests (e.g. OAuth2 token exchange). */\n getToken(): Promise<TokenResult>;\n}\n\ninterface OidcDiscoveryDocument {\n token_endpoint?: string;\n authorization_endpoint?: string;\n userinfo_endpoint?: string;\n}\n\n// ---------------------------------------------------------------------------\n// OIDC Discovery\n// ---------------------------------------------------------------------------\n\nconst discoverOidc = async (issuerUrl: string, fetchFn: typeof globalThis.fetch): Promise<OidcDiscoveryDocument> => {\n const discoveryUrl = `${issuerUrl.replace(/\\/$/, '')}/.well-known/openid-configuration`;\n const response = await fetchFn(discoveryUrl);\n\n if (!response.ok) {\n throw new AuthenticationError(`OIDC discovery failed: ${response.status} ${response.statusText}`);\n }\n\n return (await response.json()) as OidcDiscoveryDocument;\n};\n\n// ---------------------------------------------------------------------------\n// PKCE helpers\n// ---------------------------------------------------------------------------\n\nconst base64UrlEncode = (buffer: Uint8Array): string => {\n let binary = '';\n for (let i = 0; i < buffer.byteLength; i++) {\n binary += String.fromCharCode(buffer[i]);\n }\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n};\n\nconst generatePkce = async (): Promise<{ codeVerifier: string; codeChallenge: string }> => {\n const randomBytes = new Uint8Array(64);\n crypto.getRandomValues(randomBytes);\n const codeVerifier = base64UrlEncode(randomBytes);\n\n const encoder = new TextEncoder();\n const data = encoder.encode(codeVerifier);\n const digest = await crypto.subtle.digest('SHA-256', data);\n const codeChallenge = base64UrlEncode(new Uint8Array(digest));\n\n return { codeVerifier, codeChallenge };\n};\n\nconst generateState = (): string => {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n};\n\n// ---------------------------------------------------------------------------\n// OAuth2 Client Credentials Provider (Network API keys)\n// ---------------------------------------------------------------------------\n\n/**\n * Authenticates using the OAuth2 client credentials grant. Exchanges an\n * API key (client ID + secret) for a short-lived access token via the\n * Gigadrive Network token endpoint.\n *\n * Tokens are valid for 5 minutes. A 30-second safety margin is applied so\n * the SDK refreshes proactively before the token actually expires.\n *\n * This is the most common provider for server-to-server (machine-to-machine)\n * use cases.\n */\nexport class OAuth2ClientCredentialProvider implements CredentialProvider {\n readonly type = 'oauth2-client-credentials';\n\n constructor(\n private readonly clientId: string,\n private readonly clientSecret: string,\n private readonly tokenUrl: string,\n private readonly fetchFn: typeof globalThis.fetch\n ) {}\n\n async getToken(): Promise<TokenResult> {\n const credentials = btoa(`${this.clientId}:${this.clientSecret}`);\n\n const response = await this.fetchFn(this.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Basic ${credentials}`,\n },\n body: new URLSearchParams({ grant_type: 'client_credentials' }).toString(),\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n throw new AuthenticationError(`OAuth2 token request failed (${response.status}): ${body}`);\n }\n\n const data = parseTokenResponse(await response.json());\n\n return {\n accessToken: data.access_token,\n expiresAt: computeExpiresAt(data.expires_in),\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// OAuth2 Authorization Code Provider (IDP, PKCE, no local server)\n// ---------------------------------------------------------------------------\n\n/**\n * Authenticates using the OAuth2 authorization code grant with PKCE. This\n * provider is designed for interactive flows where a user authorizes the\n * application via a browser.\n *\n * The SDK generates the PKCE challenge, builds the authorization URL, and\n * passes it to your `onAuthorizationUrl` callback. Your callback is\n * responsible for presenting the URL to the user and returning the result\n * (either the full redirect URL or just the authorization code).\n *\n * The provider performs OIDC discovery to locate the authorization and token\n * endpoints automatically.\n */\nexport class OAuth2AuthorizationCodeProvider implements CredentialProvider {\n readonly type = 'oauth2-authorization-code';\n private currentRefreshToken: string | null = null;\n\n constructor(\n private readonly clientId: string,\n private readonly issuerUrl: string,\n private readonly redirectUri: string,\n private readonly onAuthorizationUrl: (url: string) => Promise<string>,\n private readonly fetchFn: typeof globalThis.fetch,\n private readonly scope: string = DEFAULT_SCOPE\n ) {}\n\n async getToken(): Promise<TokenResult> {\n const oidc = await discoverOidc(this.issuerUrl, this.fetchFn);\n\n if (!oidc.token_endpoint) {\n throw new AuthenticationError('OIDC discovery returned no token endpoint');\n }\n\n // After the first interactive exchange, refresh silently rather than\n // re-prompting the user. Only fall back to a fresh authorization when the\n // refresh token is actually rejected — transient errors are surfaced.\n if (this.currentRefreshToken) {\n const refreshed = await this.tryRefresh(oidc.token_endpoint, this.currentRefreshToken);\n if (refreshed) return refreshed;\n this.currentRefreshToken = null;\n }\n\n if (!oidc.authorization_endpoint) {\n throw new AuthenticationError('OIDC discovery returned incomplete endpoints');\n }\n\n const { codeVerifier, codeChallenge } = await generatePkce();\n const state = generateState();\n\n const authUrl = new URL(oidc.authorization_endpoint);\n authUrl.searchParams.set('client_id', this.clientId);\n authUrl.searchParams.set('redirect_uri', this.redirectUri);\n authUrl.searchParams.set('response_type', 'code');\n authUrl.searchParams.set('scope', this.scope);\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n authUrl.searchParams.set('state', state);\n\n const result = await this.onAuthorizationUrl(authUrl.toString());\n\n // Extract the authorization code — accept either a full URL or just the code\n let code: string;\n let returnedState: string | null = null;\n\n try {\n const callbackUrl = new URL(result);\n code = callbackUrl.searchParams.get('code') ?? '';\n returnedState = callbackUrl.searchParams.get('state');\n\n const error = callbackUrl.searchParams.get('error');\n if (error) {\n const description = callbackUrl.searchParams.get('error_description') ?? error;\n throw new AuthenticationError(`Authorization failed: ${description}`);\n }\n } catch (e) {\n if (e instanceof AuthenticationError) throw e;\n // Not a valid URL — treat the entire result as the code\n code = result;\n }\n\n if (!code) {\n throw new AuthenticationError('No authorization code received');\n }\n\n if (returnedState !== null && returnedState !== state) {\n throw new AuthenticationError('State mismatch — possible CSRF attack');\n }\n\n // Exchange code for tokens\n const response = await this.fetchFn(oidc.token_endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: this.clientId,\n code,\n redirect_uri: this.redirectUri,\n code_verifier: codeVerifier,\n }).toString(),\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n throw new AuthenticationError(`Token exchange failed (${response.status}): ${body}`);\n }\n\n const data = parseTokenResponse(await response.json());\n\n this.currentRefreshToken = data.refresh_token ?? null;\n\n return {\n accessToken: data.access_token,\n expiresAt: computeExpiresAt(data.expires_in),\n refreshToken: data.refresh_token,\n };\n }\n\n /**\n * Try to exchange the stored refresh token for a new access token. Returns the\n * token on success, `null` when the refresh token is definitively rejected\n * (a 4xx — caller should re-authenticate), and throws on transient failures.\n */\n private async tryRefresh(tokenEndpoint: string, refreshToken: string): Promise<TokenResult | null> {\n const response = await this.fetchFn(tokenEndpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.clientId,\n refresh_token: refreshToken,\n }).toString(),\n });\n\n if (!response.ok) {\n // A 4xx means the refresh token is invalid/expired — re-authenticate.\n if (response.status >= 400 && response.status < 500) return null;\n // Transient (network/5xx) failures surface instead of forcing a re-prompt.\n const body = await response.text().catch(() => '');\n throw new AuthenticationError(`Token refresh failed (${response.status}): ${body}`);\n }\n\n const data = parseTokenResponse(await response.json());\n\n if (data.refresh_token) {\n this.currentRefreshToken = data.refresh_token;\n }\n\n return {\n accessToken: data.access_token,\n expiresAt: computeExpiresAt(data.expires_in),\n refreshToken: data.refresh_token ?? this.currentRefreshToken ?? undefined,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// OAuth2 Refresh Token Provider (IDP)\n// ---------------------------------------------------------------------------\n\n/**\n * Authenticates using an IDP refresh token. Exchanges the refresh token for\n * a short-lived access token via the IDP's token endpoint (discovered via\n * OIDC). Handles refresh-token rotation automatically — if the IDP issues\n * a new refresh token, it is stored internally for subsequent refreshes.\n *\n * This provider is typically used when a user has previously logged in\n * (e.g. via the CLI) and you have a stored refresh token.\n */\nexport class OAuth2RefreshTokenProvider implements CredentialProvider {\n readonly type = 'oauth2-refresh-token';\n private currentRefreshToken: string;\n\n constructor(\n private readonly clientId: string,\n refreshToken: string,\n private readonly issuerUrl: string,\n private readonly fetchFn: typeof globalThis.fetch\n ) {\n this.currentRefreshToken = refreshToken;\n }\n\n async getToken(): Promise<TokenResult> {\n const oidc = await discoverOidc(this.issuerUrl, this.fetchFn);\n\n if (!oidc.token_endpoint) {\n throw new AuthenticationError('OIDC discovery returned no token endpoint');\n }\n\n const response = await this.fetchFn(oidc.token_endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.clientId,\n refresh_token: this.currentRefreshToken,\n }).toString(),\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n if (response.status === 400) {\n throw new AuthenticationError('Refresh token is invalid or expired. Please re-authenticate.');\n }\n throw new AuthenticationError(`Token refresh failed (${response.status}): ${body}`);\n }\n\n const data = parseTokenResponse(await response.json());\n\n // Handle refresh token rotation\n if (data.refresh_token) {\n this.currentRefreshToken = data.refresh_token;\n }\n\n return {\n accessToken: data.access_token,\n expiresAt: computeExpiresAt(data.expires_in),\n refreshToken: data.refresh_token ?? this.currentRefreshToken,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Bearer Token Provider (static)\n// ---------------------------------------------------------------------------\n\n/**\n * Uses a static, pre-obtained bearer token. The token is never refreshed —\n * if it expires, API requests will fail with an {@link AuthenticationError}.\n *\n * This is the simplest provider and is used when the caller already has a\n * valid access token (e.g. from an external auth flow or a long-lived token).\n */\nexport class BearerTokenProvider implements CredentialProvider {\n readonly type = 'bearer';\n\n constructor(private readonly token: string) {}\n\n getToken(): Promise<TokenResult> {\n return Promise.resolve({ accessToken: this.token, expiresAt: null });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Credential resolution\n// ---------------------------------------------------------------------------\n\nexport interface CredentialResolverConfig {\n clientId?: string;\n clientSecret?: string;\n bearerToken?: string;\n refreshToken?: string;\n idpIssuerUrl?: string;\n onAuthorizationUrl?: (url: string) => Promise<string>;\n redirectUri?: string;\n baseUrl?: string;\n fetch?: typeof globalThis.fetch;\n /** OAuth scopes to request in the authorization-code flow (in addition to identity scopes). */\n scopes?: string[];\n}\n\nconst DEFAULT_IDP_ISSUER_URL = 'https://idp.gigadrive.de';\nconst DEFAULT_BASE_URL = 'https://api.gigadrive.network';\n\n/**\n * Resolves a `CredentialProvider` from explicit config or environment variables.\n *\n * Resolution order:\n * 1. Explicit `bearerToken` → BearerTokenProvider\n * 2. Explicit `clientId` + `clientSecret` → OAuth2ClientCredentialProvider\n * 3. Explicit `refreshToken` + `clientId` → OAuth2RefreshTokenProvider\n * 4. Explicit `onAuthorizationUrl` + `clientId` → OAuth2AuthorizationCodeProvider\n * 5. `GIGADRIVE_BEARER_TOKEN` env var → BearerTokenProvider\n * 6. `GIGADRIVE_CLIENT_ID` + `GIGADRIVE_CLIENT_SECRET` → OAuth2ClientCredentialProvider\n * 7. `GIGADRIVE_REFRESH_TOKEN` + `GIGADRIVE_CLIENT_ID` → OAuth2RefreshTokenProvider\n * 8. Throws AuthenticationError\n */\nexport const resolveCredentialProvider = (config: CredentialResolverConfig): CredentialProvider => {\n // Bind the default fetch to globalThis so calling it as `this.fetchFn(...)`\n // does not throw \"Illegal invocation\" in runtimes that require a bound receiver.\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n const baseUrl = config.baseUrl ?? readEnv('GIGADRIVE_API_BASE_URL') ?? DEFAULT_BASE_URL;\n const idpIssuerUrl = config.idpIssuerUrl ?? readEnv('GIGADRIVE_IDP_ISSUER_URL') ?? DEFAULT_IDP_ISSUER_URL;\n const tokenUrl = `${baseUrl}/oauth2/token`;\n\n // 1. Explicit bearer token\n if (config.bearerToken) {\n return new BearerTokenProvider(config.bearerToken);\n }\n\n // 2. Explicit client credentials\n if (config.clientId && config.clientSecret) {\n return new OAuth2ClientCredentialProvider(config.clientId, config.clientSecret, tokenUrl, fetchFn);\n }\n\n // 3. Explicit refresh token\n if (config.refreshToken && config.clientId) {\n return new OAuth2RefreshTokenProvider(config.clientId, config.refreshToken, idpIssuerUrl, fetchFn);\n }\n\n // 4. Explicit authorization code callback\n if (config.onAuthorizationUrl && config.clientId) {\n const redirectUri = config.redirectUri ?? 'urn:ietf:wg:oauth:2.0:oob';\n const scope = config.scopes && config.scopes.length > 0 ? config.scopes.join(' ') : DEFAULT_SCOPE;\n return new OAuth2AuthorizationCodeProvider(\n config.clientId,\n idpIssuerUrl,\n redirectUri,\n config.onAuthorizationUrl,\n fetchFn,\n scope\n );\n }\n\n // 5. GIGADRIVE_BEARER_TOKEN env var\n const envBearerToken = readEnv('GIGADRIVE_BEARER_TOKEN');\n if (envBearerToken) {\n return new BearerTokenProvider(envBearerToken);\n }\n\n // 6. GIGADRIVE_CLIENT_ID + GIGADRIVE_CLIENT_SECRET env vars\n const envClientId = readEnv('GIGADRIVE_CLIENT_ID');\n const envClientSecret = readEnv('GIGADRIVE_CLIENT_SECRET');\n if (envClientId && envClientSecret) {\n return new OAuth2ClientCredentialProvider(envClientId, envClientSecret, tokenUrl, fetchFn);\n }\n\n // 7. GIGADRIVE_REFRESH_TOKEN + GIGADRIVE_CLIENT_ID env vars\n const envRefreshToken = readEnv('GIGADRIVE_REFRESH_TOKEN');\n if (envRefreshToken && envClientId) {\n return new OAuth2RefreshTokenProvider(envClientId, envRefreshToken, idpIssuerUrl, fetchFn);\n }\n\n // 8. No credentials found\n throw new AuthenticationError(\n 'No credentials provided. Set one of:\\n' +\n ' - GIGADRIVE_BEARER_TOKEN\\n' +\n ' - GIGADRIVE_CLIENT_ID + GIGADRIVE_CLIENT_SECRET\\n' +\n ' - GIGADRIVE_REFRESH_TOKEN + GIGADRIVE_CLIENT_ID\\n' +\n 'Or pass credentials directly to the GigadriveClient constructor.'\n );\n};\n","import type { CredentialProvider } from './credential-provider';\n\n/**\n * Manages the access-token lifecycle: caching, automatic expiry detection,\n * proactive refresh, and concurrent-call deduplication.\n *\n * When multiple API requests fire simultaneously with an expired token, only\n * a single refresh call is made — all concurrent callers await the same\n * pending Promise. This prevents a \"thundering herd\" of token requests.\n *\n * @internal Used internally by {@link HttpClient}. Not part of the public API.\n */\nexport class TokenManager {\n private cachedToken: string | null = null;\n private expiresAt: number | null = null;\n private pendingRefresh: Promise<string> | null = null;\n\n constructor(private readonly provider: CredentialProvider) {}\n\n /**\n * Returns a valid access token. Uses the cached token if still valid,\n * otherwise fetches a new one from the credential provider.\n *\n * Concurrent calls are deduplicated — only one refresh runs at a time.\n */\n async getToken(): Promise<string> {\n if (this.cachedToken && (this.expiresAt === null || Date.now() < this.expiresAt)) {\n return this.cachedToken;\n }\n\n // Deduplicate concurrent refresh calls\n if (this.pendingRefresh) {\n return this.pendingRefresh;\n }\n\n this.pendingRefresh = this.refresh();\n\n try {\n return await this.pendingRefresh;\n } finally {\n this.pendingRefresh = null;\n }\n }\n\n /**\n * Invalidates the cached token. The next `getToken()` call will trigger a refresh.\n */\n invalidate(): void {\n this.cachedToken = null;\n this.expiresAt = null;\n }\n\n private async refresh(): Promise<string> {\n const result = await this.provider.getToken();\n this.cachedToken = result.accessToken;\n this.expiresAt = result.expiresAt;\n return result.accessToken;\n }\n}\n","import type { TokenManager } from './auth/token-manager';\nimport { ApiError, AuthenticationError } from './errors';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * A paginated API response. List endpoints return this shape.\n *\n * @typeParam T - The type of each item in the list.\n */\nexport interface Paginated<T> {\n /** The items on the current page. */\n items: T[];\n /** The total number of items across all pages. */\n total: number;\n /** An opaque cursor for the next page, present on cursor-paginated endpoints when more items remain. */\n nextCursor?: string;\n}\n\n/** A value that can be serialized into a query-string parameter. `undefined` values are omitted. */\nexport type QueryValue = string | number | boolean | undefined;\n\n/** Common pagination query parameters accepted by list endpoints. */\nexport interface ListQuery {\n /** 1-indexed page number (for page/`perPage`-style pagination). */\n page?: number;\n /** Maximum number of items per page. */\n perPage?: number;\n /** Opaque cursor for cursor-based pagination (from a previous response's `nextCursor`). */\n cursor?: string;\n}\n\n/** @internal */\nexport interface RequestOptions {\n query?: Record<string, QueryValue>;\n body?: unknown;\n headers?: Record<string, string>;\n /** Abort signal to cancel the request (and any 401-refresh retry). */\n signal?: AbortSignal;\n}\n\nconst isRawBody = (body: unknown): boolean =>\n typeof body === 'string' ||\n body instanceof ArrayBuffer ||\n (typeof Uint8Array !== 'undefined' && body instanceof Uint8Array) ||\n (typeof Blob !== 'undefined' && body instanceof Blob) ||\n (typeof FormData !== 'undefined' && body instanceof FormData) ||\n (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream);\n\nconst hasHeader = (headers: Record<string, string>, name: string): boolean =>\n Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase());\n\n// ---------------------------------------------------------------------------\n// HTTP Client\n// ---------------------------------------------------------------------------\n\n/**\n * Low-level HTTP client used internally by all resource classes. Handles\n * authentication header injection, JSON serialization, error mapping, and\n * automatic retry on 401 responses.\n *\n * You do not need to use this class directly — interact with the API through\n * the resource properties on {@link GigadriveClient} instead.\n *\n * @internal\n */\nexport class HttpClient {\n constructor(\n private readonly baseUrl: string,\n private readonly tokenManager: TokenManager,\n private readonly fetchFn: typeof globalThis.fetch\n ) {}\n\n /** @internal */\n async get<T>(path: string, options?: Pick<RequestOptions, 'query' | 'signal'>): Promise<T> {\n return this.request<T>('GET', path, options);\n }\n\n /** @internal */\n async post<T>(\n path: string,\n body?: unknown,\n options?: Pick<RequestOptions, 'headers' | 'query' | 'signal'>\n ): Promise<T> {\n return this.request<T>('POST', path, { body, ...options });\n }\n\n /** @internal */\n async put<T>(\n path: string,\n body?: unknown,\n options?: Pick<RequestOptions, 'headers' | 'query' | 'signal'>\n ): Promise<T> {\n return this.request<T>('PUT', path, { body, ...options });\n }\n\n /** @internal */\n async patch<T>(\n path: string,\n body?: unknown,\n options?: Pick<RequestOptions, 'headers' | 'query' | 'signal'>\n ): Promise<T> {\n return this.request<T>('PATCH', path, { body, ...options });\n }\n\n /** @internal */\n async delete<T>(path: string, options?: Pick<RequestOptions, 'query' | 'signal'>): Promise<T> {\n return this.request<T>('DELETE', path, options);\n }\n\n /** @internal */\n async postRaw<T>(\n path: string,\n body: string | ArrayBuffer | Uint8Array | ReadableStream | Blob | FormData,\n headers?: Record<string, string>\n ): Promise<T> {\n return this.request<T>('POST', path, { body, headers });\n }\n\n /**\n * Make an authenticated request and return the raw `Response` without parsing\n * the body. Used for streamed (SSE) and binary responses.\n *\n * @throws {@link ApiError} if the response status is not OK.\n * @internal\n */\n async requestStream(method: string, path: string, options?: RequestOptions): Promise<Response> {\n const response = await this.fetchWithAuth(method, path, options);\n if (!response.ok) {\n throw await this.toApiError(response);\n }\n return response;\n }\n\n /**\n * Make a raw fetch request to an arbitrary URL (e.g. presigned upload URLs\n * or resumable upload endpoints). No auth header is injected and the base URL\n * is not prepended.\n *\n * @param url - The full URL to fetch.\n * @param init - Standard `RequestInit` options.\n * @returns The raw `Response` object.\n * @throws {@link ApiError} if the response status is not OK.\n *\n * @internal\n */\n async fetchRaw(url: string, init: RequestInit): Promise<Response> {\n const response = await this.fetchFn(url, init);\n if (!response.ok) {\n throw new ApiError(response.statusText, response.status);\n }\n return response;\n }\n\n private async request<T>(method: string, path: string, options?: RequestOptions): Promise<T> {\n const response = await this.fetchWithAuth(method, path, options);\n return this.handleResponse<T>(response);\n }\n\n /** Perform the request with auth injection and a single 401 refresh-retry. */\n private async fetchWithAuth(method: string, path: string, options?: RequestOptions): Promise<Response> {\n const url = this.buildUrl(path, options?.query);\n const token = await this.tokenManager.getToken();\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n ...options?.headers,\n };\n\n let requestBody: RequestInit['body'] = null;\n if (options?.body !== undefined) {\n if (isRawBody(options.body)) {\n // Raw bodies (FormData/Blob/bytes/streams) set their own Content-Type.\n requestBody = options.body as RequestInit['body'];\n } else {\n requestBody = JSON.stringify(options.body);\n if (!hasHeader(headers, 'Content-Type')) {\n headers['Content-Type'] = 'application/json';\n }\n }\n }\n\n const signal = options?.signal;\n const response = await this.fetchFn(url, { method, headers, body: requestBody, signal });\n\n // A streamed body is consumed by the first fetch and cannot be replayed, so\n // we cannot transparently retry it after a token refresh.\n const bodyIsOneShot = typeof ReadableStream !== 'undefined' && requestBody instanceof ReadableStream;\n\n // Retry once on 401 after refreshing the token.\n if (response.status === 401 && !bodyIsOneShot) {\n this.tokenManager.invalidate();\n const retryToken = await this.tokenManager.getToken();\n headers.Authorization = `Bearer ${retryToken}`;\n\n const retryResponse = await this.fetchFn(url, { method, headers, body: requestBody, signal });\n if (retryResponse.status === 401) {\n throw new AuthenticationError('Authentication failed after token refresh');\n }\n return retryResponse;\n }\n\n return response;\n }\n\n private async handleResponse<T>(response: Response): Promise<T> {\n if (response.ok) {\n // Handle empty responses (204 No Content, or responses with no body)\n if (response.status === 204) {\n return undefined as T;\n }\n\n const text = await response.text();\n if (!text) {\n return undefined as T;\n }\n\n return JSON.parse(text) as T;\n }\n\n throw await this.toApiError(response);\n }\n\n private async toApiError(response: Response): Promise<ApiError> {\n let message: string;\n let code: string | undefined;\n let reason: string | undefined;\n\n try {\n const body = (await response.json()) as {\n error?: string | { message?: string; code?: string };\n code?: unknown;\n reason?: unknown;\n };\n if (typeof body.error === 'string') {\n message = body.error;\n // Some endpoints (custom domains) send a stable code, and sometimes a reason, next to the message.\n if (typeof body.code === 'string') code = body.code;\n if (typeof body.reason === 'string') reason = body.reason;\n } else if (body.error && typeof body.error === 'object') {\n message = body.error.message ?? response.statusText;\n code = body.error.code;\n } else {\n message = response.statusText;\n }\n } catch {\n message = response.statusText;\n }\n\n return new ApiError(message, response.status, code, reason);\n }\n\n private buildUrl(path: string, query?: Record<string, QueryValue>): string {\n const url = `${this.baseUrl}${path}`;\n\n if (!query) return url;\n\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined) {\n params.set(key, String(value));\n }\n }\n\n const qs = params.toString();\n return qs ? `${url}?${qs}` : url;\n }\n}\n","/**\n * Server-Sent Events (SSE) parsing for streamed API responses (e.g. streamed\n * chat completions). Works in browsers and Node.js 18+ where `Response.body` is\n * a web `ReadableStream`.\n *\n * @internal\n */\n\n/** Extract and concatenate the `data:` payload(s) from a single SSE event block. */\nconst extractData = (rawEvent: string): string | null => {\n const dataLines = rawEvent\n .split('\\n')\n .filter((line) => line.startsWith('data:'))\n .map((line) => line.slice('data:'.length).replace(/^ /, ''));\n if (dataLines.length === 0) return null;\n const joined = dataLines.join('\\n');\n // Treat whitespace-only events (e.g. keep-alive comments or a truncated final\n // \"data:\" line) as \"no data\" so we never call JSON.parse on an empty string.\n return joined.trim().length === 0 ? null : joined;\n};\n\nconst parseEvent = <T>(data: string): T => {\n try {\n return JSON.parse(data) as T;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to parse streamed SSE data as JSON: ${message}`);\n }\n};\n\n/**\n * Parse an SSE stream, yielding each event's `data` payload parsed as JSON.\n * The `[DONE]` sentinel and empty keep-alive events are skipped; iteration ends\n * when the underlying stream closes.\n *\n * @typeParam T - The shape of each streamed JSON chunk.\n * @param response - A streaming `fetch` response.\n */\nexport async function* parseSSEStream<T = unknown>(response: Response): AsyncGenerator<T> {\n const body = response.body as ReadableStream<Uint8Array> | null;\n if (!body) {\n throw new Error('The response has no readable body to stream.');\n }\n\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n const drain = function* (flush: boolean): Generator<T> {\n // SSE events are separated by a blank line; CRLF is normalised on read.\n let separator = buffer.indexOf('\\n\\n');\n while (separator !== -1) {\n const rawEvent = buffer.slice(0, separator);\n buffer = buffer.slice(separator + 2);\n const data = extractData(rawEvent);\n if (data !== null && data !== '[DONE]') {\n yield parseEvent<T>(data);\n }\n separator = buffer.indexOf('\\n\\n');\n }\n if (flush) {\n const data = extractData(buffer);\n buffer = '';\n if (data !== null && data !== '[DONE]') {\n yield parseEvent<T>(data);\n }\n }\n };\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n // Normalise CRLF on the whole buffer so a separator split across two reads\n // (a trailing \"\\r\" then a leading \"\\n\") is still collapsed correctly.\n buffer = (buffer + decoder.decode(value, { stream: true })).replace(/\\r\\n/g, '\\n');\n yield* drain(false);\n }\n yield* drain(true);\n } finally {\n // Cancel (not just release the lock) so breaking out of the consumer's\n // `for await` early stops the underlying HTTP body instead of leaking it.\n await reader.cancel().catch(() => undefined);\n }\n}\n","import type { HttpClient } from '../http-client';\n\n/**\n * Base class for all API resource classes. Provides access to the shared\n * HTTP client for making authenticated API requests.\n *\n * @internal\n */\nexport class BaseResource {\n constructor(protected readonly httpClient: HttpClient) {}\n}\n","import type { HttpClient, Paginated } from '../../http-client';\nimport { parseSSEStream } from '../../streaming';\nimport { BaseResource } from '../base-resource';\nimport type {\n AiModel,\n ChatCompletionChunk,\n ChatCompletionRequest,\n ChatCompletionResponse,\n GatewayRequestOptions,\n GatewayResult,\n ResponsesRequest,\n ResponsesResponse,\n SpeechRequest,\n TranscriptionRequest,\n TranscriptionResponse,\n VideoGenerationRequest,\n VideoGenerationResponse,\n VideoModelList,\n} from './types';\n\nexport type * from './types';\n\nconst BASE = '/ai/v1';\n\nconst toBlob = (file: Blob | Uint8Array | ArrayBuffer): Blob => {\n if (file instanceof Uint8Array) return new Blob([file]);\n if (typeof Blob !== 'undefined' && file instanceof Blob) return file;\n return new Blob([new Uint8Array(file as ArrayBuffer)]);\n};\n\n/** Text-to-speech and speech-to-text endpoints. */\nexport class AiGatewayAudioResource extends BaseResource {\n /**\n * Synthesize speech from text. Returns the raw audio bytes.\n *\n * @returns The audio content as an `ArrayBuffer` (format per `response_format`).\n */\n async speech(data: SpeechRequest, options?: GatewayRequestOptions): Promise<ArrayBuffer> {\n const response = await this.httpClient.requestStream('POST', `${BASE}/audio/speech`, {\n body: data,\n headers: options?.headers,\n });\n return response.arrayBuffer();\n }\n\n /**\n * Transcribe an audio file to text. The file is sent as multipart form data.\n */\n async transcriptions(data: TranscriptionRequest, options?: GatewayRequestOptions): Promise<TranscriptionResponse> {\n const form = new FormData();\n const { file, filename, ...rest } = data;\n form.set('file', toBlob(file), filename ?? 'audio');\n for (const [key, value] of Object.entries(rest)) {\n if (value === undefined || value === null) continue;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- narrows to primitive so no-base-to-string is satisfied\n form.set(key, typeof value === 'object' ? JSON.stringify(value) : String(value as string | number | boolean));\n }\n return this.httpClient.postRaw(`${BASE}/audio/transcriptions`, form, options?.headers);\n }\n}\n\n/** Video generation endpoints. */\nexport class AiGatewayVideosResource extends BaseResource {\n /** Generate a video from a prompt. */\n async generations(data: VideoGenerationRequest, options?: GatewayRequestOptions): Promise<VideoGenerationResponse> {\n return this.httpClient.post(`${BASE}/videos`, data, { headers: options?.headers });\n }\n\n /** List the video models available through the gateway. */\n async listModels(): Promise<VideoModelList> {\n return this.httpClient.get(`${BASE}/videos/models`);\n }\n}\n\n/**\n * Interact with the Gigadrive AI Gateway — an OpenAI-compatible API that routes\n * requests to multiple AI providers. Accessed via {@link GigadriveClient.aiGateway}.\n *\n * @example\n * ```ts\n * // Chat completion\n * const res = await client.aiGateway.chatCompletions({\n * model: 'openai/gpt-4o',\n * messages: [{ role: 'user', content: 'Hello!' }],\n * });\n * console.log(res.choices[0].message.content);\n *\n * // Streamed chat completion\n * for await (const chunk of client.aiGateway.chatCompletionsStream({\n * model: 'openai/gpt-4o',\n * messages: [{ role: 'user', content: 'Write a haiku.' }],\n * })) {\n * process.stdout.write(chunk.choices[0]?.delta.content ?? '');\n * }\n * ```\n */\nexport class AiGatewayResource extends BaseResource {\n /** Text-to-speech and speech-to-text. */\n readonly audio: AiGatewayAudioResource;\n /** Video generation. */\n readonly videos: AiGatewayVideosResource;\n\n constructor(httpClient: HttpClient) {\n super(httpClient);\n this.audio = new AiGatewayAudioResource(httpClient);\n this.videos = new AiGatewayVideosResource(httpClient);\n }\n\n /**\n * Create a chat completion using the OpenAI-compatible endpoint.\n *\n * @param data - The chat completion request (model, messages, options, provider routing).\n * @param options - Custom headers (e.g. `X-Gigadrive-Application-Id`).\n */\n async chatCompletions(data: ChatCompletionRequest, options?: GatewayRequestOptions): Promise<ChatCompletionResponse> {\n return this.httpClient.post(`${BASE}/chat/completions`, { ...data, stream: false }, { headers: options?.headers });\n }\n\n /**\n * Like {@link chatCompletions}, but also returns the raw response and the\n * gateway request-id / cost headers.\n */\n async chatCompletionsWithResponse(\n data: ChatCompletionRequest,\n options?: GatewayRequestOptions\n ): Promise<GatewayResult<ChatCompletionResponse>> {\n const response = await this.httpClient.requestStream('POST', `${BASE}/chat/completions`, {\n body: { ...data, stream: false },\n headers: options?.headers,\n });\n const body = (await response.json()) as ChatCompletionResponse;\n const cost = response.headers.get('X-Gigadrive-Cost-Micros');\n const costMicros = cost !== null ? Number(cost) : NaN;\n return {\n data: body,\n response,\n requestId: response.headers.get('X-Gigadrive-Request-Id') ?? undefined,\n costMicros: Number.isFinite(costMicros) ? costMicros : undefined,\n };\n }\n\n /**\n * Stream a chat completion as Server-Sent Events. Yields each chunk as it\n * arrives and ends when the gateway closes the stream.\n */\n async *chatCompletionsStream(\n data: ChatCompletionRequest,\n options?: GatewayRequestOptions\n ): AsyncGenerator<ChatCompletionChunk> {\n const response = await this.httpClient.requestStream('POST', `${BASE}/chat/completions`, {\n body: { ...data, stream: true },\n headers: options?.headers,\n });\n yield* parseSSEStream<ChatCompletionChunk>(response);\n }\n\n /**\n * Create a response using the Open Responses-compatible endpoint.\n */\n async responses(data: ResponsesRequest, options?: GatewayRequestOptions): Promise<ResponsesResponse> {\n return this.httpClient.post(`${BASE}/responses`, { ...data, stream: false }, { headers: options?.headers });\n }\n\n /**\n * Stream a response using the Open Responses-compatible endpoint.\n */\n async *responsesStream(data: ResponsesRequest, options?: GatewayRequestOptions): AsyncGenerator<unknown> {\n const response = await this.httpClient.requestStream('POST', `${BASE}/responses`, {\n body: { ...data, stream: true },\n headers: options?.headers,\n });\n yield* parseSSEStream(response);\n }\n\n /**\n * List all AI models available through the gateway.\n */\n async listModels(): Promise<Paginated<AiModel>> {\n return this.httpClient.get(`${BASE}/models`);\n }\n\n /**\n * Get details for a specific AI model by its ID.\n *\n * @param modelId - The model identifier (e.g. `\"openai/gpt-4o\"`).\n */\n async getModel(modelId: string): Promise<AiModel> {\n return this.httpClient.get(`${BASE}/models/${encodeURIComponent(modelId)}`);\n }\n}\n","import type { Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n/** An application-scoped API key. The secret is never returned after creation. */\nexport interface ApiKey {\n /** Unique identifier (UUID). Used as the OAuth client ID. */\n id: string;\n /** Human-readable label. */\n name: string;\n /** Application this key is scoped to. */\n applicationId: string | null;\n /** API capability scopes granted to the key. */\n scopes: string[];\n /** ISO 8601 expiry, or `null` if the key never expires. */\n expiresAt: string | null;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Input for creating an application-scoped API key. */\nexport interface CreateApiKeyInput {\n /** Human-readable label for the key. */\n name: string;\n /** Application to scope the key to. The key can only act on this application. */\n applicationId: string;\n /**\n * API capability scopes to grant. Each must be a subset of your own access and\n * cannot include API key management. Defaults to a minimal read-only set.\n */\n scopes?: string[];\n /** Optional ISO 8601 expiry. Defaults to 90 days when omitted. */\n expiresAt?: string;\n}\n\n/**\n * The result of creating an API key. Includes the plaintext {@link secret},\n * which is returned only once and cannot be retrieved again.\n */\nexport interface CreateApiKeyResult extends ApiKey {\n /** The plaintext client secret. Store it now — it cannot be retrieved again. */\n secret: string;\n}\n\n/** Query for {@link ApiKeysResource.list}. */\nexport interface ListApiKeysQuery {\n /** Application whose keys should be listed. */\n applicationId: string;\n}\n\n/**\n * Manage application-scoped API keys. Accessed via {@link GigadriveClient.apiKeys}.\n *\n * @example\n * ```ts\n * const key = await client.apiKeys.create({ name: 'ci', applicationId: 'app-id' });\n * // Use key.id + key.secret as OAuth client credentials. Store the secret now.\n * ```\n */\nexport class ApiKeysResource extends BaseResource {\n /**\n * Provision a new application-scoped API key. The plaintext secret is returned\n * exactly once — store it immediately.\n *\n * @param data - The key name, target application, and optional scopes/expiry.\n * @returns The created key including its one-time plaintext secret.\n */\n async create(data: CreateApiKeyInput): Promise<CreateApiKeyResult> {\n return this.httpClient.post('/api-keys', data);\n }\n\n /**\n * List the API keys scoped to an application. Secrets are never returned.\n *\n * @param query - The application whose keys should be listed.\n * @returns A paginated list of API key metadata.\n */\n async list(query: ListApiKeysQuery): Promise<Paginated<ApiKey>> {\n return this.httpClient.get('/api-keys', {\n query: query as unknown as Record<string, string | number | undefined>,\n });\n }\n\n /**\n * Permanently revoke an API key.\n *\n * @param apiKeyId - The API key ID (UUID).\n */\n async delete(apiKeyId: string): Promise<void> {\n return this.httpClient.delete(`/api-keys/${apiKeyId}`);\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport type { CreateEnvVarInput, EnvVar, PullEnvVarsQuery, PullEnvVarsResult, UpdateEnvVarInput } from './env-vars';\n\n/**\n * Manage environment variables scoped to an application.\n * Accessed via `client.applications.envVars`.\n */\nexport class ApplicationEnvVarsResource extends BaseResource {\n /**\n * List all environment variables for an application.\n *\n * @param applicationId - The application ID (UUID).\n * @returns A paginated list of environment variables.\n *\n * @example\n * ```ts\n * const { items } = await client.applications.envVars.list('app-id');\n * for (const v of items) {\n * console.log(`${v.key}=${v.sensitive ? '***' : v.value}`);\n * }\n * ```\n */\n async list(applicationId: string, query?: ListQuery): Promise<Paginated<EnvVar>> {\n return this.httpClient.get(`/applications/${applicationId}/env-vars`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Pull the environment variables that apply to an application for local\n * development. Merges organization-wide, application-wide, and (optionally)\n * environment-specific overrides, returning only non-sensitive values — ready\n * to write to a local `.env` file.\n *\n * @param applicationId - The application ID (UUID).\n * @param query - Optional environment targeting.\n * @returns The resolved non-sensitive variables plus the count of omitted secrets.\n *\n * @example\n * ```ts\n * const { items } = await client.applications.envVars.pull('app-id');\n * const dotenv = items.map((v) => `${v.key}=${v.value}`).join('\\n');\n * ```\n */\n async pull(applicationId: string, query?: PullEnvVarsQuery): Promise<PullEnvVarsResult> {\n return this.httpClient.get(`/applications/${applicationId}/env-vars/pull`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Create a new environment variable for an application.\n *\n * @param applicationId - The application ID (UUID).\n * @param data - The variable key, value, and optional settings.\n * @returns The newly created environment variable.\n *\n * @example\n * ```ts\n * const envVar = await client.applications.envVars.create('app-id', {\n * key: 'DATABASE_URL',\n * value: 'postgres://...',\n * sensitive: true,\n * });\n * ```\n */\n async create(applicationId: string, data: CreateEnvVarInput): Promise<EnvVar> {\n return this.httpClient.post(`/applications/${applicationId}/env-vars`, data);\n }\n\n /**\n * Update an existing environment variable. Only the fields you provide\n * will be changed; omitted fields are left unchanged.\n *\n * @param applicationId - The application ID (UUID).\n * @param envVarId - The environment variable ID (UUID).\n * @param data - The fields to update.\n * @returns The updated environment variable.\n *\n * @example\n * ```ts\n * await client.applications.envVars.update('app-id', 'var-id', {\n * value: 'postgres://new-host/db',\n * });\n * ```\n */\n async update(applicationId: string, envVarId: string, data: UpdateEnvVarInput): Promise<EnvVar> {\n return this.httpClient.patch(`/applications/${applicationId}/env-vars/${envVarId}`, data);\n }\n\n /**\n * Permanently delete an environment variable.\n *\n * @param applicationId - The application ID (UUID).\n * @param envVarId - The environment variable ID (UUID).\n *\n * @example\n * ```ts\n * await client.applications.envVars.delete('app-id', 'var-id');\n * ```\n */\n async delete(applicationId: string, envVarId: string): Promise<void> {\n return this.httpClient.delete(`/applications/${applicationId}/env-vars/${envVarId}`);\n }\n}\n","import type { Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n/** A nested reference to the application that served a request. */\nexport interface NetworkRequestApplicationRef {\n id: string;\n name: string;\n}\n\n/** A nested reference to the deployment that served a request. */\nexport interface NetworkRequestDeploymentRef {\n id: string;\n status: string;\n}\n\n/** A nested reference to the function route that handled a request. */\nexport interface NetworkRequestFunctionRef {\n id: string;\n name: string | null;\n path: string;\n region: string | null;\n}\n\n/** A nested reference to the static asset that served a request. */\nexport interface NetworkRequestAssetRef {\n id: string;\n path: string;\n objectKey: string;\n}\n\n/** A nested reference to the storage bucket involved in a request. */\nexport interface NetworkRequestBucketRef {\n id: string;\n name: string;\n slug: string;\n}\n\n/** A nested reference to the storage object involved in a request. */\nexport interface NetworkRequestObjectRef {\n id: string;\n key: string;\n contentType: string | null;\n}\n\n/** The HTTP request details captured for a network request. */\nexport interface NetworkRequestDetails {\n method: string;\n hostname: string;\n path: string;\n query: string | null;\n protocol: string | null;\n country: string | null;\n userAgent: string | null;\n referer: string | null;\n}\n\n/** The HTTP response details captured for a network request. */\nexport interface NetworkResponseDetails {\n status: number | null;\n cacheStatus: 'hit' | 'miss' | 'bypass' | 'revalidated' | 'stale' | 'updating' | null;\n cacheHit: boolean | null;\n region: string | null;\n edgeLocation: string | null;\n}\n\n/** Byte and timing metrics for a network request. */\nexport interface NetworkRequestMetrics {\n requestBodyBytes: number | null;\n responseBodyBytes: number | null;\n bytesSent: number | null;\n durationMs: number | null;\n}\n\n/** A single observed request served through the Gigadrive Network edge (summary form). */\nexport interface NetworkRequestSummary {\n id: string;\n application: NetworkRequestApplicationRef;\n deployment: NetworkRequestDeploymentRef | null;\n deploymentFunction: NetworkRequestFunctionRef | null;\n deploymentAsset: NetworkRequestAssetRef | null;\n storageBucket: NetworkRequestBucketRef | null;\n storageObject: NetworkRequestObjectRef | null;\n request: NetworkRequestDetails;\n response: NetworkResponseDetails;\n metrics: NetworkRequestMetrics;\n startedAt: string;\n completedAt: string | null;\n}\n\n/** A full network request record, including sanitized request/response headers. */\nexport interface NetworkRequest extends NetworkRequestSummary {\n /** Sanitized request headers captured for debugging. */\n requestHeaders: Record<string, string>;\n /** Sanitized response headers captured for debugging. */\n responseHeaders: Record<string, string>;\n}\n\n/** Query filters for listing application requests. All fields are optional. */\nexport interface ListRequestsQuery {\n /** Filter to requests served by one deployment. */\n deploymentId?: string;\n /** Filter to requests served by one function route. */\n deploymentFunctionId?: string;\n /** Filter to requests served by one static asset route. */\n deploymentAssetId?: string;\n /** Filter to storage delivery requests for one bucket. */\n storageBucketId?: string;\n /** Filter to storage delivery requests for one object. */\n storageObjectId?: string;\n /** Only include requests that started at or after this ISO 8601 timestamp. */\n from?: string;\n /** Only include requests that started before or at this ISO 8601 timestamp. */\n to?: string;\n /** Maximum number of records to return. */\n limit?: number;\n /** Opaque cursor from a previous response's `nextCursor`. */\n cursor?: string;\n /** Filter by HTTP method (e.g. `\"GET\"`). */\n method?: string;\n /** Filter by exact HTTP status code. */\n status?: number;\n /** Filter by status family (`2`, `3`, `4`, or `5`). */\n statusFamily?: number;\n /** Filter by request hostname. */\n hostname?: string;\n /** Filter to requests whose path starts with this prefix. */\n pathPrefix?: string;\n /** Filter by ISO 3166-1 alpha-2 country code. */\n country?: string;\n /** Filter by origin region. */\n region?: string;\n /** Filter by edge location. */\n edgeLocation?: string;\n /** Filter by CDN cache state. */\n cacheStatus?: string;\n /** Filter by whether the response was served from cache. */\n cacheHit?: boolean;\n}\n\n/**\n * Read observed traffic (request logs) for an application. Accessed via\n * `client.applications.requests`.\n *\n * @example\n * ```ts\n * // Recent 5xx responses for a deployment\n * const { items } = await client.applications.requests.list('app-id', {\n * deploymentId: 'dep-id',\n * statusFamily: 5,\n * limit: 100,\n * });\n * ```\n */\nexport class ApplicationRequestsResource extends BaseResource {\n /**\n * List requests for an application, with rich filtering and cursor pagination.\n *\n * @param applicationId - The application ID (UUID).\n * @param query - Optional filters and pagination.\n * @returns A page of request summaries.\n */\n async list(applicationId: string, query?: ListRequestsQuery): Promise<Paginated<NetworkRequestSummary>> {\n return this.httpClient.get(`/applications/${applicationId}/requests`, {\n query: query as Record<string, string | number | boolean | undefined> | undefined,\n });\n }\n\n /**\n * Get a single request by ID, including sanitized request/response headers.\n *\n * @param applicationId - The application ID (UUID).\n * @param requestId - The request record ID (UUID).\n * @returns The full request record.\n */\n async get(applicationId: string, requestId: string): Promise<NetworkRequest> {\n return this.httpClient.get(`/applications/${applicationId}/requests/${requestId}`);\n }\n}\n","/**\n * Checksum helpers used to satisfy the storage upload contract, which requires\n * a SHA-256 of the object content (SHA-1 and MD5 are optional integrity hints).\n *\n * SHA-256 and SHA-1 are computed with the Web Crypto API (`crypto.subtle`),\n * which is available in modern browsers and Node.js 18+. MD5 is not provided by\n * Web Crypto, so it is computed with Node's `crypto` module and is therefore\n * Node-only — pass `checksumMd5` explicitly if you need it in the browser.\n *\n * @internal\n */\n\n/** SHA-256 of empty input — the only checksum the API accepts for a zero-byte upload. */\nexport const EMPTY_SHA256 = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';\n\n/** A set of computed content checksums (lowercase hex). */\nexport interface Checksums {\n /** SHA-256 checksum. Always computed. */\n sha256: string;\n /** SHA-1 checksum, when requested. */\n sha1?: string;\n /** MD5 checksum, when requested (Node.js only). */\n md5?: string;\n}\n\n/** Which optional checksums to compute alongside the always-required SHA-256. */\nexport interface ChecksumRequest {\n /** Also compute a SHA-1 checksum. */\n sha1?: boolean;\n /** Also compute an MD5 checksum (Node.js only). */\n md5?: boolean;\n}\n\nconst toHex = (buffer: ArrayBuffer): string => {\n const bytes = new Uint8Array(buffer);\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += bytes[i].toString(16).padStart(2, '0');\n }\n return hex;\n};\n\nconst subtleDigest = async (algorithm: 'SHA-256' | 'SHA-1', bytes: Uint8Array): Promise<string> =>\n toHex(await crypto.subtle.digest(algorithm, bytes));\n\nconst importNodeCrypto = async (): Promise<typeof import('node:crypto') | null> => {\n if (typeof process === 'undefined' || !process.versions?.node) return null;\n try {\n return await import('node:crypto');\n } catch {\n return null;\n }\n};\n\nconst md5Hex = async (bytes: Uint8Array): Promise<string> => {\n const nodeCrypto = await importNodeCrypto();\n if (!nodeCrypto) {\n throw new Error('MD5 checksums are only supported in Node.js. Provide checksumMd5 explicitly in the browser.');\n }\n return nodeCrypto.createHash('md5').update(bytes).digest('hex');\n};\n\n/**\n * Compute checksums for an in-memory byte buffer.\n *\n * @param bytes - The content bytes.\n * @param request - Which optional checksums to compute (SHA-256 is always computed).\n */\nexport const computeChecksums = async (bytes: Uint8Array, request: ChecksumRequest = {}): Promise<Checksums> => {\n const checksums: Checksums = { sha256: await subtleDigest('SHA-256', bytes) };\n if (request.sha1) checksums.sha1 = await subtleDigest('SHA-1', bytes);\n if (request.md5) checksums.md5 = await md5Hex(bytes);\n return checksums;\n};\n\n/**\n * Compute checksums for a file on disk by streaming it through Node's hashing\n * primitives — avoids loading the whole file into memory. Node.js only.\n *\n * @param path - Filesystem path to hash.\n * @param request - Which optional checksums to compute (SHA-256 is always computed).\n */\nexport const hashNodeFile = async (path: string, request: ChecksumRequest = {}): Promise<Checksums> => {\n const [fs, nodeCrypto] = await Promise.all([import('node:fs'), import('node:crypto')]);\n const sha256 = nodeCrypto.createHash('sha256');\n const sha1 = request.sha1 ? nodeCrypto.createHash('sha1') : null;\n const md5 = request.md5 ? nodeCrypto.createHash('md5') : null;\n\n await new Promise<void>((resolve, reject) => {\n const stream = fs.createReadStream(path);\n stream.on('data', (chunk) => {\n sha256.update(chunk);\n sha1?.update(chunk);\n md5?.update(chunk);\n });\n stream.on('end', () => resolve());\n stream.on('error', reject);\n });\n\n const checksums: Checksums = { sha256: sha256.digest('hex') };\n if (sha1) checksums.sha1 = sha1.digest('hex');\n if (md5) checksums.md5 = md5.digest('hex');\n return checksums;\n};\n","/**\n * Minimal filename → MIME type inference used to populate an upload's content\n * type when the caller does not provide one. Intentionally dependency-free and\n * covers the most common web/asset types; callers can always pass an explicit\n * `contentType` to override.\n *\n * @internal\n */\n\nconst MIME_TYPES: Record<string, string> = {\n // Text & code\n txt: 'text/plain',\n csv: 'text/csv',\n html: 'text/html',\n htm: 'text/html',\n css: 'text/css',\n js: 'text/javascript',\n mjs: 'text/javascript',\n json: 'application/json',\n xml: 'application/xml',\n md: 'text/markdown',\n // Images\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n avif: 'image/avif',\n ico: 'image/x-icon',\n bmp: 'image/bmp',\n tiff: 'image/tiff',\n heic: 'image/heic',\n // Audio\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n oga: 'audio/ogg',\n flac: 'audio/flac',\n aac: 'audio/aac',\n m4a: 'audio/mp4',\n // Video\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n // Documents\n pdf: 'application/pdf',\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n // Archives & binaries\n zip: 'application/zip',\n gz: 'application/gzip',\n tar: 'application/x-tar',\n br: 'application/x-brotli',\n wasm: 'application/wasm',\n // Fonts\n woff: 'font/woff',\n woff2: 'font/woff2',\n ttf: 'font/ttf',\n otf: 'font/otf',\n};\n\n/**\n * Infer a MIME type from a filename or object key by its extension.\n *\n * @param nameOrKey - A filename or object key (e.g. `\"images/photo.jpg\"`).\n * @returns The inferred MIME type, or `undefined` if the extension is unknown.\n */\nexport const inferContentType = (nameOrKey: string): string | undefined => {\n const lastDot = nameOrKey.lastIndexOf('.');\n if (lastDot === -1 || lastDot === nameOrKey.length - 1) return undefined;\n const ext = nameOrKey.slice(lastDot + 1).toLowerCase();\n return MIME_TYPES[ext];\n};\n","/**\n * Resolves the various accepted upload inputs (in-memory bytes, a Node.js file\n * path, or a Node.js readable stream) into the concrete values the upload flow\n * needs: the object tus-js-client consumes, the byte size, an inferred content\n * type, and the required checksums.\n *\n * @internal\n */\n\nimport { computeChecksums, EMPTY_SHA256, hashNodeFile, type Checksums } from './checksum';\nimport { inferContentType } from './content-type';\n\n/** A minimal Node.js `Readable`-like shape (avoids depending on `node:stream` types). */\nexport interface NodeReadableLike {\n on(event: string, listener: (...args: unknown[]) => void): unknown;\n pipe?: unknown;\n read?: unknown;\n}\n\n/** In-memory data accepted by the upload helpers. `Buffer` is a `Uint8Array`. */\nexport type UploadData = Blob | ArrayBuffer | Uint8Array;\n\n/** The tus-js-client file input union. */\nexport type TusFile = File | Blob | Uint8Array | NodeReadableLike;\n\n/** Input describing what to upload and any pre-supplied metadata. */\nexport interface UploadSourceInput {\n /** The object key/path the upload targets — used to infer content type. */\n key: string;\n /** In-memory data (browser `File`/`Blob`, Node `Buffer`, `Uint8Array`, `ArrayBuffer`). */\n data?: UploadData;\n /** A filesystem path to stream from (Node.js only). */\n path?: string;\n /** A readable stream (Node.js only). Requires `contentLength` and `checksumSha256`. */\n stream?: NodeReadableLike;\n /** Explicit content type. Inferred from `key` when omitted. */\n contentType?: string;\n /** Explicit byte size. Required for `stream`; computed otherwise. */\n contentLength?: number;\n /** Pre-computed SHA-256 (skips hashing). Required for `stream`. */\n checksumSha256?: string;\n /** Pre-computed SHA-1. */\n checksumSha1?: string;\n /** Pre-computed MD5. */\n checksumMd5?: string;\n}\n\n/** The fully resolved upload source. */\nexport interface ResolvedUploadSource {\n /** The value handed to tus-js-client. */\n tusFile: TusFile;\n /** Total upload size in bytes. */\n size: number;\n /** Resolved content type, if known. */\n contentType?: string;\n /** Checksums (always includes SHA-256). */\n checksums: Checksums;\n /** Whether a finite chunk size is required (true for streamed/file-path inputs). */\n requiresFiniteChunkSize: boolean;\n /**\n * Releases resources the SDK opened for {@link tusFile} (the read stream for a\n * `path` input). Call it once the transfer settles, whether it succeeded,\n * failed or was aborted, and when the bytes will not be sent at all, for\n * example when the API stored an empty file without a transfer.\n * Caller-supplied streams are never touched.\n */\n release: () => void;\n}\n\nconst noop = () => {};\n\nconst isNode = (): boolean => typeof process !== 'undefined' && !!process.versions?.node;\n\nconst toBytes = async (data: UploadData): Promise<Uint8Array> => {\n if (typeof Blob !== 'undefined' && data instanceof Blob) return new Uint8Array(await data.arrayBuffer());\n if (data instanceof Uint8Array) return data;\n if (data instanceof ArrayBuffer) return new Uint8Array(data);\n throw new Error('Unsupported upload data type. Pass a File, Blob, Buffer, Uint8Array, or ArrayBuffer.');\n};\n\nconst sizeOf = (data: UploadData): number => {\n if (typeof Blob !== 'undefined' && data instanceof Blob) return data.size;\n if (data instanceof Uint8Array) return data.byteLength;\n if (data instanceof ArrayBuffer) return data.byteLength;\n throw new Error('Cannot determine upload size. Pass a File, Blob, Buffer, Uint8Array, or ArrayBuffer.');\n};\n\n/** Convert in-memory data into a value tus-js-client accepts in the current runtime. */\nconst toTusFile = async (data: UploadData): Promise<TusFile> => {\n if (!isNode()) {\n if (typeof Blob !== 'undefined' && data instanceof Blob) return data;\n const bytes = data instanceof Uint8Array ? data : new Uint8Array(data as ArrayBuffer);\n return new Blob([bytes]);\n }\n\n const { Buffer } = await import('node:buffer');\n const bytes =\n typeof Blob !== 'undefined' && data instanceof Blob\n ? new Uint8Array(await data.arrayBuffer())\n : data instanceof Uint8Array\n ? data\n : new Uint8Array(data as ArrayBuffer);\n return Buffer.isBuffer(data) ? data : Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n};\n\n/**\n * Build the checksum set, always honoring caller-supplied SHA-1/MD5 (they are\n * passed through, never recomputed). Only SHA-256 is ever computed by the SDK.\n */\nconst buildChecksums = (input: UploadSourceInput, sha256: string): Checksums => {\n const checksums: Checksums = { sha256 };\n if (input.checksumSha1) checksums.sha1 = input.checksumSha1;\n if (input.checksumMd5) checksums.md5 = input.checksumMd5;\n return checksums;\n};\n\n/**\n * Resolve an {@link UploadSourceInput} into a {@link ResolvedUploadSource},\n * computing size, content type, and the SHA-256 as needed.\n *\n * @param input - The upload source description. Exactly one of `data`, `path`,\n * or `stream` must be provided.\n * @param options - Set `hash: false` to skip SHA-256 computation (e.g. when\n * uploading to an already-authorized URL, where checksums are not needed).\n */\nexport const resolveUploadSource = async (\n input: UploadSourceInput,\n options: { hash?: boolean } = {}\n): Promise<ResolvedUploadSource> => {\n const sourceCount = [input.data !== undefined, input.path !== undefined, input.stream !== undefined].filter(\n Boolean\n ).length;\n if (sourceCount > 1) {\n throw new Error('Provide only one upload source: data, path, or stream.');\n }\n\n const hash = options.hash !== false;\n const contentType = input.contentType ?? inferContentType(input.key);\n\n if (input.data !== undefined) {\n const size = input.contentLength ?? sizeOf(input.data);\n const sha256 = input.checksumSha256 ?? (hash ? (await computeChecksums(await toBytes(input.data))).sha256 : '');\n return {\n tusFile: await toTusFile(input.data),\n size,\n contentType,\n checksums: buildChecksums(input, sha256),\n requiresFiniteChunkSize: false,\n release: noop,\n };\n }\n\n if (input.path !== undefined) {\n if (!isNode()) throw new Error('Uploading from a file path is only supported in Node.js.');\n const fs = await import('node:fs');\n const size = input.contentLength ?? fs.statSync(input.path).size;\n const sha256 = input.checksumSha256 ?? (hash ? (await hashNodeFile(input.path)).sha256 : '');\n // A fresh read stream is handed to tus for the byte upload.\n const stream = fs.createReadStream(input.path);\n return {\n tusFile: stream as unknown as NodeReadableLike,\n size,\n contentType,\n checksums: buildChecksums(input, sha256),\n requiresFiniteChunkSize: true,\n release: () => {\n // The stream opens lazily; an error from that pending open is moot once\n // the stream is discarded, so it must not surface as an uncaught error.\n stream.on('error', noop);\n stream.destroy();\n },\n };\n }\n\n if (input.stream !== undefined) {\n if (input.contentLength === undefined) {\n throw new Error('Uploading from a stream requires contentLength to be provided.');\n }\n // An empty stream has exactly one valid digest, so it need not be supplied.\n const sha256 = input.checksumSha256 ?? (input.contentLength === 0 ? EMPTY_SHA256 : undefined);\n if (hash && !sha256) {\n throw new Error('Uploading from a stream requires checksumSha256 to be provided.');\n }\n return {\n tusFile: input.stream,\n size: input.contentLength,\n contentType,\n checksums: buildChecksums(input, sha256 ?? ''),\n requiresFiniteChunkSize: true,\n release: noop,\n };\n }\n\n throw new Error('No upload source provided. Pass one of: data, path, or stream.');\n};\n","/**\n * Thin, injectable wrapper around `tus-js-client` that performs the resumable\n * byte upload. Isolated here so the upload flow can be unit-tested with a fake\n * transport (no real network I/O) and so abort/resume behaviour lives in one\n * place.\n *\n * @internal\n */\n\nimport * as tus from 'tus-js-client';\nimport { UploadError, UploadSessionExpiredError } from '../errors';\nimport type { ResolvedUploadSource, TusFile } from './source';\n\n/** Default chunk size for streamed/file-path uploads, which require a finite chunk size. */\nexport const DEFAULT_STREAM_CHUNK_SIZE = 50 * 1024 * 1024;\n\n/** A persistence backend for resumable upload fingerprints (matches tus-js-client's `UrlStorage`). */\nexport interface UploadUrlStorage {\n findAllUploads(): Promise<unknown[]>;\n findUploadsByFingerprint(fingerprint: string): Promise<unknown[]>;\n removeUpload(urlStorageKey: string): Promise<void>;\n addUpload(fingerprint: string, upload: unknown): Promise<string>;\n}\n\n/** Parameters for a single byte upload. */\nexport interface TusUploadParams {\n /** The file/data passed to tus-js-client. */\n data: TusFile;\n /** Signed upload URL (already includes the short-lived upload token). */\n uploadUrl: string;\n /** Total upload size in bytes. */\n uploadSize: number;\n /** Headers issued with the upload session. */\n headers: Record<string, string>;\n /** Maximum chunk size in bytes. Required for streamed inputs. */\n chunkSize?: number;\n /** Retry backoff in milliseconds. `null`/`[]` disables retries. */\n retryDelays?: number[] | null;\n /** Progress callback. */\n onProgress?: (bytesSent: number, bytesTotal: number) => void;\n /** Abort signal to cancel the upload. */\n signal?: AbortSignal;\n /** Persist a resumable fingerprint so the upload can resume later. */\n resume?: boolean;\n /** Custom storage for resumable fingerprints (defaults to the tus-js-client default for the runtime). */\n urlStorage?: UploadUrlStorage;\n}\n\n/** Performs a single resumable byte upload. Resolves on success, rejects on error/abort. */\nexport type UploadTransport = (params: TusUploadParams) => Promise<void>;\n\nconst DEFAULT_RETRY_DELAYS = [0, 1000, 3000, 5000];\n\n/** An `AbortError`-named error, consistent with the Fetch/DOM cancellation convention. */\nexport const createAbortError = (): Error => {\n const error = new Error('The upload was aborted.');\n error.name = 'AbortError';\n return error;\n};\n\n/** The default upload transport, backed by `tus-js-client`. */\nexport const tusUploadTransport: UploadTransport = (params) =>\n new Promise<void>((resolve, reject) => {\n if (params.signal?.aborted) {\n reject(createAbortError());\n return;\n }\n\n let settled = false;\n const cleanup = () => {\n if (params.signal) params.signal.removeEventListener('abort', onAbort);\n };\n const finish = (fn: () => void) => {\n if (settled) return;\n settled = true;\n cleanup();\n fn();\n };\n\n const headers = Object.fromEntries(\n Object.entries(params.headers).filter(([name]) => name.toLowerCase() !== 'tus-resumable')\n );\n\n const upload = new tus.Upload(params.data as tus.Upload['file'], {\n uploadUrl: params.uploadUrl,\n uploadSize: params.uploadSize,\n // tus-js-client sets Tus-Resumable itself. In browsers, forwarding the\n // session's copy makes XMLHttpRequest combine both values and produces\n // an invalid `1.0.0, 1.0.0` protocol header.\n headers,\n chunkSize: params.chunkSize ?? Infinity,\n retryDelays: params.retryDelays === undefined ? DEFAULT_RETRY_DELAYS : params.retryDelays,\n storeFingerprintForResuming: params.resume ?? false,\n removeFingerprintOnSuccess: true,\n ...(params.urlStorage ? { urlStorage: params.urlStorage as never } : {}),\n onProgress: params.onProgress ?? null,\n onError: (error) => finish(() => reject(error)),\n onSuccess: () => finish(() => resolve()),\n });\n\n const onAbort = () => {\n void upload.abort();\n finish(() => reject(createAbortError()));\n };\n // `once` ensures the listener detaches after firing, even if `finish` (and\n // thus `cleanup`) never runs because the upload hangs without settling.\n if (params.signal) params.signal.addEventListener('abort', onAbort, { once: true });\n\n upload.start();\n });\n\n/** Options shared by the high-level upload entry points. */\nexport interface RunUploadOptions {\n /** Maximum chunk size in bytes. */\n chunkSize?: number;\n /** Retry backoff in milliseconds. `null`/`[]` disables retries. */\n retryDelays?: number[] | null;\n /** Progress callback. */\n onProgress?: (bytesSent: number, bytesTotal: number) => void;\n /** Abort signal to cancel the upload. */\n signal?: AbortSignal;\n /** Persist a resumable fingerprint so the upload can resume later. */\n resume?: boolean;\n /** Custom storage for resumable fingerprints. */\n urlStorage?: UploadUrlStorage;\n}\n\n/** Run a resolved upload through the given transport, applying sensible chunk-size defaults. */\nexport const runResolvedUpload = (\n transport: UploadTransport,\n uploadUrl: string,\n resolved: ResolvedUploadSource,\n options: RunUploadOptions = {},\n headers: Record<string, string> = { 'Tus-Resumable': '1.0.0' }\n): Promise<void> =>\n transport({\n data: resolved.tusFile,\n uploadUrl,\n uploadSize: resolved.size,\n headers,\n chunkSize: options.chunkSize ?? (resolved.requiresFiniteChunkSize ? DEFAULT_STREAM_CHUNK_SIZE : undefined),\n retryDelays: options.retryDelays,\n onProgress: options.onProgress,\n signal: options.signal,\n resume: options.resume,\n urlStorage: options.urlStorage,\n });\n\nconst tusStatus = (error: unknown): number | undefined => {\n const response = (error as tus.DetailedError | undefined)?.originalResponse;\n return response ? response.getStatus() : undefined;\n};\n\n/**\n * Normalise a transport-layer error into an SDK error. Aborts are re-thrown\n * as-is; auth/expiry statuses become {@link UploadSessionExpiredError}; anything\n * else becomes a generic {@link UploadError}.\n */\nexport const toUploadError = (error: unknown): never => {\n if (error instanceof Error && error.name === 'AbortError') throw error;\n const status = tusStatus(error);\n if (status === 401 || status === 403 || status === 410) {\n throw new UploadSessionExpiredError(undefined, error);\n }\n throw new UploadError(error instanceof Error ? error.message : 'The upload failed.', error);\n};\n","import { ConfigurationError } from '../errors';\n\n/**\n * Canonical environment-scoped bucket name or a deprecated bucket UUID.\n *\n * REST callers should use the immutable bucket `name`. UUID values remain\n * accepted while existing integrations migrate. Global delivery/S3 slugs are\n * not valid REST bucket references.\n */\nexport type StorageBucketReference = string;\n\n/** Selects an application environment by slug or UUID for management calls. */\nexport interface StorageEnvironmentOptions {\n /**\n * Environment slug or UUID. Deployed workloads normally omit this because\n * their credential determines the authoritative environment.\n */\n environment?: string;\n}\n\n/** @internal */\nexport const resolveStorageApplicationId = (\n defaultApplicationId: string | undefined,\n explicitApplicationId?: string\n): string => {\n const applicationId = explicitApplicationId ?? defaultApplicationId;\n if (applicationId) return applicationId;\n\n throw new ConfigurationError(\n 'No application context is configured. Pass an application ID to this call, set GigadriveClientConfig.applicationId, or run inside a Gigadrive deployment with GIGADRIVE_APPLICATION_ID.'\n );\n};\n\n/** @internal */\nexport const resolveStorageBucketReference = (input: {\n bucket?: string;\n bucketId?: string;\n}): StorageBucketReference => {\n const hasBucket = typeof input.bucket === 'string';\n const hasBucketId = typeof input.bucketId === 'string';\n\n if (hasBucket === hasBucketId) {\n throw new ConfigurationError(\n 'Provide exactly one storage bucket reference using `bucket` or deprecated `bucketId`.'\n );\n }\n\n return hasBucket ? (input.bucket as string) : (input.bucketId as string);\n};\n\n/** @internal */\nexport const encodeStorageBucketReference = (bucketRef: StorageBucketReference): string =>\n encodeURIComponent(bucketRef);\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport {\n encodeStorageBucketReference,\n resolveStorageApplicationId,\n type StorageBucketReference,\n type StorageEnvironmentOptions,\n} from './storage-context';\n\n/** A storage bucket belonging to one application environment. */\nexport interface StorageBucket {\n /**\n * Internal bucket UUID. New REST calls should use {@link name} instead.\n * @deprecated Use the environment-scoped bucket `name` for API addressing.\n */\n id: string;\n /** The application this bucket belongs to. */\n applicationId: string;\n /** Canonical immutable API/IaC identifier, unique within {@link environmentId}. */\n name: string;\n /** Global CDN/S3 identifier. This is not the bucket reference used by REST methods. */\n slug: string;\n /** `\"public\"` buckets use stable CDN URLs; `\"private\"` buckets require signed access URLs. */\n visibility: 'public' | 'private';\n /** Hostname used to serve public objects or signed private-object URLs. */\n cdnHostname: string;\n /** The application environment this bucket is scoped to. */\n environmentId: string;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\ninterface CreateStorageBucketBase {\n /**\n * Immutable lowercase URL-safe identifier. The API accepts 3–63 ASCII\n * letters, numbers, and internal hyphens and does not normalize the value.\n */\n name: string;\n /** Bucket visibility. Defaults to `\"private\"`. */\n visibility?: 'public' | 'private';\n /**\n * Explicit global delivery/S3 slug.\n * @deprecated Omit this field and let the API generate the global slug.\n */\n slug?: string;\n}\n\n/** Input for creating an environment-scoped storage bucket. */\nexport type CreateStorageBucketInput = CreateStorageBucketBase &\n (\n | {\n /** Canonical environment slug or UUID. */\n environment: string;\n /**\n * Deprecated compatibility selector. When both fields are supplied,\n * they must resolve to the same environment.\n * @deprecated Use {@link environment}.\n */\n environmentId?: string;\n }\n | {\n environment?: undefined;\n /**\n * Application environment UUID.\n * @deprecated Use `environment` with an environment slug or UUID.\n */\n environmentId: string;\n }\n );\n\n/** Query parameters for listing storage buckets. */\nexport interface ListStorageBucketsQuery extends ListQuery, StorageEnvironmentOptions {}\n\n/**\n * Manages storage buckets for an application.\n *\n * Methods accept an application ID as their first argument for compatibility.\n * When the client has an application context, callers can omit it and address\n * buckets directly by their environment-scoped names.\n */\nexport class StorageBucketsResource extends BaseResource {\n constructor(\n httpClient: ConstructorParameters<typeof BaseResource>[0],\n private readonly defaultApplicationId?: string\n ) {\n super(httpClient);\n }\n\n /** Lists buckets, optionally restricted to an environment slug or UUID. */\n async list(query?: ListStorageBucketsQuery): Promise<Paginated<StorageBucket>>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async list(applicationId: string, query?: ListStorageBucketsQuery): Promise<Paginated<StorageBucket>>;\n async list(\n applicationIdOrQuery?: string | ListStorageBucketsQuery,\n legacyQuery?: ListStorageBucketsQuery\n ): Promise<Paginated<StorageBucket>> {\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n typeof applicationIdOrQuery === 'string' ? applicationIdOrQuery : undefined\n );\n const query = typeof applicationIdOrQuery === 'string' ? legacyQuery : applicationIdOrQuery;\n return this.httpClient.get(`/applications/${applicationId}/storage/buckets`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /** Creates a bucket with an immutable environment-scoped name. */\n async create(data: CreateStorageBucketInput): Promise<StorageBucket>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async create(applicationId: string, data: CreateStorageBucketInput): Promise<StorageBucket>;\n async create(\n applicationIdOrData: string | CreateStorageBucketInput,\n legacyData?: CreateStorageBucketInput\n ): Promise<StorageBucket> {\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n typeof applicationIdOrData === 'string' ? applicationIdOrData : undefined\n );\n const data = typeof applicationIdOrData === 'string' ? legacyData! : applicationIdOrData;\n return this.httpClient.post(`/applications/${applicationId}/storage/buckets`, data);\n }\n\n /** Gets a bucket by canonical environment-scoped name or deprecated UUID. */\n async get(bucketRef: StorageBucketReference, options?: StorageEnvironmentOptions): Promise<StorageBucket>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async get(\n applicationId: string,\n bucketRef: StorageBucketReference,\n options?: StorageEnvironmentOptions\n ): Promise<StorageBucket>;\n async get(\n applicationIdOrBucketRef: string,\n bucketRefOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<StorageBucket> {\n const explicitApplication = typeof bucketRefOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrOptions : applicationIdOrBucketRef;\n const options = explicitApplication ? legacyOptions : bucketRefOrOptions;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}`,\n {\n query: { environment: options?.environment },\n }\n );\n }\n\n /** Permanently deletes a bucket and all of its live and trashed objects. */\n async delete(bucketRef: StorageBucketReference, options?: StorageEnvironmentOptions): Promise<void>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async delete(\n applicationId: string,\n bucketRef: StorageBucketReference,\n options?: StorageEnvironmentOptions\n ): Promise<void>;\n async delete(\n applicationIdOrBucketRef: string,\n bucketRefOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<void> {\n const explicitApplication = typeof bucketRefOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrOptions : applicationIdOrBucketRef;\n const options = explicitApplication ? legacyOptions : bucketRefOrOptions;\n return this.httpClient.delete(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}`,\n { query: { environment: options?.environment } }\n );\n }\n}\n","import type { Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport {\n encodeStorageBucketReference,\n resolveStorageApplicationId,\n type StorageBucketReference,\n type StorageEnvironmentOptions,\n} from './storage-context';\n\n/** A file stored in a storage bucket. */\nexport interface StorageObject {\n /** Unique object identifier (UUID). */\n id: string;\n /** Internal UUID of the bucket containing this object. */\n bucketId: string;\n /** The application this object belongs to. */\n applicationId: string;\n /** The upload session that created this object, or `null` for imported objects. */\n uploadSessionId: string | null;\n /** The object key within the bucket, such as `\"images/photo.jpg\"`. */\n key: string;\n /** MIME content type, or `null` when none was recorded. */\n contentType: string | null;\n /** File size in bytes. */\n contentLength: number;\n /** SHA-1 checksum, if available. */\n checksumSha1: string | null;\n /** SHA-256 checksum, if available. */\n checksumSha256: string | null;\n /** MD5 checksum, if available. */\n checksumMd5: string | null;\n /** ISO 8601 timestamp of upload finalization. */\n uploadedAt: string;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Access URL details for a public or private storage object. */\nexport interface StorageObjectAccess {\n /** `\"public\"` for stable CDN URLs or `\"signed\"` for expiring URLs. */\n accessType: 'public' | 'signed';\n /** URL used to read the object. */\n url: string;\n /** ISO 8601 expiry for signed URLs, or `null` for public URLs. */\n expiresAt: string | null;\n}\n\n/** Query parameters for listing objects in a bucket. */\nexport interface ListStorageObjectsQuery extends StorageEnvironmentOptions {\n /** Only return objects whose key starts with this prefix. */\n prefix?: string;\n /** Group keys by this delimiter into virtual folders. Defaults to `\"/\"`. */\n delimiter?: string;\n /** Opaque cursor from a previous response. */\n cursor?: string;\n /** Maximum objects to return, from 1 through 1000. */\n limit?: number;\n}\n\n/** Options for creating an object access URL. */\nexport interface StorageObjectAccessOptions extends StorageEnvironmentOptions {\n /** Signed URL lifetime in seconds, from 60 through 86,400. */\n expiresInSeconds?: number;\n}\n\n/** A page of storage objects, including any common virtual-folder prefixes. */\nexport interface StorageObjectList extends Paginated<StorageObject> {\n commonPrefixes: string[];\n}\n\n/**\n * Reads and soft-deletes objects and creates access URLs.\n *\n * The context-bound overloads use the application configured on the client.\n * Explicit application overloads remain available for management tools and\n * compatibility. Bucket references should be canonical names; UUIDs remain a\n * deprecated server-side fallback.\n */\nexport class StorageObjectsResource extends BaseResource {\n constructor(\n httpClient: ConstructorParameters<typeof BaseResource>[0],\n private readonly defaultApplicationId?: string\n ) {\n super(httpClient);\n }\n\n /** Lists objects in a bucket. */\n async list(bucketRef: StorageBucketReference, query?: ListStorageObjectsQuery): Promise<StorageObjectList>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async list(\n applicationId: string,\n bucketRef: StorageBucketReference,\n query?: ListStorageObjectsQuery\n ): Promise<StorageObjectList>;\n async list(\n applicationIdOrBucketRef: string,\n bucketRefOrQuery?: string | ListStorageObjectsQuery,\n legacyQuery?: ListStorageObjectsQuery\n ): Promise<StorageObjectList> {\n const explicitApplication = typeof bucketRefOrQuery === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrQuery : applicationIdOrBucketRef;\n const query = explicitApplication ? legacyQuery : bucketRefOrQuery;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/objects`,\n {\n query: query as Record<string, string | number | undefined> | undefined,\n }\n );\n }\n\n /** Gets object metadata by object UUID. */\n async get(\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async get(\n applicationId: string,\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject>;\n async get(\n applicationIdOrBucketRef: string,\n bucketRefOrObjectId: string,\n objectIdOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<StorageObject> {\n const explicitApplication = typeof objectIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrObjectId : applicationIdOrBucketRef;\n const objectId = explicitApplication ? objectIdOrOptions : bucketRefOrObjectId;\n const options = explicitApplication ? legacyOptions : objectIdOrOptions;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/objects/${objectId}`,\n { query: { environment: options?.environment } }\n );\n }\n\n /**\n * Resolves an object by exact key by paging a prefix listing.\n *\n * The API has no get-by-key endpoint. This helper preserves the same\n * application, bucket, and environment across every page.\n */\n async getByKey(\n bucketRef: StorageBucketReference,\n key: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject | null>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async getByKey(\n applicationId: string,\n bucketRef: StorageBucketReference,\n key: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject | null>;\n async getByKey(\n applicationIdOrBucketRef: string,\n bucketRefOrKey: string,\n keyOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<StorageObject | null> {\n const explicitApplication = typeof keyOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrKey : applicationIdOrBucketRef;\n const key = explicitApplication ? keyOrOptions : bucketRefOrKey;\n const options = explicitApplication ? legacyOptions : keyOrOptions;\n\n let cursor: string | undefined;\n do {\n const page = await this.list(applicationId, bucketRef, {\n environment: options?.environment,\n prefix: key,\n cursor,\n });\n const match = page.items.find((object) => object.key === key);\n if (match) return match;\n cursor = page.nextCursor;\n } while (cursor);\n return null;\n }\n\n /** Moves a live object into the bucket trash. */\n async delete(bucketRef: StorageBucketReference, objectId: string, options?: StorageEnvironmentOptions): Promise<void>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async delete(\n applicationId: string,\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<void>;\n async delete(\n applicationIdOrBucketRef: string,\n bucketRefOrObjectId: string,\n objectIdOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<void> {\n const explicitApplication = typeof objectIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrObjectId : applicationIdOrBucketRef;\n const objectId = explicitApplication ? objectIdOrOptions : bucketRefOrObjectId;\n const options = explicitApplication ? legacyOptions : objectIdOrOptions;\n return this.httpClient.delete(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/objects/${objectId}`,\n { query: { environment: options?.environment } }\n );\n }\n\n /** Creates a stable public or time-limited signed object URL. */\n async getAccessUrl(\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageObjectAccessOptions\n ): Promise<StorageObjectAccess>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async getAccessUrl(\n applicationId: string,\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageObjectAccessOptions\n ): Promise<StorageObjectAccess>;\n async getAccessUrl(\n applicationIdOrBucketRef: string,\n bucketRefOrObjectId: string,\n objectIdOrOptions?: string | StorageObjectAccessOptions,\n legacyOptions?: StorageObjectAccessOptions\n ): Promise<StorageObjectAccess> {\n const explicitApplication = typeof objectIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrObjectId : applicationIdOrBucketRef;\n const objectId = explicitApplication ? objectIdOrOptions : bucketRefOrObjectId;\n const options = explicitApplication ? legacyOptions : objectIdOrOptions;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/objects/${objectId}/access-url`,\n { query: { environment: options?.environment, expiresInSeconds: options?.expiresInSeconds } }\n );\n }\n}\n","import type { Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport {\n encodeStorageBucketReference,\n resolveStorageApplicationId,\n type StorageBucketReference,\n type StorageEnvironmentOptions,\n} from './storage-context';\nimport type { StorageObject } from './storage-objects';\n\n/** A soft-deleted storage object returned by a bucket trash listing. */\nexport interface TrashedStorageObject extends StorageObject {\n /** ISO 8601 timestamp when the object was moved to trash. */\n deletedAt: string;\n}\n\n/** Query parameters for listing a bucket's trashed objects. */\nexport interface ListStorageTrashQuery extends StorageEnvironmentOptions {\n /** Only return trashed objects whose keys start with this prefix. */\n prefix?: string;\n /** Opaque cursor returned by a previous trash listing. */\n cursor?: string;\n /** Maximum objects to return, from 1 through 1000. */\n limit?: number;\n}\n\n/** A page of soft-deleted objects. */\nexport type StorageTrashList = Paginated<TrashedStorageObject>;\n\n/** Result returned after permanently deleting every object in a bucket's trash. */\nexport interface EmptyStorageTrashResult {\n /** Number of trashed objects permanently deleted. */\n purgedCount: number;\n}\n\n/**\n * Manages the lifecycle of soft-deleted storage objects.\n *\n * Restoring can fail with HTTP 409 when a live object already uses the same\n * key. Purge and empty operations are irreversible.\n */\nexport class StorageTrashResource extends BaseResource {\n constructor(\n httpClient: ConstructorParameters<typeof BaseResource>[0],\n private readonly defaultApplicationId?: string\n ) {\n super(httpClient);\n }\n\n /** Lists soft-deleted objects in a bucket. */\n async list(bucketRef: StorageBucketReference, query?: ListStorageTrashQuery): Promise<StorageTrashList>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async list(\n applicationId: string,\n bucketRef: StorageBucketReference,\n query?: ListStorageTrashQuery\n ): Promise<StorageTrashList>;\n async list(\n applicationIdOrBucketRef: string,\n bucketRefOrQuery?: string | ListStorageTrashQuery,\n legacyQuery?: ListStorageTrashQuery\n ): Promise<StorageTrashList> {\n const explicitApplication = typeof bucketRefOrQuery === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrQuery : applicationIdOrBucketRef;\n const query = explicitApplication ? legacyQuery : bucketRefOrQuery;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/trash`,\n { query: query as Record<string, string | number | undefined> | undefined }\n );\n }\n\n /** Restores a soft-deleted object to its original key. */\n async restore(\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async restore(\n applicationId: string,\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageObject>;\n async restore(\n applicationIdOrBucketRef: string,\n bucketRefOrObjectId: string,\n objectIdOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<StorageObject> {\n const explicitApplication = typeof objectIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrObjectId : applicationIdOrBucketRef;\n const objectId = explicitApplication ? objectIdOrOptions : bucketRefOrObjectId;\n const options = explicitApplication ? legacyOptions : objectIdOrOptions;\n return this.httpClient.post(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/trash/${objectId}/restore`,\n undefined,\n { query: { environment: options?.environment } }\n );\n }\n\n /** Permanently deletes one object from bucket trash. */\n async purge(bucketRef: StorageBucketReference, objectId: string, options?: StorageEnvironmentOptions): Promise<void>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async purge(\n applicationId: string,\n bucketRef: StorageBucketReference,\n objectId: string,\n options?: StorageEnvironmentOptions\n ): Promise<void>;\n async purge(\n applicationIdOrBucketRef: string,\n bucketRefOrObjectId: string,\n objectIdOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<void> {\n const explicitApplication = typeof objectIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrObjectId : applicationIdOrBucketRef;\n const objectId = explicitApplication ? objectIdOrOptions : bucketRefOrObjectId;\n const options = explicitApplication ? legacyOptions : objectIdOrOptions;\n return this.httpClient.delete(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/trash/${objectId}`,\n { query: { environment: options?.environment } }\n );\n }\n\n /** Permanently deletes every object in a bucket's trash. */\n async empty(bucketRef: StorageBucketReference, options?: StorageEnvironmentOptions): Promise<EmptyStorageTrashResult>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async empty(\n applicationId: string,\n bucketRef: StorageBucketReference,\n options?: StorageEnvironmentOptions\n ): Promise<EmptyStorageTrashResult>;\n async empty(\n applicationIdOrBucketRef: string,\n bucketRefOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<EmptyStorageTrashResult> {\n const explicitApplication = typeof bucketRefOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrOptions : applicationIdOrBucketRef;\n const options = explicitApplication ? legacyOptions : bucketRefOrOptions;\n return this.httpClient.delete(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/trash`,\n { query: { environment: options?.environment } }\n );\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { resolveUploadSource, type NodeReadableLike, type UploadData } from '../upload/source';\nimport {\n runResolvedUpload,\n toUploadError,\n tusUploadTransport,\n type RunUploadOptions,\n type UploadTransport,\n} from '../upload/transport';\nimport { BaseResource } from './base-resource';\nimport {\n encodeStorageBucketReference,\n resolveStorageApplicationId,\n type StorageBucketReference,\n type StorageEnvironmentOptions,\n} from './storage-context';\nimport type { StorageObject } from './storage-objects';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Represents an upload session for a storage object. Upload sessions track the\n * lifecycle of a file upload from creation through completion.\n */\nexport interface StorageUploadSession {\n /** Unique identifier (UUID). */\n id: string;\n /** The bucket this upload targets. */\n bucketId: string;\n /** The application this upload belongs to. */\n applicationId: string;\n /** The object key/path the file will be stored at (e.g. `\"images/photo.jpg\"`). */\n key: string;\n /** MIME content type declared at creation, or `null` if not specified. */\n contentType: string | null;\n /** Expected file size in bytes declared at creation, or `null`. */\n contentLength: number | null;\n /** SHA-1 checksum for server-side verification, if provided. */\n checksumSha1: string | null;\n /** SHA-256 checksum for server-side verification, if provided. */\n checksumSha256: string | null;\n /** MD5 checksum for server-side verification, if provided. */\n checksumMd5: string | null;\n /**\n * Current session state:\n * - `\"pending\"` — Session created, awaiting the first bytes.\n * - `\"ready\"` — Receiving file data.\n * - `\"completed\"` — Upload verified and storage object created.\n * - `\"failed\"` — Upload failed or was rejected.\n * - `\"expired\"` — Session exceeded its expiration time.\n */\n state: 'pending' | 'ready' | 'completed' | 'failed' | 'expired';\n /** ISO 8601 timestamp when this session (and its upload URL) expires. */\n expiresAt: string;\n /** ISO 8601 timestamp when the upload was finalized, or `null`. */\n uploadedAt: string | null;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Input for creating a new upload session. */\nexport interface CreateUploadSessionInput {\n /** The object key/path the file will be stored at (e.g. `\"images/photo.jpg\"`). 1–1024 characters. */\n key: string;\n /**\n * File size in bytes: an integer, `0` or greater. `0` stores an empty object\n * during the create call (see {@link CreateUploadSessionResponse}).\n */\n contentLength: number;\n /**\n * Lowercase hex SHA-256 checksum (64 chars) of the content. Required for\n * server-side verification. For an empty file this must be the digest of\n * empty input, `e3b0c442…b855`.\n */\n checksumSha256: string;\n /** MIME content type of the file (e.g. `\"image/jpeg\"`). */\n contentType?: string;\n /** Optional lowercase hex SHA-1 checksum (40 chars). */\n checksumSha1?: string;\n /** Optional lowercase hex MD5 checksum (32 chars). */\n checksumMd5?: string;\n}\n\n/** Query parameters for listing upload sessions in a bucket. */\nexport interface ListStorageUploadSessionsQuery extends ListQuery, StorageEnvironmentOptions {}\n\n/**\n * Response from creating an upload session. Contains the session metadata and\n * either the resumable upload instructions (signed URL + headers) or, for an\n * empty file, the object the API already stored.\n *\n * | Field | `contentLength` 0 | `contentLength` > 0 |\n * | --------- | ------------------------------------------ | ------------------------------- |\n * | `session` | `state: \"completed\"`, `uploadedAt` set | `state: \"ready\"` |\n * | `upload` | `null` | Signed URL, method and headers |\n * | `object` | The stored object | `null` |\n */\nexport interface CreateUploadSessionResponse {\n /** The created upload session. */\n session: StorageUploadSession;\n /**\n * Resumable upload instructions — use these to send the file data. `null`\n * when `contentLength` was 0: the empty object already exists and there is\n * nothing to send.\n */\n upload: {\n /** The HTTP method for the byte upload (resumable upload protocol). */\n method: 'PATCH';\n /** Signed upload URL. Send your file data here. */\n url: string;\n /** Required headers to include with the upload request. */\n headers: Record<string, string>;\n /** The URL where the object will be accessible after upload (CDN URL for public buckets). */\n publicObjectUrl: string;\n } | null;\n /**\n * The stored object when the upload finished during the create call, which\n * happens only for an empty file. `null` while bytes are still expected.\n */\n object: StorageObject | null;\n /**\n * Canonical object URL for the key, returned for every size (the same value\n * as `upload.publicObjectUrl` when an upload instruction is returned). Older\n * API deployments omit it.\n */\n publicObjectUrl?: string;\n}\n\n/** A byte source for uploading directly to a known signed URL. */\nexport interface UploadByteSource {\n /** In-memory data (`File`/`Blob`/`Buffer`/`Uint8Array`/`ArrayBuffer`). */\n data?: UploadData;\n /** A filesystem path to stream from (Node.js only). */\n path?: string;\n /** A readable stream (Node.js only). Requires `contentLength`. */\n stream?: NodeReadableLike;\n /** Byte size — required for `stream` inputs, computed otherwise. */\n contentLength?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Resource\n// ---------------------------------------------------------------------------\n\n/**\n * Manage upload sessions and upload bytes to a signed upload URL using the\n * resumable upload protocol. Accessed via `client.storage.uploadSessions`.\n *\n * For most use cases, prefer the high-level `client.storage.upload()`\n * which creates the session, computes the required checksum, uploads the bytes,\n * and returns the public URL.\n */\nexport class StorageUploadSessionsResource extends BaseResource {\n constructor(\n httpClient: ConstructorParameters<typeof BaseResource>[0],\n private readonly transport: UploadTransport = tusUploadTransport,\n private readonly defaultApplicationId?: string\n ) {\n super(httpClient);\n }\n\n /**\n * List upload sessions for a bucket.\n *\n * @param bucketRef - Canonical bucket name or deprecated UUID fallback.\n * @param query - Optional pagination parameters.\n * @returns A paginated list of upload sessions.\n */\n async list(\n bucketRef: StorageBucketReference,\n query?: ListStorageUploadSessionsQuery\n ): Promise<Paginated<StorageUploadSession>>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async list(\n applicationId: string,\n bucketRef: StorageBucketReference,\n query?: ListStorageUploadSessionsQuery\n ): Promise<Paginated<StorageUploadSession>>;\n async list(\n applicationIdOrBucketRef: string,\n bucketRefOrQuery?: string | ListStorageUploadSessionsQuery,\n legacyQuery?: ListStorageUploadSessionsQuery\n ): Promise<Paginated<StorageUploadSession>> {\n const explicitApplication = typeof bucketRefOrQuery === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrQuery : applicationIdOrBucketRef;\n const query = explicitApplication ? legacyQuery : bucketRefOrQuery;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/uploads`,\n { query: query as Record<string, string | number | undefined> | undefined }\n );\n }\n\n /**\n * Create an upload session. Returns the session metadata and a signed upload\n * URL for sending file data. This is the low-level method — for most use\n * cases prefer `client.storage.upload()` which also computes the\n * required SHA-256 checksum for you.\n *\n * @param bucketRef - Canonical bucket name or deprecated UUID fallback.\n * @param data - Object key, content length, SHA-256 checksum, and optional content type / extra checksums.\n * @returns The session and resumable upload instructions (URL, method, headers).\n * For `contentLength: 0` the session is already `completed`, `upload` is\n * `null` and `object` holds the stored empty object.\n */\n async create(\n bucketRef: StorageBucketReference,\n data: CreateUploadSessionInput,\n options?: StorageEnvironmentOptions\n ): Promise<CreateUploadSessionResponse>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async create(\n applicationId: string,\n bucketRef: StorageBucketReference,\n data: CreateUploadSessionInput,\n options?: StorageEnvironmentOptions\n ): Promise<CreateUploadSessionResponse>;\n async create(\n applicationIdOrBucketRef: string,\n bucketRefOrData: string | CreateUploadSessionInput,\n dataOrOptions?: CreateUploadSessionInput | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<CreateUploadSessionResponse> {\n const explicitApplication = typeof bucketRefOrData === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrData : applicationIdOrBucketRef;\n const data = explicitApplication ? (dataOrOptions as CreateUploadSessionInput) : bucketRefOrData;\n const options = explicitApplication ? legacyOptions : (dataOrOptions as StorageEnvironmentOptions | undefined);\n return this.httpClient.post(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/uploads`,\n data,\n { query: { environment: options?.environment } }\n );\n }\n\n /**\n * Get an upload session by ID. Use this to track server-side processing after\n * an upload (poll until `state === 'completed'`).\n *\n * @param bucketRef - Canonical bucket name or deprecated UUID fallback.\n * @param sessionId - The upload session ID (UUID).\n * @returns The current session state.\n */\n async get(\n bucketRef: StorageBucketReference,\n sessionId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageUploadSession>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async get(\n applicationId: string,\n bucketRef: StorageBucketReference,\n sessionId: string,\n options?: StorageEnvironmentOptions\n ): Promise<StorageUploadSession>;\n async get(\n applicationIdOrBucketRef: string,\n bucketRefOrSessionId: string,\n sessionIdOrOptions?: string | StorageEnvironmentOptions,\n legacyOptions?: StorageEnvironmentOptions\n ): Promise<StorageUploadSession> {\n const explicitApplication = typeof sessionIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrSessionId : applicationIdOrBucketRef;\n const sessionId = explicitApplication ? sessionIdOrOptions : bucketRefOrSessionId;\n const options = explicitApplication ? legacyOptions : sessionIdOrOptions;\n return this.httpClient.get(\n `/applications/${applicationId}/storage/buckets/${encodeStorageBucketReference(bucketRef)}/uploads/${sessionId}`,\n { query: { environment: options?.environment } }\n );\n }\n\n /**\n * Upload bytes directly to a pre-existing signed upload URL — for example, a\n * URL returned by {@link create} or handed to your client by a backend. Skips\n * session creation and checksum computation.\n *\n * @param url - A signed upload URL.\n * @param source - The bytes to upload.\n * @param options - Chunk size, retry config, progress, abort signal, resume,\n * and any required `headers` returned with the upload session.\n * @throws {@link UploadError} if the upload fails after all retries.\n */\n async uploadToUrl(\n url: string,\n source: UploadByteSource,\n options?: RunUploadOptions & { headers?: Record<string, string> }\n ): Promise<void> {\n const resolved = await resolveUploadSource({ key: '', ...source }, { hash: false });\n const headers = { 'Tus-Resumable': '1.0.0', ...options?.headers };\n await runResolvedUpload(this.transport, url, resolved, options, headers)\n .catch(toUploadError)\n // Closes a file-path stream a failed or aborted transfer left open.\n .finally(resolved.release);\n }\n\n /**\n * Resume an interrupted upload to a previously issued signed upload URL. The\n * resumable protocol negotiates the current offset and continues from there.\n *\n * @param url - The signed upload URL from the original {@link create} call.\n * @param source - The full bytes to upload (the same content as the original).\n * @param options - Chunk size, retry config, progress, abort signal.\n */\n async resumeFromUrl(\n url: string,\n source: UploadByteSource,\n options?: RunUploadOptions & { headers?: Record<string, string> }\n ): Promise<void> {\n return this.uploadToUrl(url, source, { ...options, resume: true });\n }\n}\n","import { UploadError } from '../errors';\nimport type { HttpClient } from '../http-client';\nimport { resolveUploadSource, type NodeReadableLike, type UploadData } from '../upload/source';\nimport {\n createAbortError,\n runResolvedUpload,\n toUploadError,\n tusUploadTransport,\n type UploadTransport,\n type UploadUrlStorage,\n} from '../upload/transport';\nimport { StorageBucketsResource } from './storage-buckets';\nimport {\n resolveStorageApplicationId,\n resolveStorageBucketReference,\n type StorageBucketReference,\n type StorageEnvironmentOptions,\n} from './storage-context';\nimport { StorageObjectsResource, type StorageObject } from './storage-objects';\nimport { StorageTrashResource } from './storage-trash';\nimport {\n StorageUploadSessionsResource,\n type CreateUploadSessionResponse,\n type StorageUploadSession,\n} from './storage-upload-sessions';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Options controlling whether and how to wait for an upload to finalize server-side. */\nexport interface WaitForCompletionOptions extends StorageEnvironmentOptions {\n /** Maximum time to wait in milliseconds. Default: 60000. */\n timeoutMs?: number;\n /** How often to poll the session state, in milliseconds. Default: 1000. */\n pollIntervalMs?: number;\n}\n\ninterface UploadFileOptions {\n /**\n * Explicit application UUID. Omit this when the client was configured with\n * `applicationId` or is running with `GIGADRIVE_APPLICATION_ID`.\n * @deprecated Configure `GigadriveClientConfig.applicationId` or use workload context.\n */\n applicationId?: string;\n /**\n * Environment slug or UUID. Workloads normally omit this because the API\n * infers and enforces the deployment environment from their credential. If\n * completion options also specify an environment, this top-level value takes\n * precedence for the entire upload lifecycle.\n */\n environment?: string;\n /** The object key/path in the bucket (e.g. `\"images/logo.png\"`). */\n key: string;\n /** In-memory data (browser `File`/`Blob`, Node `Buffer`, `Uint8Array`, `ArrayBuffer`). */\n data?: UploadData;\n /** A filesystem path to upload from (Node.js only). Size, checksum, and content type are derived automatically. */\n path?: string;\n /** A readable stream to upload from (Node.js only). Requires `contentLength` and `checksumSha256`. */\n stream?: NodeReadableLike;\n /** MIME content type. Inferred from `key` when omitted. */\n contentType?: string;\n /** Byte size. Required for `stream`; computed otherwise. */\n contentLength?: number;\n /** Pre-computed SHA-256 (skips hashing). Required for `stream`. */\n checksumSha256?: string;\n /** Also send a SHA-1 checksum. */\n checksumSha1?: string;\n /** Also send an MD5 checksum (Node.js only unless provided). */\n checksumMd5?: string;\n /** Maximum chunk size in bytes (for very large files / streams). */\n chunkSize?: number;\n /** Retry backoff in milliseconds; `null`/`[]` disables retries. */\n retryDelays?: number[] | null;\n /** Progress callback invoked during the byte upload. */\n onProgress?: (bytesSent: number, bytesTotal: number) => void;\n /** Abort signal to cancel the upload. */\n signal?: AbortSignal;\n /** Persist a resumable fingerprint so the upload can be resumed later. */\n resume?: boolean;\n /** Custom storage backend for resumable fingerprints. */\n urlStorage?: UploadUrlStorage;\n /** Wait until the object is finalized server-side before resolving. Pass options to tune polling. */\n waitForCompletion?: boolean | WaitForCompletionOptions;\n}\n\n/** Input for the high-level {@link ApplicationStorageResource.upload | upload()} method. */\nexport type UploadFileInput = UploadFileOptions &\n (\n | {\n /** Canonical environment-scoped bucket name, or a deprecated UUID fallback. */\n bucket: StorageBucketReference;\n bucketId?: never;\n }\n | {\n bucket?: never;\n /**\n * Internal bucket UUID.\n * @deprecated Use `bucket` with the canonical environment-scoped name.\n */\n bucketId: string;\n }\n );\n\n/** Result of a successful upload. */\nexport interface UploadFileResult {\n /** The upload session. When `waitForCompletion` was set, `state` is `\"completed\"`. */\n session: StorageUploadSession;\n /** The public/CDN URL of the uploaded object. */\n url: string;\n /**\n * The finalized storage object — present when `waitForCompletion` was set,\n * and always for an empty file, which the API stores during session creation.\n */\n object?: StorageObject;\n}\n\n/** Options for {@link ApplicationStorageResource.uploadBatch | uploadBatch()}. */\nexport interface UploadBatchOptions {\n /** Maximum number of concurrent uploads. Default: 4. */\n concurrency?: number;\n /** Called after each file settles, with the number completed and the total. */\n onProgress?: (completed: number, total: number) => void;\n}\n\n/** The outcome of one file within a batch upload. Errors are isolated per file. */\nexport interface UploadBatchItemResult {\n /** The input that produced this result. */\n input: UploadFileInput;\n /** The successful result, if the upload succeeded. */\n result?: UploadFileResult;\n /** The error, if this upload failed. */\n error?: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Resource\n// ---------------------------------------------------------------------------\n\nconst delay = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Build the public CDN URL for an object key, matching the `publicObjectUrl`\n * the API issues: each path segment is URL-encoded and `/` separators are kept.\n */\nconst buildStorageObjectUrl = (cdnHostname: string, key: string): string =>\n `https://${cdnHostname}/${encodeURIComponent(key).replace(/%2F/g, '/')}`;\n\n/**\n * Namespace for all storage operations on an application: bucket management,\n * object listing/access, low-level upload sessions, and the high-level\n * {@link upload} / {@link uploadBatch} helpers.\n *\n * Accessed canonically via `client.storage`. `client.applications.storage`\n * references the same resource for compatibility.\n *\n * @example\n * ```ts\n * // High-level upload (Node.js, from a path — checksum/size/content-type inferred)\n * const { url } = await client.storage.upload({\n * bucket: 'photos',\n * key: 'photos/cat.jpg',\n * path: './cat.jpg',\n * });\n *\n * // Browser upload from a file input, with progress and abort\n * const controller = new AbortController();\n * const { url } = await client.storage.upload({\n * bucket: 'uploads',\n * key: `uploads/${file.name}`,\n * data: file,\n * onProgress: (sent, total) => console.log(`${Math.round((sent / total) * 100)}%`),\n * signal: controller.signal,\n * });\n * ```\n */\nexport class ApplicationStorageResource {\n /** Create, list, get, and delete storage buckets. */\n readonly buckets: StorageBucketsResource;\n /** List, get, delete objects, and generate access URLs. */\n readonly objects: StorageObjectsResource;\n /** Low-level upload sessions and direct-to-URL byte uploads. */\n readonly uploadSessions: StorageUploadSessionsResource;\n /** Lists, restores, and permanently purges soft-deleted objects. */\n readonly trash: StorageTrashResource;\n\n private readonly transport: UploadTransport;\n\n constructor(\n httpClient: HttpClient,\n transport: UploadTransport = tusUploadTransport,\n private readonly defaultApplicationId?: string\n ) {\n this.transport = transport;\n this.buckets = new StorageBucketsResource(httpClient, defaultApplicationId);\n this.objects = new StorageObjectsResource(httpClient, defaultApplicationId);\n this.uploadSessions = new StorageUploadSessionsResource(httpClient, transport, defaultApplicationId);\n this.trash = new StorageTrashResource(httpClient, defaultApplicationId);\n }\n\n /**\n * Upload a file to a storage bucket. Handles the full flow: computes the\n * required SHA-256 checksum, creates an upload session, uploads the bytes with\n * automatic retries (and optional progress/abort/resume), and returns the\n * public URL.\n *\n * Accepts browser `File`/`Blob`, Node `Buffer`/`Uint8Array`/`ArrayBuffer`, a\n * Node filesystem `path`, or a Node readable `stream` (with `contentLength`\n * and `checksumSha256`). The content type is inferred from `key` when omitted.\n *\n * Empty (zero-byte) files are supported for every input kind. The API stores\n * them during session creation, so no bytes are transferred, `onProgress` is\n * not called, `waitForCompletion` does not poll, and `object` is always set.\n *\n * @param input - What and where to upload, plus optional transfer options.\n * @returns The upload session and public object URL (and the finalized object when `waitForCompletion` is set).\n * @throws {@link UploadError} if the byte upload fails.\n * @throws {@link UploadSessionExpiredError} if the session expires mid-upload.\n *\n * @example\n * ```ts\n * const { session, url, object } = await client.storage.upload({\n * bucket: 'reports', key: 'q1.pdf', path: './q1.pdf',\n * waitForCompletion: true,\n * });\n * console.log(object?.contentLength, 'bytes available at', url);\n * ```\n */\n async upload(input: UploadFileInput): Promise<UploadFileResult> {\n const applicationId = resolveStorageApplicationId(this.defaultApplicationId, input.applicationId);\n const bucketRef = resolveStorageBucketReference(input);\n const completionOptions = typeof input.waitForCompletion === 'object' ? input.waitForCompletion : undefined;\n const environment = input.environment ?? completionOptions?.environment;\n const resolved = await resolveUploadSource({\n key: input.key,\n data: input.data,\n path: input.path,\n stream: input.stream,\n contentType: input.contentType,\n contentLength: input.contentLength,\n checksumSha256: input.checksumSha256,\n checksumSha1: input.checksumSha1,\n checksumMd5: input.checksumMd5,\n });\n\n // Checked before the create call: for an empty file that call alone stores\n // the object, so an already-aborted upload must not reach it.\n if (input.signal?.aborted) {\n resolved.release();\n throw createAbortError();\n }\n\n let created: CreateUploadSessionResponse;\n try {\n created = await this.uploadSessions.create(\n applicationId,\n bucketRef,\n {\n key: input.key,\n contentLength: resolved.size,\n checksumSha256: resolved.checksums.sha256,\n contentType: resolved.contentType,\n checksumSha1: resolved.checksums.sha1,\n checksumMd5: resolved.checksums.md5,\n },\n { environment }\n );\n } catch (error) {\n resolved.release();\n throw error;\n }\n const { session, upload } = created;\n\n // An empty file is stored during session creation: the session is already\n // completed, so there are no bytes to send and nothing to poll.\n if (upload === null) {\n resolved.release();\n const object = created.object;\n if (!object) {\n throw new UploadError('The upload session completed without returning the stored object.');\n }\n // API deployments that predate the top-level `publicObjectUrl` need the\n // bucket's CDN hostname to build the same URL.\n const url =\n created.publicObjectUrl ??\n buildStorageObjectUrl(\n (await this.buckets.get(applicationId, bucketRef, { environment })).cdnHostname,\n object.key\n );\n return { session, url, object };\n }\n\n await runResolvedUpload(\n this.transport,\n upload.url,\n resolved,\n {\n chunkSize: input.chunkSize,\n retryDelays: input.retryDelays,\n onProgress: input.onProgress,\n signal: input.signal,\n resume: input.resume,\n urlStorage: input.urlStorage,\n },\n // Forward any required headers the API issued with the session.\n { 'Tus-Resumable': '1.0.0', ...upload.headers }\n )\n .catch(toUploadError)\n // Closes a file-path stream a failed or aborted transfer left open.\n .finally(resolved.release);\n\n if (input.waitForCompletion) {\n const options = completionOptions ?? {};\n const completed = await this.waitForCompletion(applicationId, bucketRef, session.id, {\n ...options,\n environment,\n });\n const object = (await this.objects.getByKey(applicationId, bucketRef, input.key, { environment })) ?? undefined;\n return { session: completed, url: upload.publicObjectUrl, object };\n }\n\n return { session, url: upload.publicObjectUrl };\n }\n\n /**\n * Upload many files concurrently. Each file is uploaded independently; a\n * failure for one file does not abort the others — inspect each item's\n * `error`/`result`.\n *\n * @param inputs - The files to upload.\n * @param options - Concurrency limit and an aggregated progress callback.\n * @returns One result per input, in the same order.\n *\n * @example\n * ```ts\n * const results = await client.storage.uploadBatch(\n * files.map((f) => ({ bucket: 'uploads', key: f.name, data: f })),\n * { concurrency: 6, onProgress: (done, total) => console.log(`${done}/${total}`) },\n * );\n * const failed = results.filter((r) => r.error);\n * ```\n */\n async uploadBatch(inputs: UploadFileInput[], options?: UploadBatchOptions): Promise<UploadBatchItemResult[]> {\n const concurrency = Math.max(1, options?.concurrency ?? 4);\n const results: UploadBatchItemResult[] = new Array(inputs.length);\n let completed = 0;\n let next = 0;\n\n const worker = async (): Promise<void> => {\n for (;;) {\n const index = next++;\n if (index >= inputs.length) return;\n try {\n results[index] = { input: inputs[index], result: await this.upload(inputs[index]) };\n } catch (error) {\n results[index] = { input: inputs[index], error };\n }\n completed++;\n options?.onProgress?.(completed, inputs.length);\n }\n };\n\n await Promise.all(Array.from({ length: Math.min(concurrency, inputs.length) }, () => worker()));\n return results;\n }\n\n /**\n * Poll an upload session until the object is finalized server-side.\n *\n * @param bucketRef - Canonical bucket name or deprecated UUID fallback.\n * @param sessionId - The upload session ID (UUID).\n * @param options - Timeout and polling interval.\n * @returns The completed session.\n * @throws {@link UploadError} if the session fails, expires, or the timeout elapses.\n */\n async waitForCompletion(\n bucketRef: StorageBucketReference,\n sessionId: string,\n options?: WaitForCompletionOptions\n ): Promise<StorageUploadSession>;\n /** @deprecated Prefer the context-bound overload through `client.storage`. */\n async waitForCompletion(\n applicationId: string,\n bucketRef: StorageBucketReference,\n sessionId: string,\n options?: WaitForCompletionOptions\n ): Promise<StorageUploadSession>;\n async waitForCompletion(\n applicationIdOrBucketRef: string,\n bucketRefOrSessionId: string,\n sessionIdOrOptions?: string | WaitForCompletionOptions,\n legacyOptions?: WaitForCompletionOptions\n ): Promise<StorageUploadSession> {\n const explicitApplication = typeof sessionIdOrOptions === 'string';\n const applicationId = resolveStorageApplicationId(\n this.defaultApplicationId,\n explicitApplication ? applicationIdOrBucketRef : undefined\n );\n const bucketRef = explicitApplication ? bucketRefOrSessionId : applicationIdOrBucketRef;\n const sessionId = explicitApplication ? sessionIdOrOptions : bucketRefOrSessionId;\n const options = explicitApplication ? legacyOptions : sessionIdOrOptions;\n const timeoutMs = options?.timeoutMs ?? 60_000;\n const pollIntervalMs = options?.pollIntervalMs ?? 1000;\n const deadline = Date.now() + timeoutMs;\n\n for (;;) {\n const session = await this.uploadSessions.get(applicationId, bucketRef, sessionId, {\n environment: options?.environment,\n });\n if (session.state === 'completed') return session;\n if (session.state === 'failed' || session.state === 'expired') {\n throw new UploadError(`Upload session ${session.state}.`);\n }\n if (Date.now() >= deadline) {\n throw new UploadError('Timed out waiting for the upload to complete.');\n }\n await delay(pollIntervalMs);\n }\n }\n}\n","import { ApiError, GigadriveError } from '../errors';\nimport type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n/** Lifecycle state of a custom domain. Only `active` and `degraded` serve traffic. */\nexport type CustomDomainState =\n | 'pending_ownership'\n | 'pending_dns'\n | 'issuing_certificate'\n | 'active'\n | 'degraded'\n | 'failed'\n | 'suspended'\n | 'removing';\n\n/** A DNS record to publish for a custom domain. */\nexport interface RequiredDnsRecord {\n /** `ownership` proves control of the domain; `routing` sends traffic to Gigadrive Network. */\n purpose: 'ownership' | 'routing';\n /** `ALIAS` stands for the apex record your DNS provider offers (ALIAS, ANAME or CNAME flattening). */\n type: 'TXT' | 'CNAME' | 'ALIAS';\n /** Fully qualified record name. */\n name: string;\n /** Record name relative to the registrable domain, as DNS dashboards expect it (`@` for the apex). */\n host: string;\n /** Record value to publish. */\n value: string;\n /** Whether the last check found the record. */\n status: 'ok' | 'pending' | 'mismatch';\n}\n\n/** What a custom domain serves. */\nexport interface CustomDomainTarget {\n type: 'production' | 'branch' | 'redirect';\n branchId: string | null;\n redirectTo: string | null;\n redirectStatusCode: 301 | 302 | 307 | 308 | null;\n redirectPreservePath: boolean;\n}\n\n/** A problem that keeps a domain from working, with a stable code and guidance. */\nexport interface DomainProblem {\n /** Stable code, for example `dns_record_missing` or `cert_blocked_caa`. */\n code: string;\n /** What is wrong and how to fix it. */\n message: string;\n}\n\n/** A hostname attached to an application. */\nexport interface CustomDomain {\n id: string;\n applicationId: string;\n /** Hostname in ASCII (punycode) form, lowercased. */\n hostname: string;\n /** Hostname for display, with international characters. */\n unicodeHostname: string;\n /** Registrable domain of the hostname. */\n apex: string;\n /** Whether the hostname is the registrable domain itself (needs an ALIAS record). */\n isApex: boolean;\n state: CustomDomainState;\n suspendedReason: 'claimed' | 'admin' | 'plan_limit' | null;\n target: CustomDomainTarget;\n /** Whether this is the application's primary URL. */\n primary: boolean;\n /** The domain whose verification authorizes this hostname. */\n ownership: { name: string | null; verified: boolean };\n /** DNS records to publish, in the order to add them. */\n requiredRecords: RequiredDnsRecord[];\n /** Why the domain is not working yet, or `null`. */\n error: DomainProblem | null;\n certificate: {\n status: 'none' | 'pending' | 'issued' | 'failed' | 'blocked_caa';\n expiresAt: string | null;\n };\n /** What the last DNS check saw, or `null` before the first check. */\n dns: {\n checkedAt: string | null;\n cname: string[];\n a: string[];\n aaaa: string[];\n nameservers: string[];\n pointsToEdge: boolean;\n } | null;\n /** When Gigadrive Network checks the domain next, or `null`. */\n nextCheckAt: string | null;\n activatedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** What a custom domain should serve. */\nexport type CustomDomainTargetInput =\n | { type: 'production' }\n | { type: 'branch'; branchId: string }\n | {\n type: 'redirect';\n /** Hostname to redirect to. */\n to: string;\n /** Defaults to `308`. */\n statusCode?: 301 | 302 | 307 | 308;\n /** Keep the path and query string. Defaults to `true`. */\n preservePath?: boolean;\n };\n\n/** Input for {@link ApplicationDomainsResource.add}. */\nexport interface AddCustomDomainInput {\n /** Hostname such as `shop.example.com` or `example.com`. Normalized by the API. */\n hostname: string;\n /** Defaults to production. Redirects are available on paid plans. */\n target?: CustomDomainTargetInput;\n}\n\n/** Input for {@link ApplicationDomainsResource.update}. */\nexport interface UpdateCustomDomainInput {\n target?: CustomDomainTargetInput;\n /** Make this the application's primary URL. */\n primary?: boolean;\n}\n\n/** A domain an organization claimed or verified. */\nexport interface DomainOwnership {\n id: string;\n organizationId: string;\n name: string;\n unicodeName: string;\n status: 'pending' | 'verified';\n verificationMethod: 'txt' | 'nameservers' | 'domain_connect' | 'legacy_fqdn_txt' | null;\n /** The TXT record that proves control of the domain. */\n record: { type: 'TXT'; name: string; host: string; value: string };\n error: DomainProblem | null;\n verifiedAt: string | null;\n nextCheckAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Options for {@link ApplicationDomainsResource.waitUntilActive}. */\nexport interface WaitUntilActiveOptions {\n /** Give up after this long. Defaults to 10 minutes. */\n timeoutMs?: number;\n /** Time between checks. Defaults to 5 seconds. */\n intervalMs?: number;\n /** Stops waiting when aborted. */\n signal?: AbortSignal;\n /** Called with the domain whenever its state changes. */\n onState?: (domain: CustomDomain) => void;\n}\n\n/** Why {@link ApplicationDomainsResource.waitUntilActive} stopped without an active domain. */\nexport type DomainNotActiveReason = 'timeout' | 'failed' | 'suspended' | 'removing';\n\n/**\n * Thrown by {@link ApplicationDomainsResource.waitUntilActive} when the domain did not become active\n * in time, stopped in a state that needs you to act (`failed` or `suspended`), or was removed.\n */\nexport class DomainNotActiveError extends GigadriveError {\n /** The domain as of the last successful check. */\n readonly domain: CustomDomain;\n /** `timeout` when the wait ran out, `removing` when the domain was removed, otherwise the state that ended it. */\n readonly reason: DomainNotActiveReason;\n\n constructor(domain: CustomDomain, reason: DomainNotActiveReason) {\n const detail = domain.error ? `: ${domain.error.message}` : '';\n super(\n reason === 'timeout'\n ? `${domain.unicodeHostname} is not active yet (state: ${domain.state})${detail}`\n : `${domain.unicodeHostname} is ${reason}${detail}`\n );\n this.name = 'DomainNotActiveError';\n this.domain = domain;\n this.reason = reason;\n }\n}\n\nconst SERVING_STATES = new Set<CustomDomainState>(['active', 'degraded']);\n\n/** Rate limits, server errors and network failures are worth another poll; anything else is final. */\nconst isTransient = (error: unknown) =>\n error instanceof ApiError ? error.status === 429 || error.status >= 500 : error instanceof TypeError;\n\n/**\n * A signal for one poll that aborts when the caller's signal does or after `ms`. Built by hand\n * because `AbortSignal.any` needs Node 18.17 and the SDK supports every Node 18 release.\n */\nconst pollSignal = (ms: number, signal?: AbortSignal) => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(new DOMException('The operation timed out.', 'TimeoutError')), ms);\n const onAbort = () => controller.abort(signal?.reason);\n if (signal?.aborted) onAbort();\n else signal?.addEventListener('abort', onAbort, { once: true });\n return {\n signal: controller.signal,\n dispose: () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n },\n };\n};\n\nconst sleep = (ms: number, signal?: AbortSignal) =>\n new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason instanceof Error ? signal.reason : new GigadriveError('Aborted'));\n return;\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason instanceof Error ? signal.reason : new GigadriveError('Aborted'));\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n\n/**\n * Custom domains attached to an application. Accessed via `client.applications.domains`.\n *\n * Adding a domain returns the DNS records to publish. Gigadrive Network then verifies ownership,\n * checks DNS, issues the certificate and starts serving on its own; poll {@link get} or use\n * {@link waitUntilActive}.\n */\nexport class ApplicationDomainsResource extends BaseResource {\n /**\n * List the custom domains of an application.\n *\n * @example\n * ```ts\n * const { items } = await client.applications.domains.list('app-id');\n * for (const domain of items) console.log(domain.hostname, domain.state);\n * ```\n */\n async list(applicationId: string, query?: ListQuery): Promise<Paginated<CustomDomain>> {\n return this.httpClient.get(`/applications/${applicationId}/domains`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Attach a hostname to an application.\n *\n * @returns The new domain, including the `requiredRecords` to publish at your DNS provider.\n *\n * @example\n * ```ts\n * const domain = await client.applications.domains.add('app-id', { hostname: 'shop.example.com' });\n * for (const record of domain.requiredRecords) console.log(record.type, record.host, record.value);\n * ```\n */\n async add(applicationId: string, data: AddCustomDomainInput): Promise<CustomDomain> {\n return this.httpClient.post(`/applications/${applicationId}/domains`, data);\n }\n\n /** Get one custom domain with its current state. */\n async get(applicationId: string, domainId: string, options?: { signal?: AbortSignal }): Promise<CustomDomain> {\n const path = `/applications/${applicationId}/domains/${domainId}`;\n return options?.signal ? this.httpClient.get(path, { signal: options.signal }) : this.httpClient.get(path);\n }\n\n /**\n * Change what a domain serves, or make it the primary domain.\n *\n * @example\n * ```ts\n * await client.applications.domains.update('app-id', 'domain-id', {\n * target: { type: 'redirect', to: 'www.example.com' },\n * });\n * ```\n */\n async update(applicationId: string, domainId: string, data: UpdateCustomDomainInput): Promise<CustomDomain> {\n return this.httpClient.patch(`/applications/${applicationId}/domains/${domainId}`, data);\n }\n\n /** Check the domain now instead of waiting for the next scheduled check. Rate limited. */\n async refresh(applicationId: string, domainId: string): Promise<CustomDomain> {\n return this.httpClient.post(`/applications/${applicationId}/domains/${domainId}/refresh`);\n }\n\n /** Stop serving the domain and remove it. */\n async remove(applicationId: string, domainId: string): Promise<void> {\n return this.httpClient.delete(`/applications/${applicationId}/domains/${domainId}`);\n }\n\n /**\n * Move a hostname another organization attached to this application. Verify the domain for your\n * organization first and keep its TXT record published: the claim checks the record again.\n */\n async claim(applicationId: string, hostname: string): Promise<CustomDomain> {\n return this.httpClient.post(`/applications/${applicationId}/domains/claim`, { hostname });\n }\n\n /**\n * Poll a domain until it serves traffic.\n *\n * Rate limits, server errors and network failures do not end the wait; the next poll retries until\n * the timeout. Aborting the signal or reaching the timeout also cancels a request in flight.\n *\n * @returns The domain once it is `active` (or `degraded`, which also serves).\n * @throws {DomainNotActiveError} When it fails, is suspended or removed, or the timeout runs out.\n *\n * @example\n * ```ts\n * const domain = await client.applications.domains.add('app-id', { hostname: 'shop.example.com' });\n * await client.applications.domains.waitUntilActive('app-id', domain.id, {\n * onState: (current) => console.log(current.state),\n * });\n * ```\n */\n async waitUntilActive(\n applicationId: string,\n domainId: string,\n options: WaitUntilActiveOptions = {}\n ): Promise<CustomDomain> {\n const { timeoutMs = 10 * 60_000, intervalMs = 5_000, signal, onState } = options;\n const deadline = Date.now() + timeoutMs;\n let last: CustomDomain | undefined;\n\n for (;;) {\n const poll = pollSignal(Math.max(deadline - Date.now(), 1), signal);\n\n let domain: CustomDomain | undefined;\n try {\n domain = await this.get(applicationId, domainId, { signal: poll.signal });\n } catch (error) {\n if (signal?.aborted) throw error;\n // A domain that disappears mid-wait was removed; report it like any other terminal state.\n if (last && error instanceof ApiError && error.status === 404) throw new DomainNotActiveError(last, 'removing');\n // A final error such as a 403 ends the wait even at the deadline; only the poll's own\n // timeout and transient failures fall through to the timeout handling below.\n if (!poll.signal.aborted && !isTransient(error)) throw error;\n if (Date.now() >= deadline && !last) throw error;\n } finally {\n poll.dispose();\n }\n\n if (domain) {\n if (domain.state !== last?.state) onState?.(domain);\n last = domain;\n if (SERVING_STATES.has(domain.state)) return domain;\n if (domain.state === 'failed' || domain.state === 'suspended' || domain.state === 'removing') {\n throw new DomainNotActiveError(domain, domain.state);\n }\n }\n\n const untilDeadline = deadline - Date.now();\n if (untilDeadline <= 0) {\n if (last) throw new DomainNotActiveError(last, 'timeout');\n throw new GigadriveError('Timed out before the domain could be read');\n }\n // Sleep at most until the deadline, so the last check happens at the deadline and not an interval early.\n await sleep(Math.min(intervalMs, untilDeadline), signal);\n }\n }\n}\n\n/**\n * Domains an organization verified. Accessed via `client.organizations.domains`.\n *\n * A verified domain lets every application of the organization attach hostnames at or below it\n * without another TXT record.\n */\nexport class OrganizationDomainsResource extends BaseResource {\n /** List the organization's claimed and verified domains. */\n async list(organizationId: string, query?: ListQuery): Promise<Paginated<DomainOwnership>> {\n return this.httpClient.get(`/organizations/${organizationId}/domains`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Claim a domain for verification.\n *\n * @returns The claim, including the TXT `record` to publish.\n *\n * @example\n * ```ts\n * const claim = await client.organizations.domains.add('org-id', 'example.com');\n * console.log(claim.record.host, claim.record.value);\n * ```\n */\n async add(organizationId: string, name: string): Promise<DomainOwnership> {\n return this.httpClient.post(`/organizations/${organizationId}/domains`, { name });\n }\n\n /** Get one claimed or verified domain. */\n async get(organizationId: string, domainId: string): Promise<DomainOwnership> {\n return this.httpClient.get(`/organizations/${organizationId}/domains/${domainId}`);\n }\n\n /** Check the TXT record now. Rate limited. */\n async verify(organizationId: string, domainId: string): Promise<DomainOwnership> {\n return this.httpClient.post(`/organizations/${organizationId}/domains/${domainId}/verify`);\n }\n\n /** Remove a domain. Refused while custom domains still rely on it. */\n async remove(organizationId: string, domainId: string): Promise<void> {\n return this.httpClient.delete(`/organizations/${organizationId}/domains/${domainId}`);\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { ApplicationEnvVarsResource } from './application-env-vars';\nimport { ApplicationRequestsResource } from './application-requests';\nimport { ApplicationStorageResource } from './application-storage';\nimport { BaseResource } from './base-resource';\nimport { ApplicationDomainsResource } from './domains';\nimport type { ApplicationHostnameList, HostnameAvailability, SetProductionHostnameResult } from './hostnames';\nimport type { Organization } from './organizations';\n\n/** A Gigadrive Network application, belonging to an {@link Organization}. */\nexport interface Application {\n /** Unique identifier (UUID). */\n id: string;\n /** The organization this application belongs to. */\n organization: Organization;\n /** Display name of the application. */\n name: string;\n /** Avatar / logo URL. */\n imageUrl: string;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Input accepted when creating a Gigadrive Network application. */\nexport interface CreateApplicationInput {\n /** Organization that will own the application. */\n organizationId: string;\n /** Display name. Surrounding whitespace is removed by the API. */\n name: string;\n /** Optional lowercase slug. Generated from {@link name} when omitted. */\n slug?: string;\n /**\n * Project directory relative to the repository root. The API normalizes\n * redundant separators and rejects absolute paths and traversal segments.\n */\n rootDirectory?: string;\n}\n\n/**\n * Application creation result used to start the first deployment without an\n * additional lookup.\n */\nexport interface CreatedApplication {\n /** Stable application UUID. */\n id: string;\n /** Owning organization UUID. */\n organizationId: string;\n /** Normalized display name. */\n name: string;\n /** Generated or caller-supplied application slug. */\n slug: string;\n /** Application icon URL. */\n imageUrl: string;\n /** Normalized project directory, or `null` for the repository root. */\n rootDirectory: string | null;\n /** Production environment slug to use for the first deployment. */\n defaultEnvironmentSlug: string;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Query filters for listing applications. */\nexport interface ListApplicationsQuery extends ListQuery {\n /** Only return applications belonging to this organization. */\n organizationId?: string;\n}\n\n/**\n * Manage applications. Accessed via {@link GigadriveClient.applications}.\n *\n * @example\n * ```ts\n * const { items: apps } = await client.applications.list();\n * console.log(apps.map((a) => `${a.name} (${a.organization.name})`));\n * ```\n */\nexport class ApplicationsResource extends BaseResource {\n /**\n * Manage environment variables scoped to an application.\n *\n * @example\n * ```ts\n * await client.applications.envVars.create('app-id', {\n * key: 'DATABASE_URL',\n * value: 'postgres://...',\n * sensitive: true,\n * });\n * ```\n */\n readonly envVars: ApplicationEnvVarsResource;\n\n /**\n * Manage storage buckets, objects, and file uploads for an application.\n *\n * @example\n * ```ts\n * // Upload a file\n * const { url } = await client.storage.upload({\n * bucket: 'assets',\n * key: 'images/logo.png',\n * data: fileData,\n * });\n *\n * // List objects in a bucket\n * const { items } = await client.storage.objects.list('assets');\n * ```\n */\n readonly storage: ApplicationStorageResource;\n\n /**\n * Read observed traffic (request logs) for an application.\n *\n * @example\n * ```ts\n * const { items } = await client.applications.requests.list('app-id', { statusFamily: 5 });\n * ```\n */\n readonly requests: ApplicationRequestsResource;\n\n /**\n * Custom domains attached to the application.\n *\n * @example\n * ```ts\n * const domain = await client.applications.domains.add('app-id', { hostname: 'shop.example.com' });\n * await client.applications.domains.waitUntilActive('app-id', domain.id);\n * ```\n */\n readonly domains: ApplicationDomainsResource;\n\n constructor(httpClient: ConstructorParameters<typeof BaseResource>[0], defaultApplicationId?: string) {\n super(httpClient);\n this.envVars = new ApplicationEnvVarsResource(this.httpClient);\n this.storage = new ApplicationStorageResource(this.httpClient, undefined, defaultApplicationId);\n this.requests = new ApplicationRequestsResource(this.httpClient);\n this.domains = new ApplicationDomainsResource(this.httpClient);\n }\n\n /**\n * List applications the authenticated actor has access to.\n *\n * Requires the `network:applications:read` scope.\n *\n * @param query - Optional organization filter and pagination.\n * @returns A paginated list of applications.\n *\n * @example\n * ```ts\n * const { items, total } = await client.applications.list({ organizationId: 'org-id' });\n * console.log(`Found ${total} applications`);\n * ```\n */\n async list(query?: ListApplicationsQuery): Promise<Paginated<Application>> {\n return this.httpClient.get('/applications', {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Creates an application with production and preview environments.\n *\n * Requires the `network:applications:write` scope and access to the owning\n * organization. Application-, deployment-, and function-scoped tokens cannot\n * create applications.\n *\n * @param input - Ownership, display name, and optional repository layout.\n * @returns The persisted application plus the default production environment\n * slug, ready for an immediate deployment request.\n *\n * @example\n * ```ts\n * const app = await client.applications.create({\n * organizationId: 'org-id',\n * name: 'Next.js Storefront',\n * });\n * console.log(app.id, app.defaultEnvironmentSlug);\n * ```\n */\n async create(input: CreateApplicationInput): Promise<CreatedApplication> {\n return this.httpClient.post('/applications', input);\n }\n\n /**\n * List the `*.gigadrive.app` hostnames for an application (production alias\n * and per-branch aliases).\n *\n * @param applicationId - The application ID (UUID).\n * @returns The hostnames plus the production hostname `label`.\n *\n * @example\n * ```ts\n * const { items, label } = await client.applications.hostnames('app-id');\n * console.log(`Production: ${label}.gigadrive.app`);\n * ```\n */\n async hostnames(applicationId: string): Promise<ApplicationHostnameList> {\n return this.httpClient.get(`/applications/${applicationId}/hostnames`);\n }\n\n /**\n * Check whether a candidate production hostname label is allowed and globally\n * available before setting it with {@link setProductionHostname}.\n *\n * Requires the `network:applications:read` scope.\n *\n * @param applicationId - The application ID (UUID).\n * @param label - The candidate production hostname label (e.g. `\"my-app\"`).\n * @returns Whether the label is available, plus a `reason` when it is not.\n *\n * @example\n * ```ts\n * const { available, reason } = await client.applications.checkHostnameAvailability('app-id', 'my-app');\n * if (!available) console.log(`Unavailable: ${reason}`);\n * ```\n */\n async checkHostnameAvailability(applicationId: string, label: string): Promise<HostnameAvailability> {\n return this.httpClient.get(`/applications/${applicationId}/hostname/availability`, {\n query: { label },\n });\n }\n\n /**\n * Set the application's production hostname. The production alias\n * `{label}.gigadrive.app` is re-pointed to the latest production deployment.\n *\n * Requires the `network:applications:write` scope. Deployment- and\n * function-scoped tokens cannot change the production hostname.\n *\n * @param applicationId - The application ID (UUID).\n * @param label - The production hostname label (e.g. `\"my-app\"`). It is\n * normalized (slugified) server-side.\n * @returns The saved label, the resulting hostname, and whether it is live yet.\n *\n * @example\n * ```ts\n * const { hostname, live } = await client.applications.setProductionHostname('app-id', 'my-app');\n * console.log(live ? `Live at ${hostname}` : `Reserved ${hostname} (deploy to go live)`);\n * ```\n */\n async setProductionHostname(applicationId: string, label: string): Promise<SetProductionHostnameResult> {\n return this.httpClient.put(`/applications/${applicationId}/hostname`, { label });\n }\n}\n","import type { Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport type { Hostname } from './hostnames';\n\n/**\n * The lifecycle status of a deployment.\n * - `\"PENDING\"` — Created, waiting for artifact upload.\n * - `\"QUEUED\"` — Queued for processing.\n * - `\"STARTING\"` — Processing is starting.\n * - `\"BUILDING\"` — Build pipeline is running.\n * - `\"PROVISIONING\"` — Infrastructure is being provisioned.\n * - `\"ACTIVE\"` — Successfully deployed and serving traffic.\n * - `\"FAILED\"` — Build or provisioning failed.\n */\nexport type DeploymentStatus = 'PENDING' | 'QUEUED' | 'STARTING' | 'BUILDING' | 'PROVISIONING' | 'ACTIVE' | 'FAILED';\n\n/** The severity level of a deployment log entry. */\nexport type DeploymentLogType = 'INFO' | 'ERROR' | 'WARN' | 'DEBUG';\n\n/** A deployment of an application to the Gigadrive Network. */\nexport interface Deployment {\n /** Unique identifier (UUID). */\n id: string;\n /** The application this deployment belongs to. */\n applicationId: string;\n /** Current lifecycle status. */\n status: DeploymentStatus;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** A single log entry from a deployment's build or provisioning pipeline. */\nexport interface DeploymentLog {\n /** Unique identifier. */\n id: string;\n /** The log message text. */\n message: string;\n /** Severity level: `\"INFO\"`, `\"ERROR\"`, `\"WARN\"`, or `\"DEBUG\"`. */\n type: DeploymentLogType;\n /** ISO 8601 timestamp of when this log entry was created. */\n createdAt: string;\n}\n\n/** A paginated page of deployment log entries. */\nexport interface DeploymentLogPage {\n /** Total number of log entries for this deployment. */\n totalItems: number;\n /** Maximum number of entries per page. */\n limit: number;\n /** Number of entries skipped (for pagination). */\n offset: number;\n /** The log entries on this page. */\n items: DeploymentLog[];\n}\n\n/** Input for creating a new deployment. */\nexport interface CreateDeploymentInput {\n /** The application to deploy. */\n applicationId: string;\n /** Optional git source for the deployment. When omitted, the deployment expects an artifact upload. */\n gitSource?: {\n /** The git ref to deploy (e.g. `\"main\"`, `\"v1.0.0\"`). */\n ref: string;\n /** A specific commit SHA to deploy. If omitted, the HEAD of the ref is used. */\n sha?: string;\n };\n}\n\n/** Query filters for listing deployments. All fields are optional. */\nexport interface ListDeploymentsQuery {\n /** Filter by organization ID. */\n organizationId?: string;\n /** Filter by application ID. */\n applicationId?: string;\n /** Filter by deployment status. */\n status?: DeploymentStatus;\n}\n\n/** Query parameters for fetching deployment logs. */\nexport interface ListDeploymentLogsQuery {\n /** Number of log entries to skip (for pagination). */\n offset?: number;\n /** Maximum number of log entries to return per page. */\n limit?: number;\n /** Only return log entries created after this ISO 8601 timestamp. Useful for tailing logs. */\n 'createdAt[gt]'?: string;\n}\n\n/** Result from starting a multipart deployment upload. */\nexport interface StartUploadResult {\n /** The multipart upload ID. Pass this to subsequent `getPresignedUrl` and `completeUpload` calls. */\n uploadId: string;\n}\n\n/** A presigned URL for uploading a single part of a multipart deployment upload. */\nexport interface PresignedUrlResult {\n /** The presigned URL to PUT the part data to. */\n url: string;\n}\n\n/** A successfully uploaded part, used to complete the multipart upload. */\nexport interface UploadPart {\n /** The 1-based part number. */\n partNumber: number;\n /** The ETag returned by the storage provider after uploading this part. */\n etag: string;\n}\n\n/**\n * Manage deployments — create, monitor, upload artifacts, and read logs.\n * Accessed via {@link GigadriveClient.deployments}.\n *\n * ## Deployment lifecycle\n *\n * 1. **Create** a deployment with {@link create}.\n * 2. **Upload** build artifacts using the multipart upload flow\n * ({@link startUpload} → {@link getPresignedUrl} → {@link uploadPart} → {@link completeUpload}).\n * 3. **Monitor** the build with {@link get} and {@link getLogs}.\n *\n * @example\n * ```ts\n * // Create a deployment\n * const deployment = await client.deployments.create({ applicationId: 'app-id' });\n *\n * // Check status\n * const updated = await client.deployments.get(deployment.id);\n * console.log(`Status: ${updated.status}`);\n *\n * // Read build logs\n * const logs = await client.deployments.getLogs(deployment.id, { limit: 50 });\n * for (const entry of logs.items) {\n * console.log(`[${entry.type}] ${entry.message}`);\n * }\n * ```\n */\nexport class DeploymentsResource extends BaseResource {\n /**\n * List deployments, optionally filtered by organization, application, or status.\n *\n * Requires the `network:deployments:read` scope.\n *\n * @param query - Optional filters.\n * @returns A paginated list of deployments.\n *\n * @example\n * ```ts\n * // All deployments for an application\n * const { items } = await client.deployments.list({ applicationId: 'app-id' });\n *\n * // Only active deployments\n * const { items } = await client.deployments.list({ status: 'ACTIVE' });\n * ```\n */\n async list(query?: ListDeploymentsQuery): Promise<Paginated<Deployment>> {\n return this.httpClient.get('/deployments', {\n query: query as Record<string, string | undefined> | undefined,\n });\n }\n\n /**\n * Get a deployment by ID, including its current status.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @returns The deployment with its current status.\n *\n * @example\n * ```ts\n * const deployment = await client.deployments.get('deployment-id');\n * if (deployment.status === 'ACTIVE') {\n * console.log('Deployment is live!');\n * }\n * ```\n */\n async get(deploymentId: string): Promise<Deployment> {\n return this.httpClient.get(`/deployments/${deploymentId}`);\n }\n\n /**\n * Create a new deployment. The deployment starts in `\"PENDING\"` status,\n * waiting for artifact upload. Use the multipart upload methods\n * ({@link startUpload}, {@link getPresignedUrl}, {@link uploadPart},\n * {@link completeUpload}) to upload build artifacts.\n *\n * Requires the `network:deployments:trigger` scope.\n *\n * @param data - The application ID and optional git source.\n * @returns The newly created deployment.\n *\n * @example\n * ```ts\n * const deployment = await client.deployments.create({\n * applicationId: 'app-id',\n * });\n * console.log(`Created deployment ${deployment.id} (${deployment.status})`);\n * ```\n */\n async create(data: CreateDeploymentInput): Promise<Deployment> {\n return this.httpClient.post('/deployments', data);\n }\n\n /**\n * Start a multipart upload for deployment artifacts. This initiates a new\n * multipart upload and returns an upload ID for subsequent part uploads.\n *\n * The deployment must be in `\"PENDING\"` status.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @returns An object containing the `uploadId` for subsequent calls.\n *\n * @example\n * ```ts\n * const { uploadId } = await client.deployments.startUpload('deployment-id');\n * ```\n */\n async startUpload(deploymentId: string): Promise<StartUploadResult> {\n return this.httpClient.post(`/deployments/${deploymentId}/upload/start`);\n }\n\n /**\n * Get a presigned URL for uploading a single part of a multipart upload.\n * The URL is temporary and should be used immediately with {@link uploadPart}.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @param uploadId - The multipart upload ID from {@link startUpload}.\n * @param partNumber - The 1-based part number.\n * @returns An object containing the presigned `url` to PUT the part data to.\n *\n * @example\n * ```ts\n * const { url } = await client.deployments.getPresignedUrl(\n * 'deployment-id', uploadId, 1,\n * );\n * ```\n */\n async getPresignedUrl(deploymentId: string, uploadId: string, partNumber: number): Promise<PresignedUrlResult> {\n if (!Number.isInteger(partNumber) || partNumber < 1) {\n throw new Error(`partNumber must be a positive integer, received ${partNumber}`);\n }\n return this.httpClient.post(`/deployments/${deploymentId}/upload/part`, { uploadId, partNumber });\n }\n\n /**\n * Upload a part to a presigned URL obtained from {@link getPresignedUrl}.\n * This sends the chunk data directly to the backend storage service, not\n * to the Gigadrive API. The returned `etag` is needed for\n * {@link completeUpload}.\n *\n * @param presignedUrl - The presigned URL from {@link getPresignedUrl}.\n * @param data - The chunk data to upload.\n * @param partNumber - The 1-based part number (used for error messages).\n * @returns The part number and ETag. Collect these for {@link completeUpload}.\n * @throws {@link ApiError} if the PUT request fails.\n * @throws Error if the storage provider does not return an ETag header.\n *\n * @example\n * ```ts\n * const chunk = fileBuffer.subarray(0, 10 * 1024 * 1024); // 10 MB\n * const part = await client.deployments.uploadPart(presignedUrl, chunk, 1);\n * // part = { partNumber: 1, etag: '\"abc123...\"' }\n * ```\n */\n async uploadPart(\n presignedUrl: string,\n data: ArrayBuffer | Uint8Array | Blob,\n partNumber: number\n ): Promise<UploadPart> {\n if (!Number.isInteger(partNumber) || partNumber < 1) {\n throw new Error(`partNumber must be a positive integer, received ${partNumber}`);\n }\n const response = await this.httpClient.fetchRaw(presignedUrl, {\n method: 'PUT',\n headers: {\n // Deployment artifacts are always ZIP archives.\n 'Content-Type': 'application/zip',\n 'Content-Length': String(data instanceof Blob ? data.size : data.byteLength),\n },\n body: data,\n });\n\n const etag = response.headers.get('ETag');\n if (!etag) {\n throw new Error(`No ETag received for part ${partNumber}`);\n }\n\n return { partNumber, etag };\n }\n\n /**\n * Complete a multipart upload after all parts have been uploaded via\n * {@link uploadPart}. This signals the storage provider to assemble the\n * parts into a single object and triggers the deployment build pipeline.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @param uploadId - The multipart upload ID from {@link startUpload}.\n * @param parts - Array of `{ partNumber, etag }` from each {@link uploadPart} call.\n *\n * @example\n * ```ts\n * await client.deployments.completeUpload(deploymentId, uploadId, [\n * { partNumber: 1, etag: '\"abc...\"' },\n * { partNumber: 2, etag: '\"def...\"' },\n * ]);\n * ```\n */\n async completeUpload(deploymentId: string, uploadId: string, parts: UploadPart[]): Promise<void> {\n return this.httpClient.post(`/deployments/${deploymentId}/upload/complete`, { uploadId, parts });\n }\n\n /**\n * Fetch deployment logs. Supports pagination and filtering by timestamp\n * for incremental log tailing.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @param query - Optional pagination and filter parameters.\n * @returns A page of log entries with total count.\n *\n * @example\n * ```ts\n * // Get the first page of logs\n * const page = await client.deployments.getLogs('deployment-id', {\n * offset: 0,\n * limit: 100,\n * });\n *\n * for (const entry of page.items) {\n * const prefix = entry.type === 'ERROR' ? 'ERR' : entry.type === 'WARN' ? 'WRN' : 'INF';\n * console.log(`[${prefix}] ${entry.message}`);\n * }\n *\n * // Tail new logs since last fetch\n * const newLogs = await client.deployments.getLogs('deployment-id', {\n * 'createdAt[gt]': lastEntry.createdAt,\n * });\n * ```\n */\n async getLogs(deploymentId: string, query?: ListDeploymentLogsQuery): Promise<DeploymentLogPage> {\n return this.httpClient.get(`/deployments/${deploymentId}/logs`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * List the immutable `*.gigadrive.app` hostnames assigned to a deployment.\n *\n * @param deploymentId - The deployment ID (UUID).\n * @returns A paginated list of hostnames.\n *\n * @example\n * ```ts\n * const { items } = await client.deployments.getHostnames('deployment-id');\n * console.log(items.map((h) => h.hostname));\n * ```\n */\n async getHostnames(deploymentId: string): Promise<Paginated<Hostname>> {\n return this.httpClient.get(`/deployments/${deploymentId}/hostnames`);\n }\n}\n","import type { NormalizedImagePolicy } from '@gigadrive/network-config';\n\nimport { BaseResource } from './base-resource';\n\nexport interface ImageCacheInspection {\n enabled: boolean;\n deploymentTag: string;\n sourceTag: string | null;\n policy: NormalizedImagePolicy | null;\n}\n\nexport interface ImageCachePurgeResult {\n purged: true;\n tag: string;\n}\n\nexport interface ManagedImageUrlOptions {\n /** Deployment or custom application origin, for example `https://app.gigadrive.app`. */\n origin: string;\n /** Local application path or approved absolute remote URL. */\n source: string;\n filename?: string;\n width?: number;\n height?: number;\n quality?: number;\n format?: 'avif' | 'webp' | 'jpeg' | 'png';\n fit?: 'contain' | 'cover' | 'fill' | 'inside' | 'outside';\n variant?: string;\n}\n\n/** Creates the stable, framework-neutral managed image URL served on an application hostname. */\nexport const createManagedImageUrl = (options: ManagedImageUrlOptions): string => {\n const inferredFilename = options.source.split('/').filter(Boolean).at(-1)?.split('?')[0] || 'image.image';\n const filename = (options.filename ?? inferredFilename).replace(/[^A-Za-z0-9._-]/g, '_') || 'image.image';\n const url = new URL(\n `/_gigadrive/image/${encodeURIComponent(options.source)}/${encodeURIComponent(filename)}`,\n options.origin\n );\n for (const [name, value] of Object.entries({\n width: options.width,\n height: options.height,\n quality: options.quality,\n format: options.format,\n fit: options.fit,\n variant: options.variant,\n })) {\n if (value !== undefined) url.searchParams.set(name, String(value));\n }\n return url.toString();\n};\n\n/** Managed image optimization cache inspection and source/deployment purge operations. */\nexport class ImageOptimizationResource extends BaseResource {\n /** Create a managed image URL without making an API request. */\n url(options: ManagedImageUrlOptions): string {\n return createManagedImageUrl(options);\n }\n\n /** Inspect the immutable deployment policy and Bunny cache tags used for a source. */\n inspect(deploymentId: string, source?: string): Promise<ImageCacheInspection> {\n return this.httpClient.get(`/deployments/${deploymentId}/image-cache`, {\n query: { source },\n });\n }\n\n /** Purge all variants for one source, or every optimized image in the deployment when omitted. */\n purge(deploymentId: string, source?: string): Promise<ImageCachePurgeResult> {\n return this.httpClient.delete(`/deployments/${deploymentId}/image-cache`, {\n query: { source },\n });\n }\n}\n","import type { HttpClient, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** One bucket of an AI Gateway usage breakdown (by model, provider, or user). */\nexport interface AiGatewayUsageBreakdown {\n /** Bucket label (a model, provider, or user identifier). */\n label: string;\n /** Number of requests in this bucket. */\n requests: number;\n /** Total tokens in this bucket. */\n tokens: number;\n /** Input tokens in this bucket. */\n inputTokens: number;\n /** Output tokens in this bucket. */\n outputTokens: number;\n /** Billable cost in micros of USD for this bucket. */\n costMicros: number;\n}\n\n/** Aggregated AI Gateway usage over a time range, with breakdowns. */\nexport interface AiGatewayUsageSummary {\n summary: {\n requestCount: number;\n successCount: number;\n errorCount: number;\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n billableCostMicros: number;\n avgLatencyMs: number;\n };\n byModel: AiGatewayUsageBreakdown[];\n byProvider: AiGatewayUsageBreakdown[];\n byUser: AiGatewayUsageBreakdown[];\n}\n\n/** One provider attempt recorded while routing an AI Gateway request. */\nexport interface AiGatewayProviderAttempt {\n provider: string;\n error?: string;\n statusCode?: number;\n tag?: string;\n}\n\n/** A single AI Gateway request event with full telemetry. */\nexport interface AiGatewayRequestEvent {\n id: string;\n requestId: string;\n traceId: string | null;\n billingSubjectType: 'organization' | 'application';\n organizationId: string;\n applicationId: string | null;\n actorId: string | null;\n actorType: string;\n apiKeyId: string | null;\n authenticatedUserId: string | null;\n callerEndUserId: string | null;\n modelRequested: string;\n modelServed: string | null;\n provider: string | null;\n providerAttempts: AiGatewayProviderAttempt[] | null;\n status: 'pending' | 'success' | 'error' | 'cancelled';\n errorCode: string | null;\n errorType: string | null;\n inputTokens: number;\n outputTokens: number;\n cachedInputTokens: number;\n totalTokens: number;\n usageSource: 'provider' | 'estimated' | 'none';\n providerCostMicros: number;\n billableCostMicros: number;\n streaming: boolean;\n latencyMs: number | null;\n metadata: Record<string, string> | null;\n startedAt: string;\n completedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** An AI Gateway spend/usage budget. */\nexport interface AiGatewayBudget {\n id: string;\n organizationId: string;\n /** Application-specific target, or `null` for organization-wide. */\n applicationId: string | null;\n /** User-specific target, or `null` for all users. */\n userId: string | null;\n period: 'day' | 'month';\n maxCostMicros: number | null;\n maxRequests: number | null;\n maxTokens: number | null;\n maxRequestCostMicros: number | null;\n enabled: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Input for one budget when replacing the budget set. */\nexport interface AiGatewayBudgetInput {\n applicationId?: string;\n userId?: string;\n period?: 'day' | 'month';\n maxCostMicros?: number | null;\n maxRequests?: number | null;\n maxTokens?: number | null;\n maxRequestCostMicros?: number | null;\n enabled?: boolean;\n}\n\n/** An AI Gateway governance policy. */\nexport interface AiGatewayPolicy {\n id: string;\n organizationId: string;\n /** Application-specific target, or `null` for organization-wide. */\n applicationId: string | null;\n /** Allowed model IDs, or `null` to allow all. */\n allowedModels: string[] | null;\n /** Allowed provider IDs, or `null` to allow all. */\n allowedProviders: string[] | null;\n requireZdr: boolean;\n allowFallbacks: boolean;\n maxOutputTokens: number | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Input for creating or updating an AI Gateway policy. */\nexport interface AiGatewayPolicyInput {\n applicationId?: string;\n allowedModels?: string[] | null;\n allowedProviders?: string[] | null;\n requireZdr?: boolean;\n allowFallbacks?: boolean;\n maxOutputTokens?: number | null;\n}\n\n/** Query for usage summary. */\nexport interface AiGatewayUsageQuery {\n /** Only include usage at or after this ISO 8601 timestamp. */\n from?: string;\n /** Only include usage before or at this ISO 8601 timestamp. */\n to?: string;\n /** Restrict to one application. */\n applicationId?: string;\n}\n\n/** Query for the request-event log and CSV export. */\nexport interface AiGatewayRequestsQuery extends AiGatewayUsageQuery {\n model?: string;\n provider?: string;\n status?: 'pending' | 'success' | 'error' | 'cancelled';\n requestId?: string;\n authenticatedUserId?: string;\n callerEndUserId?: string;\n limit?: number;\n cursor?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Sub-resources\n// ---------------------------------------------------------------------------\n\n/** AI Gateway usage analytics for an organization. */\nexport class AiGatewayUsageResource extends BaseResource {\n /** Get an aggregated usage summary with breakdowns by model, provider, and user. */\n async summary(organizationId: string, query?: AiGatewayUsageQuery): Promise<AiGatewayUsageSummary> {\n return this.httpClient.get(`/organizations/${organizationId}/ai-gateway/usage/summary`, {\n query: query as Record<string, string | undefined> | undefined,\n });\n }\n\n /** List request-level usage events. */\n async requests(organizationId: string, query?: AiGatewayRequestsQuery): Promise<Paginated<AiGatewayRequestEvent>> {\n return this.httpClient.get(`/organizations/${organizationId}/ai-gateway/usage/requests`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /** Export request-level usage events as CSV text. */\n async export(organizationId: string, query?: AiGatewayRequestsQuery): Promise<string> {\n const response = await this.httpClient.requestStream(\n 'GET',\n `/organizations/${organizationId}/ai-gateway/usage/export`,\n { query: query as Record<string, string | number | undefined> | undefined }\n );\n return response.text();\n }\n}\n\n/** AI Gateway budgets for an organization. */\nexport class AiGatewayBudgetsResource extends BaseResource {\n /** List all budgets for an organization. */\n async list(organizationId: string): Promise<{ items: AiGatewayBudget[] }> {\n return this.httpClient.get(`/organizations/${organizationId}/ai-gateway/budgets`);\n }\n\n /**\n * Replace the organization's entire budget set. Pass an empty array to clear\n * all budgets.\n */\n async replace(organizationId: string, budgets: AiGatewayBudgetInput[]): Promise<{ items: AiGatewayBudget[] }> {\n return this.httpClient.put(`/organizations/${organizationId}/ai-gateway/budgets`, { budgets });\n }\n}\n\n/** AI Gateway governance policies for an organization. */\nexport class AiGatewayPoliciesResource extends BaseResource {\n /**\n * Get the governance policy for an organization, or for a specific\n * application when `applicationId` is provided. Returns `null` if no policy is set.\n */\n async get(organizationId: string, options?: { applicationId?: string }): Promise<AiGatewayPolicy | null> {\n const { policy } = await this.httpClient.get<{ policy: AiGatewayPolicy | null }>(\n `/organizations/${organizationId}/ai-gateway/policies`,\n { query: { applicationId: options?.applicationId } }\n );\n return policy;\n }\n\n /** Create or update an AI Gateway policy. */\n async put(organizationId: string, data: AiGatewayPolicyInput): Promise<AiGatewayPolicy> {\n const { policy } = await this.httpClient.put<{ policy: AiGatewayPolicy }>(\n `/organizations/${organizationId}/ai-gateway/policies`,\n data\n );\n return policy;\n }\n}\n\n/**\n * Organization-scoped AI Gateway governance: usage analytics, budgets, and\n * model/provider policies. Accessed via `client.organizations.aiGateway`.\n */\nexport class OrganizationAiGatewayResource {\n /** Usage analytics (summary, request log, CSV export). */\n readonly usage: AiGatewayUsageResource;\n /** Spend/usage budgets. */\n readonly budgets: AiGatewayBudgetsResource;\n /** Model/provider governance policies. */\n readonly policies: AiGatewayPoliciesResource;\n\n constructor(httpClient: HttpClient) {\n this.usage = new AiGatewayUsageResource(httpClient);\n this.budgets = new AiGatewayBudgetsResource(httpClient);\n this.policies = new AiGatewayPoliciesResource(httpClient);\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport type { CreateEnvVarInput, EnvVar, UpdateEnvVarInput } from './env-vars';\n\n/**\n * Manage environment variables scoped to an organization.\n * Accessed via `client.organizations.envVars`.\n */\nexport class OrganizationEnvVarsResource extends BaseResource {\n /**\n * List all environment variables for an organization.\n *\n * @param organizationId - The organization ID (UUID).\n * @returns A paginated list of environment variables.\n *\n * @example\n * ```ts\n * const { items } = await client.organizations.envVars.list('org-id');\n * for (const v of items) {\n * console.log(`${v.key}=${v.sensitive ? '***' : v.value}`);\n * }\n * ```\n */\n async list(organizationId: string, query?: ListQuery): Promise<Paginated<EnvVar>> {\n return this.httpClient.get(`/organizations/${organizationId}/env-vars`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Create a new environment variable for an organization.\n *\n * @param organizationId - The organization ID (UUID).\n * @param data - The variable key, value, and optional settings.\n * @returns The newly created environment variable.\n *\n * @example\n * ```ts\n * const envVar = await client.organizations.envVars.create('org-id', {\n * key: 'STRIPE_SECRET',\n * value: 'sk_live_...',\n * sensitive: true,\n * });\n * ```\n */\n async create(organizationId: string, data: CreateEnvVarInput): Promise<EnvVar> {\n return this.httpClient.post(`/organizations/${organizationId}/env-vars`, data);\n }\n\n /**\n * Update an existing environment variable. Only the fields you provide\n * will be changed; omitted fields are left unchanged.\n *\n * @param organizationId - The organization ID (UUID).\n * @param envVarId - The environment variable ID (UUID).\n * @param data - The fields to update.\n * @returns The updated environment variable.\n *\n * @example\n * ```ts\n * await client.organizations.envVars.update('org-id', 'var-id', {\n * value: 'new-value',\n * });\n * ```\n */\n async update(organizationId: string, envVarId: string, data: UpdateEnvVarInput): Promise<EnvVar> {\n return this.httpClient.patch(`/organizations/${organizationId}/env-vars/${envVarId}`, data);\n }\n\n /**\n * Permanently delete an environment variable.\n *\n * @param organizationId - The organization ID (UUID).\n * @param envVarId - The environment variable ID (UUID).\n *\n * @example\n * ```ts\n * await client.organizations.envVars.delete('org-id', 'var-id');\n * ```\n */\n async delete(organizationId: string, envVarId: string): Promise<void> {\n return this.httpClient.delete(`/organizations/${organizationId}/env-vars/${envVarId}`);\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n/** Organization membership role used for administration privileges. */\nexport type OrganizationMembershipRole = 'OWNER' | 'ADMIN' | 'MEMBER';\n\n/** A user membership in a Gigadrive organization. */\nexport interface OrganizationMember {\n /** Unique membership identifier (UUID). */\n membershipId: string;\n /** Organization that owns this membership. */\n organizationId: string;\n /** User who belongs to the organization. */\n userId: string;\n /** Email address of the organization member. */\n email: string;\n /** Given name of the organization member, or null when unset. */\n givenName: string | null;\n /** Family name of the organization member, or null when unset. */\n familyName: string | null;\n /** Avatar URL for the organization member, or null when unset. */\n imageUrl: string | null;\n /** Organization membership role. */\n role: OrganizationMembershipRole;\n /** ISO 8601 timestamp when the user joined the organization. */\n joinedAt: string;\n}\n\n/**\n * List organization members. Accessed via {@link OrganizationsResource.members}.\n *\n * @example\n * ```ts\n * const { items } = await client.organizations.members.list('org-id');\n * console.log(items.map((m) => `${m.email} (${m.role})`));\n * ```\n */\nexport class OrganizationMembersResource extends BaseResource {\n /**\n * List the users who belong to an organization.\n *\n * @param organizationId - Organization whose members should be listed.\n * @param query - Optional pagination.\n * @returns A paginated list of organization members.\n *\n * @example\n * ```ts\n * const { items, total } = await client.organizations.members.list('org-id');\n * console.log(`Found ${total} members`);\n * ```\n */\n async list(organizationId: string, query?: ListQuery): Promise<Paginated<OrganizationMember>> {\n return this.httpClient.get(`/organizations/${organizationId}/members`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\n\n/** Product access mode from the code-defined product registry. */\nexport type ProductAccessMode = 'organization' | 'user';\n\n/** Fallback access policy when no explicit entitlement override exists. */\nexport type ProductDefaultAccessPolicy = 'granted' | 'explicit_entitlement_required';\n\n/** Lifecycle status of an explicit product entitlement override. */\nexport type ProductEntitlementStatus = 'ACTIVE' | 'SUSPENDED' | 'REVOKED';\n\n/** Lifecycle status of a local organization product subscription. */\nexport type ProductSubscriptionStatus = 'ACTIVE' | 'CANCELED';\n\n/** Whether effective access was resolved from an override or the registry default. */\nexport type ProductAccessResolutionSource = 'explicit' | 'default';\n\n/** A plan defined for a product in the product registry. */\nexport interface ProductPlan {\n /** Stable plan slug. */\n slug: string;\n /** Human-readable plan name. */\n displayName: string;\n /** Short description of the plan. */\n description: string;\n}\n\n/** Product metadata from the code-defined product registry. */\nexport interface ProductDefinition {\n /** Stable product slug (e.g. `network`, `office`). */\n slug: string;\n /** Human-readable product name. */\n displayName: string;\n /** Whether the product is granted to organizations or directly to users. */\n accessMode: ProductAccessMode;\n /** Fallback access policy when no explicit entitlement override exists. */\n defaultAccessPolicy: ProductDefaultAccessPolicy;\n /** Locally activatable plans for the product. */\n plans: ProductPlan[];\n}\n\n/** Explicit organization product entitlement override. */\nexport interface OrganizationProductEntitlement {\n /** Unique identifier (UUID). */\n id: string;\n /** Product slug this entitlement applies to. */\n product: string;\n /** Lifecycle status of the override. */\n status: ProductEntitlementStatus;\n /** User who last granted or updated the override, if known. */\n grantedByUserId: string | null;\n /** ISO 8601 timestamp when the entitlement was revoked, if revoked. */\n revokedAt: string | null;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Local organization product subscription / plan selection. */\nexport interface OrganizationProductSubscription {\n /** Unique identifier (UUID). */\n id: string;\n /** Product slug this subscription applies to. */\n product: string;\n /** Currently selected plan slug. */\n plan: string;\n /** Local subscription lifecycle status. */\n status: ProductSubscriptionStatus;\n /** User who activated the current plan, if known. */\n activatedByUserId: string | null;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Effective product access summary for an organization-scoped product. */\nexport interface OrganizationProductAccess {\n /** Product metadata from the registry. */\n product: ProductDefinition;\n /** Whether the organization currently has effective access. */\n hasAccess: boolean;\n /** Whether access was resolved from an explicit override or the default policy. */\n resolutionSource: ProductAccessResolutionSource;\n /** Explicit entitlement override when one exists. */\n explicitEntitlement: OrganizationProductEntitlement | null;\n /** Local product subscription when one exists. */\n subscription: OrganizationProductSubscription | null;\n}\n\n/** Compact yes/no entitlement check for an organization product. */\nexport interface OrganizationProductEntitlementCheck {\n /** Organization that was checked. */\n organizationId: string;\n /** Product slug that was checked. */\n product: string;\n /** Whether the organization currently has effective access. */\n hasAccess: boolean;\n}\n\n/**\n * Inspect organization product access / entitlements.\n *\n * Accessed via {@link OrganizationsResource.products}.\n *\n * Subscriptions are read-only through the public API — plan changes happen in\n * Gigadrive product surfaces, not via the SDK.\n *\n * @example\n * ```ts\n * const { items } = await client.organizations.products.list('org-id');\n * const check = await client.organizations.products.checkEntitlement('org-id', 'office');\n * console.log(check.hasAccess);\n * ```\n */\nexport class OrganizationProductsResource extends BaseResource {\n /**\n * List effective product access for every organization-scoped product.\n *\n * @param organizationId - Organization whose product access should be listed.\n * @param query - Optional pagination.\n * @returns A paginated list of product access summaries.\n *\n * @example\n * ```ts\n * const { items } = await client.organizations.products.list('org-id');\n * for (const item of items) {\n * console.log(item.product.slug, item.hasAccess);\n * }\n * ```\n */\n async list(organizationId: string, query?: ListQuery): Promise<Paginated<OrganizationProductAccess>> {\n return this.httpClient.get(`/organizations/${organizationId}/products`, {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Get effective access for one organization-scoped product.\n *\n * @param organizationId - Organization to inspect.\n * @param product - Product slug from the product registry.\n * @returns Product access summary including entitlement and subscription state.\n *\n * @example\n * ```ts\n * const access = await client.organizations.products.get('org-id', 'office');\n * console.log(access.hasAccess, access.subscription?.plan);\n * ```\n */\n async get(organizationId: string, product: string): Promise<OrganizationProductAccess> {\n return this.httpClient.get(`/organizations/${organizationId}/products/${product}`);\n }\n\n /**\n * Check whether an organization currently has access to a product.\n *\n * @param organizationId - Organization to check.\n * @param product - Product slug from the product registry.\n * @returns Compact entitlement check result.\n *\n * @example\n * ```ts\n * const { hasAccess } = await client.organizations.products.checkEntitlement('org-id', 'network');\n * ```\n */\n async checkEntitlement(organizationId: string, product: string): Promise<OrganizationProductEntitlementCheck> {\n return this.httpClient.get(`/organizations/${organizationId}/products/${product}/entitlement`);\n }\n}\n","import type { ListQuery, Paginated } from '../http-client';\nimport { BaseResource } from './base-resource';\nimport { OrganizationDomainsResource } from './domains';\nimport { OrganizationAiGatewayResource } from './organization-ai-gateway';\nimport { OrganizationEnvVarsResource } from './organization-env-vars';\nimport { OrganizationMembersResource } from './organization-members';\nimport { OrganizationProductsResource } from './organization-products';\n\n/** A Gigadrive Network organization. */\nexport interface Organization {\n /** Unique identifier (UUID). */\n id: string;\n /** Display name of the organization. */\n name: string;\n /** URL-safe slug (e.g. `gigadrive`). */\n slug: string;\n /** Avatar / logo URL. */\n imageUrl: string;\n /** ISO 8601 creation timestamp. */\n createdAt: string;\n /** ISO 8601 last-updated timestamp. */\n updatedAt: string;\n}\n\n/** Input for creating an organization. */\nexport interface CreateOrganizationInput {\n /** Display name for the new organization. */\n name: string;\n /** Optional URL-safe slug. Generated from the name when omitted. */\n slug?: string;\n}\n\n/**\n * Manage organizations. Accessed via {@link GigadriveClient.organizations}.\n *\n * @example\n * ```ts\n * const { items: orgs } = await client.organizations.list();\n * console.log(orgs.map((o) => o.name));\n * ```\n */\nexport class OrganizationsResource extends BaseResource {\n /**\n * Manage environment variables scoped to an organization.\n *\n * @example\n * ```ts\n * // List all env vars for an organization\n * const { items } = await client.organizations.envVars.list('org-id');\n *\n * // Create a new env var\n * await client.organizations.envVars.create('org-id', {\n * key: 'ANALYTICS_KEY',\n * value: 'ak_live_...',\n * sensitive: true,\n * });\n * ```\n */\n readonly envVars: OrganizationEnvVarsResource;\n\n /**\n * AI Gateway governance for an organization: usage analytics, budgets, and\n * model/provider policies.\n *\n * @example\n * ```ts\n * const usage = await client.organizations.aiGateway.usage.summary('org-id', { from: '2026-06-01' });\n * console.log(usage.summary.totalTokens);\n * ```\n */\n readonly aiGateway: OrganizationAiGatewayResource;\n\n /**\n * List organization members and membership roles.\n *\n * @example\n * ```ts\n * const { items } = await client.organizations.members.list('org-id');\n * ```\n */\n readonly members: OrganizationMembersResource;\n\n /**\n * Inspect organization product entitlements. Read-only through the public\n * API — plan changes happen in Gigadrive product surfaces, not via the SDK.\n *\n * @example\n * ```ts\n * const check = await client.organizations.products.checkEntitlement('org-id', 'office');\n * ```\n */\n readonly products: OrganizationProductsResource;\n\n /**\n * Domains the organization verified. A verified domain lets every application attach hostnames\n * below it without another TXT record.\n *\n * @example\n * ```ts\n * const claim = await client.organizations.domains.add('org-id', 'example.com');\n * ```\n */\n readonly domains: OrganizationDomainsResource;\n\n constructor(...args: ConstructorParameters<typeof BaseResource>) {\n super(...args);\n this.envVars = new OrganizationEnvVarsResource(this.httpClient);\n this.aiGateway = new OrganizationAiGatewayResource(this.httpClient);\n this.members = new OrganizationMembersResource(this.httpClient);\n this.products = new OrganizationProductsResource(this.httpClient);\n this.domains = new OrganizationDomainsResource(this.httpClient);\n }\n\n /**\n * List organizations the authenticated actor has access to.\n *\n * @param query - Optional pagination.\n * @returns A paginated list of organizations.\n *\n * @example\n * ```ts\n * const { items, total } = await client.organizations.list();\n * console.log(`Found ${total} organizations`);\n * ```\n */\n async list(query?: ListQuery): Promise<Paginated<Organization>> {\n return this.httpClient.get('/organizations', {\n query: query as Record<string, string | number | undefined> | undefined,\n });\n }\n\n /**\n * Get a single organization by ID.\n *\n * @param organizationId - Organization to retrieve.\n * @returns The organization.\n *\n * @example\n * ```ts\n * const org = await client.organizations.get('org-id');\n * console.log(org.name, org.slug);\n * ```\n */\n async get(organizationId: string): Promise<Organization> {\n return this.httpClient.get(`/organizations/${organizationId}`);\n }\n\n /**\n * Create a new organization.\n *\n * Requires a user-backed token with the `platform:organizations:write` scope.\n * The authenticated user becomes the organization owner.\n *\n * @param input - Organization creation input.\n * @returns The created organization.\n *\n * @example\n * ```ts\n * const org = await client.organizations.create({ name: 'Acme Corp' });\n * console.log(org.id, org.slug);\n * ```\n */\n async create(input: CreateOrganizationInput): Promise<Organization> {\n return this.httpClient.post('/organizations', input);\n }\n}\n","/**\n * Byte, base64 and duration helpers shared by the queue client, the push\n * handler and the Workflow adapter. Runtime-neutral: Web APIs only.\n *\n * @internal\n */\n\nconst DURATION_PATTERN = /^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h|d)$/;\nconst UNIT_SECONDS = { ms: 0.001, s: 1, m: 60, h: 3_600, d: 86_400 } as const;\n\n/**\n * A duration as seconds, or a string such as `'500ms'`, `'30s'`, `'10m'`,\n * `'12h'` or `'7d'`.\n */\nexport type QueueDuration = number | `${number}${'ms' | 's' | 'm' | 'h' | 'd'}`;\n\n/**\n * Converts a {@link QueueDuration} to whole seconds, rounding up so a\n * sub-second delay never becomes \"now\".\n *\n * @throws {Error} When the value is negative, not finite, or not a recognised duration string.\n */\nexport const durationToSeconds = (value: QueueDuration): number => {\n let seconds: number;\n if (typeof value === 'number') {\n seconds = value;\n } else {\n const match = DURATION_PATTERN.exec(value.trim());\n if (!match) throw new Error(`Invalid duration \"${value}\". Use seconds or a string such as 30s, 10m, 12h or 7d.`);\n seconds = Number(match[1]) * UNIT_SECONDS[match[2] as keyof typeof UNIT_SECONDS];\n }\n if (!Number.isFinite(seconds) || seconds < 0) throw new Error(`Invalid duration \"${String(value)}\"`);\n return Math.ceil(seconds);\n};\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder();\n\nexport const utf8Encode = (value: string): Uint8Array => textEncoder.encode(value);\nexport const utf8Decode = (bytes: Uint8Array): string => textDecoder.decode(bytes);\n\nexport const bytesToBase64 = (bytes: Uint8Array): string => {\n let binary = '';\n for (let index = 0; index < bytes.length; index += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(index, index + 0x8000));\n }\n return btoa(binary);\n};\n\nexport const base64ToBytes = (value: string): Uint8Array => {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);\n return bytes;\n};\n\nexport const toHex = (buffer: ArrayBuffer): string =>\n Array.from(new Uint8Array(buffer), (byte) => byte.toString(16).padStart(2, '0')).join('');\n\n/** Copies bytes into a fresh `ArrayBuffer`, which Web Crypto and `fetch` accept everywhere. */\nexport const toArrayBuffer = (bytes: Uint8Array): ArrayBuffer => {\n const copy = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(copy).set(bytes);\n return copy;\n};\n","import { GigadriveError } from '../errors';\nimport { durationToSeconds, type QueueDuration } from './encoding';\n\n/**\n * Throw from a queue handler to have the message delivered again later\n * without spending one of its attempts. Use it for \"not yet\" outcomes, such\n * as waiting on a dependency or backing off a rate-limited API.\n *\n * @example\n * ```ts\n * export const POST = emails.handler(async (email) => {\n * if (await provider.isThrottled()) throw new RetryLaterError('30s');\n * await provider.send(email);\n * });\n * ```\n */\nexport class RetryLaterError extends GigadriveError {\n /** Seconds until the next delivery. */\n readonly delaySeconds: number;\n\n constructor(delay: QueueDuration, message = 'Message deferred') {\n super(message);\n this.name = 'RetryLaterError';\n this.delaySeconds = durationToSeconds(delay);\n }\n}\n\n/**\n * Throw from a queue handler when retrying cannot help, such as a payload\n * that fails validation. The message moves to the dead-letter list straight\n * away (or is dropped when the queue keeps no dead letters), with this\n * error's message recorded as the reason.\n */\nexport class NonRetryableError extends GigadriveError {\n constructor(message: string) {\n super(message);\n this.name = 'NonRetryableError';\n }\n}\n","import { toArrayBuffer, toHex, utf8Encode } from './encoding';\n\n/** Header carrying the delivery signature: `t=<unix ms>,v1=<hex HMAC-SHA256>`. */\nexport const QUEUE_SIGNATURE_HEADER = 'x-gigadrive-queue-signature';\n\n/** How far a delivery's signing time may drift from the receiver's clock. */\nexport const QUEUE_SIGNATURE_TOLERANCE_MS = 5 * 60_000;\n\n/** The environment variable the platform injects with the environment's queue signing secret. */\nexport const QUEUE_SIGNING_SECRET_ENV = 'GIGADRIVE_QUEUE_SIGNING_SECRET';\n\n/** What a delivery signature covers. */\nexport interface QueueSignatureInput {\n /** The environment's signing secret, `GIGADRIVE_QUEUE_SIGNING_SECRET` in a deployment. */\n secret: string;\n /** Queue name from `x-gigadrive-queue-name`. */\n queue: string;\n /** Message id from `x-gigadrive-queue-message-id`. */\n messageId: string;\n /** Delivery attempt from `x-gigadrive-queue-attempt`. */\n attempt: number;\n /** The raw request body, exactly as received. */\n body: Uint8Array | string;\n}\n\nconst hmacSha256Hex = async (secret: string, payload: string): Promise<string> => {\n const key = await crypto.subtle.importKey(\n 'raw',\n toArrayBuffer(utf8Encode(secret)),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n );\n return toHex(await crypto.subtle.sign('HMAC', key, toArrayBuffer(utf8Encode(payload))));\n};\n\nconst signedPayload = async (input: Omit<QueueSignatureInput, 'secret'>, timestamp: number): Promise<string> => {\n const body = typeof input.body === 'string' ? utf8Encode(input.body) : input.body;\n const bodyHash = toHex(await crypto.subtle.digest('SHA-256', toArrayBuffer(body)));\n return `${String(timestamp)}.${input.queue}.${input.messageId}.${String(input.attempt)}.${bodyHash}`;\n};\n\n/** Constant-time comparison of two equal-length hex strings. */\nconst safeEqual = (left: string, right: string): boolean => {\n if (left.length !== right.length) return false;\n let difference = 0;\n for (let index = 0; index < left.length; index++) difference |= left.charCodeAt(index) ^ right.charCodeAt(index);\n return difference === 0;\n};\n\n/**\n * Computes the `x-gigadrive-queue-signature` header value for a delivery.\n *\n * Gigadrive Network signs every push delivery this way. Use it to build\n * signed requests when you unit-test a queue handler.\n *\n * @param input - Secret and delivery fields to sign.\n * @param timestamp - Signing time in Unix milliseconds. Defaults to now.\n * @returns The header value, `t=<ms>,v1=<hex>`.\n *\n * @example\n * ```ts\n * const signature = await signQueueDelivery({ secret, queue: 'emails', messageId, attempt: 1, body });\n * await handler(new Request(url, { method: 'POST', body, headers: { 'x-gigadrive-queue-signature': signature, ... } }));\n * ```\n */\nexport async function signQueueDelivery(input: QueueSignatureInput, timestamp = Date.now()): Promise<string> {\n return `t=${String(timestamp)},v1=${await hmacSha256Hex(input.secret, await signedPayload(input, timestamp))}`;\n}\n\n/**\n * Verifies a push delivery's `x-gigadrive-queue-signature` header.\n *\n * Rejects a missing or malformed header, a signature made with another\n * secret or over different fields, and one signed more than five minutes\n * away from `now`. {@link Queue.handler} calls this for you.\n *\n * @param header - The header value, or `null` when absent.\n * @param input - Secret and the delivery fields the signature must cover.\n * @param now - The receiver's clock in Unix milliseconds. Defaults to now.\n * @returns `true` only for a valid, fresh signature.\n */\nexport async function verifyQueueSignature(\n header: string | null | undefined,\n input: QueueSignatureInput,\n now = Date.now()\n): Promise<boolean> {\n if (!header || !input.secret) return false;\n const fields = new Map<string, string>();\n for (const part of header.split(',')) {\n const separator = part.indexOf('=');\n if (separator > 0) fields.set(part.slice(0, separator).trim(), part.slice(separator + 1).trim());\n }\n const timestamp = Number(fields.get('t'));\n const signature = fields.get('v1');\n if (!Number.isSafeInteger(timestamp) || !signature || Math.abs(now - timestamp) > QUEUE_SIGNATURE_TOLERANCE_MS) {\n return false;\n }\n const expected = await hmacSha256Hex(input.secret, await signedPayload(input, timestamp));\n return safeEqual(signature.toLowerCase(), expected);\n}\n","import { ApiError, ConfigurationError } from '../errors';\nimport type {\n QueueInfo,\n QueueMessageInput,\n QueueMessageRecord,\n QueueSchedule,\n QueueScopeOptions,\n QueueSettings,\n QueuesResource,\n} from '../resources/queues';\nimport {\n base64ToBytes,\n bytesToBase64,\n durationToSeconds,\n type QueueDuration,\n utf8Decode,\n utf8Encode,\n} from './encoding';\nimport { NonRetryableError, RetryLaterError } from './errors';\nimport { QUEUE_SIGNATURE_HEADER, QUEUE_SIGNING_SECRET_ENV, verifyQueueSignature } from './signature';\n\n/** Headers the platform sets on a push delivery. */\nexport const QUEUE_DELIVERY_HEADERS = {\n name: 'x-gigadrive-queue-name',\n messageId: 'x-gigadrive-queue-message-id',\n attempt: 'x-gigadrive-queue-attempt',\n createdAt: 'x-gigadrive-queue-created-at',\n expiresAt: 'x-gigadrive-queue-expires-at',\n deadline: 'x-gigadrive-queue-deadline',\n groupKey: 'x-gigadrive-queue-group-key',\n deduplicationKey: 'x-gigadrive-queue-deduplication-key',\n deploymentId: 'x-gigadrive-queue-deployment-id',\n deploymentFallback: 'x-gigadrive-queue-deployment-fallback',\n signature: QUEUE_SIGNATURE_HEADER,\n} as const;\n\n/** Headers a push consumer sets on its response to steer redelivery. */\nexport const QUEUE_RESPONSE_HEADERS = {\n /** On a 2xx: deliver again after this many seconds without spending an attempt. */\n retryAfter: 'x-gigadrive-queue-retry-after',\n /** `dead-letter`: stop retrying now, whatever the status. */\n action: 'x-gigadrive-queue-action',\n /**\n * Reason recorded on the message. Read only together with `action:\n * dead-letter`; for any other failure the platform records `HTTP <status>`\n * and the first 512 bytes of the response body.\n */\n error: 'x-gigadrive-queue-error',\n} as const;\n\n/** Serializes payloads to message bodies and back. */\nexport interface QueueCodec<T> {\n encode(payload: T): { body: string; encoding: 'utf8' | 'base64'; contentType: string };\n decode(body: Uint8Array, contentType: string): T;\n}\n\nconst isJsonContentType = (contentType: string) => /^application\\/(?:[\\w.+-]+\\+)?json\\b/i.test(contentType);\n\n/**\n * The default codec. `Uint8Array` and `ArrayBuffer` payloads travel as raw\n * bytes (`application/octet-stream`); everything else as JSON. On the way\n * back, JSON content types are parsed, `text/*` becomes a string and\n * anything else a `Uint8Array`.\n */\nexport const defaultQueueCodec: QueueCodec<unknown> = {\n encode(payload) {\n if (payload instanceof Uint8Array || payload instanceof ArrayBuffer) {\n const bytes = payload instanceof Uint8Array ? payload : new Uint8Array(payload);\n return { body: bytesToBase64(bytes), encoding: 'base64', contentType: 'application/octet-stream' };\n }\n const json = JSON.stringify(payload);\n if (json === undefined) throw new TypeError('Queue payloads must be JSON-serializable or binary');\n return { body: json, encoding: 'utf8', contentType: 'application/json' };\n },\n decode(body, contentType) {\n if (isJsonContentType(contentType)) return body.length === 0 ? null : (JSON.parse(utf8Decode(body)) as unknown);\n if (/^text\\//i.test(contentType)) return utf8Decode(body);\n return body;\n },\n};\n\n/** Options for a {@link Queue} handle. */\nexport interface QueueOptions<T> extends QueueScopeOptions {\n /** Body serialization. Defaults to {@link defaultQueueCodec}. */\n codec?: QueueCodec<T>;\n /**\n * Validates every decoded payload before your handler sees it, for example\n * a Zod schema's `parse`. A payload that fails is dead-lettered, since\n * retrying cannot fix it.\n */\n validate?: (payload: unknown) => T;\n /** Create a pull queue with default settings on the first send to a new name. Default `true`. */\n autoCreate?: boolean;\n /** Push signing secret. Defaults to `GIGADRIVE_QUEUE_SIGNING_SECRET`, which deployments receive. */\n signingSecret?: string;\n /**\n * Accept push deliveries without a valid signature. Only for local\n * development: anyone who can reach the endpoint could then inject messages.\n */\n allowUnsigned?: boolean;\n}\n\n/** Options for one send. */\nexport interface QueueSendOptions {\n /** Deliver after this delay, such as `'10m'` or `90` seconds. Up to one year. */\n delay?: QueueDuration;\n /** Deliver at this time, up to one year ahead. Wins over {@link delay}. */\n at?: Date | string | number;\n /** Messages with the same key are delivered one at a time, in send order. */\n groupKey?: string;\n /** A repeat of this key within the queue's deduplication window is dropped and returns the first id. */\n deduplicationKey?: string;\n /** Deliver to this deployment instead of the environment's current one. */\n deploymentId?: string;\n /** Extra headers sent with push deliveries. */\n headers?: Record<string, string>;\n}\n\n/** A message that was accepted. */\nexport interface QueueSent {\n messageId: string;\n /** `true` when the deduplication key matched an earlier message, whose id this is. */\n deduplicated: boolean;\n /** When the message becomes deliverable. */\n deliverAt: Date;\n}\n\n/** Per-message outcome of {@link Queue.sendBatch}, in input order. */\nexport type QueueBatchSent = (QueueSent & { error?: undefined }) | { messageId: null; error: ApiError };\n\n/** What a handler knows about the message it is processing. */\nexport interface QueueMessageMeta {\n messageId: string;\n queue: string;\n /** 1 on the first delivery. Deferrals with {@link RetryLaterError} do not count. */\n attempt: number;\n createdAt: Date | null;\n groupKey: string | null;\n deduplicationKey: string | null;\n /** Push: the deployment serving this delivery. Pull: the deployment the message was pinned to, if any. */\n deploymentId: string | null;\n /** Message headers, as sent. */\n headers: Record<string, string>;\n}\n\n/** A leased message from {@link Queue.receive}. Settle it before its lease ends. */\nexport interface ReceivedQueueMessage<T> extends QueueMessageMeta {\n payload: T;\n receipt: string;\n leaseExpiresAt: Date | null;\n /** Deletes the message: processing succeeded. */\n ack(): Promise<void>;\n /** Releases the message for another attempt, after backoff or `delay`. */\n retry(options?: { delay?: QueueDuration; error?: string }): Promise<void>;\n /** Releases the message for later without spending an attempt. */\n defer(delay: QueueDuration): Promise<void>;\n /** Moves the message to the dead-letter list now. */\n deadLetter(reason?: string): Promise<void>;\n /** Extends the lease to `duration` from now. */\n extendLease(duration: QueueDuration): Promise<void>;\n}\n\n/** A function that processes one message. Throw to retry. */\nexport type QueueMessageHandler<T> = (payload: T, meta: QueueMessageMeta) => unknown;\n\nconst errorText = (error: unknown) => (error instanceof Error ? error.message : String(error)).slice(0, 2_000);\n\n/** Header-safe, single-line error text. */\nconst headerText = (text: string) =>\n text\n .replace(/[^\\x20-\\x7e]/g, ' ')\n .trim()\n .slice(0, 500);\n\nconst toDate = (value: string | null | undefined) => {\n if (!value) return null;\n const date = new Date(/^\\d+$/.test(value) ? Number(value) : value);\n return Number.isNaN(date.getTime()) ? null : date;\n};\n\nconst BATCH_LIMIT = 100;\n/** {@link Queue.consume} gathers acknowledgements this long into one batch request. */\nconst ACK_FLUSH_MS = 25;\n/** Pauses before each retry of a batch acknowledgement that failed in transit or with a 5xx or 429. */\nconst ACK_RETRY_DELAYS_MS = [200, 1_000];\n/** Shortest and longest pause after an empty receive in {@link Queue.consume}. */\nconst EMPTY_POLL_MIN_MS = 1_000;\nconst EMPTY_POLL_MAX_MS = 5_000;\n\n/** Resolves after `ms`, or as soon as `signal` aborts. */\nconst sleep = (ms: number, signal: AbortSignal | undefined) =>\n new Promise<void>((resolve) => {\n if (signal?.aborted) return resolve();\n const timer = setTimeout(done, ms);\n function done() {\n clearTimeout(timer);\n signal?.removeEventListener('abort', done);\n resolve();\n }\n signal?.addEventListener('abort', done, { once: true });\n });\n\n/**\n * A typed handle on one queue: send messages, receive and process them, or\n * serve them as a push consumer.\n *\n * Get one with the top-level {@link queue} function (zero-config inside a\n * deployment) or with `client.queues.queue(name)`.\n *\n * @typeParam T - The payload type.\n */\nexport class Queue<T = unknown> {\n private readonly codec: QueueCodec<T>;\n\n constructor(\n /** The queue name. */\n readonly name: string,\n private readonly resource: () => QueuesResource,\n private readonly options: QueueOptions<T> = {}\n ) {\n this.codec = options.codec ?? (defaultQueueCodec as QueueCodec<T>);\n }\n\n private get scope(): QueueScopeOptions {\n return { applicationId: this.options.applicationId, environment: this.options.environment };\n }\n\n private toMessage(payload: T, options: QueueSendOptions = {}): QueueMessageInput {\n const encoded = this.codec.encode(payload);\n const at = options.at === undefined ? undefined : new Date(options.at);\n if (at && Number.isNaN(at.getTime())) throw new ConfigurationError('Invalid `at` time for a queue message');\n return {\n body: encoded.body,\n encoding: encoded.encoding,\n contentType: encoded.contentType,\n ...(options.headers ? { headers: options.headers } : {}),\n ...(at ? { deliverAt: at.toISOString() } : {}),\n ...(options.delay !== undefined && !at ? { delaySeconds: durationToSeconds(options.delay) } : {}),\n ...(options.groupKey ? { groupKey: options.groupKey } : {}),\n ...(options.deduplicationKey ? { deduplicationKey: options.deduplicationKey } : {}),\n ...(options.deploymentId ? { deploymentId: options.deploymentId } : {}),\n };\n }\n\n private decode(body: Uint8Array, contentType: string): T {\n const decoded = this.codec.decode(body, contentType);\n return this.options.validate ? this.options.validate(decoded) : decoded;\n }\n\n /**\n * Sends one message.\n *\n * @example\n * ```ts\n * await emails.send({ to: 'jane@example.com' });\n * await emails.send({ to: 'jane@example.com' }, { delay: '10m' });\n * await emails.send(reminder, { at: new Date('2027-01-01T09:00:00Z'), deduplicationKey: `reminder:${id}` });\n * ```\n *\n * @throws {@link ApiError} when the message is refused, for example with\n * `code: 'backlog_full'` when your organization's queued storage is full.\n * Its `status` is 429 when sending again later may succeed and 400 when it\n * will not, so retry logic that keys on the status stays correct.\n */\n async send(payload: T, options?: QueueSendOptions): Promise<QueueSent> {\n const result = await this.resource().send(this.name, this.toMessage(payload, options), {\n ...this.scope,\n autoCreate: this.options.autoCreate,\n });\n if (result.messageId === null) throw new ApiError(result.error, result.retryable ? 429 : 400, result.code);\n return { messageId: result.messageId, deduplicated: result.deduplicated, deliverAt: new Date(result.deliverAt) };\n }\n\n /**\n * Sends many messages, 100 per request. Results come back in input order;\n * a refused message does not fail the rest; its error carries status 429\n * when it may be sent again later and 400 when it may not. Chunks are split by count only:\n * a request whose message bodies exceed 4 MiB in total is refused whole.\n */\n async sendBatch(messages: readonly ({ payload: T } & QueueSendOptions)[]): Promise<QueueBatchSent[]> {\n const results: QueueBatchSent[] = [];\n for (let index = 0; index < messages.length; index += BATCH_LIMIT) {\n const chunk = messages.slice(index, index + BATCH_LIMIT);\n const sent = await this.resource().sendBatch(\n this.name,\n chunk.map(({ payload, ...options }) => this.toMessage(payload, options)),\n { ...this.scope, autoCreate: this.options.autoCreate }\n );\n for (const result of sent) {\n results.push(\n result.messageId === null\n ? { messageId: null, error: new ApiError(result.error, result.retryable ? 429 : 400, result.code) }\n : { messageId: result.messageId, deduplicated: result.deduplicated, deliverAt: new Date(result.deliverAt) }\n );\n }\n }\n return results;\n }\n\n /** Deletes a message that has not been processed yet, such as a scheduled send. */\n async cancel(messageId: string): Promise<void> {\n await this.resource().deleteMessage(this.name, messageId, this.scope);\n }\n\n /**\n * Leases messages from a pull queue. Waits up to `wait` (at most 20\n * seconds) for the first message, then returns what is available.\n */\n async receive(\n options: {\n maxMessages?: number;\n wait?: QueueDuration;\n visibilityTimeout?: QueueDuration;\n signal?: AbortSignal;\n } = {}\n ): Promise<ReceivedQueueMessage<T>[]> {\n const records = await this.resource().receive(\n this.name,\n {\n maxMessages: options.maxMessages ?? 1,\n ...(options.wait === undefined ? {} : { waitSeconds: Math.min(durationToSeconds(options.wait), 20) }),\n ...(options.visibilityTimeout === undefined\n ? {}\n : { visibilityTimeoutSeconds: durationToSeconds(options.visibilityTimeout) }),\n },\n { ...this.scope, signal: options.signal }\n );\n return records.map((record) => this.toReceived(record));\n }\n\n private toReceived(record: QueueMessageRecord): ReceivedQueueMessage<T> {\n const resource = this.resource();\n const receipt = record.receipt ?? '';\n const bytes = record.encoding === 'base64' ? base64ToBytes(record.body) : utf8Encode(record.body);\n const nack = (request: { delaySeconds?: number; deadLetter?: boolean; countAttempt?: boolean; error?: string }) =>\n resource.nack(this.name, record.id, { receipt, ...request }, this.scope).then(() => undefined);\n let payload: T | undefined;\n let decodeError: unknown;\n try {\n payload = this.decode(bytes, record.contentType);\n } catch (error) {\n decodeError = error;\n }\n return {\n messageId: record.id,\n queue: this.name,\n attempt: record.attempts,\n createdAt: toDate(record.createdAt),\n groupKey: record.groupKey,\n deduplicationKey: record.deduplicationKey,\n deploymentId: record.deploymentId,\n headers: record.headers,\n receipt,\n leaseExpiresAt: toDate(record.leaseExpiresAt),\n get payload(): T {\n if (decodeError !== undefined) throw new NonRetryableError(`Undecodable payload: ${errorText(decodeError)}`);\n return payload as T;\n },\n ack: () => resource.ack(this.name, record.id, receipt, this.scope).then(() => undefined),\n retry: (options = {}) =>\n nack({\n ...(options.delay === undefined ? {} : { delaySeconds: durationToSeconds(options.delay) }),\n ...(options.error ? { error: options.error } : {}),\n }),\n defer: (delay) => nack({ delaySeconds: durationToSeconds(delay), countAttempt: false }),\n deadLetter: (reason) => nack({ deadLetter: true, ...(reason ? { error: reason } : {}) }),\n extendLease: (duration) =>\n resource.extend(this.name, record.id, receipt, durationToSeconds(duration), this.scope).then(() => undefined),\n };\n }\n\n /**\n * Receives and processes messages until `signal` aborts, or until the queue\n * is empty with `stopWhenEmpty`. A handler that returns acknowledges the\n * message; {@link RetryLaterError} defers it, {@link NonRetryableError}\n * dead-letters it, and any other error retries it with backoff.\n *\n * @example\n * ```ts\n * const controller = new AbortController();\n * await jobs.consume(async (job) => processJob(job), { maxMessages: 10, signal: controller.signal });\n * ```\n */\n async consume(\n handler: QueueMessageHandler<T>,\n options: {\n maxMessages?: number;\n wait?: QueueDuration;\n visibilityTimeout?: QueueDuration;\n signal?: AbortSignal;\n stopWhenEmpty?: boolean;\n /** Called when settling a message fails; the message is then redelivered after its lease. */\n onError?: (error: unknown) => void;\n } = {}\n ): Promise<void> {\n const wait = options.wait ?? (options.stopWhenEmpty ? 0 : 20);\n const waitMs = Math.min(durationToSeconds(wait), 20) * 1000;\n // Handlers that finish within ACK_FLUSH_MS of each other are acknowledged\n // in one request instead of one each.\n const pending: { message: ReceivedQueueMessage<T>; settled: (error?: unknown) => void }[] = [];\n let timer: ReturnType<typeof setTimeout> | undefined;\n /**\n * Acknowledges one batch; resolves with one error (or `undefined`) per\n * message. A failed request is retried, since a lost acknowledgement makes\n * finished work run again; on a retry, `message_not_found` means an earlier\n * attempt landed. An API without the batch route gets one request per message.\n */\n const sendAcks = async (batch: ReceivedQueueMessage<T>[]): Promise<(Error | undefined)[]> => {\n const resource = this.resource();\n for (let attempt = 0; ; attempt += 1) {\n try {\n const { results } = await resource.ackBatch(\n this.name,\n batch.map((message) => ({ messageId: message.messageId, receipt: message.receipt })),\n this.scope\n );\n return batch.map((_message, index) => {\n const result = results[index];\n if (result?.acknowledged || (attempt > 0 && result?.code === 'message_not_found')) return undefined;\n const code = result?.code ?? 'no_result';\n return new ApiError(\n `Acknowledging message failed: ${code}`,\n code === 'message_not_found' ? 404 : 409,\n code\n );\n });\n } catch (error) {\n if (error instanceof ApiError && error.status === 404 && error.code !== 'queue_not_found') {\n const settled = await Promise.allSettled(\n batch.map((message) => resource.ack(this.name, message.messageId, message.receipt, this.scope))\n );\n return settled.map((outcome) =>\n outcome.status === 'fulfilled'\n ? undefined\n : outcome.reason instanceof Error\n ? outcome.reason\n : new Error(errorText(outcome.reason))\n );\n }\n const retryable = !(error instanceof ApiError) || error.status >= 500 || error.status === 429;\n const delay = ACK_RETRY_DELAYS_MS[attempt];\n if (!retryable || delay === undefined) throw error;\n await sleep(delay, undefined);\n }\n }\n };\n const flush = () => {\n clearTimeout(timer);\n timer = undefined;\n const batch = pending.splice(0, BATCH_LIMIT);\n if (pending.length > 0) timer = setTimeout(flush, 0);\n if (batch.length === 0) return;\n sendAcks(batch.map(({ message }) => message))\n .then((errors) => batch.forEach(({ settled }, index) => settled(errors[index])))\n // Settling twice is a no-op, so a malformed answer still settles every message.\n .catch((error: unknown) => batch.forEach(({ settled }) => settled(error)));\n };\n const acknowledge = (message: ReceivedQueueMessage<T>) =>\n new Promise<void>((resolve, reject) => {\n pending.push({\n message,\n settled: (error) => {\n if (error === undefined) resolve();\n else reject(error instanceof Error ? error : new Error(errorText(error)));\n },\n });\n if (pending.length >= BATCH_LIMIT) flush();\n else timer ??= setTimeout(flush, ACK_FLUSH_MS);\n });\n while (!options.signal?.aborted) {\n let messages: ReceivedQueueMessage<T>[];\n const started = Date.now();\n try {\n messages = await this.receive({\n maxMessages: options.maxMessages ?? 10,\n wait,\n visibilityTimeout: options.visibilityTimeout,\n signal: options.signal,\n });\n } catch (error) {\n if (options.signal?.aborted) return;\n throw error;\n }\n if (messages.length === 0) {\n if (options.stopWhenEmpty) return;\n // An empty answer that came back early (a paused queue, or `wait: 0`)\n // would otherwise turn this loop into a tight polling loop.\n const remaining = Math.max(waitMs, EMPTY_POLL_MIN_MS) - (Date.now() - started);\n if (remaining > 0) await sleep(Math.min(remaining, EMPTY_POLL_MAX_MS), options.signal);\n continue;\n }\n await Promise.all(\n messages.map(async (message) => {\n let outcome: Promise<void>;\n try {\n await handler(message.payload, message);\n outcome = acknowledge(message);\n } catch (error) {\n outcome =\n error instanceof RetryLaterError\n ? message.defer(error.delaySeconds)\n : error instanceof NonRetryableError\n ? message.deadLetter(error.message)\n : message.retry({ error: errorText(error) });\n }\n // A failed settle is reported, never mistaken for a failed handler: the\n // message comes back when its lease ends, and is not retried or\n // dead-lettered for work that succeeded.\n try {\n await outcome;\n } catch (settleError) {\n options.onError?.(settleError);\n }\n })\n );\n }\n }\n\n /**\n * Builds a push consumer: a `(request: Request) => Promise<Response>`\n * function for the queue's consumer path, such as a Next.js route handler.\n *\n * It verifies the delivery signature, decodes the payload and calls\n * `handler`. Returning acknowledges the message. Throw\n * {@link RetryLaterError} to defer it without spending an attempt,\n * {@link NonRetryableError} to dead-letter it, or anything else to retry\n * with backoff.\n *\n * @example\n * ```ts\n * // app/api/queues/emails/route.ts\n * export const POST = emails.handler(async (email, { attempt }) => {\n * await sendEmail(email);\n * });\n * ```\n */\n handler(handler: QueueMessageHandler<T>): (request: Request) => Promise<Response> {\n return async (request) => {\n const header = (name: string) => request.headers.get(name);\n const messageId = header(QUEUE_DELIVERY_HEADERS.messageId);\n const queueName = header(QUEUE_DELIVERY_HEADERS.name);\n const attempt = Number(header(QUEUE_DELIVERY_HEADERS.attempt) ?? '1');\n if (!messageId || !queueName) {\n return Response.json({ error: 'Not a queue delivery' }, { status: 400 });\n }\n // The signature covers the queue name: refuse another queue's delivery, so a captured\n // request cannot be replayed here, and two queues sharing one route is caught early.\n if (queueName !== this.name) {\n console.error(`[gigadrive] Rejected a delivery for queue \"${queueName}\" at the handler of \"${this.name}\"`);\n return Response.json({ error: `This endpoint consumes queue \"${this.name}\"` }, { status: 400 });\n }\n const body = new Uint8Array(await request.arrayBuffer());\n\n if (!this.options.allowUnsigned) {\n const secret = this.options.signingSecret ?? readSigningSecret();\n if (!secret) {\n console.error(\n `[gigadrive] Rejected a queue delivery: ${QUEUE_SIGNING_SECRET_ENV} is not set. Deployments receive it automatically; set allowUnsigned for local development.`\n );\n return Response.json({ error: 'Queue signing secret is not configured' }, { status: 500 });\n }\n const valid = await verifyQueueSignature(header(QUEUE_SIGNATURE_HEADER), {\n secret,\n queue: queueName,\n messageId,\n attempt,\n body,\n });\n if (!valid) return Response.json({ error: 'Invalid queue signature' }, { status: 401 });\n }\n\n const meta: QueueMessageMeta = {\n messageId,\n queue: queueName,\n attempt,\n createdAt: toDate(header(QUEUE_DELIVERY_HEADERS.createdAt)),\n groupKey: header(QUEUE_DELIVERY_HEADERS.groupKey),\n deduplicationKey: header(QUEUE_DELIVERY_HEADERS.deduplicationKey),\n deploymentId: header(QUEUE_DELIVERY_HEADERS.deploymentId),\n headers: Object.fromEntries(\n [...request.headers.entries()].filter(([name]) => !name.startsWith('x-gigadrive-queue-'))\n ),\n };\n\n let payload: T;\n try {\n payload = this.decode(body, header('content-type') ?? 'application/octet-stream');\n } catch (error) {\n return deadLetterResponse(`Undecodable payload: ${errorText(error)}`);\n }\n\n try {\n await handler(payload, meta);\n return Response.json({ ok: true });\n } catch (error) {\n if (error instanceof RetryLaterError) {\n return Response.json(\n { ok: true, retryAfter: error.delaySeconds },\n { headers: { [QUEUE_RESPONSE_HEADERS.retryAfter]: String(error.delaySeconds) } }\n );\n }\n if (error instanceof NonRetryableError) return deadLetterResponse(error.message);\n console.error(`[gigadrive] Queue handler for \"${queueName}\" failed (attempt ${String(attempt)})`, error);\n // The dispatcher records the start of the body as the attempt's error.\n return Response.json({ error: errorText(error) }, { status: 500 });\n }\n };\n }\n\n /** Creates the queue, or applies `settings` to it. Use it to make a push queue from code. */\n async ensure(settings: QueueSettings = {}): Promise<QueueInfo> {\n return this.resource().ensure(this.name, settings, this.scope);\n }\n\n /** The queue's settings and live depth. */\n async info(): Promise<QueueInfo> {\n return this.resource().get(this.name, this.scope);\n }\n\n /** Stops deliveries until {@link resume}. Sends are still accepted. */\n async pause(): Promise<void> {\n await this.resource().pause(this.name, this.scope);\n }\n\n async resume(): Promise<void> {\n await this.resource().resume(this.name, this.scope);\n }\n\n /** Deletes every message, or only the dead letters. */\n async purge(scope: 'all' | 'dead' = 'all'): Promise<number> {\n return (await this.resource().purge(this.name, scope, this.scope)).purgedMessages;\n }\n\n /** Moves dead letters back for another round of attempts. */\n async redrive(messageIds?: string[]): Promise<number> {\n return (await this.resource().redrive(this.name, messageIds, this.scope)).redrivenMessages;\n }\n\n /**\n * Creates or updates a cron schedule that sends `payload` into this queue.\n *\n * @example\n * ```ts\n * await digests.schedule('weekday-digest', { cron: '0 8 * * MON-FRI', timezone: 'Europe/Berlin', payload: { kind: 'digest' } });\n * ```\n */\n async schedule(\n name: string,\n schedule: { cron: string; timezone?: string; payload?: T; headers?: Record<string, string>; enabled?: boolean }\n ): Promise<QueueSchedule> {\n const encoded = schedule.payload === undefined ? undefined : this.codec.encode(schedule.payload);\n if (encoded?.encoding === 'base64') throw new ConfigurationError('Scheduled payloads must be text or JSON');\n const input = {\n cron: schedule.cron,\n ...(schedule.timezone ? { timezone: schedule.timezone } : {}),\n ...(encoded ? { body: encoded.body, contentType: encoded.contentType } : {}),\n ...(schedule.headers ? { headers: schedule.headers } : {}),\n ...(schedule.enabled === undefined ? {} : { enabled: schedule.enabled }),\n };\n try {\n return await this.resource().createSchedule(this.name, name, input, this.scope);\n } catch (error) {\n if (error instanceof ApiError && error.code === 'schedule_exists') {\n return this.resource().updateSchedule(this.name, name, input, this.scope);\n }\n throw error;\n }\n }\n\n /** Deletes a schedule. */\n async unschedule(name: string): Promise<void> {\n await this.resource().deleteSchedule(this.name, name, this.scope);\n }\n}\n\nconst deadLetterResponse = (reason: string) =>\n Response.json(\n { error: reason },\n {\n status: 422,\n headers: { [QUEUE_RESPONSE_HEADERS.action]: 'dead-letter', [QUEUE_RESPONSE_HEADERS.error]: headerText(reason) },\n }\n );\n\n/** @internal */\nexport const readSigningSecret = (): string | undefined => {\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n return env?.[QUEUE_SIGNING_SECRET_ENV] || undefined;\n};\n","import type { HttpClient } from '../http-client';\nimport { Queue, type QueueOptions } from '../queues/queue';\nimport { BaseResource } from './base-resource';\nimport { resolveStorageApplicationId } from './storage-context';\n\n/** Live depth and lifetime counters of a queue. */\nexport interface QueueStats {\n /** Messages ready for delivery now. */\n ready: number;\n /** Messages delayed or scheduled for later. */\n scheduled: number;\n /** Messages held behind an earlier message of the same ordering group. */\n waiting: number;\n /** Messages being delivered or leased by a consumer. */\n inflight: number;\n /** Messages in the dead-letter list. */\n dead: number;\n /** Bytes held by the queue, dead letters included. */\n bytes: number;\n sent: number;\n acknowledged: number;\n failed: number;\n deadLettered: number;\n /** ISO 8601 time the oldest ready message became deliverable. */\n oldestReadyAt: string | null;\n /** ISO 8601 time of the next scheduled delivery. */\n nextScheduledAt: string | null;\n}\n\n/** A queue in one application environment. */\nexport interface QueueInfo {\n id: string;\n name: string;\n applicationId: string;\n environmentId: string;\n /** `push` queues POST each message to {@link consumerPath}; `pull` queues are drained with receive. */\n mode: 'push' | 'pull';\n consumerPath: string | null;\n visibilityTimeoutSeconds: number;\n retentionSeconds: number;\n maxAttempts: number;\n retryBackoffMinSeconds: number;\n retryBackoffMaxSeconds: number;\n deduplicationWindowSeconds: number;\n concurrency: number | null;\n rateLimit: { count: number; periodSeconds: number } | null;\n deadLetter: boolean;\n paused: boolean;\n pausedAt: string | null;\n /** How the queue was created: `config`, `api` or `auto` (first send). */\n source: string;\n createdAt: string;\n updatedAt: string;\n /** Present on list and get responses. */\n stats?: QueueStats;\n}\n\n/** Settings accepted when creating or updating a queue. Omitted settings keep their current value or default. */\nexport interface QueueSettings {\n /** Deployment-relative path that receives push deliveries. `null` makes the queue a pull queue. */\n consumerPath?: string | null;\n /** Push delivery timeout and default pull lease, 1 to 43,200 seconds. Default 60. */\n visibilityTimeoutSeconds?: number;\n /** How long an undelivered message is kept, 60 to 1,209,600 seconds. Default four days. */\n retentionSeconds?: number;\n /** Deliveries before a message is dead-lettered, 1 to 100. Default 10. */\n maxAttempts?: number;\n /** First retry delay. Default 5 seconds. */\n retryBackoffMinSeconds?: number;\n /** Longest retry delay. Default 900 seconds. */\n retryBackoffMaxSeconds?: number;\n /** How long a deduplication key is remembered, up to seven days. Default one day. */\n deduplicationWindowSeconds?: number;\n /** Most push deliveries in flight at once, 1 to 1,000. `null` restores the default of 100. */\n concurrency?: number | null;\n /** Most deliveries started per period. `null` removes the limit. */\n rateLimit?: { count: number; periodSeconds: number } | null;\n /** Keep exhausted messages in the dead-letter list. Default `true`. */\n deadLetter?: boolean;\n}\n\n/** Scopes a call to an application and environment. */\nexport interface QueueScopeOptions {\n /** Application UUID. Defaults to the client's application, `GIGADRIVE_APPLICATION_ID` in a deployment. */\n applicationId?: string;\n /** Environment slug or UUID. Deployed workloads omit it: their credential selects the environment. */\n environment?: string;\n}\n\n/** One message on the wire. Exactly one of `json` or `body` is sent. */\nexport interface QueueMessageInput {\n /** Any JSON value, sent with content type `application/json`. */\n json?: unknown;\n /** A string body, or base64 when {@link encoding} is `base64`. */\n body?: string;\n encoding?: 'utf8' | 'base64';\n contentType?: string;\n /**\n * Headers forwarded with push deliveries, up to 32. Reserved and refused:\n * `host`, `content-length`, `content-type`, `connection`,\n * `transfer-encoding`, `te`, `upgrade`, `keep-alive`, `proxy-*`,\n * `authorization`, `cookie`, `x-gigadrive-*`, `x-nebula-*`,\n * `x-substrate-*`, `x-vercel-*`, `x-forwarded-*`, `x-bunny-*`,\n * `x-real-ip`, `true-client-ip` and `forwarded`.\n */\n headers?: Record<string, string>;\n /** Deliver after this many seconds, up to one year. */\n delaySeconds?: number;\n /** ISO 8601 time to deliver at, up to one year ahead. Wins over {@link delaySeconds}. */\n deliverAt?: string;\n /** Messages with the same key are delivered one at a time, in send order. */\n groupKey?: string;\n /** A repeat of this key within the deduplication window is dropped and returns the first message's id. */\n deduplicationKey?: string;\n /** Deliver to this deployment instead of the environment's current one. */\n deploymentId?: string;\n}\n\n/** Outcome of one sent message. */\nexport type QueueSendResult =\n | {\n messageId: string;\n /** `true` when the deduplication key matched an earlier message, whose id is returned. */\n deduplicated: boolean;\n /** ISO 8601 time the message becomes deliverable. */\n deliverAt: string;\n error?: undefined;\n }\n | {\n messageId: null;\n error: string;\n /** Machine-readable reason, such as `backlog_full`. */\n code: string;\n /** Sending again later may succeed. */\n retryable: boolean;\n };\n\n/** A stored message, as listed, fetched or received. */\nexport interface QueueMessageRecord {\n id: string;\n state: 'ready' | 'scheduled' | 'waiting' | 'inflight' | 'dead';\n /** UTF-8 text or base64, per {@link encoding}. Listings cut it to a preview; see {@link bodyTruncated}. */\n body: string;\n encoding: 'utf8' | 'base64';\n bodyTruncated: boolean;\n contentType: string;\n headers: Record<string, string>;\n /** Deliveries made so far. */\n attempts: number;\n sizeBytes: number;\n groupKey: string | null;\n deduplicationKey: string | null;\n deploymentId: string | null;\n /** What sent the message, such as `schedule:daily-digest`. `null` for API sends. */\n source: string | null;\n lastError: string | null;\n createdAt: string;\n deliverAt: string;\n expiresAt: string;\n leaseExpiresAt: string | null;\n lastDeliveredAt: string | null;\n deadAt: string | null;\n /** Lease token, present on received messages. Pass it to ack, nack and extend. */\n receipt?: string;\n}\n\n/** A recurring send into a queue. */\nexport interface QueueSchedule {\n id: string;\n name: string;\n /** Five-field cron expression or macro such as `@hourly`. */\n cron: string;\n /** IANA time zone the expression is evaluated in. */\n timezone: string;\n body: string;\n contentType: string;\n headers: Record<string, string>;\n enabled: boolean;\n nextRunAt: string | null;\n lastRunAt: string | null;\n lastMessageId: string | null;\n lastError: string | null;\n /** `config` for schedules declared in `gigadrive.yaml`, else `api`. */\n source: string;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Fields of a schedule. Use `json` for a JSON body or `body` for text. */\nexport interface QueueScheduleInput {\n cron?: string;\n timezone?: string;\n json?: unknown;\n body?: string;\n contentType?: string;\n headers?: Record<string, string>;\n enabled?: boolean;\n}\n\n/** One message's outcome in a batch acknowledgement. */\nexport type QueueAckResult =\n | { messageId: string; acknowledged: true }\n | { messageId: string; acknowledged: false; code: 'message_not_found' | 'receipt_mismatch' };\n\n/** Outcome of a nack. */\nexport type QueueNackResult = { status: 'retrying'; deliverAt: string } | { status: 'dead' | 'dropped' };\n\n/**\n * Network Queues over REST: create and manage queues and schedules, send,\n * receive and acknowledge messages.\n *\n * For typed sending and consuming, prefer {@link QueuesResource.queue}, which\n * returns a {@link Queue} handle bound to one queue name.\n */\nexport class QueuesResource extends BaseResource {\n constructor(\n httpClient: HttpClient,\n private readonly defaultApplicationId?: string\n ) {\n super(httpClient);\n }\n\n /**\n * Returns a typed handle for one queue. Nothing is sent until you call a\n * method on it, and the queue does not need to exist: the first send\n * creates a pull queue with default settings.\n *\n * @typeParam T - The payload type sent and received through this queue.\n * @param name - Queue name, unique in the environment and case-sensitive.\n * @param options - Scope, codec and default send options.\n */\n queue<T = unknown>(name: string, options: QueueOptions<T> = {}): Queue<T> {\n return new Queue<T>(name, () => this, options);\n }\n\n private base(options: QueueScopeOptions | undefined): string {\n return `/applications/${encodeURIComponent(\n resolveStorageApplicationId(this.defaultApplicationId, options?.applicationId)\n )}/queues`;\n }\n\n private path(name: string, options: QueueScopeOptions | undefined, suffix = ''): string {\n return `${this.base(options)}/${encodeURIComponent(name)}${suffix}`;\n }\n\n /** Lists the environment's queues with their live depth. */\n async list(options?: QueueScopeOptions): Promise<{ items: QueueInfo[]; total: number }> {\n return this.httpClient.get(this.base(options), { query: { environment: options?.environment } });\n }\n\n /** Fetches one queue with its live depth. */\n async get(name: string, options?: QueueScopeOptions): Promise<QueueInfo> {\n return this.httpClient.get(this.path(name, options), { query: { environment: options?.environment } });\n }\n\n /**\n * Creates a queue. Fails with `queue_exists` when the name is taken; use\n * {@link ensure} for create-or-update.\n */\n async create(name: string, settings: QueueSettings = {}, options?: QueueScopeOptions): Promise<QueueInfo> {\n return this.httpClient.post(this.base(options), { name, environment: options?.environment, ...settings });\n }\n\n /** Creates the queue, or applies `settings` to the existing one. */\n async ensure(\n name: string,\n settings: QueueSettings = {},\n options?: QueueScopeOptions\n ): Promise<QueueInfo & { created: boolean }> {\n return this.httpClient.put(this.path(name, options), { environment: options?.environment, ...settings });\n }\n\n /** Changes a queue's settings. Messages already queued keep flowing. */\n async update(name: string, settings: QueueSettings, options?: QueueScopeOptions): Promise<QueueInfo> {\n return this.httpClient.patch(this.path(name, options), { environment: options?.environment, ...settings });\n }\n\n /** Deletes a queue, its messages and its schedules. */\n async delete(name: string, options?: QueueScopeOptions): Promise<{ purgedMessages: number }> {\n return this.httpClient.delete(this.path(name, options), { query: { environment: options?.environment } });\n }\n\n /** Stops deliveries. Sends are still accepted and wait until you resume. */\n async pause(name: string, options?: QueueScopeOptions): Promise<QueueInfo> {\n return this.httpClient.post(this.path(name, options, '/pause'), { environment: options?.environment });\n }\n\n /** Restarts deliveries after {@link pause}. */\n async resume(name: string, options?: QueueScopeOptions): Promise<QueueInfo> {\n return this.httpClient.post(this.path(name, options, '/resume'), { environment: options?.environment });\n }\n\n /** Deletes every message, or only the dead letters. */\n async purge(\n name: string,\n scope: 'all' | 'dead' = 'all',\n options?: QueueScopeOptions\n ): Promise<{ purgedMessages: number }> {\n return this.httpClient.post(this.path(name, options, '/purge'), { environment: options?.environment, scope });\n }\n\n /** Moves dead letters back to the queue with fresh attempts: all of them, or the given ids. */\n async redrive(\n name: string,\n messageIds?: string[],\n options?: QueueScopeOptions\n ): Promise<{ redrivenMessages: number }> {\n return this.httpClient.post(this.path(name, options, '/redrive'), {\n environment: options?.environment,\n ...(messageIds ? { messageIds } : {}),\n });\n }\n\n /**\n * Sends one message.\n *\n * @param autoCreate - Create a pull queue with default settings when the name is new. Default `true`.\n */\n async send(\n name: string,\n message: QueueMessageInput,\n options?: QueueScopeOptions & { autoCreate?: boolean }\n ): Promise<QueueSendResult> {\n return this.httpClient.post(this.path(name, options, '/messages'), {\n environment: options?.environment,\n autoCreate: options?.autoCreate,\n ...message,\n });\n }\n\n /**\n * Sends up to 100 messages in one request. Results come back in input\n * order; one rejected message does not fail the others.\n */\n async sendBatch(\n name: string,\n messages: QueueMessageInput[],\n options?: QueueScopeOptions & { autoCreate?: boolean }\n ): Promise<QueueSendResult[]> {\n const { results } = await this.httpClient.post<{ results: QueueSendResult[] }>(\n this.path(name, options, '/messages'),\n { environment: options?.environment, autoCreate: options?.autoCreate, messages }\n );\n return results;\n }\n\n /** Lists messages in one state without leasing them. Bodies are cut to a preview. */\n async listMessages(\n name: string,\n query: { state?: 'ready' | 'scheduled' | 'inflight' | 'dead'; offset?: number; limit?: number } = {},\n options?: QueueScopeOptions\n ): Promise<{ items: QueueMessageRecord[]; total: number }> {\n return this.httpClient.get(this.path(name, options, '/messages'), {\n query: { environment: options?.environment, ...query },\n });\n }\n\n /** Fetches one message without leasing it. */\n async getMessage(name: string, messageId: string, options?: QueueScopeOptions): Promise<QueueMessageRecord> {\n return this.httpClient.get(this.path(name, options, `/messages/${encodeURIComponent(messageId)}`), {\n query: { environment: options?.environment },\n });\n }\n\n /**\n * Cancels a message that has not been delivered yet, such as a scheduled\n * send you no longer want. A message being delivered or dead-lettered\n * answers 400 `invalid_request`; settle it from its consumer, or purge or\n * redrive dead letters.\n */\n async deleteMessage(name: string, messageId: string, options?: QueueScopeOptions): Promise<{ deleted: boolean }> {\n return this.httpClient.delete(this.path(name, options, `/messages/${encodeURIComponent(messageId)}`), {\n query: { environment: options?.environment },\n });\n }\n\n /**\n * Leases up to `maxMessages` messages from a pull queue, waiting up to\n * `waitSeconds` (at most 20) for the first one. Each must be acknowledged\n * with its receipt before the lease ends, or it is delivered again.\n */\n async receive(\n name: string,\n request: { maxMessages?: number; waitSeconds?: number; visibilityTimeoutSeconds?: number } = {},\n options?: QueueScopeOptions & { signal?: AbortSignal }\n ): Promise<QueueMessageRecord[]> {\n const { messages } = await this.httpClient.post<{ messages: QueueMessageRecord[] }>(\n this.path(name, options, '/messages/receive'),\n { environment: options?.environment, ...request },\n { signal: options?.signal }\n );\n return messages;\n }\n\n /** Acknowledges a received message, deleting it. */\n async ack(\n name: string,\n messageId: string,\n receipt: string,\n options?: QueueScopeOptions\n ): Promise<{ acknowledged: boolean }> {\n return this.httpClient.post(this.path(name, options, `/messages/${encodeURIComponent(messageId)}/ack`), {\n environment: options?.environment,\n receipt,\n });\n }\n\n /**\n * Acknowledges up to 100 received messages in one request. Each settles on\n * its own: `results` reports, in order, which were acknowledged and why any\n * were not (`message_not_found`, `receipt_mismatch`). A batch counts one\n * operation per started ten acknowledged messages.\n */\n async ackBatch(\n name: string,\n messages: { messageId: string; receipt: string }[],\n options?: QueueScopeOptions\n ): Promise<{ results: QueueAckResult[] }> {\n return this.httpClient.post(this.path(name, options, '/messages/ack'), {\n environment: options?.environment,\n messages,\n });\n }\n\n /**\n * Releases a received message: retry with backoff (or after `delaySeconds`),\n * or dead-letter it now with `deadLetter: true`. `countAttempt: false`\n * reschedules without spending an attempt.\n */\n async nack(\n name: string,\n messageId: string,\n request: { receipt: string; delaySeconds?: number; deadLetter?: boolean; countAttempt?: boolean; error?: string },\n options?: QueueScopeOptions\n ): Promise<QueueNackResult> {\n return this.httpClient.post(this.path(name, options, `/messages/${encodeURIComponent(messageId)}/nack`), {\n environment: options?.environment,\n ...request,\n });\n }\n\n /** Extends a received message's lease to `visibilityTimeoutSeconds` from now. */\n async extend(\n name: string,\n messageId: string,\n receipt: string,\n visibilityTimeoutSeconds: number,\n options?: QueueScopeOptions\n ): Promise<{ leaseExpiresAt: string }> {\n return this.httpClient.post(this.path(name, options, `/messages/${encodeURIComponent(messageId)}/extend`), {\n environment: options?.environment,\n receipt,\n visibilityTimeoutSeconds,\n });\n }\n\n /** Lists a queue's schedules. */\n async listSchedules(name: string, options?: QueueScopeOptions): Promise<{ items: QueueSchedule[]; total: number }> {\n return this.httpClient.get(this.path(name, options, '/schedules'), {\n query: { environment: options?.environment },\n });\n }\n\n /**\n * Creates a schedule that sends a message into the queue on a cron.\n *\n * @example\n * ```ts\n * await client.queues.createSchedule('emails', 'daily-digest', {\n * cron: '0 8 * * MON-FRI',\n * timezone: 'Europe/Berlin',\n * json: { kind: 'digest' },\n * });\n * ```\n */\n async createSchedule(\n name: string,\n schedule: string,\n input: QueueScheduleInput & { cron: string },\n options?: QueueScopeOptions\n ): Promise<QueueSchedule> {\n return this.httpClient.post(this.path(name, options, '/schedules'), {\n environment: options?.environment,\n name: schedule,\n ...input,\n });\n }\n\n /** Changes a schedule. Its next run is recomputed when the cron or time zone changes. */\n async updateSchedule(\n name: string,\n schedule: string,\n input: QueueScheduleInput,\n options?: QueueScopeOptions\n ): Promise<QueueSchedule> {\n return this.httpClient.patch(this.path(name, options, `/schedules/${encodeURIComponent(schedule)}`), {\n environment: options?.environment,\n ...input,\n });\n }\n\n /** Deletes a schedule. Messages it already sent stay queued. */\n async deleteSchedule(name: string, schedule: string, options?: QueueScopeOptions): Promise<{ deleted: boolean }> {\n return this.httpClient.delete(this.path(name, options, `/schedules/${encodeURIComponent(schedule)}`), {\n query: { environment: options?.environment },\n });\n }\n\n /** Sends the schedule's message now, outside its cron. */\n async triggerSchedule(name: string, schedule: string, options?: QueueScopeOptions): Promise<{ messageId: string }> {\n return this.httpClient.post(this.path(name, options, `/schedules/${encodeURIComponent(schedule)}/trigger`), {\n environment: options?.environment,\n });\n }\n}\n","import { BaseResource } from './base-resource';\n\n/** Input for minting a routing-only sticky session URL. */\nexport interface CreateStickySessionUrlInput {\n /** Opaque application key shared by callers that must reach the same instance. */\n key: string;\n /** Relative deployment route, including any application query parameters. */\n endpoint: string;\n /** HTTP method used to resolve the target route. Defaults to `GET`. */\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'PATCH';\n /** URL lifetime in seconds. Defaults to four hours; accepted range is 60–86,400. */\n expiresInSeconds?: number;\n}\n\n/** A signed sticky URL and its absolute ISO 8601 expiration time. */\nexport interface CreateStickySessionUrlResult {\n url: string;\n expiresAt: string;\n}\n\n/**\n * Creates protocol-independent sticky routing URLs for MicroVM functions.\n *\n * The URL selects an instance but does not authenticate an application user or\n * store application state. Reusing the same key and unexpired URL keeps HTTP,\n * streaming, and WebSocket traffic on the same function instance.\n */\nexport class StickySessionsResource extends BaseResource {\n /**\n * Mints a signed URL for an opaque application key.\n *\n * Deployed Gigadrive workloads can call this with a zero-config\n * `GigadriveClient`; the platform injects `GIGADRIVE_CLIENT_ID` and\n * `GIGADRIVE_CLIENT_SECRET` using the SDK's existing credential chain.\n */\n async createUrl(input: CreateStickySessionUrlInput): Promise<CreateStickySessionUrlResult> {\n return this.httpClient.post('/sticky-sessions/urls', {\n ...input,\n method: input.method ?? 'GET',\n });\n }\n}\n","import { readEnv, resolveCredentialProvider } from './auth/credential-provider';\nimport { TokenManager } from './auth/token-manager';\nimport { HttpClient } from './http-client';\nimport { AiGatewayResource } from './resources/ai-gateway';\nimport { ApiKeysResource } from './resources/api-keys';\nimport type { ApplicationStorageResource } from './resources/application-storage';\nimport { ApplicationsResource } from './resources/applications';\nimport { DeploymentsResource } from './resources/deployments';\nimport { ImageOptimizationResource } from './resources/image-optimization';\nimport { OrganizationsResource } from './resources/organizations';\nimport { QueuesResource } from './resources/queues';\nimport { StickySessionsResource } from './resources/sticky-sessions';\n\nconst DEFAULT_BASE_URL = 'https://api.gigadrive.network';\n\n/**\n * Configuration for the {@link GigadriveClient}.\n *\n * Credentials are resolved in priority order: explicit config fields first,\n * then environment variables. See {@link GigadriveClient} for the full\n * resolution chain.\n */\nexport interface GigadriveClientConfig {\n /**\n * Default application UUID for context-bound storage calls.\n *\n * Falls back to `GIGADRIVE_APPLICATION_ID`, which the platform injects into\n * deployed workloads. Explicit application IDs supplied to compatibility\n * overloads take precedence over this value.\n */\n applicationId?: string;\n\n /**\n * OAuth2 client ID (the API key ID from the Gigadrive dashboard).\n * Used for both client-credentials and refresh-token flows.\n * Falls back to the `GIGADRIVE_CLIENT_ID` environment variable.\n */\n clientId?: string;\n\n /**\n * OAuth2 client secret (the API key secret from the Gigadrive dashboard).\n * Used together with {@link clientId} for the client-credentials grant.\n * Falls back to the `GIGADRIVE_CLIENT_SECRET` environment variable.\n */\n clientSecret?: string;\n\n /**\n * A pre-obtained bearer token (either an IDP or Network token).\n * When set, the SDK sends this token directly without any OAuth exchange.\n * The token is never refreshed — if it expires, requests will fail.\n * Falls back to the `GIGADRIVE_BEARER_TOKEN` environment variable.\n */\n bearerToken?: string;\n\n /**\n * An IDP refresh token for automatic access-token renewal. Used together\n * with {@link clientId}. The SDK will exchange this for short-lived access\n * tokens and handle refresh-token rotation automatically.\n * Falls back to the `GIGADRIVE_REFRESH_TOKEN` environment variable.\n */\n refreshToken?: string;\n\n /**\n * The IDP issuer URL used for OIDC discovery (fetching the\n * `.well-known/openid-configuration`). Only needed for refresh-token and\n * authorization-code flows.\n * Falls back to `GIGADRIVE_IDP_ISSUER_URL`, default: `https://idp.gigadrive.de`.\n */\n idpIssuerUrl?: string;\n\n /**\n * Callback for the OAuth2 authorization code flow with PKCE. The SDK\n * builds the authorization URL and passes it to this callback. Your code\n * must present the URL to the user (e.g. open a browser), then return\n * either the full redirect URL or just the authorization code.\n *\n * Requires {@link clientId} to be set.\n *\n * @param url - The authorization URL the user should visit.\n * @returns The full redirect URL (including `?code=...&state=...`) or the\n * bare authorization code.\n *\n * @example\n * ```ts\n * const client = new GigadriveClient({\n * clientId: 'my-app',\n * onAuthorizationUrl: async (url) => {\n * console.log('Visit:', url);\n * return await readline.question('Paste the redirect URL: ');\n * },\n * });\n * ```\n */\n onAuthorizationUrl?: (url: string) => Promise<string>;\n\n /**\n * Redirect URI for the authorization code flow.\n * Default: `urn:ietf:wg:oauth:2.0:oob` (out-of-band / manual copy-paste).\n */\n redirectUri?: string;\n\n /**\n * OAuth scopes to request during the authorization-code flow, in addition to\n * the default identity scopes (`openid profile email offline_access`). Use\n * this to request API capability scopes (e.g. `network:applications:read`) so\n * the resulting token can call the corresponding endpoints.\n */\n scopes?: string[];\n\n /**\n * Base URL of the Gigadrive Network API.\n * Falls back to `GIGADRIVE_API_BASE_URL`, default: `https://api.gigadrive.network`.\n */\n baseUrl?: string;\n\n /**\n * Custom `fetch` implementation. Useful for testing (injectable mock) or\n * non-standard runtimes like Cloudflare Workers that provide their own\n * `fetch`. Defaults to `globalThis.fetch`.\n */\n fetch?: typeof globalThis.fetch;\n}\n\n/**\n * The main entry point for the Gigadrive Network SDK.\n *\n * Create an instance to interact with organizations, applications, deployments,\n * storage, and the AI gateway. Authentication is handled automatically —\n * tokens are obtained, cached, and refreshed behind the scenes.\n *\n * ## Credential resolution order\n *\n * The client resolves credentials in the following order, using the first\n * match it finds:\n *\n * 1. Explicit `bearerToken` in config\n * 2. Explicit `clientId` + `clientSecret` in config\n * 3. Explicit `clientId` + `refreshToken` in config\n * 4. Explicit `clientId` + `onAuthorizationUrl` callback in config\n * 5. `GIGADRIVE_BEARER_TOKEN` environment variable\n * 6. `GIGADRIVE_CLIENT_ID` + `GIGADRIVE_CLIENT_SECRET` environment variables\n * 7. `GIGADRIVE_CLIENT_ID` + `GIGADRIVE_REFRESH_TOKEN` environment variables\n *\n * If no credentials are found, the constructor throws an\n * {@link AuthenticationError}.\n *\n * @example\n * ```ts\n * // Credentials auto-detected from environment variables\n * const client = new GigadriveClient();\n *\n * // Explicit API key (client credentials)\n * const client = new GigadriveClient({\n * clientId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',\n * clientSecret: 'sk_live_...',\n * });\n *\n * // Pre-obtained bearer token\n * const client = new GigadriveClient({ bearerToken: 'eyJ...' });\n *\n * // IDP refresh token — access tokens are renewed automatically\n * const client = new GigadriveClient({\n * clientId: 'my-app',\n * refreshToken: 'rt_...',\n * });\n *\n * // Use the client\n * const orgs = await client.organizations.list();\n * const deployment = await client.deployments.create({ applicationId: 'app-1' });\n * ```\n *\n * @throws {@link AuthenticationError} if no valid credentials are found.\n */\nexport class GigadriveClient {\n /** Organization management (list, environment variables). */\n readonly organizations: OrganizationsResource;\n /** Application management (list, environment variables, storage). */\n readonly applications: ApplicationsResource;\n /**\n * Context-bound file storage operations.\n *\n * Deployed workloads receive their application context through\n * `GIGADRIVE_APPLICATION_ID`; management clients can set\n * {@link GigadriveClientConfig.applicationId}. This is the same resource as\n * {@link applications}.storage.\n */\n readonly storage: ApplicationStorageResource;\n /** Deployment lifecycle (create, upload, status, logs). */\n readonly deployments: DeploymentsResource;\n /** AI Gateway — OpenAI-compatible chat completions and model listing. */\n readonly aiGateway: AiGatewayResource;\n /** Application-scoped API key management (create, list, revoke). */\n readonly apiKeys: ApiKeysResource;\n /** Signed URLs that keep related requests on one MicroVM instance. */\n readonly stickySessions: StickySessionsResource;\n /** Managed image optimization inspection and cache purge operations. */\n readonly imageOptimization: ImageOptimizationResource;\n /**\n * Network Queues: manage queues and schedules, send, receive and\n * acknowledge messages. `client.queues.queue<T>(name)` returns a typed\n * handle bound to one queue.\n */\n readonly queues: QueuesResource;\n\n constructor(config: GigadriveClientConfig = {}) {\n const baseUrl = config.baseUrl ?? readEnv('GIGADRIVE_API_BASE_URL') ?? DEFAULT_BASE_URL;\n const applicationId = config.applicationId ?? readEnv('GIGADRIVE_APPLICATION_ID');\n // Bind the default fetch to globalThis so it can be invoked as a method on\n // the HTTP client without throwing \"Illegal invocation\" in some runtimes.\n const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n\n const credentialProvider = resolveCredentialProvider({ ...config, baseUrl, fetch: fetchFn });\n const tokenManager = new TokenManager(credentialProvider);\n const httpClient = new HttpClient(baseUrl, tokenManager, fetchFn);\n\n this.organizations = new OrganizationsResource(httpClient);\n this.applications = new ApplicationsResource(httpClient, applicationId);\n this.storage = this.applications.storage;\n this.deployments = new DeploymentsResource(httpClient);\n this.aiGateway = new AiGatewayResource(httpClient);\n this.apiKeys = new ApiKeysResource(httpClient);\n this.stickySessions = new StickySessionsResource(httpClient);\n this.imageOptimization = new ImageOptimizationResource(httpClient);\n this.queues = new QueuesResource(httpClient, applicationId);\n }\n}\n","import type { Paginated } from './http-client';\n\n/**\n * Lazily iterate every item across all pages of a cursor-paginated endpoint.\n * Pass a function that fetches one page for a given cursor; iteration stops when\n * the API stops returning a `nextCursor`.\n *\n * @typeParam T - The item type.\n * @param fetchPage - Fetches a single page for the given cursor (`undefined` for the first page).\n *\n * @example\n * ```ts\n * for await (const object of paginate((cursor) =>\n * client.applications.storage.objects.list('app-id', 'bucket-id', { cursor }),\n * )) {\n * console.log(object.key);\n * }\n * ```\n */\nexport async function* paginate<T>(\n fetchPage: (cursor: string | undefined) => Promise<Paginated<T>>\n): AsyncGenerator<T> {\n let cursor: string | undefined;\n do {\n const page = await fetchPage(cursor);\n for (const item of page.items) {\n yield item;\n }\n cursor = page.nextCursor;\n } while (cursor);\n}\n","import { GigadriveClient } from '../client';\nimport type { QueuesResource } from '../resources/queues';\nimport { Queue, type QueueOptions } from './queue';\n\nlet defaultClient: GigadriveClient | undefined;\n\n/**\n * The resource behind top-level {@link queue} handles: a zero-config\n * {@link GigadriveClient}, created on first use so that a push handler,\n * which needs no API access, works without credentials.\n *\n * @internal\n */\nexport const defaultQueuesResource = (): QueuesResource => {\n defaultClient ??= new GigadriveClient();\n return defaultClient.queues;\n};\n\n/**\n * Returns a typed handle for a Gigadrive Network queue.\n *\n * Inside a deployment this needs no configuration: the platform injects the\n * credentials and the queue signing secret. Elsewhere, set\n * `GIGADRIVE_CLIENT_ID`, `GIGADRIVE_CLIENT_SECRET` and\n * `GIGADRIVE_APPLICATION_ID`, pass `environment`, or use\n * `client.queues.queue(name)` on a client you configure.\n *\n * @typeParam T - The payload type sent and received through this queue.\n * @param name - Queue name, unique in the environment and case-sensitive.\n *\n * @example\n * ```ts\n * import { queue } from '@gigadrive/sdk';\n *\n * export const emails = queue<{ to: string }>('emails');\n *\n * await emails.send({ to: 'jane@example.com' }, { delay: '10m' });\n *\n * // app/api/queues/emails/route.ts\n * export const POST = emails.handler(async (email) => sendWelcomeEmail(email.to));\n * ```\n */\nexport function queue<T = unknown>(\n name: string,\n options: QueueOptions<T> & { client?: GigadriveClient } = {}\n): Queue<T> {\n const { client, ...queueOptions } = options;\n return new Queue<T>(name, () => client?.queues ?? defaultQueuesResource(), queueOptions);\n}\n","import type { GigadriveClient } from '../client';\nimport { ApiError } from '../errors';\nimport type { QueueMessageInput, QueueScopeOptions, QueueSettings, QueuesResource } from '../resources/queues';\nimport { defaultQueuesResource } from './default-client';\nimport { base64ToBytes, bytesToBase64, toArrayBuffer, toHex, utf8Decode, utf8Encode } from './encoding';\nimport { QUEUE_DELIVERY_HEADERS, QUEUE_RESPONSE_HEADERS, readSigningSecret } from './queue';\nimport { QUEUE_SIGNATURE_HEADER, verifyQueueSignature } from './signature';\n\n/** Where the Workflow SDK serves its queue handler. */\nexport const WORKFLOW_CONSUMER_PATH = '/.well-known/workflow/v1/flow';\n\n/** Carries the Workflow SDK's queue name, which Gigadrive queue names cannot always hold. */\nexport const WORKFLOW_QUEUE_NAME_HEADER = 'x-workflow-queue-name';\n\nconst WORKFLOW_PREFIX = /^__(?:[a-z][a-z0-9]*_)?wkf_workflow_/;\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n/** Headers the API refuses on a message (`limits.ts` in the network repo); dropped here instead of failing the send. */\nconst RESERVED_HEADER =\n /^(host|content-length|content-type|connection|transfer-encoding|te|upgrade|keep-alive|proxy-.*|authorization|cookie|x-gigadrive-.*|x-nebula-.*|x-substrate-.*|x-vercel-.*|x-forwarded-.*|x-bunny-.*|x-real-ip|true-client-ip|forwarded)$/i;\n\n/** Options of a Workflow SDK queue send, as the Workflow runtime passes them. */\nexport interface WorkflowQueueSendOptions {\n deploymentId?: string;\n idempotencyKey?: string;\n headers?: Record<string, string>;\n delaySeconds?: number;\n specVersion?: number;\n region?: string;\n}\n\n/** What the Workflow runtime's handler learns about a delivery. */\nexport interface WorkflowQueueHandlerMeta<TMessageId extends string> {\n attempt: number;\n queueName: string;\n messageId: TMessageId;\n requestId?: string;\n}\n\n/**\n * The queue half of a Workflow SDK World, backed by Gigadrive Network\n * queues. It matches the World `Queue` interface of `@workflow/world`.\n */\nexport interface WorkflowQueue<TMessageId extends string = string> {\n getDeploymentId(): Promise<string>;\n queue(\n queueName: string,\n message: unknown,\n opts?: WorkflowQueueSendOptions\n ): Promise<{ messageId: TMessageId | null }>;\n queueBatch(\n queueName: string,\n messages: readonly { message: unknown; opts?: WorkflowQueueSendOptions }[]\n ): Promise<\n ({ messageId: TMessageId | null; error?: undefined } | { messageId: null; error: string; retryable: boolean })[]\n >;\n createQueueHandler(\n queueNamePrefix: string,\n handler: (message: unknown, meta: WorkflowQueueHandlerMeta<TMessageId>) => Promise<unknown>\n ): (request: Request) => Promise<Response>;\n}\n\n/** Options for {@link createWorkflowQueue}. */\nexport interface WorkflowQueueOptions extends QueueScopeOptions {\n /** Client for API calls. Defaults to a zero-config client, which works inside a deployment. */\n client?: GigadriveClient;\n /** Path of the Workflow handler on your deployment. Default `/.well-known/workflow/v1/flow`. */\n consumerPath?: string;\n /** Deployment id the Workflow runtime stamps on runs. Defaults to `GIGADRIVE_DEPLOYMENT_ID`. */\n deploymentId?: string;\n /**\n * Settings for the backing queue. Without them the queue is created once\n * with 100 attempts (the Workflow runtime gives up earlier on its own) and a\n * 900 second delivery timeout, and later changes made in the console are\n * kept. With them, every cold start applies them, so declare them here or\n * in the console, not both.\n */\n queueSettings?: Omit<QueueSettings, 'consumerPath'>;\n /** Push signing secret. Defaults to `GIGADRIVE_QUEUE_SIGNING_SECRET`. */\n signingSecret?: string;\n /** Accept unsigned deliveries. Local development only. */\n allowUnsigned?: boolean;\n}\n\n/**\n * JSON that keeps `Uint8Array` values, in the same tagged shape the\n * Workflow SDK's local World uses.\n */\nconst encodeWorkflowMessage = (message: unknown): string =>\n JSON.stringify(message, (_key, value: unknown) =>\n value instanceof Uint8Array ? { __type: 'Uint8Array', data: bytesToBase64(value) } : value\n );\n\nconst decodeWorkflowMessage = (text: string): unknown =>\n JSON.parse(text, (_key, value: unknown) => {\n if (\n typeof value === 'object' &&\n value !== null &&\n (value as { __type?: unknown }).__type === 'Uint8Array' &&\n typeof (value as { data?: unknown }).data === 'string'\n ) {\n return base64ToBytes((value as { data: string }).data);\n }\n return value;\n });\n\nconst readEnv = (name: string): string | undefined =>\n (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.[name] || undefined;\n\n/** Keys longer than a deduplication key allows are hashed, keeping them stable across retries. */\nconst deduplicationKeyFor = async (idempotencyKey: string): Promise<string> =>\n idempotencyKey.length <= 256\n ? idempotencyKey\n : `wkf:sha256:${toHex(await crypto.subtle.digest('SHA-256', toArrayBuffer(utf8Encode(idempotencyKey))))}`;\n\n/**\n * Runs the [Workflow SDK](https://workflow-sdk.dev) on Gigadrive Network\n * queues: returns the World `Queue` implementation (`getDeploymentId`,\n * `queue`, `queueBatch`, `createQueueHandler`).\n *\n * Every Workflow queue with the same prefix shares one push queue named\n * after the prefix (such as `__wkf_workflow_`), created on first use and\n * delivering to `/.well-known/workflow/v1/flow`. Sleeps and step timeouts\n * reschedule the message without spending attempts, every message is pinned\n * to the deployment that sent it (or the one the runtime names), and\n * idempotency keys become deduplication keys.\n *\n * @typeParam TMessageId - Pass the World's `MessageId` type so the result\n * satisfies `@workflow/world`'s branded message ids.\n *\n * @example\n * ```ts\n * import type { MessageId, World } from '@workflow/world';\n * import { createWorkflowQueue } from '@gigadrive/sdk';\n *\n * export const world: World = { ...createWorkflowQueue<MessageId>(), ...storage, ...streamer };\n * ```\n */\nexport function createWorkflowQueue<TMessageId extends string = string>(\n options: WorkflowQueueOptions = {}\n): WorkflowQueue<TMessageId> {\n const resource = (): QueuesResource => options.client?.queues ?? defaultQueuesResource();\n const scope: QueueScopeOptions = { applicationId: options.applicationId, environment: options.environment };\n const ensured = new Map<string, Promise<unknown>>();\n\n /** One physical queue per Workflow prefix, created or updated once per process. */\n const physicalQueue = async (queueName: string): Promise<string> => {\n const prefix = WORKFLOW_PREFIX.exec(queueName)?.[0];\n if (!prefix) throw new Error(`\"${queueName}\" is not a Workflow SDK queue name`);\n let ready = ensured.get(prefix);\n if (!ready) {\n const consumerPath = options.consumerPath ?? WORKFLOW_CONSUMER_PATH;\n ready = options.queueSettings\n ? resource().ensure(prefix, { ...options.queueSettings, consumerPath }, scope)\n : // Create-only: a queue that exists keeps the settings someone gave it in the console.\n resource()\n .create(prefix, { maxAttempts: 100, visibilityTimeoutSeconds: 900, deadLetter: true, consumerPath }, scope)\n .catch((error: unknown) => {\n if (error instanceof ApiError && error.code === 'queue_exists') return undefined;\n throw error;\n });\n ensured.set(prefix, ready);\n ready.catch(() => ensured.delete(prefix));\n }\n await ready;\n return prefix;\n };\n\n const toMessage = async (\n queueName: string,\n message: unknown,\n opts: WorkflowQueueSendOptions = {}\n ): Promise<QueueMessageInput> => {\n const headers = Object.fromEntries(\n Object.entries(opts.headers ?? {}).filter(([name]) => !RESERVED_HEADER.test(name))\n );\n headers[WORKFLOW_QUEUE_NAME_HEADER] = queueName;\n // The runtime omits the deployment on step dispatches and continuations: they belong to the\n // deployment sending them, so a promotion never moves an in-flight run to new code.\n const pin = opts.deploymentId ?? options.deploymentId ?? readEnv('GIGADRIVE_DEPLOYMENT_ID');\n return {\n body: encodeWorkflowMessage(message),\n contentType: 'application/json',\n headers,\n ...(opts.delaySeconds && opts.delaySeconds > 0 ? { delaySeconds: Math.ceil(opts.delaySeconds) } : {}),\n ...(opts.idempotencyKey ? { deduplicationKey: await deduplicationKeyFor(opts.idempotencyKey) } : {}),\n ...(pin && UUID.test(pin) ? { deploymentId: pin } : {}),\n };\n };\n\n return {\n getDeploymentId: () => Promise.resolve(options.deploymentId ?? readEnv('GIGADRIVE_DEPLOYMENT_ID') ?? 'local'),\n\n async queue(queueName, message, opts) {\n const physical = await physicalQueue(queueName);\n const result = await resource().send(physical, await toMessage(queueName, message, opts), {\n ...scope,\n autoCreate: false,\n });\n if (result.messageId === null) throw new Error(`Workflow message was refused: ${result.error}`);\n return { messageId: result.messageId as TMessageId };\n },\n\n async queueBatch(queueName, messages) {\n const physical = await physicalQueue(queueName);\n const results: Awaited<ReturnType<WorkflowQueue<TMessageId>['queueBatch']>> = [];\n for (let index = 0; index < messages.length; index += 100) {\n const chunk = messages.slice(index, index + 100);\n const sent = await resource().sendBatch(\n physical,\n await Promise.all(chunk.map(({ message, opts }) => toMessage(queueName, message, opts))),\n { ...scope, autoCreate: false }\n );\n for (const result of sent) {\n results.push(\n result.messageId === null\n ? { messageId: null, error: result.error, retryable: result.retryable }\n : { messageId: result.messageId as TMessageId }\n );\n }\n }\n return results;\n },\n\n createQueueHandler(queueNamePrefix, handler) {\n return async (request) => {\n const messageId = request.headers.get(QUEUE_DELIVERY_HEADERS.messageId);\n const physicalName = request.headers.get(QUEUE_DELIVERY_HEADERS.name);\n const attempt = Number(request.headers.get(QUEUE_DELIVERY_HEADERS.attempt) ?? '1');\n const queueName = request.headers.get(WORKFLOW_QUEUE_NAME_HEADER);\n if (!messageId || !physicalName || !queueName) {\n return Response.json({ error: 'Missing required headers' }, { status: 400 });\n }\n const body = new Uint8Array(await request.arrayBuffer());\n\n if (!options.allowUnsigned) {\n const secret = options.signingSecret ?? readSigningSecret();\n const valid =\n secret !== undefined &&\n (await verifyQueueSignature(request.headers.get(QUEUE_SIGNATURE_HEADER), {\n secret,\n queue: physicalName,\n messageId,\n attempt,\n body,\n }));\n if (!valid) return Response.json({ error: 'Invalid queue signature' }, { status: 401 });\n }\n // The physical queue name is signed; the Workflow queue name rides in a header, so both must agree.\n if (physicalName !== queueNamePrefix || !queueName.startsWith(queueNamePrefix)) {\n return Response.json({ error: 'Unhandled queue' }, { status: 400 });\n }\n\n let message: unknown;\n try {\n message = decodeWorkflowMessage(utf8Decode(body));\n } catch {\n return Response.json(\n { error: 'Malformed workflow message' },\n { status: 422, headers: { [QUEUE_RESPONSE_HEADERS.action]: 'dead-letter' } }\n );\n }\n\n try {\n const result = await handler(message, {\n attempt,\n queueName,\n messageId: messageId as TMessageId,\n requestId: request.headers.get('x-request-id') ?? undefined,\n });\n if (typeof message === 'object' && message !== null && (message as { invoke?: unknown }).invoke === true) {\n return Response.json({ result });\n }\n const timeoutSeconds =\n typeof result === 'object' && result !== null\n ? (result as { timeoutSeconds?: unknown }).timeoutSeconds\n : undefined;\n if (typeof timeoutSeconds === 'number' && Number.isFinite(timeoutSeconds) && timeoutSeconds >= 0) {\n return Response.json(\n { timeoutSeconds },\n { headers: { [QUEUE_RESPONSE_HEADERS.retryAfter]: String(Math.ceil(timeoutSeconds)) } }\n );\n }\n return Response.json({ ok: true });\n } catch (error) {\n return Response.json(String(error), { status: 500 });\n }\n };\n },\n };\n}\n"],"mappings":"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","names":["bytes","toHex","delay","toHex","sleep","delay","DEFAULT_BASE_URL","readEnv","toHex"]}