diff --git a/__tests__/database-query.test.ts b/__tests__/database-query.test.ts index 841ca1ef..f88b601f 100644 --- a/__tests__/database-query.test.ts +++ b/__tests__/database-query.test.ts @@ -36,7 +36,14 @@ test.each([undefined, 'application/vnd.volcano+json'])( }, ); const generatedFetch = jest - .fn<(path: string, options: RequestInit, mode: 'anon' | 'session') => Promise>() + .fn< + ( + path: string, + options: RequestInit, + mode: 'anon' | 'session', + timeoutMs?: number, + ) => Promise + >() .mockResolvedValue(fetchResponse); const client = { _generatedFetch: generatedFetch }; const date = new Date('2026-09-23T12:00:00.000Z'); @@ -65,6 +72,7 @@ test.each([undefined, 'application/vnd.volcano+json'])( headers: expect.any(Headers), }), 'session', + undefined, ); const call = generatedFetch.mock.calls[0]; expect(new Headers(call?.[1].headers).get('Content-Type')).toBe( diff --git a/__tests__/sandbox-review.test.ts b/__tests__/sandbox-review.test.ts new file mode 100644 index 00000000..7ad17576 --- /dev/null +++ b/__tests__/sandbox-review.test.ts @@ -0,0 +1,121 @@ +/** @jest-environment ./__tests__/node-environment.cjs */ +import { inspect } from 'node:util'; +import { afterEach, expect, jest, test } from '@jest/globals'; +import { VolcanoAuth } from '../src/index.ts'; + +const id = '11111111-1111-4111-8111-111111111111'; +const snapshot = { id, project_id: id, region: 'us-east-1', state: 'running', expires_at: '' }; +const command = { + stdout: '', + stderr: '', + exit_code: 0, + timed_out: false, + stdout_truncated: false, + stderr_truncated: false, + session_id: id, + region: 'us-east-1', + duration_ms: 0, +}; +const originalFetch = globalThis.fetch; +afterEach(() => { + globalThis.fetch = originalFetch; + jest.restoreAllMocks(); +}); + +test.each([ + [60_000, undefined, 180_000], + [60_000, 600, 720_000], + [900_000, 600, 900_000], +])( + 'command requests budget provisioning time: %s/%s', + async (timeout, timeoutSeconds, expected) => { + const client = new VolcanoAuth({ + apiUrl: 'https://api.test.com', + anonKey: 'anon', + accessToken: 'service', + timeout, + }); + const fetchMock = jest.fn().mockResolvedValueOnce(Response.json(snapshot)); + globalThis.fetch = fetchMock; + const session = await client.sandboxes.get(id); + if (session.data === null) { + throw session.error; + } + const timer = jest.spyOn(globalThis, 'setTimeout'); + const options = timeoutSeconds === undefined ? {} : { timeoutSeconds }; + fetchMock.mockImplementation(() => Promise.resolve(Response.json(command))); + const result = await session.data.exec('true', options); + expect(result.error).toBeNull(); + expect(timer).toHaveBeenLastCalledWith(expect.any(Function), expected); + const executed = await client.sandboxes.exec(id, 'true', { + ...options, + preset: 'node22', + region: 'us-east-1', + }); + expect(executed.error).toBeNull(); + expect(timer).toHaveBeenLastCalledWith(expect.any(Function), expected); + }, +); + +test.each(['terminating', 'terminated'])('disposal skips %s sessions', async (state) => { + const client = new VolcanoAuth({ anonKey: 'anon', accessToken: 'service' }); + const fetchMock = jest + .fn() + .mockResolvedValueOnce(Response.json(snapshot)) + .mockResolvedValueOnce(Response.json({ ...snapshot, state })); + globalThis.fetch = fetchMock; + const session = await client.sandboxes.get(id); + if (session.data === null) { + throw session.error; + } + const terminated = await session.data.terminate(); + expect(terminated.error).toBeNull(); + await session.data[Symbol.asyncDispose](); + expect(fetchMock).toHaveBeenCalledTimes(2); +}); + +test('disposal accepts an already removed session', async () => { + const client = new VolcanoAuth({ anonKey: 'anon', accessToken: 'service' }); + globalThis.fetch = jest + .fn() + .mockResolvedValueOnce(Response.json(snapshot)) + .mockResolvedValueOnce(Response.json({ error: 'not found' }, { status: 404 })); + const session = await client.sandboxes.get(id); + if (session.data === null) { + throw session.error; + } + await expect(session.data[Symbol.asyncDispose]()).resolves.toBeUndefined(); +}); + +test('scoped access credentials remain usable but are absent from routine logs', async () => { + const client = new VolcanoAuth({ anonKey: 'anon', accessToken: 'service' }); + globalThis.fetch = jest + .fn() + .mockResolvedValueOnce(Response.json(snapshot)) + .mockResolvedValueOnce( + Response.json({ url: 'https://session.test', token: 'private-access-token', expires_at: '' }), + ); + const session = await client.sandboxes.get(id); + if (session.data === null) { + throw session.error; + } + const access = await session.data.access(8080); + expect(access.data?.token).toBe('private-access-token'); + expect(inspect(access)).not.toContain('private-access-token'); + expect(JSON.stringify(access)).not.toContain('private-access-token'); + expect({ ...access.data }).not.toHaveProperty('token'); +}); + +test('disposal preserves network errors', async () => { + const client = new VolcanoAuth({ anonKey: 'anon', accessToken: 'service' }); + const failure = new Error('connection failed'); + globalThis.fetch = jest + .fn() + .mockResolvedValueOnce(Response.json(snapshot)) + .mockRejectedValueOnce(failure); + const session = await client.sandboxes.get(id); + if (session.data === null) { + throw session.error; + } + await expect(session.data[Symbol.asyncDispose]()).rejects.toBe(failure); +}); diff --git a/__tests__/sandbox-wire.test.ts b/__tests__/sandbox-wire.test.ts new file mode 100644 index 00000000..fe0b62bf --- /dev/null +++ b/__tests__/sandbox-wire.test.ts @@ -0,0 +1,160 @@ +/** @jest-environment ./__tests__/node-environment.cjs */ +import { describe, expect, jest, test } from '@jest/globals'; +import { commandRequest, pathId, requestOptions } from '../src/sandbox-request.ts'; +import { + commandResult, + createRequest, + encodeBytes, + presetsResult, + record, + sessionRequest, + sessionState, + text, +} from '../src/sandbox-wire.ts'; + +const command = { + stdout: '', + stderr: '', + exit_code: 0, + timed_out: false, + stdout_truncated: false, + stderr_truncated: false, +}; + +describe('Sandbox wire validation', () => { + test.each([null, undefined, 0, 'text', [], true])('rejects non-record %j', (value) => { + expect(() => record(value)).toThrow('Invalid Sandbox response'); + }); + test('accepts records and text without coercion', () => { + const value = { field: 'value' }; + expect(record(value)).toBe(value); + expect(text('')).toBe(''); + expect(() => text(1)).toThrow('Invalid Sandbox text field'); + }); + test.each([Number.NaN, Number.POSITIVE_INFINITY, '0'])( + 'rejects invalid numeric fields %j', + (exit_code) => { + expect(() => commandResult({ ...command, exit_code })).toThrow( + 'Invalid Sandbox numeric field', + ); + }, + ); + test('rejects non-boolean flags', () => { + expect(() => commandResult({ ...command, timed_out: 'false' })).toThrow('Invalid Sandbox flag'); + }); + test.each([ + 'starting', + 'running', + 'suspending', + 'suspended', + 'resuming', + 'terminating', + 'terminated', + 'unknown', + ])('preserves session state %s', (state) => { + expect(sessionState(state)).toBe(state); + }); + test('rejects unknown session state', () => { + expect(() => sessionState('future')).toThrow('Invalid Sandbox state'); + }); + test.each([ + { region: 'aws-us-east-1' }, + { region: 'aws-us-east-1', preset: 'node22' as const, sandboxId: 'template' }, + ])('requires exactly one selector %j', (options) => { + expect(() => createRequest(options)).toThrow('Choose exactly one preset or sandboxId'); + }); + test.each([{}, { data: {} }, { data: [{ id: 'node22', memory_mb: 1024, regions: {} }] }])( + 'rejects malformed catalog %j', + (value) => { + const message = + 'data' in value && Array.isArray(value.data) + ? 'Invalid Sandbox regions' + : 'Invalid Sandbox preset catalog'; + expect(() => presetsResult(value)).toThrow(message); + }, + ); + test('accepts the file limit and rejects the next byte', () => { + const limit = 8 * 1024 * 1024; + expect(encodeBytes(new Uint8Array(limit))).toHaveLength(Math.ceil(limit / 3) * 4); + expect(() => encodeBytes(new Uint8Array(limit + 1))).toThrow( + 'Sandbox files are limited to 8 MiB', + ); + }); +}); + +test.each([ + 'prefix11111111-1111-4111-8111-111111111111', + '11111111-1111-4111-8111-111111111111suffix', +])('rejects a UUID embedded in %s', (id) => { + expect(() => pathId(id)).toThrow('A Sandbox resource ID must be a UUID'); +}); + +test('forwards the caller abort signal and leaves absent signals untouched', () => { + const generated = jest + .fn< + ( + mode: 'session', + headers?: Record, + responseType?: 'blob', + timeoutMs?: number, + ) => object + >() + .mockImplementation(() => ({})); + const client = { + timeout: 60_000, + _completeOAuthExchange: () => Promise.resolve(), + _generatedOptions: generated, + }; + const signal = new AbortController().signal; + expect(requestOptions(client, { signal }).signal).toBe(signal); + expect(requestOptions(client)).not.toHaveProperty('signal'); +}); + +test('omits absent optional wire properties', () => { + expect(createRequest({ preset: 'node22', region: 'aws-us-east-1' })).toStrictEqual({ + preset: 'node22', + region: 'aws-us-east-1', + }); + expect( + createRequest({ sandboxId: 'template', region: 'aws-us-east-1', memoryMB: 2048 }), + ).toStrictEqual({ sandbox_id: 'template', region: 'aws-us-east-1', memory_mb: 2048 }); + expect(commandRequest('true', {})).toStrictEqual({ command: 'true' }); + expect(commandRequest('true', { timeoutSeconds: 5, environment: { A: 'b' } })).toStrictEqual({ + command: 'true', + timeout_seconds: 5, + environment: { A: 'b' }, + }); + expect(sessionRequest({ preset: 'node22', region: 'aws-us-east-1' })).toStrictEqual({ + preset: 'node22', + region: 'aws-us-east-1', + }); + expect( + sessionRequest({ + preset: 'node22', + region: 'aws-us-east-1', + maxDurationSeconds: 300, + idleTimeoutSeconds: 60, + }), + ).toStrictEqual({ + preset: 'node22', + region: 'aws-us-east-1', + max_duration_seconds: 300, + idle_timeout_seconds: 60, + }); +}); + +test.each([0, 1, 1023, 1025, 2047, 2049, Number.NaN])( + 'rejects unsupported memory %s before transport', + (memoryMB) => { + expect(() => createRequest({ preset: 'node22', region: 'us-east-1', memoryMB })).toThrow( + 'Sandbox memory must be 1024 or 2048 MB', + ); + }, +); +test.each([1024, 2048])('accepts catalog memory %s', (memoryMB) => { + expect(createRequest({ preset: 'catalog-preset', region: 'us-east-1', memoryMB })).toEqual({ + preset: 'catalog-preset', + region: 'us-east-1', + memory_mb: memoryMB, + }); +}); diff --git a/__tests__/sandboxes.test.ts b/__tests__/sandboxes.test.ts new file mode 100644 index 00000000..b272cef1 --- /dev/null +++ b/__tests__/sandboxes.test.ts @@ -0,0 +1,425 @@ +/** @jest-environment ./__tests__/node-environment.cjs */ +import { afterEach, describe, expect, jest, test } from '@jest/globals'; +import { VolcanoAuth } from '../src/index.ts'; +import { requestOptions, sandboxResult } from '../src/sandbox-request.ts'; + +const projectId = '11111111-1111-4111-8111-111111111111'; +const sessionId = '22222222-2222-4222-8222-222222222222'; +const requestId = '33333333-3333-4333-8333-333333333333'; +const originalFetch = globalThis.fetch; +const snapshot = { + id: sessionId, + project_id: projectId, + sandbox_id: requestId, + state: 'running', + desired_state: 'running', + region: 'aws-us-east-1', + memory_mb: 1024, + created_at: '2026-09-24T00:00:00Z', + expires_at: '2026-09-24T01:00:00Z', +}; +function client() { + return new VolcanoAuth({ + apiUrl: 'https://api.test.com', + anonKey: 'ak-project', + accessToken: 'sk-service', + }); +} +function bodyJson(call: Parameters | undefined): unknown { + const body = call?.[1]?.body; + if (typeof body !== 'string') { + throw new TypeError('Expected JSON request body'); + } + return JSON.parse(body); +} +function requestCall(calls: Parameters[], index: number): Parameters { + const call = calls[index]; + if (call === undefined) { + throw new Error('Missing request'); + } + return call; +} +afterEach(() => { + globalThis.fetch = originalFetch; +}); + +describe('Sandboxes facade', () => { + test('preserves command output and explicitly supplied replay key', async () => { + const fetchMock = jest.fn().mockResolvedValue( + Response.json({ + stdout: 'out', + stderr: 'err', + exit_code: 7, + timed_out: false, + stdout_truncated: false, + stderr_truncated: false, + session_id: sessionId, + region: 'aws-us-east-1', + duration_ms: 10, + }), + ); + globalThis.fetch = fetchMock; + const result = await client().sandboxes.exec(projectId, 'exit 7', { + preset: 'python3.12', + region: 'aws-us-east-1', + requestId, + }); + expect(result.error).toBeNull(); + expect(result.data).toMatchObject({ stdout: 'out', stderr: 'err', exitCode: 7 }); + const request = fetchMock.mock.calls[0]; + expect(request?.[0]).toBe(`https://api.test.com/projects/${projectId}/sandbox-executions`); + expect(new Headers(request?.[1]?.headers).get('Idempotency-Key')).toBe(requestId); + expect(bodyJson(request)).toEqual({ + command: 'exit 7', + preset: 'python3.12', + region: 'aws-us-east-1', + }); + }); + test('returns a session that refreshes state and controls the same id', async () => { + const fetchMock = jest + .fn() + .mockResolvedValueOnce(Response.json(snapshot)) + .mockResolvedValueOnce( + Response.json({ ...snapshot, state: 'suspended', desired_state: 'suspended' }), + ); + globalThis.fetch = fetchMock; + const result = await client().sandboxes.create(projectId, { + preset: 'node22', + region: 'aws-us-east-1', + requestId, + }); + expect(result.error).toBeNull(); + const handle = result.data; + if (handle === null) { + throw result.error; + } + expect(handle.id).toBe(sessionId); + expect(bodyJson(fetchMock.mock.calls[0])).toEqual({ + preset: 'node22', + region: 'aws-us-east-1', + }); + expect(new Headers(fetchMock.mock.calls[0]?.[1]?.headers).get('Idempotency-Key')).toBe( + requestId, + ); + const suspended = await handle.suspend(); + expect(suspended.error).toBeNull(); + expect(handle.state).toBe('suspended'); + expect(fetchMock.mock.calls[1]?.[0]).toBe( + `https://api.test.com/sandbox-sessions/${sessionId}/suspend`, + ); + }); + test('does not replay a failed command automatically', async () => { + const fetchMock = jest + .fn() + .mockResolvedValue(Response.json({ error: 'outcome unknown' }, { status: 409 })); + globalThis.fetch = fetchMock; + const result = await client().sandboxes.exec(projectId, 'increment', { + preset: 'python3.12', + region: 'aws-us-east-1', + requestId, + }); + expect(result.error).toMatchObject({ status: 409 }); + expect(result.data).toBeNull(); + expect(fetchMock).toHaveBeenCalledTimes(1); + }); +}); + +test('passes session lifetime controls and terminates on async disposal', async () => { + const fetchMock = jest + .fn() + .mockResolvedValueOnce(Response.json(snapshot)) + .mockResolvedValueOnce(Response.json({ ...snapshot, state: 'terminating' })); + globalThis.fetch = fetchMock; + const result = await client().sandboxes.create(projectId, { + preset: 'python3.12', + region: 'aws-us-east-1', + maxDurationSeconds: 300, + idleTimeoutSeconds: 60, + }); + expect(bodyJson(fetchMock.mock.calls[0])).toMatchObject({ + max_duration_seconds: 300, + idle_timeout_seconds: 60, + }); + if (result.data === null) { + throw result.error; + } + await result.data[Symbol.asyncDispose](); + const disposal = requestCall(fetchMock.mock.calls, 1); + expect(disposal[0]).toBe(`https://api.test.com/sandbox-sessions/${sessionId}`); + expect(disposal[1]?.method).toBe('DELETE'); +}); + +test('preserves binary files and returns a scoped HTTP credential', async () => { + const fetchMock = jest + .fn() + .mockResolvedValueOnce(Response.json(snapshot)) + .mockResolvedValueOnce(new Response(null, { status: 204 })) + .mockResolvedValueOnce(Response.json({ data: 'AP+A' })) + .mockResolvedValueOnce( + Response.json({ + url: 'https://session.example', + token: 'scoped-token', + expires_at: snapshot.expires_at, + }), + ); + globalThis.fetch = fetchMock; + const result = await client().sandboxes.get(sessionId); + if (result.data === null) { + throw result.error; + } + const bytes = new Uint8Array([0, 255, 128]); + const written = await result.data.files.write('/workspace/data', bytes); + expect(written.error).toBeNull(); + expect(bodyJson(fetchMock.mock.calls[1])).toEqual({ + path: '/workspace/data', + data: 'AP+A', + }); + const read = await result.data.files.read('/workspace/data'); + expect(read.data).toEqual(bytes); + expect(bodyJson(fetchMock.mock.calls[2])).toEqual({ path: '/workspace/data' }); + const access = await result.data.access(8080); + expect(bodyJson(fetchMock.mock.calls[3])).toEqual({ port: 8080 }); + expect(access.data?.token).toBe('scoped-token'); + expect(access.data).toEqual({ + url: 'https://session.example', + expiresAt: snapshot.expires_at, + }); +}); + +test('rejects invalid selectors before issuing a request', async () => { + const fetchMock = jest.fn(); + globalThis.fetch = fetchMock; + const result = await client().sandboxes.create(projectId, { region: 'aws-us-east-1' }); + expect(result.error).toBeInstanceOf(TypeError); + expect(fetchMock).not.toHaveBeenCalled(); +}); + +test('lists public presets with only anonymous credentials and cancellation', async () => { + const fetchMock = jest + .fn() + .mockResolvedValue( + Response.json({ data: [{ id: 'node22', memory_mb: 1024, regions: ['aws-us-east-1'] }] }), + ); + globalThis.fetch = fetchMock; + const signal = new AbortController().signal; + const anonymousClient = new VolcanoAuth({ + apiUrl: 'https://api.test.com', + anonKey: 'ak-project', + }); + const observed1 = await anonymousClient.sandboxes.presets({ signal }); + const request = requestCall(fetchMock.mock.calls, 0); + expect(request[0]).toBe('https://api.test.com/sandboxes/presets'); + expect(new Headers(request[1]?.headers).get('Authorization')).toBe('Bearer ak-project'); + expect(new Headers(request[1]?.headers).has('Idempotency-Key')).toBe(false); + expect(request[1]?.signal?.aborted).toBe(false); + expect(fetchMock).toHaveBeenCalledTimes(1); + expect(observed1).toEqual({ + data: [{ id: 'node22', memoryMB: 1024, regions: ['aws-us-east-1'] }], + error: null, + }); +}); + +test.each([ + null, + { data: null }, + { data: [{ regions: null }] }, + { data: [{ id: 2, memory_mb: 1024, regions: [] }] }, + { data: [{ id: 'node22', memory_mb: '1024', regions: [] }] }, +])('rejects malformed preset responses: %j', async (value) => { + globalThis.fetch = jest.fn().mockResolvedValue(Response.json(value)); + const observed2 = await client().sandboxes.presets(); + expect(observed2.error).toBeInstanceOf(TypeError); +}); + +test('selects a template and forwards command limits and cancellation', async () => { + const fetchMock = jest.fn().mockResolvedValue(Response.json(snapshot)); + globalThis.fetch = fetchMock; + const signal = new AbortController().signal; + const result = await client().sandboxes.create(projectId, { + sandboxId: requestId, + region: 'aws-us-east-1', + memoryMB: 2048, + signal, + }); + expect(result.error).toBeNull(); + expect(bodyJson(fetchMock.mock.calls[0])).toEqual({ + sandbox_id: requestId, + region: 'aws-us-east-1', + memory_mb: 2048, + }); + expect(fetchMock.mock.calls[0]?.[1]?.signal?.aborted).toBe(false); + if (result.data === null) { + throw result.error; + } + fetchMock.mockResolvedValue( + Response.json({ + stdout: 'ok', + stderr: '', + exit_code: 0, + timed_out: false, + stdout_truncated: true, + stderr_truncated: true, + }), + ); + const observed3 = await result.data.exec('echo ok', { + timeoutSeconds: 5, + environment: { A: 'b' }, + }); + expect(observed3.data).toEqual({ + stdout: 'ok', + stderr: '', + exitCode: 0, + timedOut: false, + stdoutTruncated: true, + stderrTruncated: true, + }); + expect(bodyJson(fetchMock.mock.calls[1])).toEqual({ + command: 'echo ok', + timeout_seconds: 5, + environment: { A: 'b' }, + }); +}); + +test('refreshes and resumes sessions and refuses changed identity', async () => { + const fetchMock = jest.fn().mockResolvedValue(Response.json(snapshot)); + globalThis.fetch = fetchMock; + const result = await client().sandboxes.get(sessionId); + if (result.data === null) { + throw result.error; + } + fetchMock.mockResolvedValueOnce(Response.json({ ...snapshot, state: 'suspended' })); + const observed4 = await result.data.refresh(); + expect(observed4.data).toMatchObject({ state: 'suspended' }); + fetchMock.mockResolvedValueOnce(Response.json(snapshot)); + const observed5 = await result.data.resume(); + expect(observed5.data).toMatchObject({ state: 'running' }); + expect(fetchMock.mock.calls[2]?.[0]).toBe( + `https://api.test.com/sandbox-sessions/${sessionId}/resume`, + ); + fetchMock.mockResolvedValueOnce(Response.json({ ...snapshot, id: requestId })); + const observed6 = await result.data.refresh(); + expect(observed6.error?.message).toBe('Sandbox session identity changed'); +}); + +test('grants and revokes access for one auth user', async () => { + const fetchMock = jest + .fn() + .mockImplementation(() => Promise.resolve(new Response(null, { status: 204 }))); + globalThis.fetch = fetchMock; + const api = client().sandboxes; + const observed7 = await api.grant(sessionId, requestId, snapshot.expires_at); + expect(observed7.error).toBeNull(); + expect(bodyJson(fetchMock.mock.calls[0])).toEqual({ expires_at: snapshot.expires_at }); + const observed8 = await api.revoke(sessionId, requestId); + expect(observed8.error).toBeNull(); + expect(fetchMock.mock.calls[1]?.[1]?.method).toBe('DELETE'); + expect(fetchMock.mock.calls[1]?.[0]).toContain(requestId); +}); + +test('rejects invalid IDs before sending credentials', async () => { + const fetchMock = jest.fn(); + globalThis.fetch = fetchMock; + const observed9 = await client().sandboxes.get('../other'); + expect(observed9.error).toBeInstanceOf(TypeError); + expect(fetchMock).not.toHaveBeenCalled(); +}); + +test.each(['future-state', null])('rejects invalid session state %j', async (state) => { + globalThis.fetch = jest + .fn() + .mockResolvedValue(Response.json({ ...snapshot, state })); + const observed10 = await client().sandboxes.get(sessionId); + expect(observed10.error).toBeInstanceOf(TypeError); +}); + +test('disposal of terminated sessions makes no request', async () => { + const fetchMock = jest + .fn() + .mockResolvedValue(Response.json({ ...snapshot, state: 'terminated' })); + globalThis.fetch = fetchMock; + const result = await client().sandboxes.get(sessionId); + if (result.data === null) { + throw result.error; + } + await result.data[Symbol.asyncDispose](); + expect(fetchMock).toHaveBeenCalledTimes(1); +}); + +test('disposal propagates failures and large file writes fail locally', async () => { + const fetchMock = jest.fn().mockResolvedValue(Response.json(snapshot)); + globalThis.fetch = fetchMock; + const result = await client().sandboxes.get(sessionId); + if (result.data === null) { + throw result.error; + } + const observed11 = await result.data.files.write( + '/workspace/large', + new Uint8Array(8 * 1024 * 1024 + 1), + ); + expect(observed11.error).toBeInstanceOf(RangeError); + expect(fetchMock).toHaveBeenCalledTimes(1); + fetchMock.mockResolvedValue(Response.json({ error: 'unavailable' }, { status: 503 })); + await expect(result.data[Symbol.asyncDispose]()).rejects.toMatchObject({ status: 503 }); +}); + +test('rejects malformed command flags', async () => { + globalThis.fetch = jest + .fn() + .mockResolvedValue(Response.json({ stdout: '', stderr: '', exit_code: 0, timed_out: 'false' })); + const observed12 = await client().sandboxes.exec(projectId, 'true', { + preset: 'node22', + region: 'aws-us-east-1', + }); + expect(observed12.error).toBeInstanceOf(TypeError); +}); + +test('normalizes non-Error failures without exposing arbitrary values', async () => { + const observed13 = await sandboxResult( + jest.fn<() => Promise>().mockRejectedValue('secret'), + ); + expect(observed13).toEqual({ data: null, error: new Error('Sandbox request failed') }); +}); +test('default request options contain no mutation headers', () => { + const generated = jest + .fn< + ( + mode: 'anon' | 'session', + headers?: Record, + responseType?: 'blob', + timeoutMs?: number, + ) => object + >() + .mockReturnValue({}); + requestOptions({ + timeout: 60_000, + _completeOAuthExchange: () => Promise.resolve(), + _generatedOptions: generated, + }); + expect(generated).toHaveBeenCalledWith('session', {}, undefined, undefined); +}); +test('session commands use default execution options', async () => { + const fetchMock = jest + .fn() + .mockResolvedValueOnce(Response.json(snapshot)) + .mockResolvedValueOnce( + Response.json({ + stdout: '', + stderr: '', + exit_code: 0, + timed_out: false, + stdout_truncated: false, + stderr_truncated: false, + }), + ); + globalThis.fetch = fetchMock; + const result = await client().sandboxes.get(sessionId); + if (result.data === null) { + throw result.error; + } + const observed14 = await result.data.exec('true'); + expect(observed14.error).toBeNull(); + expect(new Headers(fetchMock.mock.calls[1]?.[1]?.headers).get('Idempotency-Key')).toMatch( + /^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/i, + ); + expect(bodyJson(fetchMock.mock.calls[1])).toEqual({ command: 'true' }); +}); diff --git a/docs/README.md b/docs/README.md index 6decdf7d..89ca54f4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -92,3 +92,5 @@ Realtime support is included with the SDK and is available from ## License Apache License 2.0 - see [LICENSE](https://github.com/Kong/volcano-sdk-js/blob/main/LICENSE) for details. + +- [Sandboxes](sandboxes.md): isolated commands, sessions, files, and HTTP access. diff --git a/docs/sandboxes.md b/docs/sandboxes.md new file mode 100644 index 00000000..3e7dc9ba --- /dev/null +++ b/docs/sandboxes.md @@ -0,0 +1,94 @@ +--- +title: Sandboxes +description: Run isolated commands, keep a session for multiple steps, and access its files and HTTP services. +--- + +Run a command in a temporary Sandbox. Volcano terminates the session after the command completes. + +```javascript +import { VolcanoClient } from '@volcano.dev/sdk'; + +const client = new VolcanoClient({ + apiUrl: process.env.VOLCANO_API_URL ?? 'https://api.volcano.dev', + anonKey: process.env.VOLCANO_ANON_KEY, + accessToken: process.env.VOLCANO_SERVICE_KEY, +}); +const projectId = process.env.VOLCANO_PROJECT_ID; +const { data, error } = await client.sandboxes.exec(projectId, 'python -c "print(42)"', { + preset: 'python3.12', + region: 'aws-us-east-1', +}); +if (error) throw error; +console.log(data.stdout, data.exitCode); +``` + +Keep service keys on your backend. Creating and managing sessions requires a platform user or service key. An authenticated project user can access only sessions explicitly granted to that user. Anonymous keys can list the public preset catalog with `sandboxes.presets()`, but cannot create or access sessions. Availability depends on your platform's Sandbox rollout. + +A nonzero command exit is returned as `data.exitCode`; it is not a platform error. All methods return `{ data, error }`. Check `error` before using `data`. + +## Reuse a session + +Creation returns the current state, which may be `starting`. Poll `refresh()` until it becomes `running`; fail on `unknown` or `terminated` and keep polling bounded. Commands require a running session. + +```javascript +const created = await client.sandboxes.create(projectId, { + preset: 'python3.12', + region: 'aws-us-east-1', + maxDurationSeconds: 300, +}); +if (created.error) throw created.error; +const session = created.data; +try { + const deadline = Date.now() + 120_000; + while (session.state !== 'running') { + if (Date.now() >= deadline || ['unknown', 'terminated'].includes(session.state)) { + throw new Error(`Session unavailable: ${session.state}`); + } + await new Promise((resolve) => setTimeout(resolve, 1000)); + const refreshed = await session.refresh(); + if (refreshed.error) throw refreshed.error; + } + const written = await session.files.write( + '/workspace/input.txt', + new TextEncoder().encode('hello'), + ); + if (written.error) throw written.error; + const output = await session.exec('cat /workspace/input.txt'); + if (output.error) throw output.error; + console.log(output.data.stdout); +} finally { + const stopped = await session.terminate(); + if (stopped.error) throw stopped.error; +} +``` + +In a runtime with explicit resource management, use `await using session = created.data` after checking the creation result. Leaving the scope requests termination through `Symbol.asyncDispose`. Disposal skips sessions already terminating or terminated and accepts a 404 for a session already removed. Termination is durable and asynchronous; poll `refresh()` if you need confirmation that the session has stopped. + +`session.suspend()` and `session.resume()` request state transitions. Poll for `suspended` or `running` before the next operation. Local suspension preserves processes and files, but the container continues to reserve memory. + +## Read files and access HTTP + +`session.files.read(path)` returns `Uint8Array`. Writes accept `Uint8Array`; paths stay within the session workspace. Files are limited to 8 MiB. + +Start a background HTTP service inside the session, then obtain a short-lived credential for its port: + +```javascript +const started = await session.exec('python -m http.server 8080 >/workspace/http.log 2>&1 &'); +if (started.error) throw started.error; +const access = await session.access(8080); +if (access.error) throw access.error; +const response = await fetch(access.data.url, { + headers: { 'X-Volcano-Sandbox-Token': access.data.token }, +}); +console.log(await response.text()); +``` + +Read the scoped credential through `access.data.token`; it is omitted from JSON serialization and routine object logging. The token is bound to this session and port. Do not append it to URLs. See [Sandbox HTTP access](/platform/guides/sandboxes) for browser redemption and authorization. + +## Retry safely + +Pass a UUID `requestId` to `sandboxes.create()`, `sandboxes.exec()`, or `session.exec()`. Other operations accept cancellation through `signal` but do not accept `requestId`. Retry the same intent with the same ID after a network failure. Do not reuse the ID for a different command. The SDK does not automatically replay failed commands. + +Pass `signal` to cancel waiting. Cancellation does not prove the remote command stopped. The HTTP timeout budget is the command timeout plus 120 seconds for provisioning, or the configured client timeout if longer. A one-shot command timeout returns HTTP 504; retrying the same request ID returns HTTP 409 and does not rerun it. A session command timeout returns command data with `timedOut: true`. One-shot commands allow up to 60 seconds; session commands allow up to 3600 seconds. + +Use either `preset` or a saved template's `sandboxId`, never both. `sandboxes.presets()` lists available preset IDs, memory sizes, and regions. `sandboxes.get(sessionId)` reconnects to an existing session. Backend code can call `grant(sessionId, authUserId, expiresAt)` and `revoke(sessionId, authUserId)` to control user access. diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index bcc7f2c2..1a04c044 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -12104,6 +12104,680 @@ paths: schema: type: string example: OK + /sandboxes/presets: + get: + tags: + - Sandboxes + summary: List available sandbox presets + operationId: listSandboxPresets + security: [] + responses: + '200': + description: List available sandbox presets + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxPresetList' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/sandboxes: + get: + tags: + - Sandboxes + summary: List sandbox templates + operationId: listSandboxes + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - $ref: '#/components/parameters/Limit' + - $ref: '#/components/parameters/Cursor' + responses: + '200': + description: List sandbox templates + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxTemplatePage' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + tags: + - Sandboxes + summary: Create a sandbox template from a verified preset + operationId: createSandbox + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: Idempotency-Key + in: header + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateSandboxTemplateRequest' + responses: + '201': + description: Create a sandbox template from a verified preset + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxTemplate' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/sandboxes/{sandboxId}: + get: + tags: + - Sandboxes + summary: Get a sandbox template + operationId: getSandbox + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: sandboxId + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Get a sandbox template + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxTemplate' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + patch: + tags: + - Sandboxes + summary: Rename a sandbox template + operationId: updateSandbox + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: sandboxId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateSandboxTemplateRequest' + responses: + '200': + description: Rename a sandbox template + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxTemplate' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + tags: + - Sandboxes + summary: Retire a template and terminate its sessions + operationId: deleteSandbox + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: sandboxId + in: path + required: true + schema: + type: string + format: uuid + responses: + '202': + description: Retire a template and terminate its sessions + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/sandboxes/{sandboxId}/deployments: + get: + tags: + - Sandboxes + summary: List sandbox deployment history + operationId: listSandboxDeployments + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: sandboxId + in: path + required: true + schema: + type: string + format: uuid + - $ref: '#/components/parameters/Limit' + - $ref: '#/components/parameters/Cursor' + responses: + '200': + description: List sandbox deployment history + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxDeploymentPage' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/sandbox-sessions: + get: + tags: + - Sandboxes + summary: List project sandbox sessions + operationId: listSandboxSessions + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - $ref: '#/components/parameters/Limit' + - $ref: '#/components/parameters/Cursor' + responses: + '200': + description: List project sandbox sessions + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxSessionPage' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + tags: + - Sandboxes + summary: Start a sandbox session + operationId: createSandboxSession + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: Idempotency-Key + in: header + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateSandboxSessionRequest' + responses: + '201': + description: Start a sandbox session + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxSession' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/sandbox-executions: + post: + tags: + - Sandboxes + summary: Execute once and return after confirmed termination + operationId: executeSandbox + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: Idempotency-Key + in: header + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxExecutionRequest' + responses: + '200': + description: Execute once and return after confirmed termination + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxExecutionResult' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /sandbox-sessions/{sessionId}: + get: + tags: + - Sandboxes + summary: Get a sandbox session + operationId: getSandboxSession + security: + - UserToken: [] + - ServiceRoleKey: [] + - AuthUserAccessToken: [] + parameters: + - name: sessionId + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Get a sandbox session + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxSession' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + tags: + - Sandboxes + summary: Request sandbox termination + operationId: terminateSandboxSession + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: sessionId + in: path + required: true + schema: + type: string + format: uuid + responses: + '202': + description: Request sandbox termination + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxSession' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /sandbox-sessions/{sessionId}/suspend: + post: + tags: + - Sandboxes + summary: Suspend a sandbox session + operationId: suspendSandboxSession + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: sessionId + in: path + required: true + schema: + type: string + format: uuid + responses: + '202': + description: Suspend a sandbox session + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxSession' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /sandbox-sessions/{sessionId}/resume: + post: + tags: + - Sandboxes + summary: Resume a sandbox session + operationId: resumeSandboxSession + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: sessionId + in: path + required: true + schema: + type: string + format: uuid + responses: + '202': + description: Resume a sandbox session + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxSession' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /sandbox-sessions/{sessionId}/exec: + post: + tags: + - Sandboxes + summary: Execute a command within a session + operationId: executeSandboxSession + security: + - UserToken: [] + - ServiceRoleKey: [] + - AuthUserAccessToken: [] + parameters: + - name: sessionId + in: path + required: true + schema: + type: string + format: uuid + - name: Idempotency-Key + in: header + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxCommandRequest' + responses: + '200': + description: Execute a command within a session + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxCommandResult' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /sandbox-sessions/{sessionId}/files/read: + post: + tags: + - Sandboxes + summary: Read a workspace file + operationId: readSandboxSessionFile + security: + - UserToken: [] + - ServiceRoleKey: [] + - AuthUserAccessToken: [] + parameters: + - name: sessionId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxFileReadRequest' + responses: + '200': + description: Read a workspace file + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxFileResult' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /sandbox-sessions/{sessionId}/files/write: + post: + tags: + - Sandboxes + summary: Write a workspace file + operationId: writeSandboxSessionFile + security: + - UserToken: [] + - ServiceRoleKey: [] + - AuthUserAccessToken: [] + parameters: + - name: sessionId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxFileWriteRequest' + responses: + '204': + description: Write a workspace file + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /sandbox-sessions/{sessionId}/grants/{subjectId}: + put: + tags: + - Sandboxes + summary: Authorize an authenticated project user for this session + operationId: grantSandboxSession + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: sessionId + in: path + required: true + schema: + type: string + format: uuid + - name: subjectId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxSubjectGrantRequest' + responses: + '204': + description: Authorize an authenticated project user for this session + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + tags: + - Sandboxes + summary: Revoke a project user session grant + operationId: revokeSandboxSession + security: + - UserToken: [] + - ServiceRoleKey: [] + parameters: + - name: sessionId + in: path + required: true + schema: + type: string + format: uuid + - name: subjectId + in: path + required: true + schema: + type: string + format: uuid + responses: + '204': + description: Revoke a project user session grant + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /sandbox-sessions/{sessionId}/access: + post: + tags: + - Sandboxes + summary: Issue a short-lived port-scoped access credential + operationId: createSandboxSessionAccess + security: + - UserToken: [] + - ServiceRoleKey: [] + - AuthUserAccessToken: [] + parameters: + - name: sessionId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxAccessRequest' + responses: + '200': + description: Issue a short-lived port-scoped access credential + content: + application/json: + schema: + $ref: '#/components/schemas/SandboxAccess' + default: + description: Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). + content: + application/json: + schema: + $ref: '#/components/schemas/Error' components: securitySchemes: AnonKey: @@ -12454,6 +13128,515 @@ components: schema: $ref: '#/components/schemas/Error' schemas: + SandboxPreset: + type: object + additionalProperties: false + properties: + id: + type: string + runtime: + type: string + version: + type: string + memory_mb: + type: integer + enum: + - 1024 + - 2048 + regions: + type: array + items: + type: string + required: + - id + - runtime + - version + - memory_mb + - regions + SandboxTemplate: + type: object + additionalProperties: false + properties: + id: + type: string + format: uuid + project_id: + type: string + format: uuid + name: + type: string + pattern: ^[a-z][a-z0-9-]{0,62}$ + preset: + type: string + memory_mb: + type: integer + status: + type: string + enum: + - ready + - unavailable + - deleting + created_at: + type: string + format: date-time + required: + - id + - project_id + - name + - status + - created_at + CreateSandboxTemplateRequest: + type: object + additionalProperties: false + properties: + name: + type: string + pattern: ^[a-z][a-z0-9-]{0,62}$ + preset: + type: string + description: Preset ID from the available Sandbox preset catalog. + memory_mb: + type: integer + enum: + - 1024 + - 2048 + default: 1024 + required: + - name + - preset + UpdateSandboxTemplateRequest: + type: object + additionalProperties: false + properties: + name: + type: string + pattern: ^[a-z][a-z0-9-]{0,62}$ + required: + - name + SandboxSession: + type: object + additionalProperties: false + properties: + id: + type: string + format: uuid + project_id: + type: string + format: uuid + sandbox_id: + type: string + format: uuid + state: + type: string + enum: + - starting + - running + - suspending + - suspended + - resuming + - terminating + - terminated + - unknown + desired_state: + type: string + enum: + - running + - suspended + - terminated + region: + type: string + memory_mb: + type: integer + created_at: + type: string + format: date-time + started_at: + type: string + format: date-time + expires_at: + type: string + format: date-time + required: + - id + - project_id + - sandbox_id + - state + - desired_state + - region + - memory_mb + - created_at + - expires_at + CreateSandboxSessionRequest: + type: object + additionalProperties: false + properties: + preset: + type: string + description: Preset ID from the available Sandbox preset catalog. + sandbox_id: + type: string + format: uuid + memory_mb: + type: integer + enum: + - 1024 + - 2048 + region: + type: string + pattern: ^(aws-)?[a-z]{2}(-[a-z]+)+-[0-9]+$ + description: Region such as `us-east-1`. Region IDs issued by earlier versions of the API are still accepted. + max_duration_seconds: + type: integer + minimum: 30 + maximum: 28800 + default: 3600 + idle_timeout_seconds: + type: integer + minimum: 0 + maximum: 28800 + default: 0 + required: + - region + oneOf: + - required: + - preset + not: + required: + - sandbox_id + - required: + - sandbox_id + not: + required: + - preset + SandboxCommandRequest: + type: object + additionalProperties: false + properties: + command: + type: string + minLength: 1 + maxLength: 65536 + timeout_seconds: + type: integer + minimum: 1 + maximum: 3600 + default: 60 + environment: + type: object + additionalProperties: + type: string + maxProperties: 64 + required: + - command + SandboxExecutionRequest: + type: object + additionalProperties: false + properties: + preset: + type: string + description: Preset ID from the available Sandbox preset catalog. + sandbox_id: + type: string + format: uuid + memory_mb: + type: integer + enum: + - 1024 + - 2048 + region: + type: string + pattern: ^(aws-)?[a-z]{2}(-[a-z]+)+-[0-9]+$ + description: Region such as `us-east-1`. Region IDs issued by earlier versions of the API are still accepted. + command: + type: string + minLength: 1 + maxLength: 65536 + timeout_seconds: + type: integer + minimum: 1 + maximum: 60 + default: 60 + environment: + type: object + additionalProperties: + type: string + maxProperties: 64 + required: + - region + - command + oneOf: + - required: + - preset + not: + required: + - sandbox_id + - required: + - sandbox_id + not: + required: + - preset + SandboxCommandResult: + type: object + additionalProperties: false + properties: + stdout: + type: string + stderr: + type: string + exit_code: + type: integer + stdout_truncated: + type: boolean + stderr_truncated: + type: boolean + timed_out: + type: boolean + required: + - stdout + - stderr + - exit_code + - stdout_truncated + - stderr_truncated + - timed_out + SandboxExecutionResult: + type: object + additionalProperties: false + properties: + stdout: + type: string + stderr: + type: string + exit_code: + type: integer + stdout_truncated: + type: boolean + stderr_truncated: + type: boolean + timed_out: + type: boolean + session_id: + type: string + format: uuid + region: + type: string + duration_ms: + type: integer + format: int64 + minimum: 0 + required: + - stdout + - stderr + - exit_code + - stdout_truncated + - stderr_truncated + - timed_out + - session_id + - region + - duration_ms + SandboxFileWriteRequest: + type: object + additionalProperties: false + properties: + path: + type: string + minLength: 1 + maxLength: 4096 + data: + type: string + format: byte + maxLength: 11184812 + required: + - path + - data + SandboxFileReadRequest: + type: object + additionalProperties: false + properties: + path: + type: string + minLength: 1 + maxLength: 4096 + required: + - path + SandboxFileResult: + type: object + additionalProperties: false + properties: + data: + type: string + format: byte + required: + - data + SandboxSubjectGrantRequest: + type: object + additionalProperties: false + properties: + expires_at: + type: string + format: date-time + required: + - expires_at + SandboxAccessRequest: + type: object + additionalProperties: false + properties: + port: + type: integer + minimum: 1 + maximum: 65532 + expires_in_seconds: + type: integer + minimum: 1 + maximum: 300 + default: 300 + required: + - port + SandboxAccess: + type: object + additionalProperties: false + properties: + url: + type: string + format: uri + token: + type: string + expires_at: + type: string + format: date-time + required: + - url + - token + - expires_at + SandboxDeployment: + type: object + additionalProperties: false + properties: + id: + type: string + format: uuid + status: + type: string + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + required: + - id + - status + - created_at + - updated_at + SandboxPagination: + type: object + additionalProperties: false + properties: + limit: + type: integer + has_more: + type: boolean + next_cursor: + type: string + required: + - limit + - has_more + SandboxTemplatePage: + type: object + additionalProperties: false + properties: + data: + type: array + items: + $ref: '#/components/schemas/SandboxTemplate' + pagination: + $ref: '#/components/schemas/SandboxPagination' + required: + - data + - pagination + SandboxSessionPage: + type: object + additionalProperties: false + properties: + data: + type: array + items: + $ref: '#/components/schemas/SandboxSession' + pagination: + $ref: '#/components/schemas/SandboxPagination' + required: + - data + - pagination + SandboxDeploymentPage: + type: object + additionalProperties: false + properties: + data: + type: array + items: + $ref: '#/components/schemas/SandboxDeployment' + pagination: + $ref: '#/components/schemas/SandboxPagination' + required: + - data + - pagination + SandboxPresetList: + type: object + additionalProperties: false + properties: + data: + type: array + items: + $ref: '#/components/schemas/SandboxPreset' + required: + - data + SandboxCapacity: + type: object + additionalProperties: false + properties: + region: + type: string + allocated_memory_mb: + type: integer + format: int64 + minimum: 0 + required: + - region + - allocated_memory_mb + SandboxCapacityList: + type: object + additionalProperties: false + properties: + data: + type: array + items: + $ref: '#/components/schemas/SandboxCapacity' + required: + - data + PublishSandboxPresetRequest: + type: object + additionalProperties: false + properties: + id: + type: string + format: uuid + preset: + type: string + enum: + - python3.12 + - node22 + memory_mb: + type: integer + enum: + - 1024 + - 2048 + deployment_id: + type: string + format: uuid + required: + - id + - preset + - memory_mb + - deployment_id AnonKey: type: object properties: diff --git a/orval.config.mjs b/orval.config.mjs index 7bfe3574..25bae697 100644 --- a/orval.config.mjs +++ b/orval.config.mjs @@ -1,6 +1,24 @@ import { defineConfig, defineTransformer } from 'orval'; const sdkOperations = new Set([ + 'listSandboxPresets', + 'listSandboxes', + 'createSandbox', + 'getSandbox', + 'deleteSandbox', + 'listSandboxSessions', + 'createSandboxSession', + 'executeSandbox', + 'getSandboxSession', + 'terminateSandboxSession', + 'suspendSandboxSession', + 'resumeSandboxSession', + 'executeSandboxSession', + 'readSandboxSessionFile', + 'writeSandboxSessionFile', + 'grantSandboxSession', + 'revokeSandboxSession', + 'createSandboxSessionAccess', 'acquireProjectLock', 'authSignin', 'downloadStorageObject', diff --git a/package.json b/package.json index b8ecba0e..1568a6b8 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "test:coverage": "pnpm build && jest --coverage", "prepublishOnly": "npm run build", "test:quickstart": "pnpm test:package && pnpm test:types:package && node .quality-tools/test-package-quickstart.mjs reports/volcano-sdk.tgz", - "test:types:package": "pnpm build && tsc --noEmit -p tsconfig.consumer.json", + "test:types:package": "pnpm build && tsc --noEmit -p tsconfig.consumer.json && tsc --noEmit -p tsconfig.consumer-sandbox.json", "test:examples": "pnpm build && NEXT_PUBLIC_VOLCANO_API_URL=http://127.0.0.1:8787 NEXT_PUBLIC_VOLCANO_ANON_KEY=example-test-key NEXT_PUBLIC_VOLCANO_DATABASE_NAME=app pnpm --dir examples/nextjs-notes-app build", "audit": "pnpm build:tooling && node .quality-tools/audit-dependencies.mjs", "quality": "pnpm quality:policy && pnpm quality:checks && pnpm mutation:full", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e051640..75b8e3a5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,6 +10,8 @@ overrides: '@cucumber/messages>uuid': ^11.1.1 js-yaml@>=4.0.0 <4.3.2: ^4.3.2 typed-rest-client>qs: 6.16.0 + fast-uri@>=3.0.0 <3.1.8: ^3.1.8 + markdown-it@>=14.0.0 <14.3.1: ^14.3.1 importers: .: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 49d4f8b6..5dd9e2cd 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -17,6 +17,9 @@ overrides: 'js-yaml@>=4.0.0 <4.3.2': ^4.3.2 # Stryker's HTTP client resolves a qs release with DoS advisories. 'typed-rest-client>qs': 6.16.0 + # Patch URI parsing and Markdown denial-of-service advisories in tooling. + 'fast-uri@>=3.0.0 <3.1.8': ^3.1.8 + 'markdown-it@>=14.0.0 <14.3.1': ^14.3.1 allowBuilds: protobufjs: true diff --git a/scripts/quality-policy.test.mts b/scripts/quality-policy.test.mts index cc31d959..058751a5 100644 --- a/scripts/quality-policy.test.mts +++ b/scripts/quality-policy.test.mts @@ -23,7 +23,8 @@ const requiredTasks = { 'pnpm build && pnpm pack --out reports/volcano-sdk.tgz && publint reports/volcano-sdk.tgz --strict && attw reports/volcano-sdk.tgz', 'test:quickstart': 'pnpm test:package && pnpm test:types:package && node .quality-tools/test-package-quickstart.mjs reports/volcano-sdk.tgz', - 'test:types:package': 'pnpm build && tsc --noEmit -p tsconfig.consumer.json', + 'test:types:package': + 'pnpm build && tsc --noEmit -p tsconfig.consumer.json && tsc --noEmit -p tsconfig.consumer-sandbox.json', 'test:examples': 'pnpm build && NEXT_PUBLIC_VOLCANO_API_URL=http://127.0.0.1:8787 NEXT_PUBLIC_VOLCANO_ANON_KEY=example-test-key NEXT_PUBLIC_VOLCANO_DATABASE_NAME=app pnpm --dir examples/nextjs-notes-app build', audit: 'pnpm build:tooling && node .quality-tools/audit-dependencies.mjs', diff --git a/src/auth-fetch-retry.ts b/src/auth-fetch-retry.ts index c213458d..b2dab62d 100644 --- a/src/auth-fetch-retry.ts +++ b/src/auth-fetch-retry.ts @@ -19,6 +19,7 @@ export async function fetchWithAuthRetry( client: AuthRetryClient, url: string, options: RequestInit = {}, + timeoutMs = client.timeout, ): Promise { await client._completeOAuthExchange(); const context = client._captureAuthContext(); @@ -29,7 +30,7 @@ export async function fetchWithAuthRetry( ...options, headers: authenticatedHeaders(options.headers, accessToken), }, - client.timeout, + timeoutMs, ); }; diff --git a/src/generated-runtime/generated/client.js b/src/generated-runtime/generated/client.js index ca0ce4b7..c6c14e93 100644 --- a/src/generated-runtime/generated/client.js +++ b/src/generated-runtime/generated/client.js @@ -294,3 +294,369 @@ export const downloadStorageObject = async (bucketName, path, options) => { method: 'GET' }); }; +export const getListSandboxPresetsUrl = () => { + return `/sandboxes/presets`; +}; +/** + * @summary List available sandbox presets + */ +export const listSandboxPresets = async (options) => { + return volcanoFetch(getListSandboxPresetsUrl(), { + ...options, + method: 'GET' + }); +}; +export const getListSandboxesUrl = (id, params) => { + const normalizedParams = new URLSearchParams(); + Object.entries(params || {}).forEach(([key, value]) => { + if (value !== undefined) { + normalizedParams.append(key, value === null ? 'null' : String(value)); + } + }); + const stringifiedParams = normalizedParams.toString(); + return stringifiedParams.length > 0 ? `/projects/${id}/sandboxes?${stringifiedParams}` : `/projects/${id}/sandboxes`; +}; +/** + * @summary List sandbox templates + */ +export const listSandboxes = async (id, params, options) => { + return volcanoFetch(getListSandboxesUrl(id, params), { + ...options, + method: 'GET' + }); +}; +export const getCreateSandboxUrl = (id) => { + return `/projects/${id}/sandboxes`; +}; +/** + * @summary Create a sandbox template from a verified preset + */ +export const createSandbox = async (id, createSandboxTemplateRequest, options) => { + const getHeaders = (h) => { + if (!h) + return {}; + if (h instanceof Headers) + return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries(Array.from(h, (entry) => Array.from(entry))); + } + const headers = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) + headers[name] = value; + } + return headers; + }; + return volcanoFetch(getCreateSandboxUrl(id), { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(createSandboxTemplateRequest) + }); +}; +export const getGetSandboxUrl = (id, sandboxId) => { + return `/projects/${id}/sandboxes/${sandboxId}`; +}; +/** + * @summary Get a sandbox template + */ +export const getSandbox = async (id, sandboxId, options) => { + return volcanoFetch(getGetSandboxUrl(id, sandboxId), { + ...options, + method: 'GET' + }); +}; +export const getDeleteSandboxUrl = (id, sandboxId) => { + return `/projects/${id}/sandboxes/${sandboxId}`; +}; +/** + * @summary Retire a template and terminate its sessions + */ +export const deleteSandbox = async (id, sandboxId, options) => { + return volcanoFetch(getDeleteSandboxUrl(id, sandboxId), { + ...options, + method: 'DELETE' + }); +}; +export const getListSandboxSessionsUrl = (id, params) => { + const normalizedParams = new URLSearchParams(); + Object.entries(params || {}).forEach(([key, value]) => { + if (value !== undefined) { + normalizedParams.append(key, value === null ? 'null' : String(value)); + } + }); + const stringifiedParams = normalizedParams.toString(); + return stringifiedParams.length > 0 ? `/projects/${id}/sandbox-sessions?${stringifiedParams}` : `/projects/${id}/sandbox-sessions`; +}; +/** + * @summary List project sandbox sessions + */ +export const listSandboxSessions = async (id, params, options) => { + return volcanoFetch(getListSandboxSessionsUrl(id, params), { + ...options, + method: 'GET' + }); +}; +export const getCreateSandboxSessionUrl = (id) => { + return `/projects/${id}/sandbox-sessions`; +}; +/** + * @summary Start a sandbox session + */ +export const createSandboxSession = async (id, createSandboxSessionRequest, options) => { + const getHeaders = (h) => { + if (!h) + return {}; + if (h instanceof Headers) + return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries(Array.from(h, (entry) => Array.from(entry))); + } + const headers = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) + headers[name] = value; + } + return headers; + }; + return volcanoFetch(getCreateSandboxSessionUrl(id), { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(createSandboxSessionRequest) + }); +}; +export const getExecuteSandboxUrl = (id) => { + return `/projects/${id}/sandbox-executions`; +}; +/** + * @summary Execute once and return after confirmed termination + */ +export const executeSandbox = async (id, sandboxExecutionRequest, options) => { + const getHeaders = (h) => { + if (!h) + return {}; + if (h instanceof Headers) + return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries(Array.from(h, (entry) => Array.from(entry))); + } + const headers = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) + headers[name] = value; + } + return headers; + }; + return volcanoFetch(getExecuteSandboxUrl(id), { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxExecutionRequest) + }); +}; +export const getGetSandboxSessionUrl = (sessionId) => { + return `/sandbox-sessions/${sessionId}`; +}; +/** + * @summary Get a sandbox session + */ +export const getSandboxSession = async (sessionId, options) => { + return volcanoFetch(getGetSandboxSessionUrl(sessionId), { + ...options, + method: 'GET' + }); +}; +export const getTerminateSandboxSessionUrl = (sessionId) => { + return `/sandbox-sessions/${sessionId}`; +}; +/** + * @summary Request sandbox termination + */ +export const terminateSandboxSession = async (sessionId, options) => { + return volcanoFetch(getTerminateSandboxSessionUrl(sessionId), { + ...options, + method: 'DELETE' + }); +}; +export const getSuspendSandboxSessionUrl = (sessionId) => { + return `/sandbox-sessions/${sessionId}/suspend`; +}; +/** + * @summary Suspend a sandbox session + */ +export const suspendSandboxSession = async (sessionId, options) => { + return volcanoFetch(getSuspendSandboxSessionUrl(sessionId), { + ...options, + method: 'POST' + }); +}; +export const getResumeSandboxSessionUrl = (sessionId) => { + return `/sandbox-sessions/${sessionId}/resume`; +}; +/** + * @summary Resume a sandbox session + */ +export const resumeSandboxSession = async (sessionId, options) => { + return volcanoFetch(getResumeSandboxSessionUrl(sessionId), { + ...options, + method: 'POST' + }); +}; +export const getExecuteSandboxSessionUrl = (sessionId) => { + return `/sandbox-sessions/${sessionId}/exec`; +}; +/** + * @summary Execute a command within a session + */ +export const executeSandboxSession = async (sessionId, sandboxCommandRequest, options) => { + const getHeaders = (h) => { + if (!h) + return {}; + if (h instanceof Headers) + return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries(Array.from(h, (entry) => Array.from(entry))); + } + const headers = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) + headers[name] = value; + } + return headers; + }; + return volcanoFetch(getExecuteSandboxSessionUrl(sessionId), { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxCommandRequest) + }); +}; +export const getReadSandboxSessionFileUrl = (sessionId) => { + return `/sandbox-sessions/${sessionId}/files/read`; +}; +/** + * @summary Read a workspace file + */ +export const readSandboxSessionFile = async (sessionId, sandboxFileReadRequest, options) => { + const getHeaders = (h) => { + if (!h) + return {}; + if (h instanceof Headers) + return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries(Array.from(h, (entry) => Array.from(entry))); + } + const headers = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) + headers[name] = value; + } + return headers; + }; + return volcanoFetch(getReadSandboxSessionFileUrl(sessionId), { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxFileReadRequest) + }); +}; +export const getWriteSandboxSessionFileUrl = (sessionId) => { + return `/sandbox-sessions/${sessionId}/files/write`; +}; +/** + * @summary Write a workspace file + */ +export const writeSandboxSessionFile = async (sessionId, sandboxFileWriteRequest, options) => { + const getHeaders = (h) => { + if (!h) + return {}; + if (h instanceof Headers) + return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries(Array.from(h, (entry) => Array.from(entry))); + } + const headers = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) + headers[name] = value; + } + return headers; + }; + return volcanoFetch(getWriteSandboxSessionFileUrl(sessionId), { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxFileWriteRequest) + }); +}; +export const getGrantSandboxSessionUrl = (sessionId, subjectId) => { + return `/sandbox-sessions/${sessionId}/grants/${subjectId}`; +}; +/** + * @summary Authorize an authenticated project user for this session + */ +export const grantSandboxSession = async (sessionId, subjectId, sandboxSubjectGrantRequest, options) => { + const getHeaders = (h) => { + if (!h) + return {}; + if (h instanceof Headers) + return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries(Array.from(h, (entry) => Array.from(entry))); + } + const headers = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) + headers[name] = value; + } + return headers; + }; + return volcanoFetch(getGrantSandboxSessionUrl(sessionId, subjectId), { + ...options, + method: 'PUT', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxSubjectGrantRequest) + }); +}; +export const getRevokeSandboxSessionUrl = (sessionId, subjectId) => { + return `/sandbox-sessions/${sessionId}/grants/${subjectId}`; +}; +/** + * @summary Revoke a project user session grant + */ +export const revokeSandboxSession = async (sessionId, subjectId, options) => { + return volcanoFetch(getRevokeSandboxSessionUrl(sessionId, subjectId), { + ...options, + method: 'DELETE' + }); +}; +export const getCreateSandboxSessionAccessUrl = (sessionId) => { + return `/sandbox-sessions/${sessionId}/access`; +}; +/** + * @summary Issue a short-lived port-scoped access credential + */ +export const createSandboxSessionAccess = async (sessionId, sandboxAccessRequest, options) => { + const getHeaders = (h) => { + if (!h) + return {}; + if (h instanceof Headers) + return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries(Array.from(h, (entry) => Array.from(entry))); + } + const headers = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) + headers[name] = value; + } + return headers; + }; + return volcanoFetch(getCreateSandboxSessionAccessUrl(sessionId), { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxAccessRequest) + }); +}; diff --git a/src/generated-runtime/generated/model/createSandboxSessionRequest.js b/src/generated-runtime/generated/model/createSandboxSessionRequest.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/createSandboxSessionRequest.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/createSandboxSessionRequestMemoryMb.js b/src/generated-runtime/generated/model/createSandboxSessionRequestMemoryMb.js new file mode 100644 index 00000000..11370b51 --- /dev/null +++ b/src/generated-runtime/generated/model/createSandboxSessionRequestMemoryMb.js @@ -0,0 +1,13 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export const CreateSandboxSessionRequestMemoryMb = { + NUMBER_1024: 1024, + NUMBER_2048: 2048, +}; diff --git a/src/generated-runtime/generated/model/createSandboxTemplateRequest.js b/src/generated-runtime/generated/model/createSandboxTemplateRequest.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/createSandboxTemplateRequest.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/createSandboxTemplateRequestMemoryMb.js b/src/generated-runtime/generated/model/createSandboxTemplateRequestMemoryMb.js new file mode 100644 index 00000000..16c013ac --- /dev/null +++ b/src/generated-runtime/generated/model/createSandboxTemplateRequestMemoryMb.js @@ -0,0 +1,13 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export const CreateSandboxTemplateRequestMemoryMb = { + NUMBER_1024: 1024, + NUMBER_2048: 2048, +}; diff --git a/src/generated-runtime/generated/model/cursorParameter.js b/src/generated-runtime/generated/model/cursorParameter.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/cursorParameter.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/index.js b/src/generated-runtime/generated/model/index.js index ad0e0bf2..027bda57 100644 --- a/src/generated-runtime/generated/model/index.js +++ b/src/generated-runtime/generated/model/index.js @@ -16,8 +16,13 @@ export * from './authUserStatus'; export * from './authUserUserMetadata'; export * from './bandwidthCapExceededResponse'; export * from './completeUploadSessionResponse'; +export * from './createSandboxSessionRequest'; +export * from './createSandboxSessionRequestMemoryMb'; +export * from './createSandboxTemplateRequest'; +export * from './createSandboxTemplateRequestMemoryMb'; export * from './createUploadSessionRequest'; export * from './createUploadSessionResponse'; +export * from './cursorParameter'; export * from './databaseQueryCapExceededResponse'; export * from './databaseQueryFilter'; export * from './databaseQueryFilterOperator'; @@ -32,12 +37,38 @@ export * from './error'; export * from './hostedAuthPageType'; export * from './limitParameter'; export * from './listDurableExecutionsParams'; +export * from './listSandboxesParams'; +export * from './listSandboxSessionsParams'; export * from './lockRequestIdParameter'; export * from './lockTokenParameter'; export * from './pageParameter'; export * from './paginatedDurableExecutions'; export * from './projectLockLease'; export * from './projectLockLeaseRequest'; +export * from './sandboxAccess'; +export * from './sandboxAccessRequest'; +export * from './sandboxCommandRequest'; +export * from './sandboxCommandRequestEnvironment'; +export * from './sandboxCommandResult'; +export * from './sandboxExecutionRequest'; +export * from './sandboxExecutionRequestEnvironment'; +export * from './sandboxExecutionRequestMemoryMb'; +export * from './sandboxExecutionResult'; +export * from './sandboxFileReadRequest'; +export * from './sandboxFileResult'; +export * from './sandboxFileWriteRequest'; +export * from './sandboxPagination'; +export * from './sandboxPreset'; +export * from './sandboxPresetList'; +export * from './sandboxPresetMemoryMb'; +export * from './sandboxSession'; +export * from './sandboxSessionDesiredState'; +export * from './sandboxSessionPage'; +export * from './sandboxSessionState'; +export * from './sandboxSubjectGrantRequest'; +export * from './sandboxTemplate'; +export * from './sandboxTemplatePage'; +export * from './sandboxTemplateStatus'; export * from './storageObject'; export * from './storageObjectMetadata'; export * from './uploadSessionPart'; diff --git a/src/generated-runtime/generated/model/listSandboxSessionsParams.js b/src/generated-runtime/generated/model/listSandboxSessionsParams.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/listSandboxSessionsParams.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/listSandboxesParams.js b/src/generated-runtime/generated/model/listSandboxesParams.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/listSandboxesParams.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxAccess.js b/src/generated-runtime/generated/model/sandboxAccess.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxAccess.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxAccessRequest.js b/src/generated-runtime/generated/model/sandboxAccessRequest.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxAccessRequest.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxCommandRequest.js b/src/generated-runtime/generated/model/sandboxCommandRequest.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxCommandRequest.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxCommandRequestEnvironment.js b/src/generated-runtime/generated/model/sandboxCommandRequestEnvironment.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxCommandRequestEnvironment.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxCommandResult.js b/src/generated-runtime/generated/model/sandboxCommandResult.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxCommandResult.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxExecutionRequest.js b/src/generated-runtime/generated/model/sandboxExecutionRequest.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxExecutionRequest.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxExecutionRequestEnvironment.js b/src/generated-runtime/generated/model/sandboxExecutionRequestEnvironment.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxExecutionRequestEnvironment.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxExecutionRequestMemoryMb.js b/src/generated-runtime/generated/model/sandboxExecutionRequestMemoryMb.js new file mode 100644 index 00000000..51e1a2e7 --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxExecutionRequestMemoryMb.js @@ -0,0 +1,13 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export const SandboxExecutionRequestMemoryMb = { + NUMBER_1024: 1024, + NUMBER_2048: 2048, +}; diff --git a/src/generated-runtime/generated/model/sandboxExecutionResult.js b/src/generated-runtime/generated/model/sandboxExecutionResult.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxExecutionResult.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxFileReadRequest.js b/src/generated-runtime/generated/model/sandboxFileReadRequest.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxFileReadRequest.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxFileResult.js b/src/generated-runtime/generated/model/sandboxFileResult.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxFileResult.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxFileWriteRequest.js b/src/generated-runtime/generated/model/sandboxFileWriteRequest.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxFileWriteRequest.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxPagination.js b/src/generated-runtime/generated/model/sandboxPagination.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxPagination.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxPreset.js b/src/generated-runtime/generated/model/sandboxPreset.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxPreset.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxPresetList.js b/src/generated-runtime/generated/model/sandboxPresetList.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxPresetList.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxPresetMemoryMb.js b/src/generated-runtime/generated/model/sandboxPresetMemoryMb.js new file mode 100644 index 00000000..c53f1530 --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxPresetMemoryMb.js @@ -0,0 +1,13 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export const SandboxPresetMemoryMb = { + NUMBER_1024: 1024, + NUMBER_2048: 2048, +}; diff --git a/src/generated-runtime/generated/model/sandboxSession.js b/src/generated-runtime/generated/model/sandboxSession.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxSession.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxSessionDesiredState.js b/src/generated-runtime/generated/model/sandboxSessionDesiredState.js new file mode 100644 index 00000000..003f425f --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxSessionDesiredState.js @@ -0,0 +1,14 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export const SandboxSessionDesiredState = { + running: 'running', + suspended: 'suspended', + terminated: 'terminated', +}; diff --git a/src/generated-runtime/generated/model/sandboxSessionPage.js b/src/generated-runtime/generated/model/sandboxSessionPage.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxSessionPage.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxSessionState.js b/src/generated-runtime/generated/model/sandboxSessionState.js new file mode 100644 index 00000000..c8b9574c --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxSessionState.js @@ -0,0 +1,19 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export const SandboxSessionState = { + starting: 'starting', + running: 'running', + suspending: 'suspending', + suspended: 'suspended', + resuming: 'resuming', + terminating: 'terminating', + terminated: 'terminated', + unknown: 'unknown', +}; diff --git a/src/generated-runtime/generated/model/sandboxSubjectGrantRequest.js b/src/generated-runtime/generated/model/sandboxSubjectGrantRequest.js new file mode 100644 index 00000000..5346660d --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxSubjectGrantRequest.js @@ -0,0 +1,10 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxTemplate.js b/src/generated-runtime/generated/model/sandboxTemplate.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxTemplate.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxTemplatePage.js b/src/generated-runtime/generated/model/sandboxTemplatePage.js new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxTemplatePage.js @@ -0,0 +1 @@ +export {}; diff --git a/src/generated-runtime/generated/model/sandboxTemplateStatus.js b/src/generated-runtime/generated/model/sandboxTemplateStatus.js new file mode 100644 index 00000000..55f76c0e --- /dev/null +++ b/src/generated-runtime/generated/model/sandboxTemplateStatus.js @@ -0,0 +1,14 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +export const SandboxTemplateStatus = { + ready: 'ready', + unavailable: 'unavailable', + deleting: 'deleting', +}; diff --git a/src/generated-runtime/volcano-fetch.js b/src/generated-runtime/volcano-fetch.js index 369a465c..e1fad29c 100644 --- a/src/generated-runtime/volcano-fetch.js +++ b/src/generated-runtime/volcano-fetch.js @@ -49,11 +49,11 @@ function errorMessage(status, data) { return `Request failed with status ${String(status)}`; } export async function volcanoFetch(path, options) { - const { volcanoAuthorization, volcanoClient, volcanoResponseType, ...request } = options; + const { volcanoAuthorization, volcanoClient, volcanoResponseType, volcanoTimeoutMs, ...request } = options; if (volcanoClient === undefined || volcanoAuthorization === undefined) { throw new Error('Generated transport requires a Volcano client and authorization mode'); } - const response = await volcanoClient._generatedFetch(path, request, volcanoAuthorization); + const response = await volcanoClient._generatedFetch(path, request, volcanoAuthorization, volcanoTimeoutMs); const data = await responseData(response, volcanoResponseType); if (!response.ok) { throw responseError(response, data); diff --git a/src/generated/client.ts b/src/generated/client.ts index 31168c6a..15cb404c 100644 --- a/src/generated/client.ts +++ b/src/generated/client.ts @@ -11,20 +11,46 @@ import type { AuthSigninBody, AuthTokenResponse, BandwidthCapExceededResponse, + CreateSandboxSessionRequest, + CreateSandboxTemplateRequest, DatabaseQueryCapExceededResponse, DatabaseQueryResult, DatabaseSelectRequest, DurableExecution, Error, ListDurableExecutionsParams, + ListSandboxSessionsParams, + ListSandboxesParams, PaginatedDurableExecutions, ProjectLockLease, ProjectLockLeaseRequest, + SandboxAccess, + SandboxAccessRequest, + SandboxCommandRequest, + SandboxCommandResult, + SandboxExecutionRequest, + SandboxExecutionResult, + SandboxFileReadRequest, + SandboxFileResult, + SandboxFileWriteRequest, + SandboxPresetList, + SandboxSession, + SandboxSessionPage, + SandboxSubjectGrantRequest, + SandboxTemplate, + SandboxTemplatePage, UploadSessionStatusResponse, UploadStorageObjectBodyOne } from './model'; import { volcanoFetch } from '../volcano-fetch'; +export type HTTPStatusCode1xx = 100 | 101 | 102 | 103; +export type HTTPStatusCode2xx = 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207; +export type HTTPStatusCode3xx = 300 | 301 | 302 | 303 | 304 | 305 | 307 | 308; +export type HTTPStatusCode4xx = 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 426 | 428 | 429 | 431 | 451; +export type HTTPStatusCode5xx = 500 | 501 | 502 | 503 | 504 | 505 | 507 | 511; +export type HTTPStatusCodes = HTTPStatusCode1xx | HTTPStatusCode2xx | HTTPStatusCode3xx | HTTPStatusCode4xx | HTTPStatusCode5xx; + export type startDurableExecutionFromApplicationResponse202 = { data: DurableExecution status: 202 @@ -792,3 +818,923 @@ export const downloadStorageObject = async (bucketName: string, } );} + + + +export type listSandboxPresetsResponse200 = { + data: SandboxPresetList + status: 200 +} + +export type listSandboxPresetsResponseDefault = { + data: Error + status: Exclude +} + +export type listSandboxPresetsResponseSuccess = (listSandboxPresetsResponse200) & { + headers: Headers; +}; +export type listSandboxPresetsResponseError = (listSandboxPresetsResponseDefault) & { + headers: Headers; +}; + +export type listSandboxPresetsResponse = (listSandboxPresetsResponseSuccess | listSandboxPresetsResponseError) + +export const getListSandboxPresetsUrl = () => { + + + + + return `/sandboxes/presets` +} + +/** + * @summary List available sandbox presets + */ +export const listSandboxPresets = async ( options?: Parameters[1]): Promise => { + + return volcanoFetch(getListSandboxPresetsUrl(), + { + ...options, + method: 'GET' + + + } +);} + + + +export type listSandboxesResponse200 = { + data: SandboxTemplatePage + status: 200 +} + +export type listSandboxesResponseDefault = { + data: Error + status: Exclude +} + +export type listSandboxesResponseSuccess = (listSandboxesResponse200) & { + headers: Headers; +}; +export type listSandboxesResponseError = (listSandboxesResponseDefault) & { + headers: Headers; +}; + +export type listSandboxesResponse = (listSandboxesResponseSuccess | listSandboxesResponseError) + +export const getListSandboxesUrl = (id: string, + params?: ListSandboxesParams,) => { + const normalizedParams = new URLSearchParams(); + + Object.entries(params || {}).forEach(([key, value]) => { + + if (value !== undefined) { + normalizedParams.append(key, value === null ? 'null' : String(value)) + } + }); + + const stringifiedParams = normalizedParams.toString(); + + return stringifiedParams.length > 0 ? `/projects/${id}/sandboxes?${stringifiedParams}` : `/projects/${id}/sandboxes` +} + +/** + * @summary List sandbox templates + */ +export const listSandboxes = async (id: string, + params?: ListSandboxesParams, options?: Parameters[1]): Promise => { + + return volcanoFetch(getListSandboxesUrl(id,params), + { + ...options, + method: 'GET' + + + } +);} + + + +export type createSandboxResponse201 = { + data: SandboxTemplate + status: 201 +} + +export type createSandboxResponseDefault = { + data: Error + status: Exclude +} + +export type createSandboxResponseSuccess = (createSandboxResponse201) & { + headers: Headers; +}; +export type createSandboxResponseError = (createSandboxResponseDefault) & { + headers: Headers; +}; + +export type createSandboxResponse = (createSandboxResponseSuccess | createSandboxResponseError) + +export const getCreateSandboxUrl = (id: string,) => { + + + + + return `/projects/${id}/sandboxes` +} + +/** + * @summary Create a sandbox template from a verified preset + */ +export const createSandbox = async (id: string, + createSandboxTemplateRequest: CreateSandboxTemplateRequest, options?: Parameters[1]): Promise => { + + const getHeaders = (h?: NonNullable): Record => { + if (!h) return {}; + if (h instanceof Headers) return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries( + Array.from(h as Iterable>, (entry) => Array.from(entry) as [string, string]), + ); + } + const headers: Record = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) headers[name] = value; + } + return headers; + }; +return volcanoFetch(getCreateSandboxUrl(id), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(createSandboxTemplateRequest) + } +);} + + + +export type getSandboxResponse200 = { + data: SandboxTemplate + status: 200 +} + +export type getSandboxResponseDefault = { + data: Error + status: Exclude +} + +export type getSandboxResponseSuccess = (getSandboxResponse200) & { + headers: Headers; +}; +export type getSandboxResponseError = (getSandboxResponseDefault) & { + headers: Headers; +}; + +export type getSandboxResponse = (getSandboxResponseSuccess | getSandboxResponseError) + +export const getGetSandboxUrl = (id: string, + sandboxId: string,) => { + + + + + return `/projects/${id}/sandboxes/${sandboxId}` +} + +/** + * @summary Get a sandbox template + */ +export const getSandbox = async (id: string, + sandboxId: string, options?: Parameters[1]): Promise => { + + return volcanoFetch(getGetSandboxUrl(id,sandboxId), + { + ...options, + method: 'GET' + + + } +);} + + + +export type deleteSandboxResponse202 = { + data: void + status: 202 +} + +export type deleteSandboxResponseDefault = { + data: Error + status: Exclude +} + +export type deleteSandboxResponseSuccess = (deleteSandboxResponse202) & { + headers: Headers; +}; +export type deleteSandboxResponseError = (deleteSandboxResponseDefault) & { + headers: Headers; +}; + +export type deleteSandboxResponse = (deleteSandboxResponseSuccess | deleteSandboxResponseError) + +export const getDeleteSandboxUrl = (id: string, + sandboxId: string,) => { + + + + + return `/projects/${id}/sandboxes/${sandboxId}` +} + +/** + * @summary Retire a template and terminate its sessions + */ +export const deleteSandbox = async (id: string, + sandboxId: string, options?: Parameters[1]): Promise => { + + return volcanoFetch(getDeleteSandboxUrl(id,sandboxId), + { + ...options, + method: 'DELETE' + + + } +);} + + + +export type listSandboxSessionsResponse200 = { + data: SandboxSessionPage + status: 200 +} + +export type listSandboxSessionsResponseDefault = { + data: Error + status: Exclude +} + +export type listSandboxSessionsResponseSuccess = (listSandboxSessionsResponse200) & { + headers: Headers; +}; +export type listSandboxSessionsResponseError = (listSandboxSessionsResponseDefault) & { + headers: Headers; +}; + +export type listSandboxSessionsResponse = (listSandboxSessionsResponseSuccess | listSandboxSessionsResponseError) + +export const getListSandboxSessionsUrl = (id: string, + params?: ListSandboxSessionsParams,) => { + const normalizedParams = new URLSearchParams(); + + Object.entries(params || {}).forEach(([key, value]) => { + + if (value !== undefined) { + normalizedParams.append(key, value === null ? 'null' : String(value)) + } + }); + + const stringifiedParams = normalizedParams.toString(); + + return stringifiedParams.length > 0 ? `/projects/${id}/sandbox-sessions?${stringifiedParams}` : `/projects/${id}/sandbox-sessions` +} + +/** + * @summary List project sandbox sessions + */ +export const listSandboxSessions = async (id: string, + params?: ListSandboxSessionsParams, options?: Parameters[1]): Promise => { + + return volcanoFetch(getListSandboxSessionsUrl(id,params), + { + ...options, + method: 'GET' + + + } +);} + + + +export type createSandboxSessionResponse201 = { + data: SandboxSession + status: 201 +} + +export type createSandboxSessionResponseDefault = { + data: Error + status: Exclude +} + +export type createSandboxSessionResponseSuccess = (createSandboxSessionResponse201) & { + headers: Headers; +}; +export type createSandboxSessionResponseError = (createSandboxSessionResponseDefault) & { + headers: Headers; +}; + +export type createSandboxSessionResponse = (createSandboxSessionResponseSuccess | createSandboxSessionResponseError) + +export const getCreateSandboxSessionUrl = (id: string,) => { + + + + + return `/projects/${id}/sandbox-sessions` +} + +/** + * @summary Start a sandbox session + */ +export const createSandboxSession = async (id: string, + createSandboxSessionRequest: CreateSandboxSessionRequest, options?: Parameters[1]): Promise => { + + const getHeaders = (h?: NonNullable): Record => { + if (!h) return {}; + if (h instanceof Headers) return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries( + Array.from(h as Iterable>, (entry) => Array.from(entry) as [string, string]), + ); + } + const headers: Record = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) headers[name] = value; + } + return headers; + }; +return volcanoFetch(getCreateSandboxSessionUrl(id), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(createSandboxSessionRequest) + } +);} + + + +export type executeSandboxResponse200 = { + data: SandboxExecutionResult + status: 200 +} + +export type executeSandboxResponseDefault = { + data: Error + status: Exclude +} + +export type executeSandboxResponseSuccess = (executeSandboxResponse200) & { + headers: Headers; +}; +export type executeSandboxResponseError = (executeSandboxResponseDefault) & { + headers: Headers; +}; + +export type executeSandboxResponse = (executeSandboxResponseSuccess | executeSandboxResponseError) + +export const getExecuteSandboxUrl = (id: string,) => { + + + + + return `/projects/${id}/sandbox-executions` +} + +/** + * @summary Execute once and return after confirmed termination + */ +export const executeSandbox = async (id: string, + sandboxExecutionRequest: SandboxExecutionRequest, options?: Parameters[1]): Promise => { + + const getHeaders = (h?: NonNullable): Record => { + if (!h) return {}; + if (h instanceof Headers) return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries( + Array.from(h as Iterable>, (entry) => Array.from(entry) as [string, string]), + ); + } + const headers: Record = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) headers[name] = value; + } + return headers; + }; +return volcanoFetch(getExecuteSandboxUrl(id), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxExecutionRequest) + } +);} + + + +export type getSandboxSessionResponse200 = { + data: SandboxSession + status: 200 +} + +export type getSandboxSessionResponseDefault = { + data: Error + status: Exclude +} + +export type getSandboxSessionResponseSuccess = (getSandboxSessionResponse200) & { + headers: Headers; +}; +export type getSandboxSessionResponseError = (getSandboxSessionResponseDefault) & { + headers: Headers; +}; + +export type getSandboxSessionResponse = (getSandboxSessionResponseSuccess | getSandboxSessionResponseError) + +export const getGetSandboxSessionUrl = (sessionId: string,) => { + + + + + return `/sandbox-sessions/${sessionId}` +} + +/** + * @summary Get a sandbox session + */ +export const getSandboxSession = async (sessionId: string, options?: Parameters[1]): Promise => { + + return volcanoFetch(getGetSandboxSessionUrl(sessionId), + { + ...options, + method: 'GET' + + + } +);} + + + +export type terminateSandboxSessionResponse202 = { + data: SandboxSession + status: 202 +} + +export type terminateSandboxSessionResponseDefault = { + data: Error + status: Exclude +} + +export type terminateSandboxSessionResponseSuccess = (terminateSandboxSessionResponse202) & { + headers: Headers; +}; +export type terminateSandboxSessionResponseError = (terminateSandboxSessionResponseDefault) & { + headers: Headers; +}; + +export type terminateSandboxSessionResponse = (terminateSandboxSessionResponseSuccess | terminateSandboxSessionResponseError) + +export const getTerminateSandboxSessionUrl = (sessionId: string,) => { + + + + + return `/sandbox-sessions/${sessionId}` +} + +/** + * @summary Request sandbox termination + */ +export const terminateSandboxSession = async (sessionId: string, options?: Parameters[1]): Promise => { + + return volcanoFetch(getTerminateSandboxSessionUrl(sessionId), + { + ...options, + method: 'DELETE' + + + } +);} + + + +export type suspendSandboxSessionResponse202 = { + data: SandboxSession + status: 202 +} + +export type suspendSandboxSessionResponseDefault = { + data: Error + status: Exclude +} + +export type suspendSandboxSessionResponseSuccess = (suspendSandboxSessionResponse202) & { + headers: Headers; +}; +export type suspendSandboxSessionResponseError = (suspendSandboxSessionResponseDefault) & { + headers: Headers; +}; + +export type suspendSandboxSessionResponse = (suspendSandboxSessionResponseSuccess | suspendSandboxSessionResponseError) + +export const getSuspendSandboxSessionUrl = (sessionId: string,) => { + + + + + return `/sandbox-sessions/${sessionId}/suspend` +} + +/** + * @summary Suspend a sandbox session + */ +export const suspendSandboxSession = async (sessionId: string, options?: Parameters[1]): Promise => { + + return volcanoFetch(getSuspendSandboxSessionUrl(sessionId), + { + ...options, + method: 'POST' + + + } +);} + + + +export type resumeSandboxSessionResponse202 = { + data: SandboxSession + status: 202 +} + +export type resumeSandboxSessionResponseDefault = { + data: Error + status: Exclude +} + +export type resumeSandboxSessionResponseSuccess = (resumeSandboxSessionResponse202) & { + headers: Headers; +}; +export type resumeSandboxSessionResponseError = (resumeSandboxSessionResponseDefault) & { + headers: Headers; +}; + +export type resumeSandboxSessionResponse = (resumeSandboxSessionResponseSuccess | resumeSandboxSessionResponseError) + +export const getResumeSandboxSessionUrl = (sessionId: string,) => { + + + + + return `/sandbox-sessions/${sessionId}/resume` +} + +/** + * @summary Resume a sandbox session + */ +export const resumeSandboxSession = async (sessionId: string, options?: Parameters[1]): Promise => { + + return volcanoFetch(getResumeSandboxSessionUrl(sessionId), + { + ...options, + method: 'POST' + + + } +);} + + + +export type executeSandboxSessionResponse200 = { + data: SandboxCommandResult + status: 200 +} + +export type executeSandboxSessionResponseDefault = { + data: Error + status: Exclude +} + +export type executeSandboxSessionResponseSuccess = (executeSandboxSessionResponse200) & { + headers: Headers; +}; +export type executeSandboxSessionResponseError = (executeSandboxSessionResponseDefault) & { + headers: Headers; +}; + +export type executeSandboxSessionResponse = (executeSandboxSessionResponseSuccess | executeSandboxSessionResponseError) + +export const getExecuteSandboxSessionUrl = (sessionId: string,) => { + + + + + return `/sandbox-sessions/${sessionId}/exec` +} + +/** + * @summary Execute a command within a session + */ +export const executeSandboxSession = async (sessionId: string, + sandboxCommandRequest: SandboxCommandRequest, options?: Parameters[1]): Promise => { + + const getHeaders = (h?: NonNullable): Record => { + if (!h) return {}; + if (h instanceof Headers) return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries( + Array.from(h as Iterable>, (entry) => Array.from(entry) as [string, string]), + ); + } + const headers: Record = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) headers[name] = value; + } + return headers; + }; +return volcanoFetch(getExecuteSandboxSessionUrl(sessionId), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxCommandRequest) + } +);} + + + +export type readSandboxSessionFileResponse200 = { + data: SandboxFileResult + status: 200 +} + +export type readSandboxSessionFileResponseDefault = { + data: Error + status: Exclude +} + +export type readSandboxSessionFileResponseSuccess = (readSandboxSessionFileResponse200) & { + headers: Headers; +}; +export type readSandboxSessionFileResponseError = (readSandboxSessionFileResponseDefault) & { + headers: Headers; +}; + +export type readSandboxSessionFileResponse = (readSandboxSessionFileResponseSuccess | readSandboxSessionFileResponseError) + +export const getReadSandboxSessionFileUrl = (sessionId: string,) => { + + + + + return `/sandbox-sessions/${sessionId}/files/read` +} + +/** + * @summary Read a workspace file + */ +export const readSandboxSessionFile = async (sessionId: string, + sandboxFileReadRequest: SandboxFileReadRequest, options?: Parameters[1]): Promise => { + + const getHeaders = (h?: NonNullable): Record => { + if (!h) return {}; + if (h instanceof Headers) return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries( + Array.from(h as Iterable>, (entry) => Array.from(entry) as [string, string]), + ); + } + const headers: Record = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) headers[name] = value; + } + return headers; + }; +return volcanoFetch(getReadSandboxSessionFileUrl(sessionId), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxFileReadRequest) + } +);} + + + +export type writeSandboxSessionFileResponse204 = { + data: void + status: 204 +} + +export type writeSandboxSessionFileResponseDefault = { + data: Error + status: Exclude +} + +export type writeSandboxSessionFileResponseSuccess = (writeSandboxSessionFileResponse204) & { + headers: Headers; +}; +export type writeSandboxSessionFileResponseError = (writeSandboxSessionFileResponseDefault) & { + headers: Headers; +}; + +export type writeSandboxSessionFileResponse = (writeSandboxSessionFileResponseSuccess | writeSandboxSessionFileResponseError) + +export const getWriteSandboxSessionFileUrl = (sessionId: string,) => { + + + + + return `/sandbox-sessions/${sessionId}/files/write` +} + +/** + * @summary Write a workspace file + */ +export const writeSandboxSessionFile = async (sessionId: string, + sandboxFileWriteRequest: SandboxFileWriteRequest, options?: Parameters[1]): Promise => { + + const getHeaders = (h?: NonNullable): Record => { + if (!h) return {}; + if (h instanceof Headers) return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries( + Array.from(h as Iterable>, (entry) => Array.from(entry) as [string, string]), + ); + } + const headers: Record = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) headers[name] = value; + } + return headers; + }; +return volcanoFetch(getWriteSandboxSessionFileUrl(sessionId), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxFileWriteRequest) + } +);} + + + +export type grantSandboxSessionResponse204 = { + data: void + status: 204 +} + +export type grantSandboxSessionResponseDefault = { + data: Error + status: Exclude +} + +export type grantSandboxSessionResponseSuccess = (grantSandboxSessionResponse204) & { + headers: Headers; +}; +export type grantSandboxSessionResponseError = (grantSandboxSessionResponseDefault) & { + headers: Headers; +}; + +export type grantSandboxSessionResponse = (grantSandboxSessionResponseSuccess | grantSandboxSessionResponseError) + +export const getGrantSandboxSessionUrl = (sessionId: string, + subjectId: string,) => { + + + + + return `/sandbox-sessions/${sessionId}/grants/${subjectId}` +} + +/** + * @summary Authorize an authenticated project user for this session + */ +export const grantSandboxSession = async (sessionId: string, + subjectId: string, + sandboxSubjectGrantRequest: SandboxSubjectGrantRequest, options?: Parameters[1]): Promise => { + + const getHeaders = (h?: NonNullable): Record => { + if (!h) return {}; + if (h instanceof Headers) return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries( + Array.from(h as Iterable>, (entry) => Array.from(entry) as [string, string]), + ); + } + const headers: Record = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) headers[name] = value; + } + return headers; + }; +return volcanoFetch(getGrantSandboxSessionUrl(sessionId,subjectId), + { + ...options, + method: 'PUT', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxSubjectGrantRequest) + } +);} + + + +export type revokeSandboxSessionResponse204 = { + data: void + status: 204 +} + +export type revokeSandboxSessionResponseDefault = { + data: Error + status: Exclude +} + +export type revokeSandboxSessionResponseSuccess = (revokeSandboxSessionResponse204) & { + headers: Headers; +}; +export type revokeSandboxSessionResponseError = (revokeSandboxSessionResponseDefault) & { + headers: Headers; +}; + +export type revokeSandboxSessionResponse = (revokeSandboxSessionResponseSuccess | revokeSandboxSessionResponseError) + +export const getRevokeSandboxSessionUrl = (sessionId: string, + subjectId: string,) => { + + + + + return `/sandbox-sessions/${sessionId}/grants/${subjectId}` +} + +/** + * @summary Revoke a project user session grant + */ +export const revokeSandboxSession = async (sessionId: string, + subjectId: string, options?: Parameters[1]): Promise => { + + return volcanoFetch(getRevokeSandboxSessionUrl(sessionId,subjectId), + { + ...options, + method: 'DELETE' + + + } +);} + + + +export type createSandboxSessionAccessResponse200 = { + data: SandboxAccess + status: 200 +} + +export type createSandboxSessionAccessResponseDefault = { + data: Error + status: Exclude +} + +export type createSandboxSessionAccessResponseSuccess = (createSandboxSessionAccessResponse200) & { + headers: Headers; +}; +export type createSandboxSessionAccessResponseError = (createSandboxSessionAccessResponseDefault) & { + headers: Headers; +}; + +export type createSandboxSessionAccessResponse = (createSandboxSessionAccessResponseSuccess | createSandboxSessionAccessResponseError) + +export const getCreateSandboxSessionAccessUrl = (sessionId: string,) => { + + + + + return `/sandbox-sessions/${sessionId}/access` +} + +/** + * @summary Issue a short-lived port-scoped access credential + */ +export const createSandboxSessionAccess = async (sessionId: string, + sandboxAccessRequest: SandboxAccessRequest, options?: Parameters[1]): Promise => { + + const getHeaders = (h?: NonNullable): Record => { + if (!h) return {}; + if (h instanceof Headers) return Object.fromEntries(h.entries()); + if (Symbol.iterator in h) { + return Object.fromEntries( + Array.from(h as Iterable>, (entry) => Array.from(entry) as [string, string]), + ); + } + const headers: Record = {}; + for (const [name, value] of Object.entries(h)) { + if (value !== undefined) headers[name] = value; + } + return headers; + }; +return volcanoFetch(getCreateSandboxSessionAccessUrl(sessionId), + { + ...options, + method: 'POST', + headers: { 'Content-Type': 'application/json', ...getHeaders(options?.headers) }, + body: JSON.stringify(sandboxAccessRequest) + } +);} diff --git a/src/generated/model/createSandboxSessionRequest.ts b/src/generated/model/createSandboxSessionRequest.ts new file mode 100644 index 00000000..4e8007e5 --- /dev/null +++ b/src/generated/model/createSandboxSessionRequest.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { CreateSandboxSessionRequestMemoryMb } from './createSandboxSessionRequestMemoryMb'; + +export type CreateSandboxSessionRequest = (unknown & { + /** Preset ID from the available Sandbox preset catalog. */ + preset?: string; + sandbox_id?: string; + memory_mb?: CreateSandboxSessionRequestMemoryMb; + /** + * Region such as `us-east-1`. Region IDs issued by earlier versions of the API are still accepted. + * @pattern ^(aws-)?[a-z]{2}(-[a-z]+)+-[0-9]+$ + */ + region: string; + /** + * @minimum 30 + * @maximum 28800 + */ + max_duration_seconds?: number; + /** + * @minimum 0 + * @maximum 28800 + */ + idle_timeout_seconds?: number; +}); diff --git a/src/generated/model/createSandboxSessionRequestMemoryMb.ts b/src/generated/model/createSandboxSessionRequestMemoryMb.ts new file mode 100644 index 00000000..22687915 --- /dev/null +++ b/src/generated/model/createSandboxSessionRequestMemoryMb.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export type CreateSandboxSessionRequestMemoryMb = typeof CreateSandboxSessionRequestMemoryMb[keyof typeof CreateSandboxSessionRequestMemoryMb]; + + +export const CreateSandboxSessionRequestMemoryMb = { + NUMBER_1024: 1024, + NUMBER_2048: 2048, +} as const; diff --git a/src/generated/model/createSandboxTemplateRequest.ts b/src/generated/model/createSandboxTemplateRequest.ts new file mode 100644 index 00000000..9c228580 --- /dev/null +++ b/src/generated/model/createSandboxTemplateRequest.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { CreateSandboxTemplateRequestMemoryMb } from './createSandboxTemplateRequestMemoryMb'; + +export interface CreateSandboxTemplateRequest { + /** @pattern ^[a-z][a-z0-9-]{0,62}$ */ + name: string; + /** Preset ID from the available Sandbox preset catalog. */ + preset: string; + memory_mb?: CreateSandboxTemplateRequestMemoryMb; +} diff --git a/src/generated/model/createSandboxTemplateRequestMemoryMb.ts b/src/generated/model/createSandboxTemplateRequestMemoryMb.ts new file mode 100644 index 00000000..2380cf78 --- /dev/null +++ b/src/generated/model/createSandboxTemplateRequestMemoryMb.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export type CreateSandboxTemplateRequestMemoryMb = typeof CreateSandboxTemplateRequestMemoryMb[keyof typeof CreateSandboxTemplateRequestMemoryMb]; + + +export const CreateSandboxTemplateRequestMemoryMb = { + NUMBER_1024: 1024, + NUMBER_2048: 2048, +} as const; diff --git a/src/generated/model/cursorParameter.ts b/src/generated/model/cursorParameter.ts new file mode 100644 index 00000000..07d82948 --- /dev/null +++ b/src/generated/model/cursorParameter.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +/** + * Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ +export type CursorParameter = string; diff --git a/src/generated/model/index.ts b/src/generated/model/index.ts index 64dc4293..6cd6d4bb 100644 --- a/src/generated/model/index.ts +++ b/src/generated/model/index.ts @@ -17,8 +17,13 @@ export * from './authUserStatus'; export * from './authUserUserMetadata'; export * from './bandwidthCapExceededResponse'; export * from './completeUploadSessionResponse'; +export * from './createSandboxSessionRequest'; +export * from './createSandboxSessionRequestMemoryMb'; +export * from './createSandboxTemplateRequest'; +export * from './createSandboxTemplateRequestMemoryMb'; export * from './createUploadSessionRequest'; export * from './createUploadSessionResponse'; +export * from './cursorParameter'; export * from './databaseQueryCapExceededResponse'; export * from './databaseQueryFilter'; export * from './databaseQueryFilterOperator'; @@ -33,12 +38,38 @@ export * from './error'; export * from './hostedAuthPageType'; export * from './limitParameter'; export * from './listDurableExecutionsParams'; +export * from './listSandboxesParams'; +export * from './listSandboxSessionsParams'; export * from './lockRequestIdParameter'; export * from './lockTokenParameter'; export * from './pageParameter'; export * from './paginatedDurableExecutions'; export * from './projectLockLease'; export * from './projectLockLeaseRequest'; +export * from './sandboxAccess'; +export * from './sandboxAccessRequest'; +export * from './sandboxCommandRequest'; +export * from './sandboxCommandRequestEnvironment'; +export * from './sandboxCommandResult'; +export * from './sandboxExecutionRequest'; +export * from './sandboxExecutionRequestEnvironment'; +export * from './sandboxExecutionRequestMemoryMb'; +export * from './sandboxExecutionResult'; +export * from './sandboxFileReadRequest'; +export * from './sandboxFileResult'; +export * from './sandboxFileWriteRequest'; +export * from './sandboxPagination'; +export * from './sandboxPreset'; +export * from './sandboxPresetList'; +export * from './sandboxPresetMemoryMb'; +export * from './sandboxSession'; +export * from './sandboxSessionDesiredState'; +export * from './sandboxSessionPage'; +export * from './sandboxSessionState'; +export * from './sandboxSubjectGrantRequest'; +export * from './sandboxTemplate'; +export * from './sandboxTemplatePage'; +export * from './sandboxTemplateStatus'; export * from './storageObject'; export * from './storageObjectMetadata'; export * from './uploadSessionPart'; diff --git a/src/generated/model/listSandboxSessionsParams.ts b/src/generated/model/listSandboxSessionsParams.ts new file mode 100644 index 00000000..5e898da8 --- /dev/null +++ b/src/generated/model/listSandboxSessionsParams.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { CursorParameter } from './cursorParameter'; +import type { LimitParameter } from './limitParameter'; + +export type ListSandboxSessionsParams = { +/** + * Number of items per page (max 100) + * @minimum 1 + * @maximum 100 + */ +limit?: LimitParameter; +/** + * Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ +cursor?: CursorParameter; +}; diff --git a/src/generated/model/listSandboxesParams.ts b/src/generated/model/listSandboxesParams.ts new file mode 100644 index 00000000..9ede5b59 --- /dev/null +++ b/src/generated/model/listSandboxesParams.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { CursorParameter } from './cursorParameter'; +import type { LimitParameter } from './limitParameter'; + +export type ListSandboxesParams = { +/** + * Number of items per page (max 100) + * @minimum 1 + * @maximum 100 + */ +limit?: LimitParameter; +/** + * Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ +cursor?: CursorParameter; +}; diff --git a/src/generated/model/sandboxAccess.ts b/src/generated/model/sandboxAccess.ts new file mode 100644 index 00000000..6baac5ca --- /dev/null +++ b/src/generated/model/sandboxAccess.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export interface SandboxAccess { + url: string; + token: string; + expires_at: string; +} diff --git a/src/generated/model/sandboxAccessRequest.ts b/src/generated/model/sandboxAccessRequest.ts new file mode 100644 index 00000000..354b0dc3 --- /dev/null +++ b/src/generated/model/sandboxAccessRequest.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export interface SandboxAccessRequest { + /** + * @minimum 1 + * @maximum 65532 + */ + port: number; + /** + * @minimum 1 + * @maximum 300 + */ + expires_in_seconds?: number; +} diff --git a/src/generated/model/sandboxCommandRequest.ts b/src/generated/model/sandboxCommandRequest.ts new file mode 100644 index 00000000..feaac442 --- /dev/null +++ b/src/generated/model/sandboxCommandRequest.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { SandboxCommandRequestEnvironment } from './sandboxCommandRequestEnvironment'; + +export interface SandboxCommandRequest { + /** + * @minLength 1 + * @maxLength 65536 + */ + command: string; + /** + * @minimum 1 + * @maximum 3600 + */ + timeout_seconds?: number; + environment?: SandboxCommandRequestEnvironment; +} diff --git a/src/generated/model/sandboxCommandRequestEnvironment.ts b/src/generated/model/sandboxCommandRequestEnvironment.ts new file mode 100644 index 00000000..f2c36698 --- /dev/null +++ b/src/generated/model/sandboxCommandRequestEnvironment.ts @@ -0,0 +1,11 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export type SandboxCommandRequestEnvironment = {[key: string]: string}; diff --git a/src/generated/model/sandboxCommandResult.ts b/src/generated/model/sandboxCommandResult.ts new file mode 100644 index 00000000..454ae2a4 --- /dev/null +++ b/src/generated/model/sandboxCommandResult.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export interface SandboxCommandResult { + stdout: string; + stderr: string; + exit_code: number; + stdout_truncated: boolean; + stderr_truncated: boolean; + timed_out: boolean; +} diff --git a/src/generated/model/sandboxExecutionRequest.ts b/src/generated/model/sandboxExecutionRequest.ts new file mode 100644 index 00000000..558b25c1 --- /dev/null +++ b/src/generated/model/sandboxExecutionRequest.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { SandboxExecutionRequestEnvironment } from './sandboxExecutionRequestEnvironment'; +import type { SandboxExecutionRequestMemoryMb } from './sandboxExecutionRequestMemoryMb'; + +export type SandboxExecutionRequest = (unknown & { + /** Preset ID from the available Sandbox preset catalog. */ + preset?: string; + sandbox_id?: string; + memory_mb?: SandboxExecutionRequestMemoryMb; + /** + * Region such as `us-east-1`. Region IDs issued by earlier versions of the API are still accepted. + * @pattern ^(aws-)?[a-z]{2}(-[a-z]+)+-[0-9]+$ + */ + region: string; + /** + * @minLength 1 + * @maxLength 65536 + */ + command: string; + /** + * @minimum 1 + * @maximum 60 + */ + timeout_seconds?: number; + environment?: SandboxExecutionRequestEnvironment; +}); diff --git a/src/generated/model/sandboxExecutionRequestEnvironment.ts b/src/generated/model/sandboxExecutionRequestEnvironment.ts new file mode 100644 index 00000000..e3e0eb75 --- /dev/null +++ b/src/generated/model/sandboxExecutionRequestEnvironment.ts @@ -0,0 +1,11 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export type SandboxExecutionRequestEnvironment = {[key: string]: string}; diff --git a/src/generated/model/sandboxExecutionRequestMemoryMb.ts b/src/generated/model/sandboxExecutionRequestMemoryMb.ts new file mode 100644 index 00000000..092a1aae --- /dev/null +++ b/src/generated/model/sandboxExecutionRequestMemoryMb.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export type SandboxExecutionRequestMemoryMb = typeof SandboxExecutionRequestMemoryMb[keyof typeof SandboxExecutionRequestMemoryMb]; + + +export const SandboxExecutionRequestMemoryMb = { + NUMBER_1024: 1024, + NUMBER_2048: 2048, +} as const; diff --git a/src/generated/model/sandboxExecutionResult.ts b/src/generated/model/sandboxExecutionResult.ts new file mode 100644 index 00000000..011025ae --- /dev/null +++ b/src/generated/model/sandboxExecutionResult.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export interface SandboxExecutionResult { + stdout: string; + stderr: string; + exit_code: number; + stdout_truncated: boolean; + stderr_truncated: boolean; + timed_out: boolean; + session_id: string; + region: string; + /** @minimum 0 */ + duration_ms: number; +} diff --git a/src/generated/model/sandboxFileReadRequest.ts b/src/generated/model/sandboxFileReadRequest.ts new file mode 100644 index 00000000..20e645f6 --- /dev/null +++ b/src/generated/model/sandboxFileReadRequest.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export interface SandboxFileReadRequest { + /** + * @minLength 1 + * @maxLength 4096 + */ + path: string; +} diff --git a/src/generated/model/sandboxFileResult.ts b/src/generated/model/sandboxFileResult.ts new file mode 100644 index 00000000..55e4d795 --- /dev/null +++ b/src/generated/model/sandboxFileResult.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export interface SandboxFileResult { + data: string; +} diff --git a/src/generated/model/sandboxFileWriteRequest.ts b/src/generated/model/sandboxFileWriteRequest.ts new file mode 100644 index 00000000..d8692532 --- /dev/null +++ b/src/generated/model/sandboxFileWriteRequest.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export interface SandboxFileWriteRequest { + /** + * @minLength 1 + * @maxLength 4096 + */ + path: string; + /** @maxLength 11184812 */ + data: string; +} diff --git a/src/generated/model/sandboxPagination.ts b/src/generated/model/sandboxPagination.ts new file mode 100644 index 00000000..3c255ba8 --- /dev/null +++ b/src/generated/model/sandboxPagination.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export interface SandboxPagination { + limit: number; + has_more: boolean; + next_cursor?: string; +} diff --git a/src/generated/model/sandboxPreset.ts b/src/generated/model/sandboxPreset.ts new file mode 100644 index 00000000..d6df0020 --- /dev/null +++ b/src/generated/model/sandboxPreset.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { SandboxPresetMemoryMb } from './sandboxPresetMemoryMb'; + +export interface SandboxPreset { + id: string; + runtime: string; + version: string; + memory_mb: SandboxPresetMemoryMb; + regions: string[]; +} diff --git a/src/generated/model/sandboxPresetList.ts b/src/generated/model/sandboxPresetList.ts new file mode 100644 index 00000000..5f8144e4 --- /dev/null +++ b/src/generated/model/sandboxPresetList.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { SandboxPreset } from './sandboxPreset'; + +export interface SandboxPresetList { + data: SandboxPreset[]; +} diff --git a/src/generated/model/sandboxPresetMemoryMb.ts b/src/generated/model/sandboxPresetMemoryMb.ts new file mode 100644 index 00000000..4fb4f20b --- /dev/null +++ b/src/generated/model/sandboxPresetMemoryMb.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export type SandboxPresetMemoryMb = typeof SandboxPresetMemoryMb[keyof typeof SandboxPresetMemoryMb]; + + +export const SandboxPresetMemoryMb = { + NUMBER_1024: 1024, + NUMBER_2048: 2048, +} as const; diff --git a/src/generated/model/sandboxSession.ts b/src/generated/model/sandboxSession.ts new file mode 100644 index 00000000..67b82898 --- /dev/null +++ b/src/generated/model/sandboxSession.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { SandboxSessionDesiredState } from './sandboxSessionDesiredState'; +import type { SandboxSessionState } from './sandboxSessionState'; + +export interface SandboxSession { + id: string; + project_id: string; + sandbox_id: string; + state: SandboxSessionState; + desired_state: SandboxSessionDesiredState; + region: string; + memory_mb: number; + created_at: string; + started_at?: string; + expires_at: string; +} diff --git a/src/generated/model/sandboxSessionDesiredState.ts b/src/generated/model/sandboxSessionDesiredState.ts new file mode 100644 index 00000000..e456b318 --- /dev/null +++ b/src/generated/model/sandboxSessionDesiredState.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export type SandboxSessionDesiredState = typeof SandboxSessionDesiredState[keyof typeof SandboxSessionDesiredState]; + + +export const SandboxSessionDesiredState = { + running: 'running', + suspended: 'suspended', + terminated: 'terminated', +} as const; diff --git a/src/generated/model/sandboxSessionPage.ts b/src/generated/model/sandboxSessionPage.ts new file mode 100644 index 00000000..fc008063 --- /dev/null +++ b/src/generated/model/sandboxSessionPage.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { SandboxPagination } from './sandboxPagination'; +import type { SandboxSession } from './sandboxSession'; + +export interface SandboxSessionPage { + data: SandboxSession[]; + pagination: SandboxPagination; +} diff --git a/src/generated/model/sandboxSessionState.ts b/src/generated/model/sandboxSessionState.ts new file mode 100644 index 00000000..4e822f9d --- /dev/null +++ b/src/generated/model/sandboxSessionState.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export type SandboxSessionState = typeof SandboxSessionState[keyof typeof SandboxSessionState]; + + +export const SandboxSessionState = { + starting: 'starting', + running: 'running', + suspending: 'suspending', + suspended: 'suspended', + resuming: 'resuming', + terminating: 'terminating', + terminated: 'terminated', + unknown: 'unknown', +} as const; diff --git a/src/generated/model/sandboxSubjectGrantRequest.ts b/src/generated/model/sandboxSubjectGrantRequest.ts new file mode 100644 index 00000000..5a902682 --- /dev/null +++ b/src/generated/model/sandboxSubjectGrantRequest.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export interface SandboxSubjectGrantRequest { + expires_at: string; +} diff --git a/src/generated/model/sandboxTemplate.ts b/src/generated/model/sandboxTemplate.ts new file mode 100644 index 00000000..ae0caceb --- /dev/null +++ b/src/generated/model/sandboxTemplate.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { SandboxTemplateStatus } from './sandboxTemplateStatus'; + +export interface SandboxTemplate { + id: string; + project_id: string; + /** @pattern ^[a-z][a-z0-9-]{0,62}$ */ + name: string; + preset?: string; + memory_mb?: number; + status: SandboxTemplateStatus; + created_at: string; +} diff --git a/src/generated/model/sandboxTemplatePage.ts b/src/generated/model/sandboxTemplatePage.ts new file mode 100644 index 00000000..870e002f --- /dev/null +++ b/src/generated/model/sandboxTemplatePage.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ +import type { SandboxPagination } from './sandboxPagination'; +import type { SandboxTemplate } from './sandboxTemplate'; + +export interface SandboxTemplatePage { + data: SandboxTemplate[]; + pagination: SandboxPagination; +} diff --git a/src/generated/model/sandboxTemplateStatus.ts b/src/generated/model/sandboxTemplateStatus.ts new file mode 100644 index 00000000..c47986f9 --- /dev/null +++ b/src/generated/model/sandboxTemplateStatus.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval 🍺 + * Do not edit manually. + * Volcano Hosting API + * Public API for Volcano Hosting clients, SDKs, and CLI tooling (Port 8000). + * + * This specification intentionally excludes first-party/internal APIs. See api/openapi-internal.yaml for non-public internal and Builder operations. + * OpenAPI spec version: 3.0.0 + */ + +export type SandboxTemplateStatus = typeof SandboxTemplateStatus[keyof typeof SandboxTemplateStatus]; + + +export const SandboxTemplateStatus = { + ready: 'ready', + unavailable: 'unavailable', + deleting: 'deleting', +} as const; diff --git a/src/generated/openapi.d.ts b/src/generated/openapi.d.ts index b28f4d56..9958c91c 100644 --- a/src/generated/openapi.d.ts +++ b/src/generated/openapi.d.ts @@ -4527,59 +4527,491 @@ export interface paths { patch?: never; trace?: never; }; + "/sandboxes/presets": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List available sandbox presets */ + get: operations["listSandboxPresets"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/projects/{id}/sandboxes": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List sandbox templates */ + get: operations["listSandboxes"]; + put?: never; + /** Create a sandbox template from a verified preset */ + post: operations["createSandbox"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/projects/{id}/sandboxes/{sandboxId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get a sandbox template */ + get: operations["getSandbox"]; + put?: never; + post?: never; + /** Retire a template and terminate its sessions */ + delete: operations["deleteSandbox"]; + options?: never; + head?: never; + /** Rename a sandbox template */ + patch: operations["updateSandbox"]; + trace?: never; + }; + "/projects/{id}/sandboxes/{sandboxId}/deployments": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List sandbox deployment history */ + get: operations["listSandboxDeployments"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/projects/{id}/sandbox-sessions": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List project sandbox sessions */ + get: operations["listSandboxSessions"]; + put?: never; + /** Start a sandbox session */ + post: operations["createSandboxSession"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/projects/{id}/sandbox-executions": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Execute once and return after confirmed termination */ + post: operations["executeSandbox"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/sandbox-sessions/{sessionId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get a sandbox session */ + get: operations["getSandboxSession"]; + put?: never; + post?: never; + /** Request sandbox termination */ + delete: operations["terminateSandboxSession"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/sandbox-sessions/{sessionId}/suspend": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Suspend a sandbox session */ + post: operations["suspendSandboxSession"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/sandbox-sessions/{sessionId}/resume": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Resume a sandbox session */ + post: operations["resumeSandboxSession"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/sandbox-sessions/{sessionId}/exec": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Execute a command within a session */ + post: operations["executeSandboxSession"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/sandbox-sessions/{sessionId}/files/read": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Read a workspace file */ + post: operations["readSandboxSessionFile"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/sandbox-sessions/{sessionId}/files/write": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Write a workspace file */ + post: operations["writeSandboxSessionFile"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/sandbox-sessions/{sessionId}/grants/{subjectId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** Authorize an authenticated project user for this session */ + put: operations["grantSandboxSession"]; + post?: never; + /** Revoke a project user session grant */ + delete: operations["revokeSandboxSession"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/sandbox-sessions/{sessionId}/access": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Issue a short-lived port-scoped access credential */ + post: operations["createSandboxSessionAccess"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; } export type webhooks = Record; export interface components { schemas: { - AnonKey: { + SandboxPreset: { + id: string; + runtime: string; + version: string; + /** @enum {integer} */ + memory_mb: 1024 | 2048; + regions: string[]; + }; + SandboxTemplate: { /** Format: uuid */ id: string; /** Format: uuid */ - project_id?: string; + project_id: string; name: string; - /** @description JWT token - use this in frontend Authorization header */ - key_value: string; + preset?: string; + memory_mb?: number; + /** @enum {string} */ + status: "ready" | "unavailable" | "deleting"; + /** Format: date-time */ + created_at: string; + }; + CreateSandboxTemplateRequest: { + name: string; + /** @description Preset ID from the available Sandbox preset catalog. */ + preset: string; /** - * @description Permissions granted to this anon key. - * Auth permissions: auth.signup, auth.signin, auth.refresh, auth.logout, auth.password_reset, auth.confirm_email, auth.resend_confirmation - * Storage permissions: storage.upload, storage.download, storage.list, storage.delete - * Realtime permissions: realtime.connect, realtime.subscribe, realtime.publish - * Functions permissions: functions.invoke - * @example [ - * "auth.signup", - * "auth.signin", - * "auth.refresh", - * "auth.logout" - * ] + * @default 1024 + * @enum {integer} */ - permissions?: string[]; - /** @description Whether this is the project's configured default anon key. Only one key per project can be default. */ - is_default?: boolean; + memory_mb?: 1024 | 2048; + }; + UpdateSandboxTemplateRequest: { + name: string; + }; + SandboxSession: { + /** Format: uuid */ + id: string; + /** Format: uuid */ + project_id: string; + /** Format: uuid */ + sandbox_id: string; + /** @enum {string} */ + state: "starting" | "running" | "suspending" | "suspended" | "resuming" | "terminating" | "terminated" | "unknown"; + /** @enum {string} */ + desired_state: "running" | "suspended" | "terminated"; + region: string; + memory_mb: number; /** Format: date-time */ - created_at?: string; + created_at: string; + /** Format: date-time */ + started_at?: string; + /** Format: date-time */ + expires_at: string; }; - AuthConfig: { + CreateSandboxSessionRequest: { + /** @description Preset ID from the available Sandbox preset catalog. */ + preset?: string; /** Format: uuid */ - project_id?: string; - /** - * @description Access token lifetime in seconds - * @default 3600 - */ - access_token_lifetime?: number; - /** - * @description Refresh token lifetime in seconds - * @default 2592000 - */ - refresh_token_lifetime?: number; - /** - * @description Force re-login after inactivity (seconds, 0=never) - * @default 0 - */ - inactivity_timeout?: number; - /** - * @description Force re-login after duration (seconds, 0=never) - * @default 0 - */ + sandbox_id?: string; + /** @enum {integer} */ + memory_mb?: 1024 | 2048; + /** @description Region such as `us-east-1`. Region IDs issued by earlier versions of the API are still accepted. */ + region: string; + /** @default 3600 */ + max_duration_seconds?: number; + /** @default 0 */ + idle_timeout_seconds?: number; + } & (unknown | unknown); + SandboxCommandRequest: { + command: string; + /** @default 60 */ + timeout_seconds?: number; + environment?: { + [key: string]: string; + }; + }; + SandboxExecutionRequest: { + /** @description Preset ID from the available Sandbox preset catalog. */ + preset?: string; + /** Format: uuid */ + sandbox_id?: string; + /** @enum {integer} */ + memory_mb?: 1024 | 2048; + /** @description Region such as `us-east-1`. Region IDs issued by earlier versions of the API are still accepted. */ + region: string; + command: string; + /** @default 60 */ + timeout_seconds?: number; + environment?: { + [key: string]: string; + }; + } & (unknown | unknown); + SandboxCommandResult: { + stdout: string; + stderr: string; + exit_code: number; + stdout_truncated: boolean; + stderr_truncated: boolean; + timed_out: boolean; + }; + SandboxExecutionResult: { + stdout: string; + stderr: string; + exit_code: number; + stdout_truncated: boolean; + stderr_truncated: boolean; + timed_out: boolean; + /** Format: uuid */ + session_id: string; + region: string; + /** Format: int64 */ + duration_ms: number; + }; + SandboxFileWriteRequest: { + path: string; + /** Format: byte */ + data: string; + }; + SandboxFileReadRequest: { + path: string; + }; + SandboxFileResult: { + /** Format: byte */ + data: string; + }; + SandboxSubjectGrantRequest: { + /** Format: date-time */ + expires_at: string; + }; + SandboxAccessRequest: { + port: number; + /** @default 300 */ + expires_in_seconds?: number; + }; + SandboxAccess: { + /** Format: uri */ + url: string; + token: string; + /** Format: date-time */ + expires_at: string; + }; + SandboxDeployment: { + /** Format: uuid */ + id: string; + status: string; + /** Format: date-time */ + created_at: string; + /** Format: date-time */ + updated_at: string; + }; + SandboxPagination: { + limit: number; + has_more: boolean; + next_cursor?: string; + }; + SandboxTemplatePage: { + data: components["schemas"]["SandboxTemplate"][]; + pagination: components["schemas"]["SandboxPagination"]; + }; + SandboxSessionPage: { + data: components["schemas"]["SandboxSession"][]; + pagination: components["schemas"]["SandboxPagination"]; + }; + SandboxDeploymentPage: { + data: components["schemas"]["SandboxDeployment"][]; + pagination: components["schemas"]["SandboxPagination"]; + }; + SandboxPresetList: { + data: components["schemas"]["SandboxPreset"][]; + }; + SandboxCapacity: { + region: string; + /** Format: int64 */ + allocated_memory_mb: number; + }; + SandboxCapacityList: { + data: components["schemas"]["SandboxCapacity"][]; + }; + PublishSandboxPresetRequest: { + /** Format: uuid */ + id: string; + /** @enum {string} */ + preset: "python3.12" | "node22"; + /** @enum {integer} */ + memory_mb: 1024 | 2048; + /** Format: uuid */ + deployment_id: string; + }; + AnonKey: { + /** Format: uuid */ + id: string; + /** Format: uuid */ + project_id?: string; + name: string; + /** @description JWT token - use this in frontend Authorization header */ + key_value: string; + /** + * @description Permissions granted to this anon key. + * Auth permissions: auth.signup, auth.signin, auth.refresh, auth.logout, auth.password_reset, auth.confirm_email, auth.resend_confirmation + * Storage permissions: storage.upload, storage.download, storage.list, storage.delete + * Realtime permissions: realtime.connect, realtime.subscribe, realtime.publish + * Functions permissions: functions.invoke + * @example [ + * "auth.signup", + * "auth.signin", + * "auth.refresh", + * "auth.logout" + * ] + */ + permissions?: string[]; + /** @description Whether this is the project's configured default anon key. Only one key per project can be default. */ + is_default?: boolean; + /** Format: date-time */ + created_at?: string; + }; + AuthConfig: { + /** Format: uuid */ + project_id?: string; + /** + * @description Access token lifetime in seconds + * @default 3600 + */ + access_token_lifetime?: number; + /** + * @description Refresh token lifetime in seconds + * @default 2592000 + */ + refresh_token_lifetime?: number; + /** + * @description Force re-login after inactivity (seconds, 0=never) + * @default 0 + */ + inactivity_timeout?: number; + /** + * @description Force re-login after duration (seconds, 0=never) + * @default 0 + */ max_session_duration?: number; /** * @description Configured minimum password length in Unicode characters. @@ -8886,173 +9318,619 @@ export interface components { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** + * @description The query was rejected by a billing-cycle allowance: either the owning + * platform user's bandwidth allowance (aggregate ingress + egress across + * owned projects) or their database-request allowance. Enforcement is + * eventual: queries are rejected until the allowance increases or the + * next anniversary cycle begins. The error message identifies the resource. + */ + DatabaseQueryCapExceeded: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** + * @description The branch exists but cannot serve queries: it is still provisioning, + * being reset, expired, or its parent is being restored. Distinct from + * `404` so a caller waiting on a branch can tell it apart from a typo. + */ + DatabaseBranchQueryUnavailable: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + parameters: { + /** + * @description Backup name, unique within the database, exactly as returned by the list + * endpoint. + * + * Deliberately looser than the names you can create: a backup made by a + * schedule is named for you, so reading or deleting one accepts any name a + * backup can have. + */ + BackupName: string; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + BranchName: string; + /** @description Storage bucket name */ + BucketName: string; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + Cursor: string; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + EndingBefore: string; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + DatabaseName: string; + /** @description Frontend deployment ID */ + DeploymentId: string; + /** @description Frontend ID */ + FrontendId: string; + /** @description Function ID */ + FunctionId: string; + /** @description Durable function ID, or its name within the project */ + DurableFunctionId: string; + /** @description Durable execution ID */ + DurableExecutionId: string; + /** @description Number of items per page (max 100) */ + Limit: number; + /** @description Project-local lock name. */ + LockKey: string; + /** @description Opaque UUID generated once by the caller and retained for the lease lifetime. */ + LockToken: string; + /** + * @description UUID correlating this request across client and server logs. Repeat safety comes from + * the lock token, so a retry under a reused request ID still counts against the quota. + */ + LockRequestId: string; + /** @description Restrict a deployment feed to one kind of operation. */ + DeploymentOperation: "deploy" | "redeploy" | "update" | "delete"; + /** + * @description The user who owns the projects whose deployments to return + * (`projects.user_id`). This is ownership, not the actor that started the + * deployment — see `initiated_by_user_id` for that. Not a UUID: platform + * user ids are opaque strings. + */ + DeploymentOwnerId: string; + /** + * @description Sort key and direction. `created_at.desc` (default) is the feed order. + * `completed_at.asc` orders finished attempts by completion, oldest first, + * and excludes attempts that never completed. + */ + DeploymentOrder: "created_at.desc" | "completed_at.asc"; + /** + * @description Restrict a deployment feed to a single resource type. Omit to return + * both Function and Frontend deployments. + */ + DeploymentResourceType: "function" | "frontend"; + /** @description Restrict a deployment feed to attempts in one status. */ + DeploymentStatus: "queued" | "provisioning" | "active" | "degraded" | "failed" | "superseded" | "deleting" | "deleted"; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + Offset: number; + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + Page: number; + /** @description Project ID */ + ProjectId: string; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + Search: string; + /** @description Database restore ID */ + RestoreId: string; + /** @description Function scheduler ID */ + SchedulerId: string; + /** @description Variable name */ + VariableName: string; + }; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + startImportConnect: { + parameters: { + query?: { + /** @description Import provider to connect. Defaults to Vercel. */ + provider?: components["schemas"]["ImportProvider"]; + /** @description Validated application URL used after the provider callback. */ + redirect?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Provider authorization URL */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ImportConnectStartResponse"]; + }; + }; + /** @description Unsupported provider or invalid redirect */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Failed to start the connection */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Import provider integration is not configured */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + completeImportConnect: { + parameters: { + query: { + /** @description Signed connect state generated by startImportConnect. */ + state: string; + /** @description Provider authorization code. */ + code?: string; + /** @description Provider error category. */ + error?: string; + /** @description Vercel team selected during installation. */ + teamId?: string; + /** @description Vercel Integration configuration identifier. */ + configurationId?: string; + /** @description Provider completion URL validated by the provider adapter. */ + next?: string; + /** @description Vercel installation source indicator. */ + source?: string; + }; + header?: never; + path: { + provider: components["schemas"]["ImportProvider"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Redirect to the provider completion URL, signed application redirect, or Volcano import page */ + 303: { + headers: { + /** @description Validated redirect target */ + Location?: string; + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid callback request, state, or browser binding */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Too many callback attempts */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Failed to complete the connection */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Import provider integration is not configured */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + listImportConnections: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Stored import provider connections */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ImportConnectionsResponse"]; + }; + }; + /** @description Not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Failed to list connections */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + deleteImportConnection: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Connection ID to delete. */ + connectionId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Connection deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Malformed connection ID */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Connection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Connection changed while it was being deleted */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Failed to delete the connection */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Import provider integration is not configured */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + listImportSources: { + parameters: { + query: { + /** @description Owned provider connection used for discovery. */ + connection_id: string; + }; + header?: never; + path: { + provider: components["schemas"]["ImportProvider"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Provider sources available to import */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ImportSourcesResponse"]; + }; + }; + /** @description Invalid provider or connection ID */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The provider connection lacks a required Integration scope */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Connection or provider source not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The provider connection must be reconnected */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Provider rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Failed to list provider sources */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Provider unavailable or integration not configured */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + preflightProjectImport: { + parameters: { + query?: never; + header?: never; + path: { + provider: components["schemas"]["ImportProvider"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ProjectImportPreflightRequest"]; + }; + }; + responses: { + /** @description Import readiness report */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ProjectImportReport"]; + }; + }; + /** @description Invalid provider, source, project name, or target */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The provider connection lacks a required Integration scope */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Connection or provider source not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - }; - /** - * @description The query was rejected by a billing-cycle allowance: either the owning - * platform user's bandwidth allowance (aggregate ingress + egress across - * owned projects) or their database-request allowance. Enforcement is - * eventual: queries are rejected until the allowance increases or the - * next anniversary cycle begins. The error message identifies the resource. - */ - DatabaseQueryCapExceeded: { - headers: { - [name: string]: unknown; + /** @description The provider connection must be reconnected */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - content: { - "application/json": components["schemas"]["Error"]; + /** @description Provider rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - }; - /** - * @description The branch exists but cannot serve queries: it is still provisioning, - * being reset, expired, or its parent is being restored. Distinct from - * `404` so a caller waiting on a branch can tell it apart from a typo. - */ - DatabaseBranchQueryUnavailable: { - headers: { - [name: string]: unknown; + /** @description Failed to produce an import readiness report */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - content: { - "application/json": components["schemas"]["Error"]; + /** @description Provider unavailable or integration not configured */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - parameters: { - /** - * @description Backup name, unique within the database, exactly as returned by the list - * endpoint. - * - * Deliberately looser than the names you can create: a backup made by a - * schedule is named for you, so reading or deleting one accepts any name a - * backup can have. - */ - BackupName: string; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - BranchName: string; - /** @description Storage bucket name */ - BucketName: string; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - Cursor: string; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - EndingBefore: string; - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - DatabaseName: string; - /** @description Frontend deployment ID */ - DeploymentId: string; - /** @description Frontend ID */ - FrontendId: string; - /** @description Function ID */ - FunctionId: string; - /** @description Durable function ID, or its name within the project */ - DurableFunctionId: string; - /** @description Durable execution ID */ - DurableExecutionId: string; - /** @description Number of items per page (max 100) */ - Limit: number; - /** @description Project-local lock name. */ - LockKey: string; - /** @description Opaque UUID generated once by the caller and retained for the lease lifetime. */ - LockToken: string; - /** - * @description UUID correlating this request across client and server logs. Repeat safety comes from - * the lock token, so a retry under a reused request ID still counts against the quota. - */ - LockRequestId: string; - /** @description Restrict a deployment feed to one kind of operation. */ - DeploymentOperation: "deploy" | "redeploy" | "update" | "delete"; - /** - * @description The user who owns the projects whose deployments to return - * (`projects.user_id`). This is ownership, not the actor that started the - * deployment — see `initiated_by_user_id` for that. Not a UUID: platform - * user ids are opaque strings. - */ - DeploymentOwnerId: string; - /** - * @description Sort key and direction. `created_at.desc` (default) is the feed order. - * `completed_at.asc` orders finished attempts by completion, oldest first, - * and excludes attempts that never completed. - */ - DeploymentOrder: "created_at.desc" | "completed_at.asc"; - /** - * @description Restrict a deployment feed to a single resource type. Omit to return - * both Function and Frontend deployments. - */ - DeploymentResourceType: "function" | "frontend"; - /** @description Restrict a deployment feed to attempts in one status. */ - DeploymentStatus: "queued" | "provisioning" | "active" | "degraded" | "failed" | "superseded" | "deleting" | "deleted"; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - Offset: number; - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - Page: number; - /** @description Project ID */ - ProjectId: string; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - Search: string; - /** @description Database restore ID */ - RestoreId: string; - /** @description Function scheduler ID */ - SchedulerId: string; - /** @description Variable name */ - VariableName: string; - }; - requestBodies: never; - headers: never; - pathItems: never; -} -export type $defs = Record; -export interface operations { - startImportConnect: { + startProjectImport: { parameters: { - query?: { - /** @description Import provider to connect. Defaults to Vercel. */ - provider?: components["schemas"]["ImportProvider"]; - /** @description Validated application URL used after the provider callback. */ - redirect?: string; + query?: never; + header: { + "Idempotency-Key": string; + }; + path: { + provider: components["schemas"]["ImportProvider"]; }; - header?: never; - path?: never; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["ProjectImportStartRequest"]; + }; + }; responses: { - /** @description Provider authorization URL */ - 200: { + /** @description Import run accepted */ + 202: { headers: { + Location: string; [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ImportConnectStartResponse"]; + "application/json": components["schemas"]["ProjectImportRun"]; }; }; - /** @description Unsupported provider or invalid redirect */ + /** @description Invalid request or idempotency key */ 400: { headers: { [name: string]: unknown; @@ -9070,7 +9948,52 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to start the connection */ + /** @description Provider permission or project admission denied */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Connection or provider source not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Preflight is stale, idempotency key was reused, or destination conflicts */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Source is not importable */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Provider rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Failed to start the import */ 500: { headers: { [name: string]: unknown; @@ -9079,7 +10002,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Import provider integration is not configured */ + /** @description Provider unavailable or integration not configured */ 503: { headers: { [name: string]: unknown; @@ -9090,42 +10013,28 @@ export interface operations { }; }; }; - completeImportConnect: { + getProjectImportRun: { parameters: { - query: { - /** @description Signed connect state generated by startImportConnect. */ - state: string; - /** @description Provider authorization code. */ - code?: string; - /** @description Provider error category. */ - error?: string; - /** @description Vercel team selected during installation. */ - teamId?: string; - /** @description Vercel Integration configuration identifier. */ - configurationId?: string; - /** @description Provider completion URL validated by the provider adapter. */ - next?: string; - /** @description Vercel installation source indicator. */ - source?: string; - }; + query?: never; header?: never; path: { provider: components["schemas"]["ImportProvider"]; + runId: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Redirect to the provider completion URL, signed application redirect, or Volcano import page */ - 303: { + /** @description Import run status */ + 200: { headers: { - /** @description Validated redirect target */ - Location?: string; [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["ProjectImportRun"]; + }; }; - /** @description Invalid callback request, state, or browser binding */ + /** @description Invalid import run ID */ 400: { headers: { [name: string]: unknown; @@ -9134,8 +10043,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Too many callback attempts */ - 429: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -9143,8 +10052,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to complete the connection */ - 500: { + /** @description Import run not found */ + 404: { headers: { [name: string]: unknown; }; @@ -9152,8 +10061,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Import provider integration is not configured */ - 503: { + /** @description Failed to get the import run */ + 500: { headers: { [name: string]: unknown; }; @@ -9163,26 +10072,31 @@ export interface operations { }; }; }; - listImportConnections: { + startGitConnect: { parameters: { - query?: never; + query?: { + /** @description Git provider to connect. Defaults to github. */ + provider?: "github"; + /** @description URL to redirect the browser to after the provider callback completes. */ + redirect?: string; + }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { - /** @description Stored import provider connections */ + /** @description Provider authorization URL */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ImportConnectionsResponse"]; + "application/json": components["schemas"]["GitConnectStartResponse"]; }; }; - /** @description Not authenticated */ - 401: { + /** @description Unsupported provider or invalid redirect */ + 400: { headers: { [name: string]: unknown; }; @@ -9190,8 +10104,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to list connections */ - 500: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -9199,29 +10113,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - deleteImportConnection: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Connection ID to delete. */ - connectionId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Connection deleted */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Malformed connection ID */ - 400: { + /** @description Failed to start the connection */ + 500: { headers: { [name: string]: unknown; }; @@ -9229,8 +10122,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Not authenticated */ - 401: { + /** @description Git provider integration is not configured */ + 503: { headers: { [name: string]: unknown; }; @@ -9238,17 +10131,28 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Connection not found */ - 404: { + }; + }; + listGitConnections: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Stored git provider connections */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["GitConnectionsResponse"]; }; }; - /** @description Connection changed while it was being deleted */ - 409: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -9256,7 +10160,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to delete the connection */ + /** @description Failed to list connections */ 500: { headers: { [name: string]: unknown; @@ -9265,7 +10169,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Import provider integration is not configured */ + /** @description Git provider integration is not configured */ 503: { headers: { [name: string]: unknown; @@ -9276,30 +10180,26 @@ export interface operations { }; }; }; - listImportSources: { + deleteGitConnection: { parameters: { - query: { - /** @description Owned provider connection used for discovery. */ - connection_id: string; - }; + query?: never; header?: never; path: { - provider: components["schemas"]["ImportProvider"]; + /** @description Connection ID to delete */ + connectionId: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Provider sources available to import */ - 200: { + /** @description Connection deleted */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["ImportSourcesResponse"]; - }; + content?: never; }; - /** @description Invalid provider or connection ID */ + /** @description Malformed connection ID */ 400: { headers: { [name: string]: unknown; @@ -9317,16 +10217,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description The provider connection lacks a required Integration scope */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Connection or provider source not found */ + /** @description Connection not found */ 404: { headers: { [name: string]: unknown; @@ -9335,25 +10226,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description The provider connection must be reconnected */ - 409: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Provider rate limit exceeded */ - 429: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Failed to list provider sources */ + /** @description Failed to delete connection */ 500: { headers: { [name: string]: unknown; @@ -9362,7 +10235,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Provider unavailable or integration not configured */ + /** @description Git provider integration is not configured */ 503: { headers: { [name: string]: unknown; @@ -9373,31 +10246,28 @@ export interface operations { }; }; }; - preflightProjectImport: { + listGitInstallations: { parameters: { query?: never; header?: never; path: { - provider: components["schemas"]["ImportProvider"]; + /** @description Connection ID to browse installations for. */ + connectionId: string; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["ProjectImportPreflightRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Import readiness report */ + /** @description Installations accessible to the connection */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectImportReport"]; + "application/json": components["schemas"]["GitInstallationsResponse"]; }; }; - /** @description Invalid provider, source, project name, or target */ + /** @description Malformed connection ID */ 400: { headers: { [name: string]: unknown; @@ -9415,16 +10285,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description The provider connection lacks a required Integration scope */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Connection or provider source not found */ + /** @description Connection not found */ 404: { headers: { [name: string]: unknown; @@ -9433,25 +10294,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description The provider connection must be reconnected */ - 409: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Provider rate limit exceeded */ - 429: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Failed to produce an import readiness report */ + /** @description Failed to list installations */ 500: { headers: { [name: string]: unknown; @@ -9460,7 +10303,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Provider unavailable or integration not configured */ + /** @description Git provider integration is not configured */ 503: { headers: { [name: string]: unknown; @@ -9471,34 +10314,30 @@ export interface operations { }; }; }; - startProjectImport: { + listGitInstallationRepositories: { parameters: { query?: never; - header: { - "Idempotency-Key": string; - }; + header?: never; path: { - provider: components["schemas"]["ImportProvider"]; + /** @description Connection ID to browse repositories for. */ + connectionId: string; + /** @description GitHub App installation ID. */ + installationId: number; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["ProjectImportStartRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Import run accepted */ - 202: { + /** @description Repositories accessible through the installation */ + 200: { headers: { - Location: string; [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectImportRun"]; + "application/json": components["schemas"]["GitRepositoriesResponse"]; }; }; - /** @description Invalid request or idempotency key */ + /** @description Malformed connection or installation ID */ 400: { headers: { [name: string]: unknown; @@ -9516,8 +10355,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Provider permission or project admission denied */ - 403: { + /** @description Connection not found */ + 404: { headers: { [name: string]: unknown; }; @@ -9525,8 +10364,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Connection or provider source not found */ - 404: { + /** @description Failed to list repositories */ + 500: { headers: { [name: string]: unknown; }; @@ -9534,8 +10373,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Preflight is stale, idempotency key was reused, or destination conflicts */ - 409: { + /** @description Git provider integration is not configured */ + 503: { headers: { [name: string]: unknown; }; @@ -9543,8 +10382,35 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Source is not importable */ - 422: { + }; + }; + gitConnectCallback: { + parameters: { + query: { + /** @description GitHub user authorization code. */ + code?: string; + /** @description Signed connect state generated by startGitConnect. */ + state: string; + /** @description Provider error returned by GitHub. */ + error?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Redirect back to the app after a successful or failed connect attempt */ + 303: { + headers: { + /** @description Redirect target */ + Location?: string; + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid callback request or state */ + 400: { headers: { [name: string]: unknown; }; @@ -9552,7 +10418,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Provider rate limit exceeded */ + /** @description Too many callback attempts from this client */ 429: { headers: { [name: string]: unknown; @@ -9561,7 +10427,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to start the import */ + /** @description Failed to complete the connection */ 500: { headers: { [name: string]: unknown; @@ -9570,7 +10436,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Provider unavailable or integration not configured */ + /** @description Git provider integration is not configured */ 503: { headers: { [name: string]: unknown; @@ -9581,28 +10447,66 @@ export interface operations { }; }; }; - getProjectImportRun: { + listProjects: { parameters: { - query?: never; - header?: never; - path: { - provider: components["schemas"]["ImportProvider"]; - runId: string; + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; + /** @description Optional comma-separated project metadata expansions. */ + include?: ("git_connection" | "health")[]; }; + header?: never; + path?: never; cookie?: never; }; requestBody?: never; responses: { - /** @description Import run status */ + /** @description Successful response */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectImportRun"]; + "application/json": components["schemas"]["PaginatedProjects"]; }; }; - /** @description Invalid import run ID */ + /** @description Invalid or conflicting pagination parameters */ 400: { headers: { [name: string]: unknown; @@ -9611,17 +10515,32 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Not authenticated */ - 401: { + }; + }; + createProject: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateProjectRequest"]; + }; + }; + responses: { + /** @description Project created */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["Project"]; }; }; - /** @description Import run not found */ - 404: { + /** @description Bad request */ + 400: { headers: { [name: string]: unknown; }; @@ -9629,8 +10548,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to get the import run */ - 500: { + /** @description Project limit exceeded for the user */ + 403: { headers: { [name: string]: unknown; }; @@ -9640,31 +10559,29 @@ export interface operations { }; }; }; - startGitConnect: { + getProject: { parameters: { - query?: { - /** @description Git provider to connect. Defaults to github. */ - provider?: "github"; - /** @description URL to redirect the browser to after the provider callback completes. */ - redirect?: string; - }; + query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; cookie?: never; }; requestBody?: never; responses: { - /** @description Provider authorization URL */ + /** @description Successful response */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["GitConnectStartResponse"]; + "application/json": components["schemas"]["Project"]; }; }; - /** @description Unsupported provider or invalid redirect */ - 400: { + /** @description Project not found */ + 404: { headers: { [name: string]: unknown; }; @@ -9672,26 +10589,29 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Not authenticated */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + deleteProject: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; - /** @description Failed to start the connection */ - 500: { + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Project deletion started */ + 202: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Git provider integration is not configured */ - 503: { + /** @description Project not found */ + 404: { headers: { [name: string]: unknown; }; @@ -9701,26 +10621,37 @@ export interface operations { }; }; }; - listGitConnections: { + updateProject: { parameters: { query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateProjectRequest"]; + }; + }; responses: { - /** @description Stored git provider connections */ + /** @description Project updated */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["GitConnectionsResponse"]; + "application/json": components["schemas"]["Project"]; }; }; - /** @description Not authenticated */ - 401: { + /** + * @description Bad request (no region selected, an unknown region, or — for a + * project holding durable functions — a region that does not offer + * durable execution) + */ + 400: { headers: { [name: string]: unknown; }; @@ -9728,8 +10659,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to list connections */ - 500: { + /** @description Forbidden (for example, selecting subset regions on non-SUPERAGENT plan) */ + 403: { headers: { [name: string]: unknown; }; @@ -9737,8 +10668,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Git provider integration is not configured */ - 503: { + /** @description Project not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Conflict (project name already exists or a resource deployment blocks a region change) */ + 409: { headers: { [name: string]: unknown; }; @@ -9748,35 +10688,28 @@ export interface operations { }; }; }; - deleteGitConnection: { + getProjectHealth: { parameters: { query?: never; header?: never; path: { - /** @description Connection ID to delete */ - connectionId: string; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Connection deleted */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Malformed connection ID */ - 400: { + /** @description Project health snapshot retrieved */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["ProjectHealthResponse"]; }; }; - /** @description Not authenticated */ + /** @description Unauthorized - invalid or missing token */ 401: { headers: { [name: string]: unknown; @@ -9785,8 +10718,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Connection not found */ - 404: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -9794,8 +10727,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to delete connection */ - 500: { + /** @description Project not found */ + 404: { headers: { [name: string]: unknown; }; @@ -9803,8 +10736,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Git provider integration is not configured */ - 503: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -9814,28 +10747,32 @@ export interface operations { }; }; }; - listGitInstallations: { + queryProjectMetrics: { parameters: { query?: never; header?: never; path: { - /** @description Connection ID to browse installations for. */ - connectionId: string; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["ProjectMetricsQueryRequest"]; + }; + }; responses: { - /** @description Installations accessible to the connection */ + /** @description Project runtime metric queries evaluated */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["GitInstallationsResponse"]; + "application/json": components["schemas"]["ProjectMetricsQueryResponse"]; }; }; - /** @description Malformed connection ID */ + /** @description Invalid metric query */ 400: { headers: { [name: string]: unknown; @@ -9844,7 +10781,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Not authenticated */ + /** @description Unauthorized - invalid or missing token */ 401: { headers: { [name: string]: unknown; @@ -9853,7 +10790,16 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Connection not found */ + /** @description Access denied */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Project not found */ 404: { headers: { [name: string]: unknown; @@ -9862,7 +10808,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to list installations */ + /** @description Internal server error */ 500: { headers: { [name: string]: unknown; @@ -9871,7 +10817,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Git provider integration is not configured */ + /** @description Runtime metrics backend unavailable */ 503: { headers: { [name: string]: unknown; @@ -9882,30 +10828,74 @@ export interface operations { }; }; }; - listGitInstallationRepositories: { + getProjectLogo: { parameters: { query?: never; header?: never; path: { - /** @description Connection ID to browse repositories for. */ - connectionId: string; - /** @description GitHub App installation ID. */ - installationId: number; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Repositories accessible through the installation */ + /** @description Logo image */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["GitRepositoriesResponse"]; + "image/png": string; + "image/jpeg": string; + "image/gif": string; + "image/webp": string; + "image/svg+xml": string; }; }; - /** @description Malformed connection or installation ID */ + /** @description Project or logo not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + uploadProjectLogo: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "multipart/form-data": { + /** + * Format: binary + * @description Logo image (PNG, JPEG, GIF, WebP, or SVG; max 2 MB) + */ + logo: string; + }; + }; + }; + responses: { + /** @description Logo uploaded */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Project"]; + }; + }; + /** @description Bad request (missing file, unsupported type, or too large) */ 400: { headers: { [name: string]: unknown; @@ -9914,8 +10904,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Not authenticated */ - 401: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -9923,7 +10913,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Connection not found */ + /** @description Project not found */ 404: { headers: { [name: string]: unknown; @@ -9932,8 +10922,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to list repositories */ - 500: { + /** @description Project is being deleted */ + 409: { headers: { [name: string]: unknown; }; @@ -9941,7 +10931,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Git provider integration is not configured */ + /** @description Logo storage is not configured */ 503: { headers: { [name: string]: unknown; @@ -9952,33 +10942,29 @@ export interface operations { }; }; }; - gitConnectCallback: { + deleteProjectLogo: { parameters: { - query: { - /** @description GitHub user authorization code. */ - code?: string; - /** @description Signed connect state generated by startGitConnect. */ - state: string; - /** @description Provider error returned by GitHub. */ - error?: string; - }; + query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; cookie?: never; }; requestBody?: never; responses: { - /** @description Redirect back to the app after a successful or failed connect attempt */ - 303: { + /** @description Logo removed */ + 200: { headers: { - /** @description Redirect target */ - Location?: string; [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Project"]; + }; }; - /** @description Invalid callback request or state */ - 400: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -9986,8 +10972,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Too many callback attempts from this client */ - 429: { + /** @description Project not found */ + 404: { headers: { [name: string]: unknown; }; @@ -9995,8 +10981,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to complete the connection */ - 500: { + /** @description Project is being deleted */ + 409: { headers: { [name: string]: unknown; }; @@ -10004,7 +10990,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Git provider integration is not configured */ + /** @description Logo storage is not configured */ 503: { headers: { [name: string]: unknown; @@ -10015,67 +11001,38 @@ export interface operations { }; }; }; - listProjects: { + getProjectUsage: { parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - search?: components["parameters"]["Search"]; - /** @description Optional comma-separated project metadata expansions. */ - include?: ("git_connection" | "health")[]; - }; + query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; cookie?: never; }; requestBody?: never; responses: { - /** @description Successful response */ + /** @description Usage metrics retrieved */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedProjects"]; + "application/json": components["schemas"]["ProjectUsageResponse"]; }; }; - /** @description Invalid or conflicting pagination parameters */ - 400: { + /** @description Access denied */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Project not found */ + 404: { headers: { [name: string]: unknown; }; @@ -10085,30 +11042,69 @@ export interface operations { }; }; }; - createProject: { + replaceSharedVariables: { parameters: { query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["CreateProjectRequest"]; + "application/json": { + shared_variables: string[]; + /** @description When present, replace only if the current complete shared list matches this list. */ + expected_shared_variables?: string[]; + /** @description SHA-256 of the sorted unique current shared names joined by a newline. Use instead of expected_shared_variables for a compact conditional replacement. */ + expected_shared_variables_digest?: string; + }; + }; + }; + responses: { + /** @description Shared list replaced and affected function synchronization started. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid names or final function environment. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - }; - responses: { - /** @description Project created */ - 201: { + /** @description Project not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Shared list changed since it was read. */ + 409: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Project"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Bad request */ - 400: { + /** @description Request body exceeds 4,194,304 bytes */ + 413: { headers: { [name: string]: unknown; }; @@ -10116,8 +11112,15 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project limit exceeded for the user */ - 403: { + /** @description Persistence or synchronization failed */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Shared variable membership writes are disabled during rollout */ + 503: { headers: { [name: string]: unknown; }; @@ -10127,9 +11130,12 @@ export interface operations { }; }; }; - getProject: { + getProjectConfig: { parameters: { - query?: never; + query?: { + /** @description Response format override. Takes precedence over the Accept header. */ + format?: "json" | "yaml"; + }; header?: never; path: { /** @description Project ID */ @@ -10139,17 +11145,22 @@ export interface operations { }; requestBody?: never; responses: { - /** @description Successful response */ + /** + * @description Current project configuration. JSON by default; when YAML is + * requested the body is the canonical volcano-config.yaml document + * served verbatim with `Content-Type: application/yaml`. + */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Project"]; + "application/json": components["schemas"]["ProjectConfig"]; + "application/yaml": string; }; }; - /** @description Project not found */ - 404: { + /** @description Unauthorized - invalid or missing token */ + 401: { headers: { [name: string]: unknown; }; @@ -10157,29 +11168,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - deleteProject: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Project deletion started */ - 202: { + /** @description Project not found */ + 404: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Project not found */ - 404: { + /** @description Canonical YAML export exceeds 4,194,304 bytes */ + 413: { headers: { [name: string]: unknown; }; @@ -10189,9 +11188,12 @@ export interface operations { }; }; }; - updateProject: { + applyProjectConfig: { parameters: { - query?: never; + query?: { + /** @description Validate and report projected actions without applying changes. */ + dry_run?: boolean; + }; header?: never; path: { /** @description Project ID */ @@ -10201,24 +11203,24 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["UpdateProjectRequest"]; + "application/json": components["schemas"]["ProjectConfig"]; }; }; responses: { - /** @description Project updated */ + /** + * @description Apply report. Individual entries may still carry `action: error` + * for apply-phase failures (summary.errors > 0); already-applied + * changes are not rolled back. + */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Project"]; + "application/json": components["schemas"]["ProjectConfigApplyResult"]; }; }; - /** - * @description Bad request (no region selected, an unknown region, or — for a - * project holding durable functions — a region that does not offer - * durable execution) - */ + /** @description Malformed request body */ 400: { headers: { [name: string]: unknown; @@ -10227,8 +11229,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden (for example, selecting subset regions on non-SUPERAGENT plan) */ - 403: { + /** @description Unauthorized - invalid or missing token */ + 401: { headers: { [name: string]: unknown; }; @@ -10245,7 +11247,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Conflict (project name already exists or a resource deployment blocks a region change) */ + /** @description Another apply is in progress for this project */ 409: { headers: { [name: string]: unknown; @@ -10254,9 +11256,27 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Manifest validation failed; nothing was applied */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ProjectConfigValidationErrorResponse"]; + }; + }; + /** @description Shared variable membership writes are disabled during rollout */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - getProjectHealth: { + getProjectSourceExport: { parameters: { query?: never; header?: never; @@ -10268,13 +11288,13 @@ export interface operations { }; requestBody?: never; responses: { - /** @description Project health snapshot retrieved */ + /** @description The project's source-of-truth state */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectHealthResponse"]; + "application/json": components["schemas"]["ProjectSourceExportState"]; }; }; /** @description Unauthorized - invalid or missing token */ @@ -10286,7 +11306,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Access denied */ + /** @description Forbidden - project not owned by the caller */ 403: { headers: { [name: string]: unknown; @@ -10313,9 +11333,18 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Source export is not available in this deployment mode */ + 501: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - queryProjectMetrics: { + exportProjectSource: { parameters: { query?: never; header?: never; @@ -10327,20 +11356,20 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["ProjectMetricsQueryRequest"]; + "application/json": components["schemas"]["ExportProjectSourceRequest"]; }; }; responses: { - /** @description Project runtime metric queries evaluated */ - 200: { + /** @description The initial production-branch commit that was pushed */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectMetricsQueryResponse"]; + "application/json": components["schemas"]["ProjectSourceExport"]; }; }; - /** @description Invalid metric query */ + /** @description Malformed request body */ 400: { headers: { [name: string]: unknown; @@ -10358,7 +11387,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Access denied */ + /** @description Forbidden - project not owned by the caller */ 403: { headers: { [name: string]: unknown; @@ -10367,7 +11396,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found */ + /** @description Project not found, or it has no repository connected */ 404: { headers: { [name: string]: unknown; @@ -10376,8 +11405,13 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** + * @description The source has already been exported, the repository has already + * taken over as the source of truth, the confirmed production branch + * is stale, a function or frontend deployment is still in progress, + * or the project has no stored source to export + */ + 409: { headers: { [name: string]: unknown; }; @@ -10385,8 +11419,12 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Runtime metrics backend unavailable */ - 503: { + /** + * @description The repository refused the branch, or its contents cannot be laid + * out as a repository — a stored file that only ever carries + * credentials, or a layout Git auto-deploy would not read back + */ + 422: { headers: { [name: string]: unknown; }; @@ -10394,35 +11432,35 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - getProjectLogo: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description GitHub rate limited the request */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Logo image */ - 200: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; content: { - "image/png": string; - "image/jpeg": string; - "image/gif": string; - "image/webp": string; - "image/svg+xml": string; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Project or logo not found */ - 404: { + /** @description Source export is not available in this deployment mode */ + 501: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description GitHub integration is not configured */ + 503: { headers: { [name: string]: unknown; }; @@ -10432,7 +11470,7 @@ export interface operations { }; }; }; - uploadProjectLogo: { + cancelProjectSourceExport: { parameters: { query?: never; header?: never; @@ -10442,29 +11480,17 @@ export interface operations { }; cookie?: never; }; - requestBody: { - content: { - "multipart/form-data": { - /** - * Format: binary - * @description Logo image (PNG, JPEG, GIF, WebP, or SVG; max 2 MB) - */ - logo: string; - }; - }; - }; + requestBody?: never; responses: { - /** @description Logo uploaded */ - 200: { + /** @description The incomplete source transition was canceled */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Project"]; - }; + content?: never; }; - /** @description Bad request (missing file, unsupported type, or too large) */ - 400: { + /** @description Unauthorized - invalid or missing token */ + 401: { headers: { [name: string]: unknown; }; @@ -10472,7 +11498,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Access denied */ + /** @description Forbidden - project not owned by the caller */ 403: { headers: { [name: string]: unknown; @@ -10490,8 +11516,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project is being deleted */ - 409: { + /** @description No incomplete transition exists, or Git already took ownership */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -10499,8 +11534,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Logo storage is not configured */ - 503: { + /** @description Source export is not available in this deployment mode */ + 501: { headers: { [name: string]: unknown; }; @@ -10510,7 +11545,7 @@ export interface operations { }; }; }; - deleteProjectLogo: { + setProjectGitProductionBranch: { parameters: { query?: never; header?: never; @@ -10520,18 +11555,43 @@ export interface operations { }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["SetProjectGitProductionBranchRequest"]; + }; + }; responses: { - /** @description Logo removed */ + /** @description The project's repo connection, with the new branch */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Project"]; + "application/json": components["schemas"]["ProjectGitConnection"]; }; }; - /** @description Access denied */ + /** + * @description Malformed request body, or a production_branch that is not a valid + * Git branch name + */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Unauthorized - invalid or missing token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Project not owned by the caller */ 403: { headers: { [name: string]: unknown; @@ -10540,7 +11600,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found */ + /** + * @description Project not found, or it has no repository connected. The branch is + * part of the connection, so there is nothing to set it on until one + * exists. + */ 404: { headers: { [name: string]: unknown; @@ -10549,7 +11613,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project is being deleted */ + /** @description A Git source transition is pending */ 409: { headers: { [name: string]: unknown; @@ -10558,8 +11622,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Logo storage is not configured */ - 503: { + /** @description Failed to set the production branch */ + 500: { headers: { [name: string]: unknown; }; @@ -10569,7 +11633,7 @@ export interface operations { }; }; }; - getProjectUsage: { + getProjectGitConnection: { parameters: { query?: never; header?: never; @@ -10581,16 +11645,25 @@ export interface operations { }; requestBody?: never; responses: { - /** @description Usage metrics retrieved */ + /** @description The project's current repo connection */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectUsageResponse"]; + "application/json": components["schemas"]["ProjectGitConnection"]; }; }; - /** @description Access denied */ + /** @description Unauthorized - invalid or missing token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Project not owned by the caller */ 403: { headers: { [name: string]: unknown; @@ -10599,7 +11672,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found */ + /** @description Project not found, or has no repo connection */ 404: { headers: { [name: string]: unknown; @@ -10608,9 +11681,18 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Failed to get project git connection */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - replaceSharedVariables: { + connectProjectGit: { parameters: { query?: never; header?: never; @@ -10622,24 +11704,27 @@ export interface operations { }; requestBody: { content: { - "application/json": { - shared_variables: string[]; - /** @description When present, replace only if the current complete shared list matches this list. */ - expected_shared_variables?: string[]; - /** @description SHA-256 of the sorted unique current shared names joined by a newline. Use instead of expected_shared_variables for a compact conditional replacement. */ - expected_shared_variables_digest?: string; - }; + "application/json": components["schemas"]["ConnectProjectGitRequest"]; }; }; responses: { - /** @description Shared list replaced and affected function synchronization started. */ - 204: { + /** @description The project's repo connection */ + 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["ProjectGitConnection"]; + }; }; - /** @description Invalid names or final function environment. */ + /** + * @description Malformed request body, no repository selector, selectors that + * identify different repositories, a production_branch that is not a + * valid Git branch name, no production_branch on a repository with no + * default branch to follow (name one to connect a repository that has + * no commits yet), or a production_branch other than the new + * repository's default in a request that also changes repository. + */ 400: { headers: { [name: string]: unknown; @@ -10648,22 +11733,29 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized */ + /** @description Unauthorized - invalid or missing token */ 401: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Project not found */ - 404: { + /** + * @description Project not owned by the caller, or the selected repository is not + * accessible through installation_id + */ + 403: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Shared list changed since it was read. */ - 409: { + /** @description Project or connection not found */ + 404: { headers: { [name: string]: unknown; }; @@ -10671,8 +11763,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Request body exceeds 4,194,304 bytes */ - 413: { + /** + * @description A Git source transition is pending or complete, so the recorded + * repository and root cannot be changed + */ + 409: { headers: { [name: string]: unknown; }; @@ -10680,14 +11775,16 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Persistence or synchronization failed */ + /** @description Failed to connect project git */ 500: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Shared variable membership writes are disabled during rollout */ + /** @description Git provider integration is not configured */ 503: { headers: { [name: string]: unknown; @@ -10698,12 +11795,9 @@ export interface operations { }; }; }; - getProjectConfig: { + disconnectProjectGit: { parameters: { - query?: { - /** @description Response format override. Takes precedence over the Accept header. */ - format?: "json" | "yaml"; - }; + query?: never; header?: never; path: { /** @description Project ID */ @@ -10713,19 +11807,12 @@ export interface operations { }; requestBody?: never; responses: { - /** - * @description Current project configuration. JSON by default; when YAML is - * requested the body is the canonical volcano-config.yaml document - * served verbatim with `Content-Type: application/yaml`. - */ - 200: { + /** @description Connection removed */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["ProjectConfig"]; - "application/yaml": string; - }; + content?: never; }; /** @description Unauthorized - invalid or missing token */ 401: { @@ -10736,7 +11823,16 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found */ + /** @description Project not owned by the caller */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Project not found, or has no repo connection */ 404: { headers: { [name: string]: unknown; @@ -10745,8 +11841,20 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Canonical YAML export exceeds 4,194,304 bytes */ - 413: { + /** + * @description A Git source transition is pending or complete, so the recorded + * repository cannot be disconnected + */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Failed to disconnect project git */ + 500: { headers: { [name: string]: unknown; }; @@ -10756,12 +11864,9 @@ export interface operations { }; }; }; - applyProjectConfig: { + getProjectGitDeploySettings: { parameters: { - query?: { - /** @description Validate and report projected actions without applying changes. */ - dry_run?: boolean; - }; + query?: never; header?: never; path: { /** @description Project ID */ @@ -10769,32 +11874,15 @@ export interface operations { }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["ProjectConfig"]; - }; - }; + requestBody?: never; responses: { - /** - * @description Apply report. Individual entries may still carry `action: error` - * for apply-phase failures (summary.errors > 0); already-applied - * changes are not rolled back. - */ + /** @description The project's current Git auto-deploy settings */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectConfigApplyResult"]; - }; - }; - /** @description Malformed request body */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["ProjectGitDeploySettings"]; }; }; /** @description Unauthorized - invalid or missing token */ @@ -10806,8 +11894,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found */ - 404: { + /** @description Project not owned by the caller */ + 403: { headers: { [name: string]: unknown; }; @@ -10815,8 +11903,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Another apply is in progress for this project */ - 409: { + /** @description Project not found */ + 404: { headers: { [name: string]: unknown; }; @@ -10824,17 +11912,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Manifest validation failed; nothing was applied */ - 422: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ProjectConfigValidationErrorResponse"]; - }; - }; - /** @description Shared variable membership writes are disabled during rollout */ - 503: { + /** @description Failed to get project git deploy settings */ + 500: { headers: { [name: string]: unknown; }; @@ -10844,7 +11923,7 @@ export interface operations { }; }; }; - getProjectSourceExport: { + updateProjectGitDeploySettings: { parameters: { query?: never; header?: never; @@ -10854,15 +11933,28 @@ export interface operations { }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateProjectGitDeploySettingsRequest"]; + }; + }; responses: { - /** @description The project's source-of-truth state */ + /** @description The project's updated Git auto-deploy settings */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectSourceExportState"]; + "application/json": components["schemas"]["ProjectGitDeploySettings"]; + }; + }; + /** @description Malformed request body, or frontend_app_root without frontend_name */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; }; }; /** @description Unauthorized - invalid or missing token */ @@ -10874,7 +11966,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden - project not owned by the caller */ + /** @description Project not owned by the caller */ 403: { headers: { [name: string]: unknown; @@ -10892,8 +11984,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** + * @description A Git source transition is pending, or this change would remove + * deploy coverage after Git has taken over + */ + 409: { headers: { [name: string]: unknown; }; @@ -10901,8 +11996,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Source export is not available in this deployment mode */ - 501: { + /** @description Failed to update project git deploy settings */ + 500: { headers: { [name: string]: unknown; }; @@ -10912,32 +12007,33 @@ export interface operations { }; }; }; - exportProjectSource: { + getProjectDatabaseQueries: { parameters: { - query?: never; + query?: { + /** @description Maximum number of queries to return. */ + limit?: number; + }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["ExportProjectSourceRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description The initial production-branch commit that was pushed */ - 201: { + /** @description Database query performance retrieved */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectSourceExport"]; + "application/json": components["schemas"]["DatabaseQueryPerformanceResponse"]; }; }; - /** @description Malformed request body */ + /** @description Bad request - invalid query parameters */ 400: { headers: { [name: string]: unknown; @@ -10955,7 +12051,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden - project not owned by the caller */ + /** @description Access denied */ 403: { headers: { [name: string]: unknown; @@ -10964,7 +12060,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found, or it has no repository connected */ + /** @description Project or database not found */ 404: { headers: { [name: string]: unknown; @@ -10973,13 +12069,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The source has already been exported, the repository has already - * taken over as the source of truth, the confirmed production branch - * is stale, a function or frontend deployment is still in progress, - * or the project has no stored source to export - */ - 409: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -10987,21 +12078,88 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The repository refused the branch, or its contents cannot be laid - * out as a repository — a stored file that only ever carries - * credentials, or a layout Git auto-deploy would not read back - */ - 422: { + }; + }; + listDeployments: { + parameters: { + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description The user who owns the projects whose deployments to return + * (`projects.user_id`). This is ownership, not the actor that started the + * deployment — see `initiated_by_user_id` for that. Not a UUID: platform + * user ids are opaque strings. + */ + owner_id?: components["parameters"]["DeploymentOwnerId"]; + /** @description Restrict the feed to a single project owned by the user. */ + project_id?: string; + /** @description Restrict results to attempts created at or after this timestamp. */ + created_after?: string; + /** + * @description Restrict a deployment feed to a single resource type. Omit to return + * both Function and Frontend deployments. + */ + resource_type?: components["parameters"]["DeploymentResourceType"]; + /** @description Restrict a deployment feed to attempts in one status. */ + status?: components["parameters"]["DeploymentStatus"]; + /** @description Restrict a deployment feed to one kind of operation. */ + operation?: components["parameters"]["DeploymentOperation"]; + /** + * @description Sort key and direction. `created_at.desc` (default) is the feed order. + * `completed_at.asc` orders finished attempts by completion, oldest first, + * and excludes attempts that never completed. + */ + order?: components["parameters"]["DeploymentOrder"]; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful response */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["PaginatedProjectDeployments"]; }; }; - /** @description GitHub rate limited the request */ - 429: { + /** @description Bad request - invalid filter or pagination */ + 400: { headers: { [name: string]: unknown; }; @@ -11009,8 +12167,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** @description Unauthorized - invalid or missing token */ + 401: { headers: { [name: string]: unknown; }; @@ -11018,8 +12176,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Source export is not available in this deployment mode */ - 501: { + /** @description Forbidden - owner_id names a different user */ + 403: { headers: { [name: string]: unknown; }; @@ -11027,8 +12185,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description GitHub integration is not configured */ - 503: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -11038,9 +12196,55 @@ export interface operations { }; }; }; - cancelProjectSourceExport: { + listProjectDeployments: { parameters: { - query?: never; + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; + /** @description Restrict results to attempts created at or after this timestamp. */ + created_after?: string; + /** + * @description Restrict the feed to a single resource type. Omit to return both + * Function and Frontend deployments. + */ + resource_type?: "function" | "frontend"; + }; header?: never; path: { /** @description Project ID */ @@ -11050,24 +12254,17 @@ export interface operations { }; requestBody?: never; responses: { - /** @description The incomplete source transition was canceled */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** @description Successful response */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["PaginatedProjectDeployments"]; }; }; - /** @description Forbidden - project not owned by the caller */ - 403: { + /** @description Bad request - invalid identifier */ + 400: { headers: { [name: string]: unknown; }; @@ -11075,8 +12272,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found */ - 404: { + /** @description Unauthorized - invalid or missing token */ + 401: { headers: { [name: string]: unknown; }; @@ -11084,8 +12281,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description No incomplete transition exists, or Git already took ownership */ - 409: { + /** @description Forbidden - project ownership required */ + 403: { headers: { [name: string]: unknown; }; @@ -11102,20 +12299,18 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Source export is not available in this deployment mode */ - 501: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; }; }; - setProjectGitProductionBranch: { + summarizeProjectDeployments: { parameters: { - query?: never; + query: { + /** @description Restrict the summary to resource names containing this value. */ + search?: string; + /** @description Restrict the summary to one comparable deployment pipeline. */ + resource_type: "function" | "frontend"; + /** @description Restrict results to attempts created at or after this timestamp. */ + created_after?: string; + }; header?: never; path: { /** @description Project ID */ @@ -11123,25 +12318,18 @@ export interface operations { }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["SetProjectGitProductionBranchRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description The project's repo connection, with the new branch */ + /** @description Successful response */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectGitConnection"]; + "application/json": components["schemas"]["ProjectDeploymentSummary"]; }; }; - /** - * @description Malformed request body, or a production_branch that is not a valid - * Git branch name - */ + /** @description Bad request - invalid identifier or filter */ 400: { headers: { [name: string]: unknown; @@ -11159,7 +12347,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not owned by the caller */ + /** @description Forbidden - project ownership required */ 403: { headers: { [name: string]: unknown; @@ -11168,29 +12356,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Project not found, or it has no repository connected. The branch is - * part of the connection, so there is nothing to set it on until one - * exists. - */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description A Git source transition is pending */ - 409: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Failed to set the production branch */ + /** @description Internal server error */ 500: { headers: { [name: string]: unknown; @@ -11201,9 +12367,48 @@ export interface operations { }; }; }; - getProjectGitConnection: { + listProjectCustomDomains: { parameters: { - query?: never; + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; + }; header?: never; path: { /** @description Project ID */ @@ -11213,13 +12418,22 @@ export interface operations { }; requestBody?: never; responses: { - /** @description The project's current repo connection */ + /** @description Successful response */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectGitConnection"]; + "application/json": components["schemas"]["PaginatedProjectCustomDomains"]; + }; + }; + /** @description Bad request - invalid identifier */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; }; }; /** @description Unauthorized - invalid or missing token */ @@ -11231,7 +12445,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not owned by the caller */ + /** @description Forbidden - project ownership required */ 403: { headers: { [name: string]: unknown; @@ -11240,8 +12454,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found, or has no repo connection */ - 404: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -11249,8 +12463,70 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to get project git connection */ - 500: { + }; + }; + listFunctions: { + parameters: { + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; + }; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PaginatedFunctions"]; + }; + }; + /** @description Project not found */ + 404: { headers: { [name: string]: unknown; }; @@ -11260,7 +12536,7 @@ export interface operations { }; }; }; - connectProjectGit: { + createFunction: { parameters: { query?: never; header?: never; @@ -11272,37 +12548,77 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["ConnectProjectGitRequest"]; + "multipart/form-data": { + /** + * @description DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen) + * @example my-api-function + */ + name: string; + /** + * Format: binary + * @description ZIP or tar.gz archive containing function source code plus dependency manifests/lockfiles. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz source archive. + */ + code: string; + /** + * @description Runtime environment. Required. + * - Node.js: nodejs22.x, nodejs24.x + * - Python: python3.10, python3.11, python3.12, python3.13, python3.14 + * - Ruby: ruby3.3, ruby3.4, ruby4.0 + * @example nodejs24.x + * @enum {string} + */ + runtime: "nodejs22.x" | "nodejs24.x" | "python3.10" | "python3.11" | "python3.12" | "python3.13" | "python3.14" | "ruby3.3" | "ruby3.4" | "ruby4.0"; + /** + * @description The name of the function to invoke. Defaults to "handler" if not specified. + * Your code must export/define a function with this name: + * - Node.js: exports.handler (in index.js) + * - Python: def handler() (in main.py) + * - Ruby: def handler() (in main.rb) + * @default handler + * @example handler + */ + handler?: string; + /** + * @description Whether the function can be reached through public invocation + * ingress. Omit it to keep the function's current visibility; a + * new function starts private. + */ + is_public?: boolean; + invocation_mode?: components["schemas"]["FunctionInvocationMode"]; + http_auth_mode?: components["schemas"]["FunctionHTTPAuthMode"]; + /** @description JSON-encoded OpenAPI 3.0 or 3.1 metadata for an HTTP-mode function. */ + openapi_spec?: string; + /** + * @description Which project variables this function receives. `all` (the default) gives it only project variables marked `shared: true`; `scoped` gives it only the variables it selects. Omitting this leaves an existing function's scope unchanged. + * @enum {string} + */ + variable_scope?: "all" | "scoped"; + /** @description JSON-encoded array of project variable names this function requires, on top of the ones detected in its source. A declared name the project does not define is rejected with 400; a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing function's declared names unchanged. */ + variables?: string; + }; }; }; responses: { - /** @description The project's repo connection */ + /** @description Existing function updated; its deployment was started or queued */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectGitConnection"]; + "application/json": components["schemas"]["Function"]; }; }; - /** - * @description Malformed request body, no repository selector, selectors that - * identify different repositories, a production_branch that is not a - * valid Git branch name, no production_branch on a repository with no - * default branch to follow (name one to connect a repository that has - * no commits yet), or a production_branch other than the new - * repository's default in a request that also changes repository. - */ - 400: { + /** @description Function created and deployment workflow started */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["Function"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** @description Bad request (invalid file, too large, etc.) */ + 400: { headers: { [name: string]: unknown; }; @@ -11310,10 +12626,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Project not owned by the caller, or the selected repository is not - * accessible through installation_id - */ + /** @description Function limit exceeded for the project */ 403: { headers: { [name: string]: unknown; @@ -11322,8 +12635,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project or connection not found */ - 404: { + /** + * @description Function deletion is queued or running, or the name is already held + * by a durable function — a function cannot change kind. + */ + 409: { headers: { [name: string]: unknown; }; @@ -11331,11 +12647,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description A Git source transition is pending or complete, so the recorded - * repository and root cannot be changed - */ - 409: { + /** @description Internal server error (function deployment failed) */ + 500: { headers: { [name: string]: unknown; }; @@ -11343,17 +12656,33 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to connect project git */ - 500: { + }; + }; + getFunction: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Function ID */ + functionId: components["parameters"]["FunctionId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful response */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["Function"]; }; }; - /** @description Git provider integration is not configured */ - 503: { + /** @description Function not found */ + 404: { headers: { [name: string]: unknown; }; @@ -11363,27 +12692,29 @@ export interface operations { }; }; }; - disconnectProjectGit: { + deleteFunction: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Function ID */ + functionId: components["parameters"]["FunctionId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Connection removed */ - 204: { + /** @description Function deletion started or queued */ + 202: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** @description Function not found */ + 404: { headers: { [name: string]: unknown; }; @@ -11391,29 +12722,37 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not owned by the caller */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + updateFunction: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Function ID */ + functionId: components["parameters"]["FunctionId"]; }; - /** @description Project not found, or has no repo connection */ - 404: { + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateFunctionRequest"]; + }; + }; + responses: { + /** @description Function updated */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["Function"]; }; }; - /** - * @description A Git source transition is pending or complete, so the recorded - * repository cannot be disconnected - */ - 409: { + /** @description Bad request */ + 400: { headers: { [name: string]: unknown; }; @@ -11421,8 +12760,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to disconnect project git */ - 500: { + /** @description Function not found */ + 404: { headers: { [name: string]: unknown; }; @@ -11432,25 +12771,42 @@ export interface operations { }; }; }; - getProjectGitDeploySettings: { + invokeFunction: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description Function ID */ + functionId: components["parameters"]["FunctionId"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["FunctionInvocationRequest"]; + }; + }; responses: { - /** @description The project's current Git auto-deploy settings */ + /** @description Function response (passthrough from function runtime) */ 200: { + headers: { + /** @description Volcano API/runtime version that served this invocation (`` in production, `-` in non-production) */ + "X-Volcano-Version"?: string; + /** @description Region the function ran in (for example `us-east-1`) */ + "X-Volcano-Region"?: string; + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["FunctionInvocationResponse"]; + }; + }; + /** @description Bad request - invalid payload or function in failed state */ + 400: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectGitDeploySettings"]; + "application/json": components["schemas"]["Error"]; }; }; /** @description Unauthorized - invalid or missing token */ @@ -11462,7 +12818,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not owned by the caller */ + /** @description Forbidden - CORS blocked, missing `functions.invoke`, or private function with anon key */ 403: { headers: { [name: string]: unknown; @@ -11471,7 +12827,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found */ + /** @description Function not found */ 404: { headers: { [name: string]: unknown; @@ -11480,8 +12836,28 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to get project git deploy settings */ - 500: { + /** + * @description Rate limit exceeded (per-function or project-wide limit), or the + * owning platform user's billing-cycle bandwidth allowance (aggregate ingress + + * egress) was exceeded. + */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** + * @description Function still provisioning or rate limiting service unavailable. + * A freshly deployed (or updated) function may briefly report + * `provisioning` and reject invocations until the background status + * reconciler observes its deployment workflow completing and transitions + * it to `active`. This is expected for a few seconds after deploy; clients + * should retry. + */ + 503: { headers: { [name: string]: unknown; }; @@ -11489,34 +12865,57 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Function response (passthrough; status code/body/headers come from the function) */ + default: { + headers: { + /** @description Volcano API/runtime version that served this invocation (`` in production, `-` in non-production) */ + "X-Volcano-Version"?: string; + /** @description Region the function ran in (for example `us-east-1`) */ + "X-Volcano-Region"?: string; + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["FunctionInvocationResponse"]; + }; + }; }; }; - updateProjectGitDeploySettings: { + startDurableExecutionFromApplication: { parameters: { query?: never; - header?: never; + header?: { + /** + * @description Idempotency key for this execution. Generated when omitted. A repeat + * under a name that already names a running execution returns that + * execution and is not charged again. + * + * Letters, digits, `-`, `_` and `.`, up to 255 characters. Anything + * else is rejected with `400`. + */ + "X-Volcano-Execution-Name"?: string; + }; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; }; cookie?: never; }; - requestBody: { + requestBody?: { content: { - "application/json": components["schemas"]["UpdateProjectGitDeploySettingsRequest"]; + "application/json": unknown; }; }; responses: { - /** @description The project's updated Git auto-deploy settings */ - 200: { + /** @description Execution accepted and started */ + 202: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectGitDeploySettings"]; + "application/json": components["schemas"]["DurableExecution"]; }; }; - /** @description Malformed request body, or frontend_app_root without frontend_name */ + /** @description Payload is not valid JSON, or the execution name is invalid */ 400: { headers: { [name: string]: unknown; @@ -11525,7 +12924,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized - invalid or missing token */ + /** + * @description Missing or invalid credential. Also returned for a platform user + * token, which is not an application credential; project owners start + * executions through the project-scoped collection. + */ 401: { headers: { [name: string]: unknown; @@ -11534,7 +12937,10 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not owned by the caller */ + /** + * @description The anon key lacks `functions.invoke`, the function is not public, + * or the request's origin is refused by the project's CORS policy. + */ 403: { headers: { [name: string]: unknown; @@ -11543,7 +12949,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found */ + /** + * @description Durable function not found. Also returned for a standard function's + * id and for a durable function in another project, so the response + * cannot be used to tell those apart. + */ 404: { headers: { [name: string]: unknown; @@ -11553,8 +12963,9 @@ export interface operations { }; }; /** - * @description A Git source transition is pending, or this change would remove - * deploy coverage after Git has taken over + * @description Function is not deployed yet, or has no deployed region. Also + * returned when two starts under the same execution name raced and + * both released it, which is retryable as it stands. */ 409: { headers: { @@ -11564,8 +12975,40 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Failed to update project git deploy settings */ - 500: { + /** @description Payload is larger than 256 KiB */ + 413: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** + * @description The project has too many executions in flight for its plan, the + * function invocation rate limit was exceeded, the project is over + * its bandwidth cap, or the account is out of one of its + * billing-cycle durable allowances: executions, operations, or + * compute. Operations and compute are counted once an execution + * finishes, so a refusal on either never interrupts an execution + * already running — it declines the next start. + */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** + * @description Durable execution is not available in this environment, or the + * usage limit service could not be reached to charge the start. The + * first is returned by a deployment that has no durable execution + * engine, such as a local one, and is not retryable there; the second + * is transient. + */ + 503: { headers: { [name: string]: unknown; }; @@ -11575,33 +13018,31 @@ export interface operations { }; }; }; - getProjectDatabaseQueries: { + resolveFunctionForInvocation: { parameters: { - query?: { - /** @description Maximum number of queries to return. */ - limit?: number; - }; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; + query: { + /** + * @description DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen) + * @example my-function + */ + name: string; }; + header?: never; + path?: never; cookie?: never; }; requestBody?: never; responses: { - /** @description Database query performance retrieved */ + /** @description Function resolved successfully */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseQueryPerformanceResponse"]; + "application/json": components["schemas"]["ResolveFunctionResponse"]; }; }; - /** @description Bad request - invalid query parameters */ + /** @description Bad request - missing or invalid function name */ 400: { headers: { [name: string]: unknown; @@ -11619,7 +13060,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Access denied */ + /** @description Forbidden - CORS blocked or missing `functions.invoke` permission for anon key */ 403: { headers: { [name: string]: unknown; @@ -11628,7 +13069,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project or database not found */ + /** + * @description Function not found (or private function with anon key). A durable + * function is never resolvable here: it is started through + * `POST /durable-functions/{functionId}/executions`, not invoked. + */ 404: { headers: { [name: string]: unknown; @@ -11637,85 +13082,23 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; }; }; - listDeployments: { + getProjectLogActivity: { parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description The user who owns the projects whose deployments to return - * (`projects.user_id`). This is ownership, not the actor that started the - * deployment — see `initiated_by_user_id` for that. Not a UUID: platform - * user ids are opaque strings. - */ - owner_id?: components["parameters"]["DeploymentOwnerId"]; - /** @description Restrict the feed to a single project owned by the user. */ - project_id?: string; - /** @description Restrict results to attempts created at or after this timestamp. */ - created_after?: string; - /** - * @description Restrict a deployment feed to a single resource type. Omit to return - * both Function and Frontend deployments. - */ - resource_type?: components["parameters"]["DeploymentResourceType"]; - /** @description Restrict a deployment feed to attempts in one status. */ - status?: components["parameters"]["DeploymentStatus"]; - /** @description Restrict a deployment feed to one kind of operation. */ - operation?: components["parameters"]["DeploymentOperation"]; - /** - * @description Sort key and direction. `created_at.desc` (default) is the feed order. - * `completed_at.asc` orders finished attempts by completion, oldest first, - * and excludes attempts that never completed. - */ - order?: components["parameters"]["DeploymentOrder"]; - }; + query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["LogActivityRequest"]; + }; + }; responses: { /** @description Successful response */ 200: { @@ -11723,10 +13106,10 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedProjectDeployments"]; + "application/json": components["schemas"]["LogActivityResponse"]; }; }; - /** @description Bad request - invalid filter or pagination */ + /** @description Bad request - invalid query parameter */ 400: { headers: { [name: string]: unknown; @@ -11744,7 +13127,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden - owner_id names a different user */ + /** @description Forbidden - project ownership required */ 403: { headers: { [name: string]: unknown; @@ -11753,8 +13136,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** @description Project or resource not found */ + 404: { headers: { [name: string]: unknown; }; @@ -11764,55 +13147,9 @@ export interface operations { }; }; }; - listProjectDeployments: { + searchProjectLogs: { parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - search?: components["parameters"]["Search"]; - /** @description Restrict results to attempts created at or after this timestamp. */ - created_after?: string; - /** - * @description Restrict the feed to a single resource type. Omit to return both - * Function and Frontend deployments. - */ - resource_type?: "function" | "frontend"; - }; + query?: never; header?: never; path: { /** @description Project ID */ @@ -11820,7 +13157,11 @@ export interface operations { }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["LogSearchRequest"]; + }; + }; responses: { /** @description Successful response */ 200: { @@ -11828,10 +13169,10 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedProjectDeployments"]; + "application/json": components["schemas"]["LogSearchResponse"]; }; }; - /** @description Bad request - invalid identifier */ + /** @description Bad request - invalid query parameter */ 400: { headers: { [name: string]: unknown; @@ -11858,8 +13199,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** @description Project or resource not found */ + 404: { headers: { [name: string]: unknown; }; @@ -11869,35 +13210,38 @@ export interface operations { }; }; }; - summarizeProjectDeployments: { + streamProjectLogs: { parameters: { - query: { - /** @description Restrict the summary to resource names containing this value. */ - search?: string; - /** @description Restrict the summary to one comparable deployment pipeline. */ - resource_type: "function" | "frontend"; - /** @description Restrict results to attempts created at or after this timestamp. */ - created_after?: string; + query?: { + /** @description Opaque stream cursor fallback when setting `Last-Event-ID` is not practical. */ + last_event_id?: string; + }; + header?: { + /** @description Opaque stream cursor from the most recent SSE `id` field. */ + "Last-Event-ID"?: string; }; - header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["LogStreamRequest"]; + }; + }; responses: { - /** @description Successful response */ + /** @description Server-Sent Events stream. `log` events contain a JSON `LogSearchEvent`; `warning` events contain a JSON object with an `error` field. */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectDeploymentSummary"]; + "text/event-stream": string; }; }; - /** @description Bad request - invalid identifier or filter */ + /** @description Bad request - invalid selector, stream cursor, or unsupported stream field */ 400: { headers: { [name: string]: unknown; @@ -11924,7 +13268,16 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ + /** @description Project or resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Internal server error - log streaming setup failed */ 500: { headers: { [name: string]: unknown; @@ -11935,48 +13288,9 @@ export interface operations { }; }; }; - listProjectCustomDomains: { - parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - search?: components["parameters"]["Search"]; - }; + createFunctionsBatch: { + parameters: { + query?: never; header?: never; path: { /** @description Project ID */ @@ -11984,28 +13298,44 @@ export interface operations { }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "multipart/form-data": { + /** + * @description JSON array of functions with `name`, `runtime`, optional `handler`, and `file_field`. Each `file_field` must name a multipart file field containing that function's ZIP or tar.gz source bundle. + * + * Each entry may also declare `variable_scope` (`all` or `scoped`) and `variables` (an array of project variable names). Omitting them leaves the function's stored declaration unchanged. Volcano detects direct environment references in the uploaded source code and keeps them separate from the declared names: detected names are not written back to the declaration and do not appear in a config export. A scoped function receives its declared names plus the detected ones the project defines; a detected name the project does not define is ignored, since such a reference is often optional. Detection reads code only, so a name appearing solely in a comment or in an unrelated string is not a reference. Declare a name when the function reads it through a computed key, or when it must not deploy without the variable. The request is rejected with 400 before anything is deployed if a scoped function declares a variable the project does not define, or if the resulting environment exceeds 4096 bytes. + */ + functions: string; + /** + * Format: binary + * @description Function ZIP or tar.gz archive referenced by the first manifest entry's `file_field`; additional code_N file fields may be included. Each archive is subject to SOURCE_ARCHIVE_SIZE_LIMIT_MB. + */ + code_0?: string; + }; + }; + }; responses: { - /** @description Successful response */ - 200: { + /** @description Batch deployment accepted */ + 202: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedProjectCustomDomains"]; + "application/json": components["schemas"]["BatchFunctionDeployResponse"]; }; }; - /** @description Bad request - invalid identifier */ - 400: { + /** @description Batch deployment partially accepted; successful functions started deployment and failed functions were compensated where possible */ + 207: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["BatchFunctionDeployResponse"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** @description Bad request */ + 400: { headers: { [name: string]: unknown; }; @@ -12013,7 +13343,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden - project ownership required */ + /** @description Function limit exceeded for the project */ 403: { headers: { [name: string]: unknown; @@ -12022,8 +13352,12 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** + * @description A name in the batch is held by a function of the other kind — a + * function cannot change kind — or the project's source is managed by + * Git, where deploys come from a push to the production branch. + */ + 409: { headers: { [name: string]: unknown; }; @@ -12033,7 +13367,7 @@ export interface operations { }; }; }; - listFunctions: { + listProjectSchedulers: { parameters: { query?: { /** @@ -12084,16 +13418,41 @@ export interface operations { }; requestBody?: never; responses: { - /** @description Successful response */ + /** @description Project schedulers */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedFunctions"]; + "application/json": components["schemas"]["FunctionSchedulerListResponse"]; }; }; - /** @description Project not found */ + }; + }; + listFunctionSchedulers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Function ID */ + functionId: components["parameters"]["FunctionId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Function schedulers */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["FunctionSchedulerListResponse"]; + }; + }; + /** @description Function not found */ 404: { headers: { [name: string]: unknown; @@ -12104,88 +13463,37 @@ export interface operations { }; }; }; - createFunction: { + createFunctionScheduler: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Function ID */ + functionId: components["parameters"]["FunctionId"]; }; cookie?: never; }; requestBody: { content: { - "multipart/form-data": { - /** - * @description DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen) - * @example my-api-function - */ - name: string; - /** - * Format: binary - * @description ZIP or tar.gz archive containing function source code plus dependency manifests/lockfiles. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz source archive. - */ - code: string; - /** - * @description Runtime environment. Required. - * - Node.js: nodejs22.x, nodejs24.x - * - Python: python3.10, python3.11, python3.12, python3.13, python3.14 - * - Ruby: ruby3.3, ruby3.4, ruby4.0 - * @example nodejs24.x - * @enum {string} - */ - runtime: "nodejs22.x" | "nodejs24.x" | "python3.10" | "python3.11" | "python3.12" | "python3.13" | "python3.14" | "ruby3.3" | "ruby3.4" | "ruby4.0"; - /** - * @description The name of the function to invoke. Defaults to "handler" if not specified. - * Your code must export/define a function with this name: - * - Node.js: exports.handler (in index.js) - * - Python: def handler() (in main.py) - * - Ruby: def handler() (in main.rb) - * @default handler - * @example handler - */ - handler?: string; - /** - * @description Whether the function can be reached through public invocation - * ingress. Omit it to keep the function's current visibility; a - * new function starts private. - */ - is_public?: boolean; - invocation_mode?: components["schemas"]["FunctionInvocationMode"]; - http_auth_mode?: components["schemas"]["FunctionHTTPAuthMode"]; - /** @description JSON-encoded OpenAPI 3.0 or 3.1 metadata for an HTTP-mode function. */ - openapi_spec?: string; - /** - * @description Which project variables this function receives. `all` (the default) gives it only project variables marked `shared: true`; `scoped` gives it only the variables it selects. Omitting this leaves an existing function's scope unchanged. - * @enum {string} - */ - variable_scope?: "all" | "scoped"; - /** @description JSON-encoded array of project variable names this function requires, on top of the ones detected in its source. A declared name the project does not define is rejected with 400; a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing function's declared names unchanged. */ - variables?: string; - }; + "application/json": components["schemas"]["CreateFunctionSchedulerRequest"]; }; }; responses: { - /** @description Existing function updated; its deployment was started or queued */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Function"]; - }; - }; - /** @description Function created and deployment workflow started */ + /** @description Scheduler created */ 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Function"]; + "application/json": components["schemas"]["FunctionScheduler"]; }; }; - /** @description Bad request (invalid file, too large, etc.) */ + /** + * @description Invalid schedule, geofenced region, a scheduler of this name + * already exists on the function, or the function is not active. + */ 400: { headers: { [name: string]: unknown; @@ -12194,20 +13502,12 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Function limit exceeded for the project */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; /** - * @description Function deletion is queued or running, or the name is already held - * by a durable function — a function cannot change kind. + * @description Schedulers are not available on this plan, or the project already + * holds as many as the plan allows. The cap counts standard and + * durable function schedulers together. */ - 409: { + 403: { headers: { [name: string]: unknown; }; @@ -12215,8 +13515,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error (function deployment failed) */ - 500: { + /** @description Function not found */ + 404: { headers: { [name: string]: unknown; }; @@ -12226,7 +13526,7 @@ export interface operations { }; }; }; - getFunction: { + getFunctionScheduler: { parameters: { query?: never; header?: never; @@ -12235,21 +13535,23 @@ export interface operations { id: components["parameters"]["ProjectId"]; /** @description Function ID */ functionId: components["parameters"]["FunctionId"]; + /** @description Function scheduler ID */ + schedulerId: components["parameters"]["SchedulerId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Successful response */ + /** @description Function scheduler */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Function"]; + "application/json": components["schemas"]["FunctionScheduler"]; }; }; - /** @description Function not found */ + /** @description Function or scheduler not found */ 404: { headers: { [name: string]: unknown; @@ -12260,7 +13562,7 @@ export interface operations { }; }; }; - deleteFunction: { + deleteFunctionScheduler: { parameters: { query?: never; header?: never; @@ -12269,19 +13571,21 @@ export interface operations { id: components["parameters"]["ProjectId"]; /** @description Function ID */ functionId: components["parameters"]["FunctionId"]; + /** @description Function scheduler ID */ + schedulerId: components["parameters"]["SchedulerId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Function deletion started or queued */ - 202: { + /** @description Scheduler deleted */ + 204: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Function not found */ + /** @description Function or scheduler not found */ 404: { headers: { [name: string]: unknown; @@ -12292,7 +13596,7 @@ export interface operations { }; }; }; - updateFunction: { + updateFunctionScheduler: { parameters: { query?: never; header?: never; @@ -12301,25 +13605,30 @@ export interface operations { id: components["parameters"]["ProjectId"]; /** @description Function ID */ functionId: components["parameters"]["FunctionId"]; + /** @description Function scheduler ID */ + schedulerId: components["parameters"]["SchedulerId"]; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["UpdateFunctionRequest"]; + "application/json": components["schemas"]["UpdateFunctionSchedulerRequest"]; }; }; responses: { - /** @description Function updated */ + /** @description Scheduler updated */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Function"]; + "application/json": components["schemas"]["FunctionScheduler"]; }; }; - /** @description Bad request */ + /** + * @description Invalid schedule, geofenced region, or a scheduler of this name + * already exists on the function. + */ 400: { headers: { [name: string]: unknown; @@ -12328,7 +13637,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Function not found */ + /** @description Function or scheduler not found */ 404: { headers: { [name: string]: unknown; @@ -12339,60 +13648,38 @@ export interface operations { }; }; }; - invokeFunction: { + listFunctionDeployments: { parameters: { - query?: never; - header?: never; - path: { - /** @description Function ID */ - functionId: components["parameters"]["FunctionId"]; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["FunctionInvocationRequest"]; - }; - }; - responses: { - /** @description Function response (passthrough from function runtime) */ - 200: { - headers: { - /** @description Volcano API/runtime version that served this invocation (`` in production, `-` in non-production) */ - "X-Volcano-Version"?: string; - /** @description Region the function ran in (for example `us-east-1`) */ - "X-Volcano-Region"?: string; - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["FunctionInvocationResponse"]; - }; - }; - /** @description Bad request - invalid payload or function in failed state */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; }; - /** @description Unauthorized - invalid or missing token */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Function ID */ + functionId: components["parameters"]["FunctionId"]; }; - /** @description Forbidden - CORS blocked, missing `functions.invoke`, or private function with anon key */ - 403: { + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful response */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["PaginatedFunctionDeployments"]; }; }; /** @description Function not found */ @@ -12404,28 +13691,47 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Rate limit exceeded (per-function or project-wide limit), or the - * owning platform user's billing-cycle bandwidth allowance (aggregate ingress + - * egress) was exceeded. - */ - 429: { + }; + }; + listDurableFunctions: { + parameters: { + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; + }; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful response */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["PaginatedDurableFunctions"]; }; }; - /** - * @description Function still provisioning or rate limiting service unavailable. - * A freshly deployed (or updated) function may briefly report - * `provisioning` and reject invocations until the background status - * reconciler observes its deployment workflow completing and transitions - * it to `active`. This is expected for a few seconds after deploy; clients - * should retry. - */ - 503: { + /** @description Bad request - invalid pagination parameters */ + 400: { headers: { [name: string]: unknown; }; @@ -12433,71 +13739,105 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Function response (passthrough; status code/body/headers come from the function) */ - default: { + /** @description Project not found */ + 404: { headers: { - /** @description Volcano API/runtime version that served this invocation (`` in production, `-` in non-production) */ - "X-Volcano-Version"?: string; - /** @description Region the function ran in (for example `us-east-1`) */ - "X-Volcano-Region"?: string; [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionInvocationResponse"]; + "application/json": components["schemas"]["Error"]; }; }; }; }; - startDurableExecutionFromApplication: { + createDurableFunction: { parameters: { query?: never; - header?: { - /** - * @description Idempotency key for this execution. Generated when omitted. A repeat - * under a name that already names a running execution returns that - * execution and is not charged again. - * - * Letters, digits, `-`, `_` and `.`, up to 255 characters. Anything - * else is rejected with `400`. - */ - "X-Volcano-Execution-Name"?: string; - }; + header?: never; path: { - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; cookie?: never; }; - requestBody?: { + requestBody: { content: { - "application/json": unknown; + "multipart/form-data": { + /** + * @description DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen) + * @example order-pipeline + */ + name: string; + /** + * Format: binary + * @description ZIP or tar.gz archive containing function source code plus dependency manifests/lockfiles. + */ + code: string; + /** + * @description Runtime environment. Required. Durable execution needs the + * durable authoring API, which ships for these runtimes only; + * any other runtime is rejected with 400 and the response + * names the ones that work. Note that a durable Python + * function needs a newer runtime than a standard one defaults + * to. `GET /functions/runtimes` reports `durable_capable` per + * runtime. + * @example nodejs24.x + * @enum {string} + */ + runtime: "nodejs22.x" | "nodejs24.x" | "python3.13" | "python3.14"; + /** + * @description The name of the function to invoke. Defaults to "handler" if not specified. + * @default handler + * @example handler + */ + handler?: string; + /** + * @description Whether anon keys with `functions.invoke` may start an + * execution. Redeploying is the only way to change it, since + * the collection has no update endpoint; omit it to keep the + * current visibility, and a new function starts private. + * + * The standard collection's synchronous invocation fields — + * `invocation_mode`, `http_auth_mode`, `openapi_spec` — + * configure a request path no durable route serves, and are + * rejected with 400 rather than ignored. + */ + is_public?: boolean; + /** + * @description Which project variables this function receives. `all` (the default) gives it every project variable; `scoped` gives it only the variables it selects. Omitting this leaves an existing function's scope unchanged. + * @enum {string} + */ + variable_scope?: "all" | "scoped"; + /** @description JSON-encoded array of project variable names this function requires, on top of the ones detected in its source. A declared name the project does not define is rejected with 400; a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing function's declared names unchanged. */ + variables?: string; + }; }; }; responses: { - /** @description Execution accepted and started */ - 202: { + /** @description Existing durable function updated; its deployment was started or queued */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DurableExecution"]; + "application/json": components["schemas"]["DurableFunction"]; }; }; - /** @description Payload is not valid JSON, or the execution name is invalid */ - 400: { + /** @description Durable function created and deployment workflow started */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["DurableFunction"]; }; }; /** - * @description Missing or invalid credential. Also returned for a platform user - * token, which is not an application credential; project owners start - * executions through the project-scoped collection. + * @description Bad request (invalid archive, unsupported runtime, invalid name, or a + * project region that does not offer durable execution — a durable + * function deploys to every region of its project) */ - 401: { + 400: { headers: { [name: string]: unknown; }; @@ -12505,10 +13845,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The anon key lacks `functions.invoke`, the function is not public, - * or the request's origin is refused by the project's CORS policy. - */ + /** @description Durable function limit exceeded for the project */ 403: { headers: { [name: string]: unknown; @@ -12517,24 +13854,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Durable function not found. Also returned for a standard function's - * id and for a durable function in another project, so the response - * cannot be used to tell those apart. - */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** - * @description Function is not deployed yet, or has no deployed region. Also - * returned when two starts under the same execution name raced and - * both released it, which is retryable as it stands. - */ + /** @description Name is held by a standard function, or a deletion is queued or running */ 409: { headers: { [name: string]: unknown; @@ -12543,25 +13863,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Payload is larger than 256 KiB */ - 413: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** - * @description The project has too many executions in flight for its plan, the - * function invocation rate limit was exceeded, the project is over - * its bandwidth cap, or the account is out of one of its - * billing-cycle durable allowances: executions, operations, or - * compute. Operations and compute are counted once an execution - * finishes, so a refusal on either never interrupts an execution - * already running — it declines the next start. - */ - 429: { + /** @description Internal server error (function deployment failed) */ + 500: { headers: { [name: string]: unknown; }; @@ -12570,11 +13873,8 @@ export interface operations { }; }; /** - * @description Durable execution is not available in this environment, or the - * usage limit service could not be reached to charge the start. The - * first is returned by a deployment that has no durable execution - * engine, such as a local one, and is not retryable there; the second - * is transient. + * @description Durable deploys are paused platform-wide. The same request succeeds + * once they are re-enabled; executions already running are unaffected. */ 503: { headers: { @@ -12586,41 +13886,31 @@ export interface operations { }; }; }; - resolveFunctionForInvocation: { + getDurableFunction: { parameters: { - query: { - /** - * @description DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen) - * @example my-function - */ - name: string; - }; + query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; + }; cookie?: never; }; requestBody?: never; - responses: { - /** @description Function resolved successfully */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ResolveFunctionResponse"]; - }; - }; - /** @description Bad request - missing or invalid function name */ - 400: { + responses: { + /** @description Successful response */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["DurableFunction"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** @description Durable function not found */ + 404: { headers: { [name: string]: unknown; }; @@ -12628,19 +13918,33 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden - CORS blocked or missing `functions.invoke` permission for anon key */ - 403: { + }; + }; + deleteDurableFunction: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deletion accepted and teardown started */ + 202: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; /** - * @description Function not found (or private function with anon key). A durable - * function is never resolvable here: it is started through - * `POST /durable-functions/{functionId}/executions`, not invoked. + * @description Durable function not found. Also returned for an id that names a + * durable function in another project, so the response cannot be used + * to tell the two apart. */ 404: { headers: { @@ -12652,21 +13956,30 @@ export interface operations { }; }; }; - getProjectLogActivity: { + listDurableFunctionDeployments: { parameters: { - query?: never; + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["LogActivityRequest"]; - }; - }; + requestBody?: never; responses: { /** @description Successful response */ 200: { @@ -12674,11 +13987,11 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["LogActivityResponse"]; + "application/json": components["schemas"]["PaginatedFunctionDeployments"]; }; }; - /** @description Bad request - invalid query parameter */ - 400: { + /** @description Durable function not found */ + 404: { headers: { [name: string]: unknown; }; @@ -12686,25 +13999,32 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + listDurableFunctionSchedulers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; }; - /** @description Forbidden - project ownership required */ - 403: { + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Durable function schedulers */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["FunctionSchedulerListResponse"]; }; }; - /** @description Project or resource not found */ + /** @description Durable function not found */ 404: { headers: { [name: string]: unknown; @@ -12715,32 +14035,37 @@ export interface operations { }; }; }; - searchProjectLogs: { + createDurableFunctionScheduler: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["LogSearchRequest"]; + "application/json": components["schemas"]["CreateFunctionSchedulerRequest"]; }; }; responses: { - /** @description Successful response */ - 200: { + /** @description Scheduler created */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["LogSearchResponse"]; + "application/json": components["schemas"]["FunctionScheduler"]; }; }; - /** @description Bad request - invalid query parameter */ + /** + * @description Invalid schedule, geofenced region, a scheduler of this name + * already exists on the function, or the function is not active. + */ 400: { headers: { [name: string]: unknown; @@ -12749,16 +14074,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Forbidden - project ownership required */ + /** + * @description Schedulers are not available on this plan, or the project already + * holds as many as the plan allows. The cap counts standard and + * durable function schedulers together. + */ 403: { headers: { [name: string]: unknown; @@ -12767,7 +14087,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project or resource not found */ + /** @description Durable function not found */ 404: { headers: { [name: string]: unknown; @@ -12778,39 +14098,33 @@ export interface operations { }; }; }; - streamProjectLogs: { + getDurableFunctionScheduler: { parameters: { - query?: { - /** @description Opaque stream cursor fallback when setting `Last-Event-ID` is not practical. */ - last_event_id?: string; - }; - header?: { - /** @description Opaque stream cursor from the most recent SSE `id` field. */ - "Last-Event-ID"?: string; - }; + query?: never; + header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; + /** @description Function scheduler ID */ + schedulerId: components["parameters"]["SchedulerId"]; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["LogStreamRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Server-Sent Events stream. `log` events contain a JSON `LogSearchEvent`; `warning` events contain a JSON object with an `error` field. */ + /** @description Durable function scheduler */ 200: { headers: { [name: string]: unknown; }; content: { - "text/event-stream": string; + "application/json": components["schemas"]["FunctionScheduler"]; }; }; - /** @description Bad request - invalid selector, stream cursor, or unsupported stream field */ - 400: { + /** @description Durable function or scheduler not found */ + 404: { headers: { [name: string]: unknown; }; @@ -12818,25 +14132,32 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + deleteDurableFunctionScheduler: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; + /** @description Function scheduler ID */ + schedulerId: components["parameters"]["SchedulerId"]; }; - /** @description Forbidden - project ownership required */ - 403: { + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Scheduler deleted */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Project or resource not found */ + /** @description Durable function or scheduler not found */ 404: { headers: { [name: string]: unknown; @@ -12845,74 +14166,42 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error - log streaming setup failed */ - 500: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; }; }; - createFunctionsBatch: { + updateDurableFunctionScheduler: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; + /** @description Function scheduler ID */ + schedulerId: components["parameters"]["SchedulerId"]; }; cookie?: never; }; requestBody: { content: { - "multipart/form-data": { - /** - * @description JSON array of functions with `name`, `runtime`, optional `handler`, and `file_field`. Each `file_field` must name a multipart file field containing that function's ZIP or tar.gz source bundle. - * - * Each entry may also declare `variable_scope` (`all` or `scoped`) and `variables` (an array of project variable names). Omitting them leaves the function's stored declaration unchanged. Volcano detects direct environment references in the uploaded source code and keeps them separate from the declared names: detected names are not written back to the declaration and do not appear in a config export. A scoped function receives its declared names plus the detected ones the project defines; a detected name the project does not define is ignored, since such a reference is often optional. Detection reads code only, so a name appearing solely in a comment or in an unrelated string is not a reference. Declare a name when the function reads it through a computed key, or when it must not deploy without the variable. The request is rejected with 400 before anything is deployed if a scoped function declares a variable the project does not define, or if the resulting environment exceeds 4096 bytes. - */ - functions: string; - /** - * Format: binary - * @description Function ZIP or tar.gz archive referenced by the first manifest entry's `file_field`; additional code_N file fields may be included. Each archive is subject to SOURCE_ARCHIVE_SIZE_LIMIT_MB. - */ - code_0?: string; - }; + "application/json": components["schemas"]["UpdateFunctionSchedulerRequest"]; }; }; responses: { - /** @description Batch deployment accepted */ - 202: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["BatchFunctionDeployResponse"]; - }; - }; - /** @description Batch deployment partially accepted; successful functions started deployment and failed functions were compensated where possible */ - 207: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["BatchFunctionDeployResponse"]; - }; - }; - /** @description Bad request */ - 400: { + /** @description Scheduler updated */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["FunctionScheduler"]; }; }; - /** @description Function limit exceeded for the project */ - 403: { + /** + * @description Invalid schedule, geofenced region, or a scheduler of this name + * already exists on the function. + */ + 400: { headers: { [name: string]: unknown; }; @@ -12920,12 +14209,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description A name in the batch is held by a function of the other kind — a - * function cannot change kind — or the project's source is managed by - * Git, where deploys come from a push to the production branch. - */ - 409: { + /** @description Durable function or scheduler not found */ + 404: { headers: { [name: string]: unknown; }; @@ -12935,7 +14220,7 @@ export interface operations { }; }; }; - listProjectSchedulers: { + listDurableExecutions: { parameters: { query?: { /** @@ -12948,79 +14233,39 @@ export interface operations { page?: components["parameters"]["Page"]; /** @description Number of items per page (max 100) */ limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - search?: components["parameters"]["Search"]; + /** @description Return only executions in this status. */ + status?: components["schemas"]["DurableExecutionStatus"]; }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Project schedulers */ + /** @description Successful response */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionSchedulerListResponse"]; + "application/json": components["schemas"]["PaginatedDurableExecutions"]; }; }; - }; - }; - listFunctionSchedulers: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Function ID */ - functionId: components["parameters"]["FunctionId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Function schedulers */ - 200: { + /** @description Unsupported status filter */ + 400: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionSchedulerListResponse"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Function not found */ + /** @description Durable function not found */ 404: { headers: { [name: string]: unknown; @@ -13031,37 +14276,44 @@ export interface operations { }; }; }; - createFunctionScheduler: { + startDurableExecution: { parameters: { query?: never; - header?: never; + header?: { + /** + * @description Idempotency key for this execution. Generated when omitted. A repeat + * under a name that already names a running execution returns that + * execution and is not charged again. + * + * Letters, digits, `-`, `_` and `.`, up to 255 characters. Anything + * else is rejected with `400`. + */ + "X-Volcano-Execution-Name"?: string; + }; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Function ID */ - functionId: components["parameters"]["FunctionId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; }; cookie?: never; }; - requestBody: { + requestBody?: { content: { - "application/json": components["schemas"]["CreateFunctionSchedulerRequest"]; + "application/json": unknown; }; }; responses: { - /** @description Scheduler created */ - 201: { + /** @description Execution accepted and started */ + 202: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionScheduler"]; + "application/json": components["schemas"]["DurableExecution"]; }; }; - /** - * @description Invalid schedule, geofenced region, a scheduler of this name - * already exists on the function, or the function is not active. - */ + /** @description Payload is not valid JSON, or the execution name is invalid */ 400: { headers: { [name: string]: unknown; @@ -13070,12 +14322,21 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Durable function not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; /** - * @description Schedulers are not available on this plan, or the project already - * holds as many as the plan allows. The cap counts standard and - * durable function schedulers together. + * @description Function is not deployed yet, or has no deployed region. Also + * returned when two starts under the same execution name raced and + * both released it, which is retryable as it stands. */ - 403: { + 409: { headers: { [name: string]: unknown; }; @@ -13083,8 +14344,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Function not found */ - 404: { + /** @description Payload exceeds the maximum execution input size */ + 413: { headers: { [name: string]: unknown; }; @@ -13092,35 +14353,28 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - getFunctionScheduler: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Function ID */ - functionId: components["parameters"]["FunctionId"]; - /** @description Function scheduler ID */ - schedulerId: components["parameters"]["SchedulerId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Function scheduler */ - 200: { + /** + * @description Too many executions already in flight for this project, or the + * account is out of one of its billing-cycle durable allowances: + * executions, operations, or compute. An owner-started execution is + * metered exactly like an application-started one. + */ + 429: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionScheduler"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Function or scheduler not found */ - 404: { + /** + * @description Durable execution is not available in this environment, or the + * usage limit service could not be reached to charge the start. The + * first is returned by a deployment that has no durable execution + * engine, such as a local one, and is not retryable there; the second + * is transient. + */ + 503: { headers: { [name: string]: unknown; }; @@ -13130,30 +14384,32 @@ export interface operations { }; }; }; - deleteFunctionScheduler: { + getDurableExecution: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Function ID */ - functionId: components["parameters"]["FunctionId"]; - /** @description Function scheduler ID */ - schedulerId: components["parameters"]["SchedulerId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; + /** @description Durable execution ID */ + executionId: components["parameters"]["DurableExecutionId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Scheduler deleted */ - 204: { + /** @description Successful response */ + 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["DurableExecution"]; + }; }; - /** @description Function or scheduler not found */ + /** @description Durable function or execution not found */ 404: { headers: { [name: string]: unknown; @@ -13162,50 +14418,50 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** + * @description Durable execution is not available in this environment. Returned by + * a deployment that has no durable execution engine, such as a local + * one; the request is not retryable there. + */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - updateFunctionScheduler: { + stopDurableExecution: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Function ID */ - functionId: components["parameters"]["FunctionId"]; - /** @description Function scheduler ID */ - schedulerId: components["parameters"]["SchedulerId"]; + /** @description Durable function ID, or its name within the project */ + functionId: components["parameters"]["DurableFunctionId"]; + /** @description Durable execution ID */ + executionId: components["parameters"]["DurableExecutionId"]; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateFunctionSchedulerRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Scheduler updated */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["FunctionScheduler"]; - }; - }; /** - * @description Invalid schedule, geofenced region, or a scheduler of this name - * already exists on the function. + * @description Stop accepted. The body is the execution as it was read back, which + * may still report `running`. */ - 400: { + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["DurableExecution"]; }; }; - /** @description Function or scheduler not found */ + /** @description Durable function or execution not found */ 404: { headers: { [name: string]: unknown; @@ -13214,44 +14470,21 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - listFunctionDeployments: { - parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - }; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Function ID */ - functionId: components["parameters"]["FunctionId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Successful response */ - 200: { + /** @description Execution has not started yet */ + 409: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedFunctionDeployments"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Function not found */ - 404: { + /** + * @description Durable execution is not available in this environment. Returned by + * a deployment that has no durable execution engine, such as a local + * one; the request is not retryable there. + */ + 503: { headers: { [name: string]: unknown; }; @@ -13261,7 +14494,7 @@ export interface operations { }; }; }; - listDurableFunctions: { + listFrontends: { parameters: { query?: { /** @@ -13274,6 +14507,29 @@ export interface operations { page?: components["parameters"]["Page"]; /** @description Number of items per page (max 100) */ limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; /** * @description Case-insensitive substring match on the resource `name`. See the * endpoint description for supported pagination modes. @@ -13295,10 +14551,10 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedDurableFunctions"]; + "application/json": components["schemas"]["PaginatedFrontends"]; }; }; - /** @description Bad request - invalid pagination parameters */ + /** @description Bad request - invalid project identifier */ 400: { headers: { [name: string]: unknown; @@ -13307,6 +14563,24 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Unauthorized - invalid or missing token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Forbidden - project ownership required */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; /** @description Project not found */ 404: { headers: { @@ -13316,9 +14590,18 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - createDurableFunction: { + createFrontend: { parameters: { query?: never; header?: never; @@ -13331,80 +14614,47 @@ export interface operations { requestBody: { content: { "multipart/form-data": { - /** - * @description DNS-safe function name (lowercase letters, numbers, hyphens; cannot start or end with hyphen) - * @example order-pipeline - */ + /** @description DNS-safe frontend name */ name: string; /** - * Format: binary - * @description ZIP or tar.gz archive containing function source code plus dependency manifests/lockfiles. - */ - code: string; - /** - * @description Runtime environment. Required. Durable execution needs the - * durable authoring API, which ships for these runtimes only; - * any other runtime is rejected with 400 and the response - * names the ones that work. Note that a durable Python - * function needs a newer runtime than a standard one defaults - * to. `GET /functions/runtimes` reports `durable_capable` per - * runtime. - * @example nodejs24.x + * @description Next.js frontend. Supported Next.js majors are 15.x and 16.x. + * @default nextjs * @enum {string} */ - runtime: "nodejs22.x" | "nodejs24.x" | "python3.13" | "python3.14"; - /** - * @description The name of the function to invoke. Defaults to "handler" if not specified. - * @default handler - * @example handler - */ - handler?: string; + framework?: "nextjs"; /** - * @description Whether anon keys with `functions.invoke` may start an - * execution. Redeploying is the only way to change it, since - * the collection has no update endpoint; omit it to keep the - * current visibility, and a new function starts private. - * - * The standard collection's synchronous invocation fields — - * `invocation_mode`, `http_auth_mode`, `openapi_spec` — - * configure a request path no durable route serves, and are - * rejected with 400 rather than ignored. + * @description Optional relative POSIX path from the uploaded archive root to the Next.js app to build, for example `apps/web`. + * @example apps/web */ - is_public?: boolean; + app_root?: string; /** - * @description Which project variables this function receives. `all` (the default) gives it every project variable; `scoped` gives it only the variables it selects. Omitting this leaves an existing function's scope unchanged. - * @enum {string} + * Format: binary + * @description ZIP or tar.gz archive of the frontend project directory or monorepo workspace root. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz archive. */ - variable_scope?: "all" | "scoped"; - /** @description JSON-encoded array of project variable names this function requires, on top of the ones detected in its source. A declared name the project does not define is rejected with 400; a detected name it does not define is ignored. Only used when `variable_scope` is `scoped`. Omitting this leaves an existing function's declared names unchanged. */ - variables?: string; + archive: string; }; }; }; responses: { - /** @description Existing durable function updated; its deployment was started or queued */ + /** @description Existing frontend updated; its deployment was started or queued */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DurableFunction"]; + "application/json": components["schemas"]["Frontend"]; }; }; - /** @description Durable function created and deployment workflow started */ + /** @description Frontend created and deployment workflow started */ 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DurableFunction"]; + "application/json": components["schemas"]["Frontend"]; }; }; - /** - * @description Bad request (invalid archive, unsupported runtime, invalid name, or a - * project region that does not offer durable execution — a durable - * function deploys to every region of its project) - */ + /** @description Bad request */ 400: { headers: { [name: string]: unknown; @@ -13413,7 +14663,16 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Durable function limit exceeded for the project */ + /** @description Unauthorized - invalid or missing token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Frontend deployment limit exceeded for the current plan or project hard cap */ 403: { headers: { [name: string]: unknown; @@ -13422,7 +14681,16 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Name is held by a standard function, or a deletion is queued or running */ + /** @description Project not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Conflict - frontend deletion is queued or running */ 409: { headers: { [name: string]: unknown; @@ -13431,7 +14699,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error (function deployment failed) */ + /** @description Internal server error */ 500: { headers: { [name: string]: unknown; @@ -13440,10 +14708,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Durable deploys are paused platform-wide. The same request succeeds - * once they are re-enabled; executions already running are unaffected. - */ + /** @description Service unavailable - frontend workflow or archive limit configuration missing */ 503: { headers: { [name: string]: unknown; @@ -13454,15 +14719,15 @@ export interface operations { }; }; }; - getDurableFunction: { + getFrontend: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; + /** @description Frontend ID */ + frontendId: components["parameters"]["FrontendId"]; }; cookie?: never; }; @@ -13474,10 +14739,37 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DurableFunction"]; + "application/json": components["schemas"]["Frontend"]; }; }; - /** @description Durable function not found */ + /** @description Bad request - invalid identifier */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Unauthorized - invalid or missing token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Forbidden - project ownership required */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Frontend not found */ 404: { headers: { [name: string]: unknown; @@ -13486,35 +14778,40 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - deleteDurableFunction: { + deleteFrontend: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; + /** @description Frontend ID */ + frontendId: components["parameters"]["FrontendId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Deletion accepted and teardown started */ + /** @description Frontend deletion started or queued */ 202: { headers: { [name: string]: unknown; }; content?: never; }; - /** - * @description Durable function not found. Also returned for an id that names a - * durable function in another project, so the response cannot be used - * to tell the two apart. - */ - 404: { + /** @description Bad request - invalid identifier */ + 400: { headers: { [name: string]: unknown; }; @@ -13522,43 +14819,25 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - listDurableFunctionDeployments: { - parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - }; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; + /** @description Unauthorized - invalid or missing token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Successful response */ - 200: { + /** @description Forbidden - project ownership required */ + 403: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedFunctionDeployments"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Durable function not found */ + /** @description Frontend not found */ 404: { headers: { [name: string]: unknown; @@ -13567,33 +14846,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - listDurableFunctionSchedulers: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Durable function schedulers */ - 200: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionSchedulerListResponse"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Durable function not found */ - 404: { + /** @description Service unavailable - frontend workflow configuration missing */ + 503: { headers: { [name: string]: unknown; }; @@ -13603,37 +14866,30 @@ export interface operations { }; }; }; - createDurableFunctionScheduler: { + redeployFrontend: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; + /** @description Frontend ID */ + frontendId: components["parameters"]["FrontendId"]; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["CreateFunctionSchedulerRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Scheduler created */ - 201: { + /** @description Frontend redeploy started or queued */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionScheduler"]; + "application/json": components["schemas"]["Frontend"]; }; }; - /** - * @description Invalid schedule, geofenced region, a scheduler of this name - * already exists on the function, or the function is not active. - */ + /** @description Bad request - invalid identifier */ 400: { headers: { [name: string]: unknown; @@ -13642,12 +14898,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Schedulers are not available on this plan, or the project already - * holds as many as the plan allows. The cap counts standard and - * durable function schedulers together. - */ - 403: { + /** @description Unauthorized - invalid or missing token */ + 401: { headers: { [name: string]: unknown; }; @@ -13655,8 +14907,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Durable function not found */ - 404: { + /** @description Forbidden - project ownership required */ + 403: { headers: { [name: string]: unknown; }; @@ -13664,35 +14916,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - getDurableFunctionScheduler: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; - /** @description Function scheduler ID */ - schedulerId: components["parameters"]["SchedulerId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Durable function scheduler */ - 200: { + /** @description Frontend not found */ + 404: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionScheduler"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Durable function or scheduler not found */ - 404: { + /** @description Conflict - frontend deletion is queued or running */ + 409: { headers: { [name: string]: unknown; }; @@ -13700,33 +14934,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - deleteDurableFunctionScheduler: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; - /** @description Function scheduler ID */ - schedulerId: components["parameters"]["SchedulerId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Scheduler deleted */ - 204: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Durable function or scheduler not found */ - 404: { + /** @description Service unavailable - frontend workflow configuration missing */ + 503: { headers: { [name: string]: unknown; }; @@ -13736,39 +14954,33 @@ export interface operations { }; }; }; - updateDurableFunctionScheduler: { + getFrontendCustomDomain: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; - /** @description Function scheduler ID */ - schedulerId: components["parameters"]["SchedulerId"]; + /** @description Frontend ID */ + frontendId: components["parameters"]["FrontendId"]; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateFunctionSchedulerRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Scheduler updated */ + /** + * @description Frontend custom domain status, or null when the frontend has no + * custom domain configured (the common empty state). + */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionScheduler"]; + "application/json": components["schemas"]["FrontendCustomDomainResponse"] | null; }; }; - /** - * @description Invalid schedule, geofenced region, or a scheduler of this name - * already exists on the function. - */ + /** @description Bad request - invalid identifier */ 400: { headers: { [name: string]: unknown; @@ -13777,8 +14989,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Durable function or scheduler not found */ - 404: { + /** @description Unauthorized - invalid or missing token */ + 401: { headers: { [name: string]: unknown; }; @@ -13786,46 +14998,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - listDurableExecutions: { - parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** @description Return only executions in this status. */ - status?: components["schemas"]["DurableExecutionStatus"]; - }; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Successful response */ - 200: { + /** @description Forbidden - project ownership required */ + 403: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedDurableExecutions"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Unsupported status filter */ - 400: { + /** @description Frontend not found */ + 404: { headers: { [name: string]: unknown; }; @@ -13833,8 +15016,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Durable function not found */ - 404: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -13844,44 +15027,43 @@ export interface operations { }; }; }; - startDurableExecution: { + createFrontendCustomDomain: { parameters: { query?: never; - header?: { - /** - * @description Idempotency key for this execution. Generated when omitted. A repeat - * under a name that already names a running execution returns that - * execution and is not charged again. - * - * Letters, digits, `-`, `_` and `.`, up to 255 characters. Anything - * else is rejected with `400`. - */ - "X-Volcano-Execution-Name"?: string; - }; + header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; + /** @description Frontend ID */ + frontendId: components["parameters"]["FrontendId"]; }; cookie?: never; }; - requestBody?: { + requestBody: { content: { - "application/json": unknown; + "application/json": components["schemas"]["CreateFrontendCustomDomainRequest"]; }; }; responses: { - /** @description Execution accepted and started */ - 202: { + /** @description Custom domain already configured with same hostname */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DurableExecution"]; + "application/json": components["schemas"]["FrontendCustomDomainResponse"]; }; }; - /** @description Payload is not valid JSON, or the execution name is invalid */ + /** @description Custom domain provisioning started */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["FrontendCustomDomainResponse"]; + }; + }; + /** @description Bad request - invalid domain */ 400: { headers: { [name: string]: unknown; @@ -13890,8 +15072,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Durable function not found */ - 404: { + /** @description Unauthorized - invalid or missing token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Forbidden - custom domains require SUPERAGENT plan */ + 403: { headers: { [name: string]: unknown; }; @@ -13899,12 +15090,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Function is not deployed yet, or has no deployed region. Also - * returned when two starts under the same execution name raced and - * both released it, which is retryable as it stands. - */ - 409: { + /** @description Frontend not found */ + 404: { headers: { [name: string]: unknown; }; @@ -13912,8 +15099,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Payload exceeds the maximum execution input size */ - 413: { + /** @description Conflict - custom domain already in use, still detaching, or frontend already has a custom domain */ + 409: { headers: { [name: string]: unknown; }; @@ -13921,13 +15108,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Too many executions already in flight for this project, or the - * account is out of one of its billing-cycle durable allowances: - * executions, operations, or compute. An owner-started execution is - * metered exactly like an application-started one. - */ - 429: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -13935,13 +15117,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Durable execution is not available in this environment, or the - * usage limit service could not be reached to charge the start. The - * first is returned by a deployment that has no durable execution - * engine, such as a local one, and is not retryable there; the second - * is transient. - */ + /** @description Service unavailable - custom domain provisioning is temporarily unavailable */ 503: { headers: { [name: string]: unknown; @@ -13952,33 +15128,29 @@ export interface operations { }; }; }; - getDurableExecution: { + deleteFrontendCustomDomain: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; - /** @description Durable execution ID */ - executionId: components["parameters"]["DurableExecutionId"]; + /** @description Frontend ID */ + frontendId: components["parameters"]["FrontendId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Successful response */ - 200: { + /** @description Custom domain detach scheduled */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["DurableExecution"]; - }; + content?: never; }; - /** @description Durable function or execution not found */ - 404: { + /** @description Bad request - invalid identifier */ + 400: { headers: { [name: string]: unknown; }; @@ -13986,12 +15158,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Durable execution is not available in this environment. Returned by - * a deployment that has no durable execution engine, such as a local - * one; the request is not retryable there. - */ - 503: { + /** @description Unauthorized - invalid or missing token */ + 401: { headers: { [name: string]: unknown; }; @@ -13999,38 +15167,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - stopDurableExecution: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Durable function ID, or its name within the project */ - functionId: components["parameters"]["DurableFunctionId"]; - /** @description Durable execution ID */ - executionId: components["parameters"]["DurableExecutionId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** - * @description Stop accepted. The body is the execution as it was read back, which - * may still report `running`. - */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DurableExecution"]; - }; - }; - /** @description Durable function or execution not found */ - 404: { + /** @description Forbidden - project ownership required */ + 403: { headers: { [name: string]: unknown; }; @@ -14038,8 +15176,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Execution has not started yet */ - 409: { + /** @description Frontend or custom domain not found */ + 404: { headers: { [name: string]: unknown; }; @@ -14047,12 +15185,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Durable execution is not available in this environment. Returned by - * a deployment that has no durable execution engine, such as a local - * one; the request is not retryable there. - */ - 503: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -14062,7 +15196,7 @@ export interface operations { }; }; }; - listFrontends: { + listFrontendDeployments: { parameters: { query?: { /** @@ -14075,39 +15209,13 @@ export interface operations { page?: components["parameters"]["Page"]; /** @description Number of items per page (max 100) */ limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - search?: components["parameters"]["Search"]; }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Frontend ID */ + frontendId: components["parameters"]["FrontendId"]; }; cookie?: never; }; @@ -14119,10 +15227,10 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedFrontends"]; + "application/json": components["schemas"]["PaginatedFrontendDeployments"]; }; }; - /** @description Bad request - invalid project identifier */ + /** @description Bad request - invalid identifier */ 400: { headers: { [name: string]: unknown; @@ -14149,7 +15257,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project not found */ + /** @description Frontend not found */ 404: { headers: { [name: string]: unknown; @@ -14169,61 +15277,70 @@ export interface operations { }; }; }; - createFrontend: { + getFrontendUsageHistory: { parameters: { - query?: never; + query?: { + /** @description Number of trailing days to return (1–90, default 30). */ + days?: number; + }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Frontend ID */ + frontendId: components["parameters"]["FrontendId"]; }; cookie?: never; }; - requestBody: { - content: { - "multipart/form-data": { - /** @description DNS-safe frontend name */ - name: string; - /** - * @description Next.js frontend. Supported Next.js majors are 15.x and 16.x. - * @default nextjs - * @enum {string} - */ - framework?: "nextjs"; - /** - * @description Optional relative POSIX path from the uploaded archive root to the Next.js app to build, for example `apps/web`. - * @example apps/web - */ - app_root?: string; - /** - * Format: binary - * @description ZIP or tar.gz archive of the frontend project directory or monorepo workspace root. The API enforces SOURCE_ARCHIVE_SIZE_LIMIT_MB and stores a normalized tar.gz archive. - */ - archive: string; - }; - }; - }; + requestBody?: never; responses: { - /** @description Existing frontend updated; its deployment was started or queued */ + /** @description Successful response */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Frontend"]; + "application/json": components["schemas"]["FrontendUsageHistoryResponse"]; }; }; - /** @description Frontend created and deployment workflow started */ - 201: { + /** @description Bad request - invalid identifier */ + 400: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Frontend"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Bad request */ - 400: { + /** @description Unauthorized - invalid or missing token */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Forbidden - project ownership required */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Frontend not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -14231,22 +15348,66 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + listVariables: { + parameters: { + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; + }; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; - /** @description Frontend deployment limit exceeded for the current plan or project hard cap */ - 403: { + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful response */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["PaginatedVariables"]; }; }; /** @description Project not found */ @@ -14258,17 +15419,35 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Conflict - frontend deletion is queued or running */ - 409: { + }; + }; + createVariable: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateVariableRequest"]; + }; + }; + responses: { + /** @description Variable created */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["Variable"]; }; }; - /** @description Internal server error */ - 500: { + /** @description Bad request */ + 400: { headers: { [name: string]: unknown; }; @@ -14276,7 +15455,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Service unavailable - frontend workflow or archive limit configuration missing */ + /** @description Private variable membership writes are disabled during rollout */ 503: { headers: { [name: string]: unknown; @@ -14287,15 +15466,54 @@ export interface operations { }; }; }; - getFrontend: { + listDatabases: { parameters: { - query?: never; + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; + /** @description Return only the databases in this status. */ + status?: "provisioning" | "active" | "restoring" | "failed" | "deleting"; + }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Frontend ID */ - frontendId: components["parameters"]["FrontendId"]; }; cookie?: never; }; @@ -14307,28 +15525,37 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Frontend"]; + "application/json": components["schemas"]["PaginatedDatabases"]; }; }; - /** @description Bad request - invalid identifier */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + createDatabase: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; - /** @description Unauthorized - invalid or missing token */ - 401: { + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateDatabaseRequest"]; + }; + }; + responses: { + /** @description Database created (provisioning) */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["Database"]; }; }; - /** @description Forbidden - project ownership required */ + /** @description Database limit exceeded for the project */ 403: { headers: { [name: string]: unknown; @@ -14337,49 +15564,74 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Frontend not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + getDatabase: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; }; - /** @description Internal server error */ - 500: { + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful response */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["Database"]; }; }; }; }; - deleteFrontend: { + deleteDatabase: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Frontend ID */ - frontendId: components["parameters"]["FrontendId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Frontend deletion started or queued */ + /** + * @description Deletion accepted and in progress. The backing instance could not be + * removed synchronously, so the database is marked `deleting` and torn + * down asynchronously by the reconciler. + */ 202: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @example deleting */ + status?: string; + /** @example database deletion in progress */ + message?: string; + }; + }; + }; + /** @description Database deleted (backing instance removed synchronously) */ + 204: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Bad request - invalid identifier */ - 400: { + /** @description Project or database not found */ + 404: { headers: { [name: string]: unknown; }; @@ -14387,8 +15639,12 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** + * @description A restore is running on the database. Deleting it while a worker is + * replacing its data would race that worker, so wait for the restore + * to finish. + */ + 409: { headers: { [name: string]: unknown; }; @@ -14396,8 +15652,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden - project ownership required */ - 403: { + /** + * @description Volcano could not check whether a restore is running, and will not + * delete a database that might be mid-restore. Retry. + */ + 503: { headers: { [name: string]: unknown; }; @@ -14405,17 +15664,33 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Frontend not found */ - 404: { + }; + }; + listDatabaseBranches: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful response */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["DatabaseBranchList"]; }; }; - /** @description Internal server error */ - 500: { + /** @description Project or database not found */ + 404: { headers: { [name: string]: unknown; }; @@ -14423,7 +15698,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Service unavailable - frontend workflow configuration missing */ + /** @description Branching is temporarily unavailable */ 503: { headers: { [name: string]: unknown; @@ -14434,30 +15709,34 @@ export interface operations { }; }; }; - redeployFrontend: { + createDatabaseBranch: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Frontend ID */ - frontendId: components["parameters"]["FrontendId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateDatabaseBranchRequest"]; }; - cookie?: never; }; - requestBody?: never; responses: { - /** @description Frontend redeploy started or queued */ - 200: { + /** @description Branch accepted and provisioning */ + 202: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Frontend"]; + "application/json": components["schemas"]["DatabaseBranch"]; }; }; - /** @description Bad request - invalid identifier */ + /** @description Invalid branch name or lifetime */ 400: { headers: { [name: string]: unknown; @@ -14466,16 +15745,10 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Forbidden - project ownership required */ + /** + * @description The database has reached its branch allowance, or the owner's plan + * does not include branching. + */ 403: { headers: { [name: string]: unknown; @@ -14484,7 +15757,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Frontend not found */ + /** @description Project or database not found */ 404: { headers: { [name: string]: unknown; @@ -14493,7 +15766,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Conflict - frontend deletion is queued or running */ + /** + * @description A branch of that name already exists on this database, or the + * database cannot be branched right now because it is still + * provisioning, being restored, failed, or being deleted. + */ 409: { headers: { [name: string]: unknown; @@ -14502,16 +15779,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Service unavailable - frontend workflow configuration missing */ + /** @description Branching is temporarily unavailable */ 503: { headers: { [name: string]: unknown; @@ -14522,34 +15790,33 @@ export interface operations { }; }; }; - getFrontendCustomDomain: { + getDatabaseBranch: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Frontend ID */ - frontendId: components["parameters"]["FrontendId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** - * @description Frontend custom domain status, or null when the frontend has no - * custom domain configured (the common empty state). - */ + /** @description Successful response */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FrontendCustomDomainResponse"] | null; + "application/json": components["schemas"]["DatabaseBranch"]; }; }; - /** @description Bad request - invalid identifier */ - 400: { + /** @description Project, database, or branch not found */ + 404: { headers: { [name: string]: unknown; }; @@ -14557,8 +15824,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** @description Branching is temporarily unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -14566,16 +15833,39 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden - project ownership required */ - 403: { + }; + }; + deleteDatabaseBranch: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + branchName: components["parameters"]["BranchName"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deletion accepted and in progress */ + 202: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": { + /** @example deleting */ + status: string; + /** @example branch deletion in progress */ + message: string; + }; }; }; - /** @description Frontend not found */ + /** @description Project, database, or branch not found */ 404: { headers: { [name: string]: unknown; @@ -14584,8 +15874,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** @description Branching is temporarily unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -14595,44 +15885,46 @@ export interface operations { }; }; }; - createFrontendCustomDomain: { + updateDatabaseBranch: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Frontend ID */ - frontendId: components["parameters"]["FrontendId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["CreateFrontendCustomDomainRequest"]; + "application/json": components["schemas"]["UpdateDatabaseBranchRequest"]; }; }; responses: { - /** @description Custom domain already configured with same hostname */ + /** @description Lifetime updated */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FrontendCustomDomainResponse"]; + "application/json": components["schemas"]["DatabaseBranch"]; }; }; - /** @description Custom domain provisioning started */ - 201: { + /** @description Requested lifetime is outside the allowed range */ + 400: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FrontendCustomDomainResponse"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Bad request - invalid domain */ - 400: { + /** @description Project, database, or branch not found */ + 404: { headers: { [name: string]: unknown; }; @@ -14640,8 +15932,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** @description The branch is being deleted */ + 409: { headers: { [name: string]: unknown; }; @@ -14649,8 +15941,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden - custom domains require SUPERAGENT plan */ - 403: { + /** @description Branching is temporarily unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -14658,17 +15950,35 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Frontend not found */ - 404: { + }; + }; + resetDatabaseBranch: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + branchName: components["parameters"]["BranchName"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Branch reset accepted; the branch is provisioning */ + 202: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["DatabaseBranch"]; }; }; - /** @description Conflict - custom domain already in use, still detaching, or frontend already has a custom domain */ - 409: { + /** @description Project, database, or branch not found */ + 404: { headers: { [name: string]: unknown; }; @@ -14676,8 +15986,13 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** + * @description The branch is not active, a reset is already in progress, the parent + * database is being restored, or the parent was restored within the + * last 24 hours — a reset re-forks from the parent, and the provider + * holds a child's reset shut for that long afterwards. + */ + 409: { headers: { [name: string]: unknown; }; @@ -14685,7 +16000,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Service unavailable - custom domain provisioning is temporarily unavailable */ + /** @description Branching is temporarily unavailable */ 503: { headers: { [name: string]: unknown; @@ -14696,47 +16011,33 @@ export interface operations { }; }; }; - deleteFrontendCustomDomain: { + resetDatabaseBranchPassword: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Frontend ID */ - frontendId: components["parameters"]["FrontendId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Custom domain detach scheduled */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Bad request - invalid identifier */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** @description Password rotated */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["DatabaseBranch"]; }; }; - /** @description Forbidden - project ownership required */ - 403: { + /** @description Project, database, or branch not found */ + 404: { headers: { [name: string]: unknown; }; @@ -14744,8 +16045,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Frontend or custom domain not found */ - 404: { + /** @description The branch is not active */ + 409: { headers: { [name: string]: unknown; }; @@ -14753,8 +16054,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** @description Branching is temporarily unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -14764,26 +16065,15 @@ export interface operations { }; }; }; - listFrontendDeployments: { + listDatabaseBackups: { parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - }; + query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Frontend ID */ - frontendId: components["parameters"]["FrontendId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; }; cookie?: never; }; @@ -14795,20 +16085,11 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedFrontendDeployments"]; - }; - }; - /** @description Bad request - invalid identifier */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["DatabaseBackupList"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ + 403: { headers: { [name: string]: unknown; }; @@ -14816,8 +16097,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden - project ownership required */ - 403: { + /** @description Project or database not found */ + 404: { headers: { [name: string]: unknown; }; @@ -14825,8 +16106,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Frontend not found */ - 404: { + /** + * @description The database has no storage project yet, so there is nothing to + * list. A database reports this while it is still provisioning. + */ + 409: { headers: { [name: string]: unknown; }; @@ -14834,8 +16118,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** @description Backups are temporarily unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -14845,33 +16129,34 @@ export interface operations { }; }; }; - getFrontendUsageHistory: { + createDatabaseBackup: { parameters: { - query?: { - /** @description Number of trailing days to return (1–90, default 30). */ - days?: number; - }; + query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Frontend ID */ - frontendId: components["parameters"]["FrontendId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["CreateDatabaseBackupRequest"]; + }; + }; responses: { - /** @description Successful response */ - 200: { + /** @description Backup created */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FrontendUsageHistoryResponse"]; + "application/json": components["schemas"]["DatabaseBackup"]; }; }; - /** @description Bad request - invalid identifier */ + /** @description Invalid backup name */ 400: { headers: { [name: string]: unknown; @@ -14880,8 +16165,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized - invalid or missing token */ - 401: { + /** + * @description The database has reached its backup allowance, or the owner's plan + * does not include backups, which are SUPERAGENT-only. + */ + 403: { headers: { [name: string]: unknown; }; @@ -14889,8 +16177,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Forbidden - project ownership required */ - 403: { + /** @description Project or database not found */ + 404: { headers: { [name: string]: unknown; }; @@ -14898,8 +16186,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Frontend not found */ - 404: { + /** + * @description A backup of that name already exists, the database is not active, a + * restore is running on it, or a backup was taken too recently. + */ + 409: { headers: { [name: string]: unknown; }; @@ -14907,8 +16198,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** @description Backups are temporarily unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -14918,52 +16209,24 @@ export interface operations { }; }; }; - listVariables: { + getDatabaseBackup: { parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - search?: components["parameters"]["Search"]; - }; + query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; + /** + * @description Backup name, unique within the database, exactly as returned by the list + * endpoint. + * + * Deliberately looser than the names you can create: a backup made by a + * schedule is named for you, so reading or deleting one accepts any name a + * backup can have. + */ + backupName: components["parameters"]["BackupName"]; }; cookie?: never; }; @@ -14975,11 +16238,11 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedVariables"]; + "application/json": components["schemas"]["DatabaseBackup"]; }; }; - /** @description Project not found */ - 404: { + /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ + 403: { headers: { [name: string]: unknown; }; @@ -14987,35 +16250,20 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - createVariable: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["CreateVariableRequest"]; - }; - }; - responses: { - /** @description Variable created */ - 201: { + /** @description Project, database, or backup not found */ + 404: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Variable"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Bad request */ - 400: { + /** + * @description The database has no storage project yet, so it holds no backups. A + * database reports this while it is still provisioning. + */ + 409: { headers: { [name: string]: unknown; }; @@ -15023,7 +16271,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Private variable membership writes are disabled during rollout */ + /** @description Backups are temporarily unavailable */ 503: { headers: { [name: string]: unknown; @@ -15034,97 +16282,76 @@ export interface operations { }; }; }; - listDatabases: { + deleteDatabaseBackup: { parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - search?: components["parameters"]["Search"]; - /** @description Return only the databases in this status. */ - status?: "provisioning" | "active" | "restoring" | "failed" | "deleting"; - }; + query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; + /** + * @description Backup name, unique within the database, exactly as returned by the list + * endpoint. + * + * Deliberately looser than the names you can create: a backup made by a + * schedule is named for you, so reading or deleting one accepts any name a + * backup can have. + */ + backupName: components["parameters"]["BackupName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Successful response */ + /** @description Backup deleted */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedDatabases"]; + "application/json": { + /** @example deleted */ + status: string; + /** @example backup deleted */ + message: string; + }; }; }; - }; - }; - createDatabase: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["CreateDatabaseRequest"]; + /** @description Project, database, or backup not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - }; - responses: { - /** @description Database created (provisioning) */ - 201: { + /** + * @description The database is being restored. A restore is pinned to a backup it + * may not have restored yet, so deleting one is refused until the + * restore finishes. + */ + 409: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Database"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Database limit exceeded for the project */ - 403: { + /** @description Backups are temporarily unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -15134,7 +16361,7 @@ export interface operations { }; }; }; - getDatabase: { + getDatabaseBackupSchedule: { parameters: { query?: never; header?: never; @@ -15154,12 +16381,51 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Database"]; + "application/json": components["schemas"]["DatabaseBackupSchedule"]; + }; + }; + /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Project or database not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** + * @description The database has no storage project yet, so it has no schedule. A + * database reports this while it is still provisioning. + */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Backups are temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; }; }; }; }; - deleteDatabase: { + updateDatabaseBackupSchedule: { parameters: { query?: never; header?: never; @@ -15171,32 +16437,42 @@ export interface operations { }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["DatabaseBackupSchedule"]; + }; + }; responses: { + /** @description Schedule replaced */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DatabaseBackupSchedule"]; + }; + }; /** - * @description Deletion accepted and in progress. The backing instance could not be - * removed synchronously, so the database is marked `deleting` and torn - * down asynchronously by the reconciler. + * @description The schedule names a recurrence that cannot fire: a weekly or + * monthly one with no `day`, or a `day` outside its frequency's range + * (1-7 for weekly, 1-28 for monthly). The response says which. */ - 202: { + 400: { headers: { [name: string]: unknown; }; content: { - "application/json": { - /** @example deleting */ - status?: string; - /** @example database deletion in progress */ - message?: string; - }; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Database deleted (backing instance removed synchronously) */ - 204: { + /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ + 403: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; /** @description Project or database not found */ 404: { @@ -15208,9 +16484,9 @@ export interface operations { }; }; /** - * @description A restore is running on the database. Deleting it while a worker is - * replacing its data would race that worker, so wait for the restore - * to finish. + * @description The database is not active, or a restore is running on it — a restore + * moves the data to a new branch, and the provider keeps the schedule + * per branch. */ 409: { headers: { @@ -15220,10 +16496,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Volcano could not check whether a restore is running, and will not - * delete a database that might be mid-restore. Retry. - */ + /** @description Backups are temporarily unavailable */ 503: { headers: { [name: string]: unknown; @@ -15234,7 +16507,7 @@ export interface operations { }; }; }; - listDatabaseBranches: { + listDatabaseRestores: { parameters: { query?: never; header?: never; @@ -15254,7 +16527,16 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBranchList"]; + "application/json": components["schemas"]["DatabaseRestoreList"]; + }; + }; + /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; }; }; /** @description Project or database not found */ @@ -15266,7 +16548,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Branching is temporarily unavailable */ + /** @description Backups are temporarily unavailable */ 503: { headers: { [name: string]: unknown; @@ -15277,7 +16559,7 @@ export interface operations { }; }; }; - createDatabaseBranch: { + createDatabaseRestore: { parameters: { query?: never; header?: never; @@ -15291,20 +16573,23 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["CreateDatabaseBranchRequest"]; + "application/json": components["schemas"]["CreateDatabaseRestoreRequest"]; }; }; responses: { - /** @description Branch accepted and provisioning */ + /** @description Restore accepted and in progress */ 202: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBranch"]; + "application/json": components["schemas"]["DatabaseRestore"]; }; }; - /** @description Invalid branch name or lifetime */ + /** + * @description Neither or both restore targets were named, or the requested time is + * outside the available window. + */ 400: { headers: { [name: string]: unknown; @@ -15314,8 +16599,8 @@ export interface operations { }; }; /** - * @description The database has reached its branch allowance, or the owner's plan - * does not include branching. + * @description The owner's plan does not include backups or point-in-time restore. + * Both are SUPERAGENT-only. */ 403: { headers: { @@ -15325,7 +16610,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project or database not found */ + /** @description Project, database, or backup not found */ 404: { headers: { [name: string]: unknown; @@ -15335,9 +16620,9 @@ export interface operations { }; }; /** - * @description A branch of that name already exists on this database, or the - * database cannot be branched right now because it is still - * provisioning, being restored, failed, or being deleted. + * @description A restore is already in progress, the database is not active, + * another database operation is still running, or the database is + * holding as many pre-restore branches as it may. */ 409: { headers: { @@ -15347,7 +16632,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Branching is temporarily unavailable */ + /** @description Backups are temporarily unavailable */ 503: { headers: { [name: string]: unknown; @@ -15358,7 +16643,7 @@ export interface operations { }; }; }; - getDatabaseBranch: { + getDatabaseRestore: { parameters: { query?: never; header?: never; @@ -15367,8 +16652,8 @@ export interface operations { id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - branchName: components["parameters"]["BranchName"]; + /** @description Database restore ID */ + restoreId: components["parameters"]["RestoreId"]; }; cookie?: never; }; @@ -15380,10 +16665,19 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBranch"]; + "application/json": components["schemas"]["DatabaseRestore"]; }; }; - /** @description Project, database, or branch not found */ + /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Project, database, or restore not found */ 404: { headers: { [name: string]: unknown; @@ -15392,7 +16686,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Branching is temporarily unavailable */ + /** @description Backups are temporarily unavailable */ 503: { headers: { [name: string]: unknown; @@ -15403,7 +16697,7 @@ export interface operations { }; }; }; - deleteDatabaseBranch: { + resetDatabasePassword: { parameters: { query?: never; header?: never; @@ -15412,29 +16706,121 @@ export interface operations { id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Deletion accepted and in progress */ - 202: { + /** @description Password reset successful */ + 200: { headers: { [name: string]: unknown; }; content: { "application/json": { - /** @example deleting */ - status: string; - /** @example branch deletion in progress */ - message: string; + message?: string; + /** + * @description Volcano-managed per-database client login (also the pgproxy routing username) + * @example volcano_client_11111111-1111-1111-1111-111111111111 + */ + role_name?: string; + /** @description New Volcano-managed client password. Always starts with `vpg_`. */ + new_password?: string; + /** @description Updated pgproxy connection string using Volcano-managed credentials. */ + connection_string?: string; }; }; }; - /** @description Project, database, or branch not found */ + /** @description Database is not active */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Database not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** + * @description A restore is running on the database. A restore replaces the + * credentials as it finishes, so wait for it and rotate afterwards. + */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** + * @description Volcano could not check whether a restore is running, and will not + * rotate a credential a restore might be about to replace. Retry. + */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + }; + updateDatabaseType: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ + databaseName: components["parameters"]["DatabaseName"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateDatabaseTypeRequest"]; + }; + }; + responses: { + /** @description Database type updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Database"]; + }; + }; + /** @description Invalid database type */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Database not found */ 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** + * @description The database is not active — being provisioned, deleted, or + * restored. Compute can only be changed while it is active. + */ + 409: { headers: { [name: string]: unknown; }; @@ -15442,7 +16828,10 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Branching is temporarily unavailable */ + /** + * @description Volcano could not check whether a restore is running, and will not + * reconfigure compute a restore might be moving. Retry. + */ 503: { headers: { [name: string]: unknown; @@ -15453,36 +16842,37 @@ export interface operations { }; }; }; - updateDatabaseBranch: { + getDatabaseStats: { parameters: { - query?: never; + query?: { + /** @description Start time in RFC3339 format (e.g., "2024-01-01T00:00:00Z"). Defaults to 24 hours ago. */ + from?: string; + /** @description End time in RFC3339 format (e.g., "2024-01-02T00:00:00Z"). Defaults to now. */ + to?: string; + /** @description Level of detail for metrics aggregation */ + granularity?: "hourly" | "daily" | "monthly"; + }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateDatabaseBranchRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Lifetime updated */ + /** @description Successful response */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBranch"]; + "application/json": components["schemas"]["DatabaseStats"]; }; }; - /** @description Requested lifetime is outside the allowed range */ + /** @description Invalid parameters */ 400: { headers: { [name: string]: unknown; @@ -15491,7 +16881,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project, database, or branch not found */ + /** @description Database not found */ 404: { headers: { [name: string]: unknown; @@ -15500,16 +16890,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description The branch is being deleted */ - 409: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Branching is temporarily unavailable */ + /** @description Database metrics not available or requires upgraded plan */ 503: { headers: { [name: string]: unknown; @@ -15520,33 +16901,39 @@ export interface operations { }; }; }; - resetDatabaseBranch: { + queryDatabasePing: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Branch reset accepted; the branch is provisioning */ - 202: { + /** @description Database is reachable */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBranch"]; + /** + * @example { + * "data": [ + * { + * "?column?": 1 + * } + * ], + * "count": 1 + * } + */ + "application/json": components["schemas"]["DatabaseQueryResult"]; }; }; - /** @description Project, database, or branch not found */ - 404: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -15554,13 +16941,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The branch is not active, a reset is already in progress, the parent - * database is being restored, or the parent was restored within the - * last 24 hours — a reset re-forks from the parent, and the provider - * holds a child's reset shut for that long afterwards. - */ - 409: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -15568,8 +16950,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Branching is temporarily unavailable */ - 503: { + /** @description Database not found */ + 404: { headers: { [name: string]: unknown; }; @@ -15577,35 +16959,51 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + 429: components["responses"]["DatabaseQueryCapExceeded"]; }; }; - resetDatabaseBranchPassword: { + queryDatabaseSelect: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["DatabaseSelectRequest"]; + }; + }; responses: { - /** @description Password rotated */ + /** @description Query successful */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBranch"]; + /** + * @example { + * "data": [ + * { + * "id": "uuid-123", + * "title": "My Post", + * "content": "Post content", + * "status": "published", + * "views": 150, + * "created_at": "2026-01-13T10:00:00Z" + * } + * ], + * "count": 1 + * } + */ + "application/json": components["schemas"]["DatabaseQueryResult"]; }; }; - /** @description Project, database, or branch not found */ - 404: { + /** @description Invalid query */ + 400: { headers: { [name: string]: unknown; }; @@ -15613,8 +17011,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description The branch is not active */ - 409: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -15622,8 +17020,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Branching is temporarily unavailable */ - 503: { + /** @description Access denied */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Database not found */ + 404: { headers: { [name: string]: unknown; }; @@ -15631,33 +17038,51 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + 429: components["responses"]["DatabaseQueryCapExceeded"]; }; }; - listDatabaseBackups: { + queryDatabaseInsert: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["DatabaseInsertRequest"]; + }; + }; responses: { - /** @description Successful response */ + /** @description Insert successful */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBackupList"]; + /** + * @example { + * "data": [ + * { + * "id": "uuid-123", + * "title": "My New Post", + * "content": "This is the content", + * "status": "draft", + * "user_id": "user-uuid", + * "created_at": "2026-01-13T10:00:00Z" + * } + * ], + * "count": 1 + * } + */ + "application/json": components["schemas"]["DatabaseQueryResult"]; }; }; - /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ - 403: { + /** @description Invalid request */ + 400: { headers: { [name: string]: unknown; }; @@ -15665,8 +17090,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project or database not found */ - 404: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -15674,11 +17099,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The database has no storage project yet, so there is nothing to - * list. A database reports this while it is still provisioning. - */ - 409: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -15686,8 +17108,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Backups are temporarily unavailable */ - 503: { + /** @description Database not found */ + 404: { headers: { [name: string]: unknown; }; @@ -15695,15 +17117,14 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + 429: components["responses"]["DatabaseQueryCapExceeded"]; }; }; - createDatabaseBackup: { + queryDatabaseUpdate: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; }; @@ -15711,20 +17132,33 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["CreateDatabaseBackupRequest"]; + "application/json": components["schemas"]["DatabaseUpdateRequest"]; }; }; responses: { - /** @description Backup created */ - 201: { + /** @description Update successful */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBackup"]; + /** + * @example { + * "data": [ + * { + * "id": "post-uuid", + * "title": "Updated Title", + * "status": "published", + * "updated_at": "2026-01-13T10:05:00Z" + * } + * ], + * "count": 1 + * } + */ + "application/json": components["schemas"]["DatabaseQueryResult"]; }; }; - /** @description Invalid backup name */ + /** @description Invalid request */ 400: { headers: { [name: string]: unknown; @@ -15733,20 +17167,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The database has reached its backup allowance, or the owner's plan - * does not include backups, which are SUPERAGENT-only. - */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Project or database not found */ - 404: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -15754,11 +17176,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description A backup of that name already exists, the database is not active, a - * restore is running on it, or a backup was taken too recently. - */ - 409: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -15766,8 +17185,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Backups are temporarily unavailable */ - 503: { + /** @description Database not found */ + 404: { headers: { [name: string]: unknown; }; @@ -15775,42 +17194,47 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + 429: components["responses"]["DatabaseQueryCapExceeded"]; }; }; - getDatabaseBackup: { + queryDatabaseDelete: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; - /** - * @description Backup name, unique within the database, exactly as returned by the list - * endpoint. - * - * Deliberately looser than the names you can create: a backup made by a - * schedule is named for you, so reading or deleting one accepts any name a - * backup can have. - */ - backupName: components["parameters"]["BackupName"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["DatabaseDeleteRequest"]; + }; + }; responses: { - /** @description Successful response */ + /** @description Delete successful */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBackup"]; + /** + * @example { + * "data": [ + * { + * "id": "post-uuid", + * "title": "Deleted Post" + * } + * ], + * "count": 1 + * } + */ + "application/json": components["schemas"]["DatabaseQueryResult"]; }; }; - /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ - 403: { + /** @description Invalid request or missing filters */ + 400: { headers: { [name: string]: unknown; }; @@ -15818,8 +17242,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project, database, or backup not found */ - 404: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -15827,11 +17251,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The database has no storage project yet, so it holds no backups. A - * database reports this while it is still provisioning. - */ - 409: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -15839,8 +17260,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Backups are temporarily unavailable */ - 503: { + /** @description Database not found */ + 404: { headers: { [name: string]: unknown; }; @@ -15848,56 +17269,44 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + 429: components["responses"]["DatabaseQueryCapExceeded"]; }; }; - deleteDatabaseBackup: { + queryDatabaseBranchPing: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; - /** - * @description Backup name, unique within the database, exactly as returned by the list - * endpoint. - * - * Deliberately looser than the names you can create: a backup made by a - * schedule is named for you, so reading or deleting one accepts any name a - * backup can have. - */ - backupName: components["parameters"]["BackupName"]; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Backup deleted */ + /** @description Database is reachable */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - /** @example deleted */ - status: string; - /** @example backup deleted */ - message: string; - }; - }; - }; - /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + /** + * @example { + * "data": [ + * { + * "?column?": 1 + * } + * ], + * "count": 1 + * } + */ + "application/json": components["schemas"]["DatabaseQueryResult"]; }; }; - /** @description Project, database, or backup not found */ - 404: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -15905,12 +17314,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The database is being restored. A restore is pinned to a backup it - * may not have restored yet, so deleting one is refused until the - * restore finishes. - */ - 409: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -15918,8 +17323,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Backups are temporarily unavailable */ - 503: { + /** @description Database or branch not found */ + 404: { headers: { [name: string]: unknown; }; @@ -15927,33 +17332,54 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + 429: components["responses"]["DatabaseQueryCapExceeded"]; + 503: components["responses"]["DatabaseBranchQueryUnavailable"]; }; }; - getDatabaseBackupSchedule: { + queryDatabaseBranchSelect: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["DatabaseSelectRequest"]; + }; + }; responses: { - /** @description Successful response */ + /** @description Query successful */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBackupSchedule"]; + /** + * @example { + * "data": [ + * { + * "id": "uuid-123", + * "title": "My Post", + * "content": "Post content", + * "status": "published", + * "views": 150, + * "created_at": "2026-01-13T10:00:00Z" + * } + * ], + * "count": 1 + * } + */ + "application/json": components["schemas"]["DatabaseQueryResult"]; }; }; - /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ - 403: { + /** @description Invalid query */ + 400: { headers: { [name: string]: unknown; }; @@ -15961,8 +17387,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project or database not found */ - 404: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -15970,11 +17396,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The database has no storage project yet, so it has no schedule. A - * database reports this while it is still provisioning. - */ - 409: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -15982,8 +17405,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Backups are temporarily unavailable */ - 503: { + /** @description Database or branch not found */ + 404: { headers: { [name: string]: unknown; }; @@ -15991,40 +17414,53 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + 429: components["responses"]["DatabaseQueryCapExceeded"]; + 503: components["responses"]["DatabaseBranchQueryUnavailable"]; }; }; - updateDatabaseBackupSchedule: { + queryDatabaseBranchInsert: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["DatabaseBackupSchedule"]; + "application/json": components["schemas"]["DatabaseInsertRequest"]; }; }; responses: { - /** @description Schedule replaced */ + /** @description Insert successful */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseBackupSchedule"]; + /** + * @example { + * "data": [ + * { + * "id": "uuid-123", + * "title": "My New Post", + * "content": "This is the content", + * "status": "draft", + * "user_id": "user-uuid", + * "created_at": "2026-01-13T10:00:00Z" + * } + * ], + * "count": 1 + * } + */ + "application/json": components["schemas"]["DatabaseQueryResult"]; }; }; - /** - * @description The schedule names a recurrence that cannot fire: a weekly or - * monthly one with no `day`, or a `day` outside its frequency's range - * (1-7 for weekly, 1-28 for monthly). The response says which. - */ + /** @description Invalid request */ 400: { headers: { [name: string]: unknown; @@ -16033,17 +17469,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Project or database not found */ - 404: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -16051,12 +17478,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The database is not active, or a restore is running on it — a restore - * moves the data to a new branch, and the provider keeps the schedule - * per branch. - */ - 409: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -16064,8 +17487,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Backups are temporarily unavailable */ - 503: { + /** @description Database or branch not found */ + 404: { headers: { [name: string]: unknown; }; @@ -16073,33 +17496,61 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + 429: components["responses"]["DatabaseQueryCapExceeded"]; + 503: components["responses"]["DatabaseBranchQueryUnavailable"]; }; }; - listDatabaseRestores: { + queryDatabaseBranchUpdate: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["DatabaseUpdateRequest"]; + }; + }; responses: { - /** @description Successful response */ + /** @description Update successful */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseRestoreList"]; + /** + * @example { + * "data": [ + * { + * "id": "post-uuid", + * "title": "Updated Title", + * "status": "published", + * "updated_at": "2026-01-13T10:05:00Z" + * } + * ], + * "count": 1 + * } + */ + "application/json": components["schemas"]["DatabaseQueryResult"]; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; }; }; - /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ - 403: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -16107,8 +17558,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project or database not found */ - 404: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -16116,8 +17567,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Backups are temporarily unavailable */ - 503: { + /** @description Database or branch not found */ + 404: { headers: { [name: string]: unknown; }; @@ -16125,39 +17576,49 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + 429: components["responses"]["DatabaseQueryCapExceeded"]; + 503: components["responses"]["DatabaseBranchQueryUnavailable"]; }; }; - createDatabaseRestore: { + queryDatabaseBranchDelete: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ databaseName: components["parameters"]["DatabaseName"]; + /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ + branchName: components["parameters"]["BranchName"]; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["CreateDatabaseRestoreRequest"]; + "application/json": components["schemas"]["DatabaseDeleteRequest"]; }; }; responses: { - /** @description Restore accepted and in progress */ - 202: { + /** @description Delete successful */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseRestore"]; + /** + * @example { + * "data": [ + * { + * "id": "post-uuid", + * "title": "Deleted Post" + * } + * ], + * "count": 1 + * } + */ + "application/json": components["schemas"]["DatabaseQueryResult"]; }; }; - /** - * @description Neither or both restore targets were named, or the requested time is - * outside the available window. - */ + /** @description Invalid request or missing filters */ 400: { headers: { [name: string]: unknown; @@ -16166,20 +17627,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The owner's plan does not include backups or point-in-time restore. - * Both are SUPERAGENT-only. - */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Project, database, or backup not found */ - 404: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -16187,12 +17636,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description A restore is already in progress, the database is not active, - * another database operation is still running, or the database is - * holding as many pre-restore branches as it may. - */ - 409: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; @@ -16200,8 +17645,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Backups are temporarily unavailable */ - 503: { + /** @description Database or branch not found */ + 404: { headers: { [name: string]: unknown; }; @@ -16209,106 +17654,140 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + 429: components["responses"]["DatabaseQueryCapExceeded"]; + 503: components["responses"]["DatabaseBranchQueryUnavailable"]; }; }; - getDatabaseRestore: { + listDatabaseRegions: { parameters: { query?: never; header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - /** @description Database restore ID */ - restoreId: components["parameters"]["RestoreId"]; - }; + path?: never; cookie?: never; }; requestBody?: never; responses: { - /** @description Successful response */ + /** @description List of platform-supported regions */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseRestore"]; + "application/json": { + /** + * @description Region identifier for API usage + * @example aws-us-east-1 + */ + id?: string; + /** + * @description Human-readable region location + * @example US East (N. Virginia) + */ + name?: string; + }[]; }; }; - /** @description Backups are SUPERAGENT-only and the owner's plan does not include them */ - 403: { + }; + }; + listPostgresVersions: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of available PostgreSQL versions */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": { + /** + * @description PostgreSQL major version number + * @example 16 + */ + version?: string; + /** + * @description Human-readable version name + * @example PostgreSQL 16 + */ + name?: string; + /** @description Whether this is the default version (recommended) */ + default?: boolean; + /** @description Whether this version is deprecated (approaching EOL) */ + deprecated?: boolean; + }[]; }; }; - /** @description Project, database, or restore not found */ - 404: { + }; + }; + listFunctionRuntimes: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Supported function runtimes */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["FunctionRuntimesResponse"]; }; }; - /** @description Backups are temporarily unavailable */ - 503: { + }; + }; + listFunctionRegions: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Available function deployment regions */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["FunctionRegion"][]; }; }; }; }; - resetDatabasePassword: { + getVariable: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; + /** @description Variable name */ + name: components["parameters"]["VariableName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Password reset successful */ + /** @description Successful response */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - message?: string; - /** - * @description Volcano-managed per-database client login (also the pgproxy routing username) - * @example volcano_client_11111111-1111-1111-1111-111111111111 - */ - role_name?: string; - /** @description New Volcano-managed client password. Always starts with `vpg_`. */ - new_password?: string; - /** @description Updated pgproxy connection string using Volcano-managed credentials. */ - connection_string?: string; - }; - }; - }; - /** @description Database is not active */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["Variable"]; }; }; - /** @description Database not found */ + /** @description Variable not found */ 404: { headers: { [name: string]: unknown; @@ -16317,78 +17796,37 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description A restore is running on the database. A restore replaces the - * credentials as it finishes, so wait for it and rotate afterwards. - */ - 409: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** - * @description Volcano could not check whether a restore is running, and will not - * rotate a credential a restore might be about to replace. Retry. - */ - 503: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; }; }; - updateDatabaseType: { + updateVariable: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; + /** @description Variable name */ + name: components["parameters"]["VariableName"]; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["UpdateDatabaseTypeRequest"]; + "application/json": components["schemas"]["UpdateVariableRequest"]; }; }; responses: { - /** @description Database type updated */ + /** @description Variable updated */ 200: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Database"]; - }; - }; - /** @description Invalid database type */ - 400: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Database not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; + content: { + "application/json": components["schemas"]["Variable"]; + }; }; - /** - * @description The database is not active — being provisioned, deleted, or - * restored. Compute can only be changed while it is active. - */ - 409: { + /** @description Variable not found */ + 404: { headers: { [name: string]: unknown; }; @@ -16396,10 +17834,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description Volcano could not check whether a restore is running, and will not - * reconfigure compute a restore might be moving. Retry. - */ + /** @description Private variable membership writes are disabled during rollout */ 503: { headers: { [name: string]: unknown; @@ -16410,47 +17845,58 @@ export interface operations { }; }; }; - getDatabaseStats: { + deleteVariable: { parameters: { - query?: { - /** @description Start time in RFC3339 format (e.g., "2024-01-01T00:00:00Z"). Defaults to 24 hours ago. */ - from?: string; - /** @description End time in RFC3339 format (e.g., "2024-01-02T00:00:00Z"). Defaults to now. */ - to?: string; - /** @description Level of detail for metrics aggregation */ - granularity?: "hourly" | "daily" | "monthly"; - }; + query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; + /** @description Variable name */ + name: components["parameters"]["VariableName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Successful response */ - 200: { + /** @description Variable deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Variable not found */ + 404: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DatabaseStats"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Invalid parameters */ - 400: { + }; + }; + authGetPasswordPolicy: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Effective password policy */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["AuthPasswordPolicy"]; }; }; - /** @description Database not found */ - 404: { + /** @description Invalid, missing, or revoked anon key */ + 401: { headers: { [name: string]: unknown; }; @@ -16458,8 +17904,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Database metrics not available or requires upgraded plan */ - 503: { + /** @description Project or auth configuration not found */ + 404: { headers: { [name: string]: unknown; }; @@ -16469,57 +17915,77 @@ export interface operations { }; }; }; - queryDatabasePing: { + authSignup: { parameters: { query?: never; header?: never; - path: { - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - }; + path?: never; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": { + /** Format: email */ + email: string; + /** + * @description Password validated after NFC normalization against the + * policy returned by GET /auth/password-policy. + */ + password: string; + user_metadata?: { + [key: string]: unknown; + }; + }; + }; + }; responses: { - /** @description Database is reachable */ - 200: { + /** + * @description Signup acknowledged (session-less). Returned identically for a new + * account and for an already-registered email (anti-enumeration). + */ + 201: { headers: { [name: string]: unknown; }; content: { - /** - * @example { - * "data": [ - * { - * "?column?": 1 - * } - * ], - * "count": 1 - * } - */ - "application/json": components["schemas"]["DatabaseQueryResult"]; + "application/json": components["schemas"]["AuthSignupResponse"]; }; }; - /** @description Not authenticated */ - 401: { + /** @description Invalid input (bad email/password format) */ + 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; + content?: never; + }; + /** @description Unauthorized - Invalid, tampered, revoked, or wrong-project anon key */ + 401: { + headers: { + [name: string]: unknown; }; + content?: never; }; - /** @description Access denied */ + /** + * @description Forbidden - Signups disabled, anon key lacks signup permission, or the + * email domain is not in `allowed_email_domains`. The internal + * `anonymous.volcano.internal` domain is reserved for anonymous + * accounts and is refused whatever the project allows. + */ 403: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; + content?: never; + }; + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown; }; + content?: never; }; - /** @description Database not found */ - 404: { + /** @description Compromised-password screening is temporarily unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -16527,138 +17993,101 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - 429: components["responses"]["DatabaseQueryCapExceeded"]; }; }; - queryDatabaseSelect: { + authSignin: { parameters: { query?: never; header?: never; - path: { - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - }; + path?: never; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["DatabaseSelectRequest"]; + "application/json": { + email: string; + password: string; + /** @enum {string} */ + session_mode?: "cookie"; + }; }; }; responses: { - /** @description Query successful */ + /** @description Signin successful */ 200: { headers: { [name: string]: unknown; }; content: { - /** - * @example { - * "data": [ - * { - * "id": "uuid-123", - * "title": "My Post", - * "content": "Post content", - * "status": "published", - * "views": 150, - * "created_at": "2026-01-13T10:00:00Z" - * } - * ], - * "count": 1 - * } - */ - "application/json": components["schemas"]["DatabaseQueryResult"]; + "application/json": components["schemas"]["AuthTokenResponse"]; }; }; - /** @description Invalid query */ + /** @description Invalid input (missing email/password) */ 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Not authenticated */ + /** + * @description Unauthorized - Invalid credentials, invalid/tampered/revoked anon key, + * or account banned/deleted + */ 401: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Access denied */ + /** + * @description Forbidden - Anon key lacks signin permission, or the email domain is + * not in `allowed_email_domains` while `allowed_email_domains_mode` is + * `signup_and_signin`. The domain is taken from the account's canonical + * email (its primary identity), which is not necessarily the address in + * the request. + */ 403: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Database not found */ - 404: { + /** @description Rate limit exceeded */ + 429: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - 429: components["responses"]["DatabaseQueryCapExceeded"]; }; }; - queryDatabaseInsert: { + authRefresh: { parameters: { query?: never; header?: never; - path: { - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - }; + path?: never; cookie?: never; }; - requestBody: { + requestBody?: { content: { - "application/json": components["schemas"]["DatabaseInsertRequest"]; - }; - }; - responses: { - /** @description Insert successful */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - /** - * @example { - * "data": [ - * { - * "id": "uuid-123", - * "title": "My New Post", - * "content": "This is the content", - * "status": "draft", - * "user_id": "user-uuid", - * "created_at": "2026-01-13T10:00:00Z" - * } - * ], - * "count": 1 - * } - */ - "application/json": components["schemas"]["DatabaseQueryResult"]; + "application/json": { + refresh_token?: string; + /** @enum {string} */ + session_mode?: "cookie"; }; }; - /** @description Invalid request */ - 400: { + }; + responses: { + /** @description Token refreshed */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["AuthTokenResponse"]; }; }; - /** @description Not authenticated */ + /** @description Invalid or expired refresh token */ 401: { headers: { [name: string]: unknown; @@ -16667,7 +18096,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Access denied */ + /** + * @description The account's email domain is not in `allowed_email_domains` while + * `allowed_email_domains_mode` is `signup_and_signin`, so the session + * cannot be extended + */ 403: { headers: { [name: string]: unknown; @@ -16676,8 +18109,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Database not found */ - 404: { + /** @description Rate limit exceeded */ + 429: { headers: { [name: string]: unknown; }; @@ -16685,66 +18118,63 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - 429: components["responses"]["DatabaseQueryCapExceeded"]; }; }; - queryDatabaseUpdate: { + authLogout: { parameters: { query?: never; header?: never; - path: { - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - }; + path?: never; cookie?: never; }; - requestBody: { + requestBody?: { content: { - "application/json": components["schemas"]["DatabaseUpdateRequest"]; + "application/json": { + refresh_token?: string; + /** @enum {string} */ + session_mode?: "cookie"; + }; }; }; responses: { - /** @description Update successful */ - 200: { + /** @description Logged out successfully */ + 204: { headers: { [name: string]: unknown; }; - content: { - /** - * @example { - * "data": [ - * { - * "id": "post-uuid", - * "title": "Updated Title", - * "status": "published", - * "updated_at": "2026-01-13T10:05:00Z" - * } - * ], - * "count": 1 - * } - */ - "application/json": components["schemas"]["DatabaseQueryResult"]; - }; + content?: never; }; - /** @description Invalid request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + }; + }; + authForgotPassword: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** Format: email */ + email: string; }; }; - /** @description Not authenticated */ - 401: { + }; + responses: { + /** @description Generic success message (doesn't reveal if email exists) */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": { + /** @example If the email exists, a password reset link has been sent */ + message?: string; + }; }; }; - /** @description Access denied */ + /** @description Password reset is disabled for this project */ 403: { headers: { [name: string]: unknown; @@ -16753,8 +18183,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Database not found */ - 404: { + /** @description Rate limit exceeded (10 requests per hour per IP) */ + 429: { headers: { [name: string]: unknown; }; @@ -16762,74 +18192,56 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - 429: components["responses"]["DatabaseQueryCapExceeded"]; }; }; - queryDatabaseDelete: { + authResetPassword: { parameters: { query?: never; header?: never; - path: { - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - }; + path?: never; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["DatabaseDeleteRequest"]; + "application/json": { + /** @description Recovery token from forgot-password */ + token: string; + /** + * @description Password validated after NFC normalization against the + * policy returned by GET /auth/password-policy. + */ + new_password: string; + }; }; }; responses: { - /** @description Delete successful */ + /** @description Password reset successful */ 200: { headers: { [name: string]: unknown; }; content: { - /** - * @example { - * "data": [ - * { - * "id": "post-uuid", - * "title": "Deleted Post" - * } - * ], - * "count": 1 - * } - */ - "application/json": components["schemas"]["DatabaseQueryResult"]; + "application/json": { + message?: string; + }; }; }; - /** @description Invalid request or missing filters */ + /** @description Password doesn't meet requirements */ 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Not authenticated */ + /** @description Invalid or expired token */ 401: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Access denied */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Database not found */ - 404: { + /** @description Compromised-password screening is temporarily unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -16837,126 +18249,81 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - 429: components["responses"]["DatabaseQueryCapExceeded"]; }; }; - queryDatabaseBranchPing: { + authConfirmEmail: { parameters: { query?: never; header?: never; - path: { - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - branchName: components["parameters"]["BranchName"]; - }; + path?: never; cookie?: never; }; - requestBody?: never; - responses: { - /** @description Database is reachable */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - /** - * @example { - * "data": [ - * { - * "?column?": 1 - * } - * ], - * "count": 1 - * } - */ - "application/json": components["schemas"]["DatabaseQueryResult"]; + requestBody: { + content: { + "application/json": { + /** @description Confirmation token from email */ + token: string; }; }; - /** @description Not authenticated */ - 401: { + }; + responses: { + /** @description Email confirmed or already confirmed */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": { + /** @enum {string} */ + message?: "Email confirmed successfully" | "Email already confirmed"; + }; }; }; - /** @description Access denied */ - 403: { + /** @description Missing confirmation token in request body */ + 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Database or branch not found */ - 404: { + /** @description Invalid or expired token */ + 401: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - 429: components["responses"]["DatabaseQueryCapExceeded"]; - 503: components["responses"]["DatabaseBranchQueryUnavailable"]; }; }; - queryDatabaseBranchSelect: { + authResendConfirmation: { parameters: { query?: never; header?: never; - path: { - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - branchName: components["parameters"]["BranchName"]; - }; + path?: never; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["DatabaseSelectRequest"]; + "application/json": { + /** Format: email */ + email: string; + }; }; }; responses: { - /** @description Query successful */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - /** - * @example { - * "data": [ - * { - * "id": "uuid-123", - * "title": "My Post", - * "content": "Post content", - * "status": "published", - * "views": 150, - * "created_at": "2026-01-13T10:00:00Z" - * } - * ], - * "count": 1 - * } - */ - "application/json": components["schemas"]["DatabaseQueryResult"]; - }; - }; - /** @description Invalid query */ - 400: { + /** @description Generic success message */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": { + message?: string; + }; }; }; - /** @description Not authenticated */ - 401: { + /** @description Rate limit exceeded */ + 429: { headers: { [name: string]: unknown; }; @@ -16964,99 +18331,109 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Access denied */ - 403: { + }; + }; + authSignupAnonymous: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Optional user metadata */ + requestBody?: { + content: { + "application/json": { + /** + * @description Custom user metadata (e.g., display_name, avatar_url) + * @example { + * "display_name": "Alice", + * "avatar_url": "https://example.com/alice.jpg" + * } + */ + user_metadata?: { + [key: string]: unknown; + }; + }; + }; + }; + responses: { + /** @description Anonymous user created */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["AuthTokenResponse"]; }; }; - /** @description Database or branch not found */ - 404: { + /** @description Anonymous signins disabled */ + 403: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - 429: components["responses"]["DatabaseQueryCapExceeded"]; - 503: components["responses"]["DatabaseBranchQueryUnavailable"]; }; }; - queryDatabaseBranchInsert: { + authConvertAnonymous: { parameters: { query?: never; header?: never; - path: { - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - branchName: components["parameters"]["BranchName"]; - }; + path?: never; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["DatabaseInsertRequest"]; + "application/json": { + /** Format: email */ + email: string; + /** + * @description Password validated after NFC normalization against the + * policy returned by GET /auth/password-policy. + */ + password: string; + user_metadata?: { + [key: string]: unknown; + }; + }; }; }; responses: { - /** @description Insert successful */ + /** @description User converted successfully */ 200: { headers: { [name: string]: unknown; }; content: { - /** - * @example { - * "data": [ - * { - * "id": "uuid-123", - * "title": "My New Post", - * "content": "This is the content", - * "status": "draft", - * "user_id": "user-uuid", - * "created_at": "2026-01-13T10:00:00Z" - * } - * ], - * "count": 1 - * } - */ - "application/json": components["schemas"]["DatabaseQueryResult"]; + "application/json": { + user?: components["schemas"]["AuthUser"]; + }; }; }; - /** @description Invalid request */ + /** @description Not an anonymous user */ 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Not authenticated */ - 401: { + /** @description The chosen email domain is not in `allowed_email_domains` */ + 403: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Access denied */ - 403: { + /** @description Email already in use */ + 409: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Database or branch not found */ - 404: { + /** @description Compromised-password screening is temporarily unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -17064,51 +18441,37 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - 429: components["responses"]["DatabaseQueryCapExceeded"]; - 503: components["responses"]["DatabaseBranchQueryUnavailable"]; }; }; - queryDatabaseBranchUpdate: { + authRequestEmailChange: { parameters: { query?: never; header?: never; - path: { - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - branchName: components["parameters"]["BranchName"]; - }; + path?: never; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["DatabaseUpdateRequest"]; + "application/json": { + /** Format: email */ + new_email: string; + }; }; }; responses: { - /** @description Update successful */ + /** @description Confirmation email sent */ 200: { headers: { [name: string]: unknown; }; content: { - /** - * @example { - * "data": [ - * { - * "id": "post-uuid", - * "title": "Updated Title", - * "status": "published", - * "updated_at": "2026-01-13T10:05:00Z" - * } - * ], - * "count": 1 - * } - */ - "application/json": components["schemas"]["DatabaseQueryResult"]; + "application/json": { + message?: string; + new_email?: string; + }; }; }; - /** @description Invalid request */ + /** @description Invalid email format or same as current email */ 400: { headers: { [name: string]: unknown; @@ -17126,7 +18489,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Access denied */ + /** @description The requested email domain is not in `allowed_email_domains` */ 403: { headers: { [name: string]: unknown; @@ -17135,8 +18498,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Database or branch not found */ - 404: { + /** @description Email already in use */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Rate limit exceeded (10 requests per hour per IP) */ + 429: { headers: { [name: string]: unknown; }; @@ -17144,49 +18516,36 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - 429: components["responses"]["DatabaseQueryCapExceeded"]; - 503: components["responses"]["DatabaseBranchQueryUnavailable"]; }; }; - queryDatabaseBranchDelete: { + authConfirmEmailChange: { parameters: { query?: never; header?: never; - path: { - /** @description Database name (unique within project, lowercase letters, numbers, and underscores only) */ - databaseName: components["parameters"]["DatabaseName"]; - /** @description Branch name (unique within the parent database, lowercase letters, numbers, and underscores only) */ - branchName: components["parameters"]["BranchName"]; - }; + path?: never; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["DatabaseDeleteRequest"]; + "application/json": { + email_change_token: string; + }; }; }; responses: { - /** @description Delete successful */ + /** @description Email changed successfully */ 200: { headers: { [name: string]: unknown; }; content: { - /** - * @example { - * "data": [ - * { - * "id": "post-uuid", - * "title": "Deleted Post" - * } - * ], - * "count": 1 - * } - */ - "application/json": components["schemas"]["DatabaseQueryResult"]; + "application/json": { + message?: string; + user?: components["schemas"]["AuthUser"]; + }; }; }; - /** @description Invalid request or missing filters */ + /** @description Invalid or expired token, or no pending email change */ 400: { headers: { [name: string]: unknown; @@ -17204,7 +18563,11 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Access denied */ + /** + * @description The pending email domain is no longer in `allowed_email_domains`. + * Re-checked here because the allowlist can narrow between the request + * and the confirmation. + */ 403: { headers: { [name: string]: unknown; @@ -17213,51 +18576,18 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Database or branch not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - 429: components["responses"]["DatabaseQueryCapExceeded"]; - 503: components["responses"]["DatabaseBranchQueryUnavailable"]; - }; - }; - listDatabaseRegions: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description List of platform-supported regions */ - 200: { + /** @description Email is now in use by another user */ + 409: { headers: { [name: string]: unknown; }; - content: { - "application/json": { - /** - * @description Region identifier for API usage - * @example aws-us-east-1 - */ - id?: string; - /** - * @description Human-readable region location - * @example US East (N. Virginia) - */ - name?: string; - }[]; - }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - listPostgresVersions: { + authCancelEmailChange: { parameters: { query?: never; header?: never; @@ -17266,97 +18596,109 @@ export interface operations { }; requestBody?: never; responses: { - /** @description List of available PostgreSQL versions */ + /** @description Email change cancelled */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { - /** - * @description PostgreSQL major version number - * @example 16 - */ - version?: string; - /** - * @description Human-readable version name - * @example PostgreSQL 16 - */ - name?: string; - /** @description Whether this is the default version (recommended) */ - default?: boolean; - /** @description Whether this version is deprecated (approaching EOL) */ - deprecated?: boolean; - }[]; + message?: string; + }; }; }; - }; - }; - listFunctionRuntimes: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Supported function runtimes */ - 200: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionRuntimesResponse"]; + "application/json": components["schemas"]["Error"]; }; }; }; }; - listFunctionRegions: { + authGetMySessions: { parameters: { - query?: never; + query?: { + /** @description Page number (1-indexed) */ + page?: number; + /** @description Number of sessions per page (max 100) */ + limit?: number; + /** + * @description Sort key. `last_activity` (default) orders by most recent activity and + * supports offset pagination only. `created_at` orders by session start + * and supports both offset and cursor pagination. + */ + sort?: "last_activity" | "created_at"; + /** + * @description Filter by whether the session can still be refreshed. Omit for every + * stored session, including expired ones. `expired` is not supported + * with cursor pagination. + */ + status?: "active" | "expired"; + /** + * @description Opaque keyset cursor from a previous response's `next_cursor`. Requires + * `sort=created_at`; mutually exclusive with `page` and `ending_before`. + */ + cursor?: string; + /** + * @description Opaque keyset cursor from a previous response's `prev_cursor`, paging + * backward. Requires `sort=created_at`; mutually exclusive with `page` + * and `cursor`. + */ + ending_before?: string; + /** + * @description Bounded number of rows to skip past the cursor anchor (the hybrid + * jump, maximum 100000). Ignored unless `cursor` or `ending_before` is + * supplied. + */ + offset?: number; + }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { - /** @description Available function deployment regions */ + /** @description Paginated list of user sessions */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["FunctionRegion"][]; + "application/json": { + sessions?: components["schemas"]["AuthSession"][]; + /** @description Total number of sessions */ + total?: number; + /** @description Current page number */ + page?: number; + /** @description Number of sessions per page */ + limit?: number; + /** @description Total number of pages */ + total_pages?: number; + /** @description Sessions for this page (cursor pagination only) */ + data?: components["schemas"]["AuthSession"][]; + /** @description Whether a further page exists (cursor pagination only) */ + has_more?: boolean; + /** @description Opaque cursor for the next page (cursor pagination only) */ + next_cursor?: string; + /** @description Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. */ + prev_cursor?: string; + }; }; }; - }; - }; - getVariable: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Variable name */ - name: components["parameters"]["VariableName"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Successful response */ - 200: { + /** @description Invalid or conflicting pagination parameters */ + 400: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Variable"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Variable not found */ - 404: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -17366,44 +18708,24 @@ export interface operations { }; }; }; - updateVariable: { + authDeleteAllMySessions: { parameters: { query?: never; header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Variable name */ - name: components["parameters"]["VariableName"]; - }; + path?: never; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateVariableRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Variable updated */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Variable"]; - }; - }; - /** @description Variable not found */ - 404: { + /** @description All other sessions deleted */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Private variable membership writes are disabled during rollout */ - 503: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -17413,28 +18735,35 @@ export interface operations { }; }; }; - deleteVariable: { + authDeleteMySession: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Variable name */ - name: components["parameters"]["VariableName"]; + /** @description The session ID to delete */ + sessionId: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Variable deleted */ + /** @description Session deleted */ 204: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Variable not found */ + /** @description Not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Session not found */ 404: { headers: { [name: string]: unknown; @@ -17445,7 +18774,7 @@ export interface operations { }; }; }; - authGetPasswordPolicy: { + authGetUser: { parameters: { query?: never; header?: never; @@ -17454,16 +18783,18 @@ export interface operations { }; requestBody?: never; responses: { - /** @description Effective password policy */ + /** @description User profile */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthPasswordPolicy"]; + "application/json": { + user?: components["schemas"]["AuthUser"]; + }; }; }; - /** @description Invalid, missing, or revoked anon key */ + /** @description Not authenticated - access token missing or invalid */ 401: { headers: { [name: string]: unknown; @@ -17472,34 +18803,28 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project or auth configuration not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; }; }; - authSignup: { + authUpdateUser: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody: { + requestBody?: { content: { "application/json": { - /** Format: email */ - email: string; /** * @description Password validated after NFC normalization against the * policy returned by GET /auth/password-policy. */ - password: string; + password?: string; + /** + * @description Metadata keys to merge into the current user metadata. + * Omitted keys remain unchanged; set a key to null to remove it. + * Merging is shallow; nested objects replace the stored value for that top-level key. + */ user_metadata?: { [key: string]: unknown; }; @@ -17507,50 +18832,34 @@ export interface operations { }; }; responses: { - /** - * @description Signup acknowledged (session-less). Returned identically for a new - * account and for an already-registered email (anti-enumeration). - */ - 201: { + /** @description Profile updated */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthSignupResponse"]; + "application/json": { + user?: components["schemas"]["AuthUser"]; + }; }; }; - /** @description Invalid input (bad email/password format) */ + /** @description Bad request - invalid password or metadata format */ 400: { headers: { [name: string]: unknown; }; - content?: never; - }; - /** @description Unauthorized - Invalid, tampered, revoked, or wrong-project anon key */ - 401: { - headers: { - [name: string]: unknown; + content: { + "application/json": components["schemas"]["Error"]; }; - content?: never; }; - /** - * @description Forbidden - Signups disabled, anon key lacks signup permission, or the - * email domain is not in `allowed_email_domains`. The internal - * `anonymous.volcano.internal` domain is reserved for anonymous - * accounts and is refused whatever the project allows. - */ - 403: { + /** @description Not authenticated - access token missing or invalid */ + 401: { headers: { [name: string]: unknown; }; - content?: never; - }; - /** @description Rate limit exceeded */ - 429: { - headers: { - [name: string]: unknown; + content: { + "application/json": components["schemas"]["Error"]; }; - content?: never; }; /** @description Compromised-password screening is temporarily unavailable */ 503: { @@ -17563,100 +18872,56 @@ export interface operations { }; }; }; - authSignin: { + authListIdentities: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody: { - content: { - "application/json": { - email: string; - password: string; - /** @enum {string} */ - session_mode?: "cookie"; - }; - }; - }; + requestBody?: never; responses: { - /** @description Signin successful */ + /** @description List of identities */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthTokenResponse"]; - }; - }; - /** @description Invalid input (missing email/password) */ - 400: { - headers: { - [name: string]: unknown; + "application/json": components["schemas"]["AuthIdentitiesResponse"]; }; - content?: never; }; - /** - * @description Unauthorized - Invalid credentials, invalid/tampered/revoked anon key, - * or account banned/deleted - */ + /** @description Not authenticated */ 401: { headers: { [name: string]: unknown; }; - content?: never; - }; - /** - * @description Forbidden - Anon key lacks signin permission, or the email domain is - * not in `allowed_email_domains` while `allowed_email_domains_mode` is - * `signup_and_signin`. The domain is taken from the account's canonical - * email (its primary identity), which is not necessarily the address in - * the request. - */ - 403: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Rate limit exceeded */ - 429: { - headers: { - [name: string]: unknown; + content: { + "application/json": components["schemas"]["Error"]; }; - content?: never; }; }; }; - authRefresh: { + authUnlinkIdentity: { parameters: { query?: never; header?: never; - path?: never; - cookie?: never; - }; - requestBody?: { - content: { - "application/json": { - refresh_token?: string; - /** @enum {string} */ - session_mode?: "cookie"; - }; + path: { + /** @description The identity ID to unlink */ + identityId: string; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Token refreshed */ - 200: { + /** @description Identity unlinked */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["AuthTokenResponse"]; - }; + content?: never; }; - /** @description Invalid or expired refresh token */ - 401: { + /** @description Identity cannot be unlinked (primary, last, or would remove last sign-in method), or the identity id is malformed */ + 400: { headers: { [name: string]: unknown; }; @@ -17664,12 +18929,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** - * @description The account's email domain is not in `allowed_email_domains` while - * `allowed_email_domains_mode` is `signup_and_signin`, so the session - * cannot be extended - */ - 403: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; @@ -17677,8 +18938,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Rate limit exceeded */ - 429: { + /** @description Identity not found */ + 404: { headers: { [name: string]: unknown; }; @@ -17688,61 +18949,75 @@ export interface operations { }; }; }; - authLogout: { + authListMethods: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody?: { - content: { - "application/json": { - refresh_token?: string; - /** @enum {string} */ - session_mode?: "cookie"; + requestBody?: never; + responses: { + /** @description List of sign-in methods */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["AuthMethodsResponse"]; }; }; - }; - responses: { - /** @description Logged out successfully */ - 204: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - authForgotPassword: { + authPromoteMethod: { parameters: { query?: never; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - /** Format: email */ - email: string; - }; + path: { + /** @description The method ID to promote */ + methodId: string; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Generic success message (doesn't reveal if email exists) */ + /** @description The promoted method */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - /** @example If the email exists, a password reset link has been sent */ - message?: string; - }; + "application/json": components["schemas"]["AuthMethodSummary"]; }; }; - /** @description Password reset is disabled for this project */ + /** @description This method cannot be set as primary (password stub, converted anonymous method, or unverified email), or the method id is malformed */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The promoted identity's email domain is not in the project's allowed_email_domains */ 403: { headers: { [name: string]: unknown; @@ -17751,8 +19026,8 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Rate limit exceeded (10 requests per hour per IP) */ - 429: { + /** @description Method not found */ + 404: { headers: { [name: string]: unknown; }; @@ -17762,54 +19037,68 @@ export interface operations { }; }; }; - authResetPassword: { + getAuthInsights: { parameters: { - query?: never; + query?: { + /** @description Inclusive UTC start date. Defaults to 29 days before `to`. */ + from?: string; + /** @description Inclusive UTC end date. Defaults to today. */ + to?: string; + /** @description Chart bucket size. Defaults to `day`. */ + interval?: components["schemas"]["AuthInsightsInterval"]; + }; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - /** @description Recovery token from forgot-password */ - token: string; - /** - * @description Password validated after NFC normalization against the - * policy returned by GET /auth/password-policy. - */ - new_password: string; - }; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Password reset successful */ + /** @description Auth insights retrieved */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - message?: string; - }; + /** + * @example { + * "project_id": "4f165080-a931-4e03-b3bd-41c45c3f0058", + * "observed_at": "2026-07-20T18:00:00Z", + * "window": { + * "from": "2026-06-21", + * "to": "2026-07-20", + * "interval": "day" + * }, + * "summary": { + * "total_users": 1234, + * "active_users_30d": 418 + * }, + * "series": [ + * { + * "bucket_start": "2026-07-20", + * "signups": 12, + * "signins": 97, + * "is_partial": true + * } + * ] + * } + */ + "application/json": components["schemas"]["AuthInsightsResponse"]; }; }; - /** @description Password doesn't meet requirements */ + /** @description Invalid date range or interval */ 400: { headers: { [name: string]: unknown; }; - content?: never; - }; - /** @description Invalid or expired token */ - 401: { - headers: { - [name: string]: unknown; + content: { + "application/json": components["schemas"]["Error"]; }; - content?: never; }; - /** @description Compromised-password screening is temporarily unavailable */ - 503: { + /** @description Unauthorized - invalid or missing token */ + 401: { headers: { [name: string]: unknown; }; @@ -17817,81 +19106,99 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - authConfirmEmail: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - /** @description Confirmation token from email */ - token: string; - }; - }; - }; - responses: { - /** @description Email confirmed or already confirmed */ - 200: { + /** @description Access denied */ + 403: { headers: { [name: string]: unknown; }; content: { - "application/json": { - /** @enum {string} */ - message?: "Email confirmed successfully" | "Email already confirmed"; - }; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Missing confirmation token in request body */ - 400: { + /** @description Project not found */ + 404: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Invalid or expired token */ - 401: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - authResendConfirmation: { + listAuthUsers: { parameters: { - query?: never; + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; + /** @description Filter by effective status. `banned` returns only currently-banned users; an expired temporary ban lists as `active`. */ + status?: "active" | "banned"; + }; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - /** Format: email */ - email: string; - }; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Generic success message */ + /** @description Successful response */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - message?: string; - }; + "application/json": components["schemas"]["PaginatedAuthUsers"]; }; }; - /** @description Rate limit exceeded */ - 429: { + /** @description Invalid status or pagination parameters */ + 400: { headers: { [name: string]: unknown; }; @@ -17901,145 +19208,127 @@ export interface operations { }; }; }; - authSignupAnonymous: { + getAuthUser: { parameters: { query?: never; header?: never; - path?: never; - cookie?: never; - }; - /** @description Optional user metadata */ - requestBody?: { - content: { - "application/json": { - /** - * @description Custom user metadata (e.g., display_name, avatar_url) - * @example { - * "display_name": "Alice", - * "avatar_url": "https://example.com/alice.jpg" - * } - */ - user_metadata?: { - [key: string]: unknown; - }; - }; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + userId: string; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Anonymous user created */ - 201: { + /** @description Auth user details */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthTokenResponse"]; - }; - }; - /** @description Anonymous signins disabled */ - 403: { - headers: { - [name: string]: unknown; + "application/json": components["schemas"]["AuthUser"]; }; - content?: never; }; }; }; - authConvertAnonymous: { + deleteAuthUser: { parameters: { query?: never; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - /** Format: email */ - email: string; - /** - * @description Password validated after NFC normalization against the - * policy returned by GET /auth/password-policy. - */ - password: string; - user_metadata?: { - [key: string]: unknown; - }; - }; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + userId: string; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description User converted successfully */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - user?: components["schemas"]["AuthUser"]; - }; - }; - }; - /** @description Not an anonymous user */ - 400: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description The chosen email domain is not in `allowed_email_domains` */ - 403: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Email already in use */ - 409: { + /** @description User deleted */ + 204: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Compromised-password screening is temporarily unavailable */ - 503: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; }; }; - authRequestEmailChange: { + listUserSessions: { parameters: { - query?: never; + query?: { + /** @description Page number (1-indexed) */ + page?: number; + /** @description Number of sessions per page (max 100) */ + limit?: number; + /** + * @description Sort key. `last_activity` (default) orders by most recent activity and + * supports offset pagination only. `created_at` orders by session start + * and supports both offset and cursor pagination. + */ + sort?: "last_activity" | "created_at"; + /** + * @description Filter by whether the session can still be refreshed. Omit for every + * stored session, including expired ones. `expired` is not supported + * with cursor pagination. + */ + status?: "active" | "expired"; + /** + * @description Opaque keyset cursor from a previous response's `next_cursor`. Requires + * `sort=created_at`; mutually exclusive with `page` and `ending_before`. + */ + cursor?: string; + /** + * @description Opaque keyset cursor from a previous response's `prev_cursor`, paging + * backward. Requires `sort=created_at`; mutually exclusive with `page` + * and `cursor`. + */ + ending_before?: string; + /** + * @description Bounded number of rows to skip past the cursor anchor (the hybrid + * jump, maximum 100000). Ignored unless `cursor` or `ending_before` is + * supplied. + */ + offset?: number; + }; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - /** Format: email */ - new_email: string; - }; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + userId: string; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Confirmation email sent */ + /** @description Paginated list of user sessions */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { - message?: string; - new_email?: string; + sessions?: components["schemas"]["AuthSession"][]; + /** @description Total number of sessions */ + total?: number; + /** @description Current page number */ + page?: number; + /** @description Number of sessions per page */ + limit?: number; + /** @description Total number of pages */ + total_pages?: number; + /** @description Sessions for this page (cursor pagination only) */ + data?: components["schemas"]["AuthSession"][]; + /** @description Whether a further page exists (cursor pagination only) */ + has_more?: boolean; + /** @description Opaque cursor for the next page (cursor pagination only) */ + next_cursor?: string; + /** @description Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. */ + prev_cursor?: string; }; }; }; - /** @description Invalid email format or same as current email */ + /** @description Invalid or conflicting pagination parameters */ 400: { headers: { [name: string]: unknown; @@ -18048,73 +19337,109 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Not authenticated */ - 401: { + /** @description User not found */ + 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description The requested email domain is not in `allowed_email_domains` */ - 403: { + }; + }; + deleteAllUserSessions: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + userId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description All sessions deleted */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Email already in use */ - 409: { + /** @description User not found */ + 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Rate limit exceeded (10 requests per hour per IP) */ - 429: { + }; + }; + deleteUserSession: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + userId: string; + sessionId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Session deleted */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; + content?: never; + }; + /** @description Session or user not found */ + 404: { + headers: { + [name: string]: unknown; }; + content?: never; }; }; }; - authConfirmEmailChange: { + banAuthUser: { parameters: { query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + userId: string; + }; cookie?: never; }; - requestBody: { + requestBody?: { content: { "application/json": { - email_change_token: string; + /** + * Format: date-time + * @description When the ban expires (omit for permanent ban) + * @example 2026-12-31T23:59:59Z + */ + banned_until?: string; }; }; }; responses: { - /** @description Email changed successfully */ + /** @description User banned successfully */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - message?: string; - user?: components["schemas"]["AuthUser"]; - }; + "application/json": components["schemas"]["BanUserResponse"]; }; }; - /** @description Invalid or expired token, or no pending email change */ - 400: { + /** @description User not found */ + 404: { headers: { [name: string]: unknown; }; @@ -18122,30 +19447,32 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Not authenticated */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + unbanAuthUser: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + userId: string; }; - /** - * @description The pending email domain is no longer in `allowed_email_domains`. - * Re-checked here because the allowlist can narrow between the request - * and the confirmation. - */ - 403: { + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User unbanned successfully */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["UnbanUserResponse"]; }; }; - /** @description Email is now in use by another user */ - 409: { + /** @description User not found */ + 404: { headers: { [name: string]: unknown; }; @@ -18155,108 +19482,57 @@ export interface operations { }; }; }; - authCancelEmailChange: { + listEmailTemplates: { parameters: { query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; cookie?: never; }; requestBody?: never; responses: { - /** @description Email change cancelled */ + /** @description Email templates list */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { - message?: string; + data?: components["schemas"]["EmailTemplate"][]; }; }; }; - /** @description Not authenticated */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; }; }; - authGetMySessions: { + createEmailTemplate: { parameters: { - query?: { - /** @description Page number (1-indexed) */ - page?: number; - /** @description Number of sessions per page (max 100) */ - limit?: number; - /** - * @description Sort key. `last_activity` (default) orders by most recent activity and - * supports offset pagination only. `created_at` orders by session start - * and supports both offset and cursor pagination. - */ - sort?: "last_activity" | "created_at"; - /** - * @description Filter by whether the session can still be refreshed. Omit for every - * stored session, including expired ones. `expired` is not supported - * with cursor pagination. - */ - status?: "active" | "expired"; - /** - * @description Opaque keyset cursor from a previous response's `next_cursor`. Requires - * `sort=created_at`; mutually exclusive with `page` and `ending_before`. - */ - cursor?: string; - /** - * @description Opaque keyset cursor from a previous response's `prev_cursor`, paging - * backward. Requires `sort=created_at`; mutually exclusive with `page` - * and `cursor`. - */ - ending_before?: string; - /** - * @description Bounded number of rows to skip past the cursor anchor (the hybrid - * jump, maximum 100000). Ignored unless `cursor` or `ending_before` is - * supplied. - */ - offset?: number; - }; + query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["CreateEmailTemplateRequest"]; + }; + }; responses: { - /** @description Paginated list of user sessions */ - 200: { + /** @description Template created */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": { - sessions?: components["schemas"]["AuthSession"][]; - /** @description Total number of sessions */ - total?: number; - /** @description Current page number */ - page?: number; - /** @description Number of sessions per page */ - limit?: number; - /** @description Total number of pages */ - total_pages?: number; - /** @description Sessions for this page (cursor pagination only) */ - data?: components["schemas"]["AuthSession"][]; - /** @description Whether a further page exists (cursor pagination only) */ - has_more?: boolean; - /** @description Opaque cursor for the next page (cursor pagination only) */ - next_cursor?: string; - /** @description Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. */ - prev_cursor?: string; - }; + "application/json": components["schemas"]["EmailTemplate"]; }; }; - /** @description Invalid or conflicting pagination parameters */ + /** @description Invalid template type */ 400: { headers: { [name: string]: unknown; @@ -18265,8 +19541,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Not authenticated */ - 401: { + /** @description Custom email templates require the SUPERAGENT plan */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description The project already has a template of this type */ + 409: { headers: { [name: string]: unknown; }; @@ -18276,54 +19561,65 @@ export interface operations { }; }; }; - authDeleteAllMySessions: { + getEmailTemplate: { parameters: { query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + type: "welcome" | "confirmation" | "password_reset" | "password_changed"; + }; cookie?: never; }; requestBody?: never; responses: { - /** @description All other sessions deleted */ - 204: { + /** @description Email template */ + 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["EmailTemplate"]; + }; }; - /** @description Not authenticated */ - 401: { + /** @description Template not found */ + 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - authDeleteMySession: { + updateEmailTemplate: { parameters: { query?: never; header?: never; path: { - /** @description The session ID to delete */ - sessionId: string; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + type: "welcome" | "confirmation" | "password_reset" | "password_changed"; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateEmailTemplateRequest"]; + }; + }; responses: { - /** @description Session deleted */ - 204: { + /** @description Template updated */ + 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["EmailTemplate"]; + }; }; - /** @description Not authenticated */ - 401: { + /** @description Custom email templates require the SUPERAGENT plan */ + 403: { headers: { [name: string]: unknown; }; @@ -18331,39 +19627,37 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Session not found */ + /** @description Template not found */ 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - authGetUser: { + deleteEmailTemplate: { parameters: { query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + type: "welcome" | "confirmation" | "password_reset" | "password_changed"; + }; cookie?: never; }; requestBody?: never; responses: { - /** @description User profile */ - 200: { + /** @description Template deleted */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": { - user?: components["schemas"]["AuthUser"]; - }; - }; + content?: never; }; - /** @description Not authenticated - access token missing or invalid */ - 401: { + /** @description Custom email templates require the SUPERAGENT plan */ + 403: { headers: { [name: string]: unknown; }; @@ -18371,95 +19665,123 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Template not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; }; }; - authUpdateUser: { + getDefaultEmailTemplates: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - requestBody?: { - content: { - "application/json": { - /** - * @description Password validated after NFC normalization against the - * policy returned by GET /auth/password-policy. - */ - password?: string; - /** - * @description Metadata keys to merge into the current user metadata. - * Omitted keys remain unchanged; set a key to null to remove it. - * Merging is shallow; nested objects replace the stored value for that top-level key. - */ - user_metadata?: { - [key: string]: unknown; - }; - }; - }; - }; + requestBody?: never; responses: { - /** @description Profile updated */ + /** @description Default templates */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { - user?: components["schemas"]["AuthUser"]; + data?: components["schemas"]["EmailTemplate"][]; }; }; }; - /** @description Bad request - invalid password or metadata format */ - 400: { + }; + }; + getDefaultEmailTemplate: { + parameters: { + query?: never; + header?: never; + path: { + type: "welcome" | "confirmation" | "password_reset" | "password_changed"; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Default template */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["EmailTemplate"]; }; }; - /** @description Not authenticated - access token missing or invalid */ - 401: { + /** @description Template type not found */ + 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Compromised-password screening is temporarily unavailable */ - 503: { + }; + }; + getAuthConfig: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Auth configuration */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["AuthConfig"]; }; }; }; }; - authListIdentities: { + updateAuthConfig: { parameters: { query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; cookie?: never; }; - requestBody?: never; + requestBody?: { + content: { + "application/json": components["schemas"]["UpdateAuthConfigRequest"]; + }; + }; responses: { - /** @description List of identities */ + /** @description Configuration updated */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthIdentitiesResponse"]; + "application/json": components["schemas"]["AuthConfig"]; }; }; - /** @description Not authenticated */ - 401: { + /** + * @description The update would turn on, widen, or otherwise edit the email domain + * allowlist (`allowed_email_domains`, `allowed_email_domains_mode`) + * for a project that is not on the SUPERAGENT plan. A HOBBY project keeps + * whatever allowlist it already has — parked, enforcing nothing until + * it upgrades — and may still remove it, so a downgrade never leaves a + * project locked out of its own signups. + */ + 403: { headers: { [name: string]: unknown; }; @@ -18469,152 +19791,151 @@ export interface operations { }; }; }; - authUnlinkIdentity: { + testEmailConfig: { parameters: { query?: never; header?: never; path: { - /** @description The identity ID to unlink */ - identityId: string; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["TestEmailRequest"]; + }; + }; responses: { - /** @description Identity unlinked */ - 204: { + /** @description Test email sent */ + 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["TestEmailResponse"]; + }; }; - /** @description Identity cannot be unlinked (primary, last, or would remove last sign-in method), or the identity id is malformed */ + /** @description Invalid request or email delivery not configured */ 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Not authenticated */ + /** @description Unauthorized */ 401: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; }; + content?: never; }; - /** @description Identity not found */ + /** @description Project not found */ 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; + content?: never; + }; + /** @description Template render failure or SMTP delivery failed */ + 502: { + headers: { + [name: string]: unknown; }; + content?: never; }; }; }; - authListMethods: { + getAuthHostedPage: { parameters: { query?: never; header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description List of sign-in methods */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["AuthMethodsResponse"]; - }; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + pageType: components["schemas"]["HostedAuthPageType"]; }; - /** @description Not authenticated */ - 401: { + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Hosted page loaded */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["AuthHostedPageResponse"]; }; }; }; }; - authPromoteMethod: { + updateAuthHostedPage: { parameters: { query?: never; header?: never; path: { - /** @description The method ID to promote */ - methodId: string; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + pageType: components["schemas"]["HostedAuthPageType"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateAuthHostedPageRequest"]; + }; + }; responses: { - /** @description The promoted method */ + /** @description Hosted page updated */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthMethodSummary"]; + "application/json": components["schemas"]["AuthHostedPageResponse"]; }; }; - /** @description This method cannot be set as primary (password stub, converted anonymous method, or unverified email), or the method id is malformed */ + /** @description Invalid input or unsafe markup */ 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Not authenticated */ + /** @description Unauthorized */ 401: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description The promoted identity's email domain is not in the project's allowed_email_domains */ + /** @description Forbidden */ 403: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Method not found */ + /** @description Project not found */ 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - getAuthInsights: { + getAuthPageAppearance: { parameters: { - query?: { - /** @description Inclusive UTC start date. Defaults to 29 days before `to`. */ - from?: string; - /** @description Inclusive UTC end date. Defaults to today. */ - to?: string; - /** @description Chart bucket size. Defaults to `day`. */ - interval?: components["schemas"]["AuthInsightsInterval"]; - }; + query?: never; header?: never; path: { /** @description Project ID */ @@ -18624,48 +19945,16 @@ export interface operations { }; requestBody?: never; responses: { - /** @description Auth insights retrieved */ + /** @description Saved appearance and effective plan state */ 200: { headers: { [name: string]: unknown; }; content: { - /** - * @example { - * "project_id": "4f165080-a931-4e03-b3bd-41c45c3f0058", - * "observed_at": "2026-07-20T18:00:00Z", - * "window": { - * "from": "2026-06-21", - * "to": "2026-07-20", - * "interval": "day" - * }, - * "summary": { - * "total_users": 1234, - * "active_users_30d": 418 - * }, - * "series": [ - * { - * "bucket_start": "2026-07-20", - * "signups": 12, - * "signins": 97, - * "is_partial": true - * } - * ] - * } - */ - "application/json": components["schemas"]["AuthInsightsResponse"]; - }; - }; - /** @description Invalid date range or interval */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["AuthPageAppearanceResponse"]; }; }; - /** @description Unauthorized - invalid or missing token */ + /** @description Unauthorized */ 401: { headers: { [name: string]: unknown; @@ -18692,7 +19981,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ + /** @description Appearance could not be read */ 500: { headers: { [name: string]: unknown; @@ -18703,50 +19992,9 @@ export interface operations { }; }; }; - listAuthUsers: { + updateAuthPageTheme: { parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - search?: components["parameters"]["Search"]; - /** @description Filter by effective status. `banned` returns only currently-banned users; an expired temporary ban lists as `active`. */ - status?: "active" | "banned"; - }; + query?: never; header?: never; path: { /** @description Project ID */ @@ -18754,18 +20002,22 @@ export interface operations { }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateAuthPageThemeRequest"]; + }; + }; responses: { - /** @description Successful response */ + /** @description Theme saved */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedAuthUsers"]; + "application/json": components["schemas"]["UpdateAuthPageThemeRequest"]; }; }; - /** @description Invalid status or pagination parameters */ + /** @description Invalid or unreadable theme */ 400: { headers: { [name: string]: unknown; @@ -18774,130 +20026,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - getAuthUser: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - userId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Auth user details */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["AuthUser"]; - }; - }; - }; - }; - deleteAuthUser: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - userId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description User deleted */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; - listUserSessions: { - parameters: { - query?: { - /** @description Page number (1-indexed) */ - page?: number; - /** @description Number of sessions per page (max 100) */ - limit?: number; - /** - * @description Sort key. `last_activity` (default) orders by most recent activity and - * supports offset pagination only. `created_at` orders by session start - * and supports both offset and cursor pagination. - */ - sort?: "last_activity" | "created_at"; - /** - * @description Filter by whether the session can still be refreshed. Omit for every - * stored session, including expired ones. `expired` is not supported - * with cursor pagination. - */ - status?: "active" | "expired"; - /** - * @description Opaque keyset cursor from a previous response's `next_cursor`. Requires - * `sort=created_at`; mutually exclusive with `page` and `ending_before`. - */ - cursor?: string; - /** - * @description Opaque keyset cursor from a previous response's `prev_cursor`, paging - * backward. Requires `sort=created_at`; mutually exclusive with `page` - * and `cursor`. - */ - ending_before?: string; - /** - * @description Bounded number of rows to skip past the cursor anchor (the hybrid - * jump, maximum 100000). Ignored unless `cursor` or `ending_before` is - * supplied. - */ - offset?: number; - }; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - userId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Paginated list of user sessions */ - 200: { + /** @description Unauthorized */ + 401: { headers: { [name: string]: unknown; }; content: { - "application/json": { - sessions?: components["schemas"]["AuthSession"][]; - /** @description Total number of sessions */ - total?: number; - /** @description Current page number */ - page?: number; - /** @description Number of sessions per page */ - limit?: number; - /** @description Total number of pages */ - total_pages?: number; - /** @description Sessions for this page (cursor pagination only) */ - data?: components["schemas"]["AuthSession"][]; - /** @description Whether a further page exists (cursor pagination only) */ - has_more?: boolean; - /** @description Opaque cursor for the next page (cursor pagination only) */ - next_cursor?: string; - /** @description Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. */ - prev_cursor?: string; - }; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Invalid or conflicting pagination parameters */ - 400: { + /** @description Plan does not permit customisation */ + 403: { headers: { [name: string]: unknown; }; @@ -18905,108 +20044,137 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description User not found */ + /** @description Project not found */ 404: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Theme could not be saved */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - deleteAllUserSessions: { + deleteAuthPageTheme: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - userId: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description All sessions deleted */ + /** @description Theme cleared */ 204: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description User not found */ - 404: { + /** @description Unauthorized */ + 401: { headers: { [name: string]: unknown; }; - content?: never; - }; - }; - }; - deleteUserSession: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - userId: string; - sessionId: string; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Session deleted */ - 204: { + /** @description Plan does not permit customisation */ + 403: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Session or user not found */ + /** @description Project not found */ 404: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Theme could not be cleared */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - banAuthUser: { + updateAuthPageLayout: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - userId: string; + pageType: components["schemas"]["HostedAuthPageType"]; }; cookie?: never; }; - requestBody?: { + requestBody: { content: { - "application/json": { - /** - * Format: date-time - * @description When the ban expires (omit for permanent ban) - * @example 2026-12-31T23:59:59Z - */ - banned_until?: string; - }; + "application/json": components["schemas"]["UpdateAuthPageLayoutRequest"]; }; }; responses: { - /** @description User banned successfully */ + /** @description Layout saved */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["BanUserResponse"]; + "application/json": components["schemas"]["UpdateAuthPageLayoutRequest"]; }; }; - /** @description User not found */ + /** @description Invalid page type or layout */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Plan does not permit customisation */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Project not found */ 404: { headers: { [name: string]: unknown; @@ -19015,31 +20183,65 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Layout could not be saved */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - unbanAuthUser: { + deleteAuthPageLayout: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - userId: string; + pageType: components["schemas"]["HostedAuthPageType"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description User unbanned successfully */ - 200: { + /** @description Layout cleared */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid page type */ + 400: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["UnbanUserResponse"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description User not found */ + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Plan does not permit customisation */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Project not found */ 404: { headers: { [name: string]: unknown; @@ -19048,59 +20250,89 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; + /** @description Layout could not be cleared */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - listEmailTemplates: { + renderAuthPagePreview: { parameters: { - query?: never; + query: { + /** @description Short-lived signed preview ticket returned by the POST operation. */ + ticket: string; + }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + pageType: components["schemas"]["HostedAuthPageType"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Email templates list */ + /** @description Rendered preview document */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - data?: components["schemas"]["EmailTemplate"][]; - }; + "text/html": string; + }; + }; + /** @description Ticket is invalid or expired, its path does not match, or managed authentication is disabled */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "text/plain": string; + }; + }; + /** @description Preview could not be rendered */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "text/plain": string; }; }; }; }; - createEmailTemplate: { + previewAuthPage: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + pageType: components["schemas"]["HostedAuthPageType"]; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["CreateEmailTemplateRequest"]; + "application/json": components["schemas"]["PreviewAuthPageRequest"]; }; }; responses: { - /** @description Template created */ - 201: { + /** @description Short-lived URL for the rendered preview document */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["EmailTemplate"]; + "application/json": components["schemas"]["PreviewAuthPageResponse"]; }; }; - /** @description Invalid template type */ + /** @description Invalid page type or draft */ 400: { headers: { [name: string]: unknown; @@ -19109,7 +20341,16 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Custom email templates require the SUPERAGENT plan */ + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Access denied */ 403: { headers: { [name: string]: unknown; @@ -19118,8 +20359,17 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description The project already has a template of this type */ - 409: { + /** @description Project not found or managed authentication is disabled */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Preview could not be rendered */ + 500: { headers: { [name: string]: unknown; }; @@ -19129,29 +20379,36 @@ export interface operations { }; }; }; - getEmailTemplate: { + renderManagedAuthPage: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - type: "welcome" | "confirmation" | "password_reset" | "password_changed"; + pageType: components["schemas"]["HostedRenderablePageType"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Email template */ + /** @description Hosted auth page HTML */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["EmailTemplate"]; + "text/html": string; }; }; - /** @description Template not found */ + /** @description Invalid project id or unsupported Accept header */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Managed pages disabled or page type not found */ 404: { headers: { [name: string]: unknown; @@ -19160,42 +20417,55 @@ export interface operations { }; }; }; - updateEmailTemplate: { + renderDefaultManagedAuthPage: { parameters: { - query?: never; + query?: { + /** + * @description Optional deep-link action for the unified hosted page. Ignored when a + * custom login page is configured. `action=device` renders the device + * authorization approval UI inline (no redirect to any external app); + * it signs the user in and calls `POST /auth/device/verify`. + */ + action?: "login" | "signup" | "forgot-password" | "device"; + /** @description Device user code (from `POST /auth/device/authorize`) used with `action=device`. */ + user_code?: string; + /** @description Project anon key used by built-in managed auth flows (required for login/signup/device actions). */ + anon_key?: string; + /** + * @description Opaque one-time nonce generated by the client SDK before redirecting + * here. On successful login/signup it is echoed back in the post-auth + * redirect fragment as `state`, so the SDK can bind the returned session + * to the flow it initiated (login-CSRF / session-fixation defense). The + * SDK rejects a returned session whose `state` does not match. + */ + state?: string; + }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - type: "welcome" | "confirmation" | "password_reset" | "password_changed"; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateEmailTemplateRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Template updated */ + /** @description Hosted auth page HTML */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["EmailTemplate"]; + "text/html": string; }; }; - /** @description Custom email templates require the SUPERAGENT plan */ - 403: { + /** @description Invalid project id or unsupported Accept header */ + 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Template not found */ + /** @description Managed pages disabled */ 404: { headers: { [name: string]: unknown; @@ -19204,119 +20474,97 @@ export interface operations { }; }; }; - deleteEmailTemplate: { + getHostedLoginOptions: { parameters: { - query?: never; + query: { + anon_key: string; + }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - type: "welcome" | "confirmation" | "password_reset" | "password_changed"; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Template deleted */ - 204: { + /** @description Hosted login options returned */ + 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["HostedLoginOptionsResponse"]; + }; }; - /** @description Custom email templates require the SUPERAGENT plan */ - 403: { + /** @description Invalid or missing anon key */ + 401: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Template not found */ + /** @description Managed pages disabled */ 404: { headers: { [name: string]: unknown; }; content?: never; }; - }; - }; - getDefaultEmailTemplates: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Default templates */ - 200: { + /** @description Rate limit exceeded */ + 429: { headers: { [name: string]: unknown; }; - content: { - "application/json": { - data?: components["schemas"]["EmailTemplate"][]; - }; - }; + content?: never; }; }; }; - getDefaultEmailTemplate: { + hostedLoginCheckEmail: { parameters: { query?: never; - header?: never; + header: { + /** @description Bearer anon key (`Bearer `) */ + Authorization: string; + }; path: { - type: "welcome" | "confirmation" | "password_reset" | "password_changed"; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["HostedLoginEmailCheckRequest"]; + }; + }; responses: { - /** @description Default template */ + /** @description Email existence evaluated */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["EmailTemplate"]; + "application/json": components["schemas"]["HostedLoginEmailCheckResponse"]; }; }; - /** @description Template type not found */ - 404: { + /** @description Invalid or missing anon key */ + 401: { headers: { [name: string]: unknown; }; content?: never; }; - }; - }; - getAuthConfig: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Auth configuration */ - 200: { + /** @description Rate limit exceeded */ + 429: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["AuthConfig"]; - }; + content?: never; }; }; }; - updateAuthConfig: { + getAuthMethods: { parameters: { query?: never; header?: never; @@ -19326,40 +20574,47 @@ export interface operations { }; cookie?: never; }; - requestBody?: { - content: { - "application/json": components["schemas"]["UpdateAuthConfigRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Configuration updated */ + /** @description Authentication methods configuration */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthConfig"]; - }; - }; - /** - * @description The update would turn on, widen, or otherwise edit the email domain - * allowlist (`allowed_email_domains`, `allowed_email_domains_mode`) - * for a project that is not on the SUPERAGENT plan. A HOBBY project keeps - * whatever allowlist it already has — parked, enforcing nothing until - * it upgrades — and may still remove it, so a downgrade never leaves a - * project locked out of its own signups. - */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + "application/json": { + email_password?: { + enabled?: boolean; + method?: string; + name?: string; + }; + anonymous?: { + enabled?: boolean; + method?: string; + name?: string; + }; + oauth_providers?: { + enabled?: boolean; + method?: string; + provider?: string; + name?: string; + redirect_url?: string; + scopes?: string[]; + }[]; + /** + * @example [ + * "email_password", + * "oauth_google", + * "oauth_github" + * ] + */ + available_methods?: string[]; + }; }; }; }; }; - testEmailConfig: { + configureAuthMethods: { parameters: { query?: never; header?: never; @@ -19369,51 +20624,28 @@ export interface operations { }; cookie?: never; }; - requestBody: { + requestBody?: { content: { - "application/json": components["schemas"]["TestEmailRequest"]; - }; - }; - responses: { - /** @description Test email sent */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["TestEmailResponse"]; - }; - }; - /** @description Invalid request or email delivery not configured */ - 400: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Forbidden */ - 403: { - headers: { - [name: string]: unknown; + "application/json": { + enable_email_password?: boolean; + enable_anonymous?: boolean; + oauth_providers?: { + provider?: string; + enabled?: boolean; + }[]; }; - content?: never; }; - /** @description Project not found */ - 404: { + }; + responses: { + /** @description Methods configured */ + 200: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Template render failure or SMTP delivery failed */ - 502: { + /** @description At least one method must be enabled */ + 400: { headers: { [name: string]: unknown; }; @@ -19421,79 +20653,58 @@ export interface operations { }; }; }; - getAuthHostedPage: { + listOAuthConfigs: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - pageType: components["schemas"]["HostedAuthPageType"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Hosted page loaded */ + /** @description List of OAuth configurations */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthHostedPageResponse"]; + "application/json": { + configs?: components["schemas"]["OAuthConfig"][]; + }; }; }; }; }; - updateAuthHostedPage: { + createOAuthConfig: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - pageType: components["schemas"]["HostedAuthPageType"]; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["UpdateAuthHostedPageRequest"]; + "application/json": components["schemas"]["CreateOAuthConfigRequest"]; }; }; responses: { - /** @description Hosted page updated */ - 200: { + /** @description OAuth config created */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthHostedPageResponse"]; - }; - }; - /** @description Invalid input or unsafe markup */ - 400: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Forbidden */ - 403: { - headers: { - [name: string]: unknown; + "application/json": components["schemas"]["OAuthConfig"]; }; - content?: never; }; - /** @description Project not found */ - 404: { + /** @description Provider already configured */ + 409: { headers: { [name: string]: unknown; }; @@ -19501,138 +20712,90 @@ export interface operations { }; }; }; - getAuthPageAppearance: { + getOAuthConfig: { parameters: { - query?: never; + query?: { + /** @description Required when `provider=device` to select a specific device client. */ + client_id?: string; + }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + provider: "google" | "github" | "microsoft" | "apple" | "device"; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Saved appearance and effective plan state */ + /** @description OAuth configuration */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthPageAppearanceResponse"]; - }; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Access denied */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Project not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Appearance could not be read */ - 500: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["OAuthConfig"]; }; }; }; }; - updateAuthPageTheme: { + updateOAuthConfig: { parameters: { - query?: never; + query?: { + /** @description Required when `provider=device` to select a specific device client. */ + client_id?: string; + }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + provider: "google" | "github" | "microsoft" | "apple" | "device"; }; cookie?: never; }; - requestBody: { + requestBody?: { content: { - "application/json": components["schemas"]["UpdateAuthPageThemeRequest"]; + "application/json": components["schemas"]["UpdateOAuthConfigRequest"]; }; }; responses: { - /** @description Theme saved */ + /** @description OAuth config updated */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["UpdateAuthPageThemeRequest"]; - }; - }; - /** @description Invalid or unreadable theme */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["OAuthConfig"]; }; }; - /** @description Plan does not permit customisation */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + deleteOAuthConfig: { + parameters: { + query?: { + /** @description Required when `provider=device` to select a specific device client. */ + client_id?: string; }; - /** @description Project not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + provider: "google" | "github" | "microsoft" | "apple" | "device"; }; - /** @description Theme could not be saved */ - 500: { + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OAuth config deleted */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - deleteAuthPageTheme: { + listAvailableOAuthProviders: { parameters: { query?: never; header?: never; @@ -19644,272 +20807,341 @@ export interface operations { }; requestBody?: never; responses: { - /** @description Theme cleared */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Unauthorized */ - 401: { + /** @description Available providers */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": { + providers?: { + id?: string; + name?: string; + default_scopes?: string[]; + }[]; + }; }; }; - /** @description Plan does not permit customisation */ - 403: { + }; + }; + authOAuthAuthorize: { + parameters: { + query: { + /** @description Project anon key (required - identifies the project) */ + anon_key: string; + /** + * @description URL to redirect to after the OAuth flow (optional). Must exactly + * match an entry in the project's `allowed_redirect_urls`, including + * its query string, or be the project's own managed hosted-auth page + * URL. + */ + redirect_url?: string; + /** + * @description Optional application nonce. It is stored with the server-generated + * provider state and echoed to redirect_url as `state`. + */ + client_state?: string; + /** + * @description Set to `code` to receive a short-lived authorization code at + * redirect_url, then use POST /auth/oauth/exchange to obtain the + * session. `redirect_url` is required in this mode. When omitted, the + * established session-fragment response is retained for compatibility + * with existing clients. + */ + response_mode?: "code"; + }; + header?: never; + path: { + provider: "google" | "github" | "microsoft" | "apple"; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Redirect to OAuth provider */ + 307: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Project not found */ - 404: { + /** + * @description OAuth provider is disabled for this project, or `redirect_url` is + * not registered in `allowed_redirect_urls` + */ + 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Theme could not be cleared */ - 500: { + /** @description OAuth provider not configured */ + 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - updateAuthPageLayout: { + authOAuthCallback: { parameters: { - query?: never; + query: { + code: string; + state: string; + error?: string; + }; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - pageType: components["schemas"]["HostedAuthPageType"]; + provider: "google" | "github" | "microsoft" | "apple"; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateAuthPageLayoutRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Layout saved */ + /** @description Existing user signed in (when redirect_url was omitted) */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["UpdateAuthPageLayoutRequest"]; + "application/json": components["schemas"]["AuthTokenResponse"]; }; }; - /** @description Invalid page type or layout */ - 400: { + /** @description New user created and signed in (when redirect_url was omitted) */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["AuthTokenResponse"]; }; }; - /** @description Unauthorized */ - 401: { + /** + * @description Redirect to the exact registered redirect_url. Flows that requested + * response_mode=code receive a short-lived, single-use `code` and + * optional application `state`; compatibility flows receive the + * established session fragment. + */ + 303: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Plan does not permit customisation */ - 403: { + /** + * @description Missing/invalid code or state, the state parameter expired, or the + * flow's stored redirect_url is no longer registered in + * allowed_redirect_urls (re-checked at callback time) + */ + 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Project not found */ - 404: { + /** + * @description The provider's email domain is not in `allowed_email_domains`. Creating + * an account is refused under `signup` and `signup_and_signin`; signing in + * an already-linked account is refused under `signup_and_signin`. + */ + 403: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Layout could not be saved */ - 500: { + /** @description Email already exists (requires linking) */ + 409: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - deleteAuthPageLayout: { + authOAuthExchange: { parameters: { query?: never; header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - pageType: components["schemas"]["HostedAuthPageType"]; - }; + path?: never; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": { + code: string; + /** Format: uri */ + redirect_url: string; + }; + }; + }; responses: { - /** @description Layout cleared */ - 204: { + /** @description Authorization code consumed and session created */ + 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["AuthTokenResponse"]; + }; }; - /** @description Invalid page type */ + /** @description Invalid, expired, consumed, or redirect-mismatched code */ 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Unauthorized */ + /** @description Missing or invalid project anon key */ 401: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Plan does not permit customisation */ + /** + * @description Email confirmation is now required, or the account's email domain is not + * in `allowed_email_domains` while `allowed_email_domains_mode` is + * `signup_and_signin`. Both are re-checked here because the code outlives + * the callback that issued it. + */ 403: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; + content?: never; + }; + /** @description Too many exchange attempts from this client */ + 429: { + headers: { + [name: string]: unknown; }; + content?: never; }; - /** @description Project not found */ - 404: { + }; + }; + authDeviceAuthorize: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Enabled `device` OAuth client ID for the target project */ + client_id: string; + }; + }; + }; + responses: { + /** @description Device authorization started */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["DeviceAuthorizationResponse"]; }; }; - /** @description Layout could not be cleared */ - 500: { + /** @description Invalid request or unauthorized client */ + 400: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["OAuthErrorResponse"]; }; }; }; }; - renderAuthPagePreview: { + authDeviceToken: { parameters: { - query: { - /** @description Short-lived signed preview ticket returned by the POST operation. */ - ticket: string; - }; + query?: never; header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - pageType: components["schemas"]["HostedAuthPageType"]; - }; + path?: never; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": { + /** @enum {string} */ + grant_type: "urn:ietf:params:oauth:grant-type:device_code"; + device_code: string; + client_id: string; + }; + }; + }; responses: { - /** @description Rendered preview document */ + /** @description Device flow completed, auth-user session minted */ 200: { headers: { [name: string]: unknown; }; content: { - "text/html": string; + "application/json": components["schemas"]["AuthTokenResponse"]; }; }; - /** @description Ticket is invalid or expired, its path does not match, or managed authentication is disabled */ - 404: { + /** @description Polling state/error response */ + 400: { headers: { [name: string]: unknown; }; content: { - "text/plain": string; + "application/json": components["schemas"]["OAuthErrorResponse"]; }; }; - /** @description Preview could not be rendered */ - 500: { + /** + * @description `access_denied` - the approving account's email domain is not in + * `allowed_email_domains` while `allowed_email_domains_mode` is + * `signup_and_signin`. Re-checked here because approval and redemption + * are separate requests. + */ + 403: { headers: { [name: string]: unknown; }; content: { - "text/plain": string; + "application/json": components["schemas"]["OAuthErrorResponse"]; }; }; }; }; - previewAuthPage: { + authDeviceVerify: { parameters: { query?: never; header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - pageType: components["schemas"]["HostedAuthPageType"]; - }; + path?: never; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["PreviewAuthPageRequest"]; + "application/json": { + user_code: string; + /** + * @default approve + * @enum {string} + */ + action?: "approve" | "deny"; + }; }; }; responses: { - /** @description Short-lived URL for the rendered preview document */ + /** @description Verification action accepted */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PreviewAuthPageResponse"]; - }; - }; - /** @description Invalid page type or draft */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + "application/json": { + success?: boolean; + status?: string; + }; }; }; - /** @description Unauthorized */ + /** @description Not authenticated */ 401: { headers: { [name: string]: unknown; @@ -19918,26 +21150,40 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Access denied */ - 403: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + }; + }; + authPlatformExchange: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + client_id: string; }; }; - /** @description Project not found or managed authentication is disabled */ - 404: { + }; + responses: { + /** @description Platform token minted */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["PlatformExchangeResponse"]; }; }; - /** @description Preview could not be rendered */ - 500: { + /** + * @description Exchange not allowed for this session/client/project, or the + * account's email domain is not in `allowed_email_domains` while + * `allowed_email_domains_mode` is `signup_and_signin`. The domain is + * re-checked here because the minted platform token outlives the + * session it is exchanged from. + */ + 403: { headers: { [name: string]: unknown; }; @@ -19947,503 +21193,503 @@ export interface operations { }; }; }; - renderManagedAuthPage: { + authListOAuthProviders: { parameters: { query?: never; header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - pageType: components["schemas"]["HostedRenderablePageType"]; - }; + path?: never; cookie?: never; }; requestBody?: never; responses: { - /** @description Hosted auth page HTML */ + /** @description Linked providers */ 200: { headers: { [name: string]: unknown; }; content: { - "text/html": string; + "application/json": { + providers?: { + provider?: string; + /** Format: date-time */ + linked_at?: string; + /** Format: date-time */ + updated_at?: string; + }[]; + }; }; }; - /** @description Invalid project id or unsupported Accept header */ - 400: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; - content?: never; - }; - /** @description Managed pages disabled or page type not found */ - 404: { - headers: { - [name: string]: unknown; + content: { + "application/json": components["schemas"]["Error"]; }; - content?: never; }; }; }; - renderDefaultManagedAuthPage: { + authLinkOAuthProvider: { parameters: { query?: { /** - * @description Optional deep-link action for the unified hosted page. Ignored when a - * custom login page is configured. `action=device` renders the device - * authorization approval UI inline (no redirect to any external app); - * it signs the user in and calls `POST /auth/device/verify`. + * @description URL to redirect to after linking completes (optional). Same + * allowed_redirect_urls requirement as GET /auth/oauth/{provider}/authorize. */ - action?: "login" | "signup" | "forgot-password" | "device"; - /** @description Device user code (from `POST /auth/device/authorize`) used with `action=device`. */ - user_code?: string; - /** @description Project anon key used by built-in managed auth flows (required for login/signup/device actions). */ - anon_key?: string; + redirect_url?: string; + /** @description Optional application nonce echoed to redirect_url as `state`. */ + client_state?: string; /** - * @description Opaque one-time nonce generated by the client SDK before redirecting - * here. On successful login/signup it is echoed back in the post-auth - * redirect fragment as `state`, so the SDK can bind the returned session - * to the flow it initiated (login-CSRF / session-fixation defense). The - * SDK rejects a returned session whose `state` does not match. + * @description Set to `code` to receive a short-lived authorization code at + * redirect_url. `redirect_url` is required in this mode. When + * omitted, the established session-fragment response is retained for + * compatibility with existing clients. */ - state?: string; + response_mode?: "code"; }; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + provider: "google" | "github" | "microsoft" | "apple"; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Hosted auth page HTML */ + /** @description Authorization URL generated */ 200: { headers: { [name: string]: unknown; }; content: { - "text/html": string; + "application/json": { + authorization_url?: string; + }; }; }; - /** @description Invalid project id or unsupported Accept header */ + /** @description redirect_url is not registered in allowed_redirect_urls */ 400: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Managed pages disabled */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; - getHostedLoginOptions: { - parameters: { - query: { - anon_key: string; - }; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Hosted login options returned */ - 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["HostedLoginOptionsResponse"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Invalid or missing anon key */ + /** @description Not authenticated */ 401: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Managed pages disabled */ + /** @description OAuth provider not configured */ 404: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Rate limit exceeded */ - 429: { + /** @description Provider already linked */ + 409: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - hostedLoginCheckEmail: { + authUnlinkOAuthProvider: { parameters: { query?: never; - header: { - /** @description Bearer anon key (`Bearer `) */ - Authorization: string; - }; + header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + provider: "google" | "github" | "microsoft" | "apple"; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["HostedLoginEmailCheckRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Email existence evaluated */ - 200: { + /** @description Provider unlinked */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["HostedLoginEmailCheckResponse"]; - }; + content?: never; }; - /** @description Invalid or missing anon key */ - 401: { + /** @description Cannot unlink last authentication method */ + 400: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Rate limit exceeded */ - 429: { + /** @description Not authenticated */ + 401: { headers: { [name: string]: unknown; }; - content?: never; - }; - }; - }; - getAuthMethods: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Authentication methods configuration */ - 200: { + /** @description Provider not linked */ + 404: { headers: { [name: string]: unknown; }; content: { - "application/json": { - email_password?: { - enabled?: boolean; - method?: string; - name?: string; - }; - anonymous?: { - enabled?: boolean; - method?: string; - name?: string; - }; - oauth_providers?: { - enabled?: boolean; - method?: string; - provider?: string; - name?: string; - redirect_url?: string; - scopes?: string[]; - }[]; - /** - * @example [ - * "email_password", - * "oauth_google", - * "oauth_github" - * ] - */ - available_methods?: string[]; - }; + "application/json": components["schemas"]["Error"]; }; }; }; }; - configureAuthMethods: { + refreshOAuthProviderToken: { parameters: { query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - }; - cookie?: never; - }; - requestBody?: { - content: { - "application/json": { - enable_email_password?: boolean; - enable_anonymous?: boolean; - oauth_providers?: { - provider?: string; - enabled?: boolean; - }[]; - }; + header?: never; + path: { + provider: "google" | "github" | "microsoft" | "apple"; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Methods configured */ + /** @description Token refreshed successfully */ 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": { + message?: string; + provider?: string; + expires_in?: number; + }; + }; }; - /** @description At least one method must be enabled */ + /** @description No refresh token available or refresh failed */ 400: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Provider not linked */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - listOAuthConfigs: { + getOAuthProviderToken: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + provider: "google" | "github" | "microsoft" | "apple"; }; cookie?: never; }; requestBody?: never; responses: { - /** @description List of OAuth configurations */ + /** @description Current access token */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { - configs?: components["schemas"]["OAuthConfig"][]; + message?: string; + provider?: string; + expires_in?: number; }; }; }; + /** @description Not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Provider not linked */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; }; }; - createOAuthConfig: { + callOAuthProviderAPI: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + provider: "google" | "github" | "microsoft" | "apple"; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["CreateOAuthConfigRequest"]; + "application/json": { + /** + * @description Relative path on the provider's API, beginning with `/`. It is + * joined with the provider's fixed base URL; it must not contain a + * scheme, host, userinfo, or a leading `//`. + * @example /user/repos + */ + endpoint: string; + /** + * @description HTTP method to use + * @default GET + * @enum {string} + */ + method?: "GET" | "POST"; + /** @description Request body for POST requests */ + body?: { + [key: string]: unknown; + }; + }; }; }; responses: { - /** @description OAuth config created */ - 201: { + /** @description Provider API response */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["OAuthConfig"]; + "application/json": { + /** @enum {string} */ + provider: "google" | "github" | "microsoft" | "apple"; + endpoint: string; + status_code: number; + /** @description Raw provider JSON value, or null when the provider returns no body */ + data: unknown; + }; }; }; - /** @description Provider already configured */ - 409: { + /** + * @description Invalid request (for example: missing `endpoint`, an `endpoint` that is + * not a relative path, or an unsupported HTTP method), or a provider + * redirect to another origin. + */ + 400: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - }; - }; - getOAuthConfig: { - parameters: { - query?: { - /** @description Required when `provider=device` to select a specific device client. */ - client_id?: string; + /** @description Not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - provider: "google" | "github" | "microsoft" | "apple" | "device"; + /** @description OAuth provider configuration not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description OAuth configuration */ - 200: { + /** @description Failed to create the provider API request */ + 500: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["OAuthConfig"]; + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Provider transport failure, invalid JSON, or response body larger than 8 MiB */ + 502: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; }; }; }; }; - updateOAuthConfig: { + listAnonKeys: { parameters: { query?: { - /** @description Required when `provider=device` to select a specific device client. */ - client_id?: string; + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; }; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - provider: "google" | "github" | "microsoft" | "apple" | "device"; }; cookie?: never; }; - requestBody?: { - content: { - "application/json": components["schemas"]["UpdateOAuthConfigRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description OAuth config updated */ + /** @description List of anon keys */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["OAuthConfig"]; + "application/json": { + data?: components["schemas"]["AnonKey"][]; + /** @description Total number of items matching the query (so the UI can render numbered pages). */ + total?: number; + /** @description Whether a next page exists. */ + has_more?: boolean; + /** @description Opaque cursor for the next page (cursor pagination only) */ + next_cursor?: string; + /** @description Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. */ + prev_cursor?: string; + }; }; }; }; }; - deleteOAuthConfig: { + createAnonKey: { parameters: { - query?: { - /** @description Required when `provider=device` to select a specific device client. */ - client_id?: string; - }; + query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; - provider: "google" | "github" | "microsoft" | "apple" | "device"; }; - cookie?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** + * @description Key name for identification. + * Can only contain letters, numbers, underscores, and hyphens. + * @example frontend-app + */ + name: string; + /** + * @description Optional list of permissions for this key. + * If not provided, defaults to auth-only permissions: auth.signup, auth.signin, auth.refresh, auth.logout, auth.password_reset, auth.confirm_email, auth.resend_confirmation. + * Storage, realtime, and functions permissions must be explicitly added if needed. + * @example [ + * "auth.signup", + * "auth.signin", + * "auth.refresh", + * "auth.logout" + * ] + */ + permissions?: ("auth.signup" | "auth.signin" | "auth.refresh" | "auth.logout" | "auth.password_reset" | "auth.confirm_email" | "auth.resend_confirmation" | "storage.upload" | "storage.download" | "storage.list" | "storage.delete" | "realtime.connect" | "realtime.subscribe" | "realtime.publish" | "functions.invoke")[]; + }; + }; }; - requestBody?: never; responses: { - /** @description OAuth config deleted */ - 204: { + /** @description Anon key created */ + 201: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["AnonKey"]; + }; }; }; }; - listAvailableOAuthProviders: { + getAnonKey: { parameters: { query?: never; header?: never; path: { /** @description Project ID */ id: components["parameters"]["ProjectId"]; + keyId: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Available providers */ + /** @description Anon key details */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - providers?: { - id?: string; - name?: string; - default_scopes?: string[]; - }[]; - }; - }; - }; - }; - }; - authOAuthAuthorize: { - parameters: { - query: { - /** @description Project anon key (required - identifies the project) */ - anon_key: string; - /** - * @description URL to redirect to after the OAuth flow (optional). Must exactly - * match an entry in the project's `allowed_redirect_urls`, including - * its query string, or be the project's own managed hosted-auth page - * URL. - */ - redirect_url?: string; - /** - * @description Optional application nonce. It is stored with the server-generated - * provider state and echoed to redirect_url as `state`. - */ - client_state?: string; - /** - * @description Set to `code` to receive a short-lived authorization code at - * redirect_url, then use POST /auth/oauth/exchange to obtain the - * session. `redirect_url` is required in this mode. When omitted, the - * established session-fragment response is retained for compatibility - * with existing clients. - */ - response_mode?: "code"; - }; - header?: never; - path: { - provider: "google" | "github" | "microsoft" | "apple"; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Redirect to OAuth provider */ - 307: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** - * @description OAuth provider is disabled for this project, or `redirect_url` is - * not registered in `allowed_redirect_urls` - */ - 400: { - headers: { - [name: string]: unknown; + "application/json": components["schemas"]["AnonKey"]; }; - content?: never; }; - /** @description OAuth provider not configured */ + /** @description Key not found */ 404: { headers: { [name: string]: unknown; @@ -20452,552 +21698,704 @@ export interface operations { }; }; }; - authOAuthCallback: { + revokeAnonKey: { parameters: { - query: { - code: string; - state: string; - error?: string; - }; + query?: never; header?: never; path: { - provider: "google" | "github" | "microsoft" | "apple"; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + keyId: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Existing user signed in (when redirect_url was omitted) */ - 200: { + /** @description Key revoked */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["AuthTokenResponse"]; - }; + content?: never; }; - /** @description New user created and signed in (when redirect_url was omitted) */ - 201: { + /** @description Unauthorized */ + 401: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["AuthTokenResponse"]; - }; + content?: never; }; - /** - * @description Redirect to the exact registered redirect_url. Flows that requested - * response_mode=code receive a short-lived, single-use `code` and - * optional application `state`; compatibility flows receive the - * established session fragment. - */ - 303: { + /** @description Forbidden */ + 403: { headers: { [name: string]: unknown; }; content?: never; }; - /** - * @description Missing/invalid code or state, the state parameter expired, or the - * flow's stored redirect_url is no longer registered in - * allowed_redirect_urls (re-checked at callback time) - */ - 400: { + /** @description Key not found */ + 404: { headers: { [name: string]: unknown; }; content?: never; }; - /** - * @description The provider's email domain is not in `allowed_email_domains`. Creating - * an account is refused under `signup` and `signup_and_signin`; signing in - * an already-linked account is refused under `signup_and_signin`. - */ - 403: { + /** @description Cannot delete the project's default anon key */ + 409: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Email already exists (requires linking) */ - 409: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - authOAuthExchange: { + regenerateAnonKey: { parameters: { query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + keyId: string; + }; cookie?: never; }; - requestBody: { - content: { - "application/json": { - code: string; - /** Format: uri */ - redirect_url: string; + requestBody?: never; + responses: { + /** @description Key regenerated */ + 200: { + headers: { + [name: string]: unknown; }; + content: { + "application/json": components["schemas"]["AnonKey"]; + }; + }; + }; + }; + setDefaultAnonKey: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + keyId: string; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Authorization code consumed and session created */ + /** @description Key set as default */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AuthTokenResponse"]; + "application/json": components["schemas"]["AnonKey"]; }; }; - /** @description Invalid, expired, consumed, or redirect-mismatched code */ - 400: { + /** @description Unauthorized */ + 401: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Missing or invalid project anon key */ - 401: { + /** @description Forbidden */ + 403: { headers: { [name: string]: unknown; }; content?: never; }; - /** - * @description Email confirmation is now required, or the account's email domain is not - * in `allowed_email_domains` while `allowed_email_domains_mode` is - * `signup_and_signin`. Both are re-checked here because the code outlives - * the callback that issued it. - */ - 403: { + /** @description Anon key not found */ + 404: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Too many exchange attempts from this client */ - 429: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - authDeviceAuthorize: { + listServiceKeys: { parameters: { - query?: never; + query?: { + /** + * @description Page number (1-indexed) for offset pagination. Declares no schema + * default so the request validator does not inject one: handlers that omit + * `page` see it unset (nil) and default to 1 in code, while cursor-first + * endpoints (e.g. the project deployments feed) can detect its absence to + * stay in keyset/search mode. Supplying `page` selects offset pagination. + */ + page?: components["parameters"]["Page"]; + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; + }; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - /** @description Enabled `device` OAuth client ID for the target project */ - client_id: string; - }; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Device authorization started */ + /** @description Paginated list of service keys */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["DeviceAuthorizationResponse"]; - }; - }; - /** @description Invalid request or unauthorized client */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["OAuthErrorResponse"]; + "application/json": components["schemas"]["PaginatedServiceKeys"]; }; }; }; }; - authDeviceToken: { + createServiceKey: { parameters: { query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; cookie?: never; }; requestBody: { content: { "application/json": { - /** @enum {string} */ - grant_type: "urn:ietf:params:oauth:grant-type:device_code"; - device_code: string; - client_id: string; + /** + * @description Descriptive name for the key (e.g., "admin-dashboard", "background-jobs"). + * Can only contain letters, numbers, underscores, and hyphens. + * @example admin-dashboard + */ + name: string; + /** + * @description Optional least-privilege scope for the key. When omitted, empty, or + * containing only blank strings, the key is granted full access (["*"]) + * for backward compatibility. Provide an explicit list (e.g. + * ["functions.invoke", "locks.manage"]) to restrict the key; "*" + * grants everything. Scope enforcement applies to function invocation, + * storage object operations, and project locks. + * @example [ + * "functions.invoke", + * "locks.manage" + * ] + */ + permissions?: string[]; }; }; }; responses: { - /** @description Device flow completed, auth-user session minted */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["AuthTokenResponse"]; - }; - }; - /** @description Polling state/error response */ - 400: { + /** @description Service key created - save the key_value immediately! */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["OAuthErrorResponse"]; + "application/json": components["schemas"]["ServiceKey"]; }; }; - /** - * @description `access_denied` - the approving account's email domain is not in - * `allowed_email_domains` while `allowed_email_domains_mode` is - * `signup_and_signin`. Re-checked here because approval and redemption - * are separate requests. - */ - 403: { + /** @description Key with this name already exists */ + 409: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["OAuthErrorResponse"]; - }; + content?: never; }; }; }; - authDeviceVerify: { + getServiceKey: { parameters: { query?: never; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - user_code: string; - /** - * @default approve - * @enum {string} - */ - action?: "approve" | "deny"; - }; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + keyId: string; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Verification action accepted */ + /** @description Service key details */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - success?: boolean; - status?: string; - }; + "application/json": components["schemas"]["ServiceKey"]; }; }; - /** @description Not authenticated */ - 401: { + /** @description Key not found */ + 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - authPlatformExchange: { + deleteServiceKey: { parameters: { query?: never; header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - client_id: string; - }; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + keyId: string; }; + cookie?: never; }; + requestBody?: never; responses: { - /** @description Platform token minted */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["PlatformExchangeResponse"]; - }; - }; - /** - * @description Exchange not allowed for this session/client/project, or the - * account's email domain is not in `allowed_email_domains` while - * `allowed_email_domains_mode` is `signup_and_signin`. The domain is - * re-checked here because the minted platform token outlives the - * session it is exchanged from. - */ - 403: { + /** @description Key deleted */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - authListOAuthProviders: { + regenerateServiceKey: { parameters: { query?: never; header?: never; - path?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + keyId: string; + }; cookie?: never; }; requestBody?: never; responses: { - /** @description Linked providers */ + /** @description Key regenerated - save the new key_value immediately! */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - providers?: { - provider?: string; - /** Format: date-time */ - linked_at?: string; - /** Format: date-time */ - updated_at?: string; - }[]; - }; - }; - }; - /** @description Not authenticated */ - 401: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["ServiceKey"]; }; }; }; }; - authLinkOAuthProvider: { + listStorageBuckets: { parameters: { query?: { + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; /** - * @description URL to redirect to after linking completes (optional). Same - * allowed_redirect_urls requirement as GET /auth/oauth/{provider}/authorize. + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. */ - redirect_url?: string; - /** @description Optional application nonce echoed to redirect_url as `state`. */ - client_state?: string; + cursor?: components["parameters"]["Cursor"]; /** - * @description Set to `code` to receive a short-lived authorization code at - * redirect_url. `redirect_url` is required in this mode. When - * omitted, the established session-fragment response is retained for - * compatibility with existing clients. + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. */ - response_mode?: "code"; + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; }; header?: never; path: { - provider: "google" | "github" | "microsoft" | "apple"; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Authorization URL generated */ + /** + * @description Either the full bucket list (bare array, legacy) or a paginated + * envelope when cursor pagination is requested. + */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - authorization_url?: string; - }; + "application/json": components["schemas"]["StorageBucket"][] | components["schemas"]["PaginatedStorageBuckets"]; }; }; - /** @description redirect_url is not registered in allowed_redirect_urls */ - 400: { + }; + }; + createStorageBucket: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateStorageBucketRequest"]; + }; + }; + responses: { + /** @description Bucket created */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["StorageBucket"]; }; }; - /** @description Not authenticated */ - 401: { + /** @description Bucket already exists */ + 409: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description OAuth provider not configured */ - 404: { + }; + }; + getStorageBucket: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Bucket details */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["StorageBucket"]; }; }; - /** @description Provider already linked */ - 409: { + /** @description Bucket not found */ + 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - authUnlinkOAuthProvider: { + deleteStorageBucket: { parameters: { query?: never; header?: never; path: { - provider: "google" | "github" | "microsoft" | "apple"; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Provider unlinked */ - 204: { + /** @description Bucket deleted */ + 200: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Cannot unlink last authentication method */ - 400: { + }; + }; + updateStorageBucket: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateStorageBucketRequest"]; + }; + }; + responses: { + /** @description Bucket updated */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["StorageBucket"]; }; }; - /** @description Not authenticated */ - 401: { + }; + }; + listStoragePolicies: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of policies */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["StoragePolicy"][]; }; }; - /** @description Provider not linked */ - 404: { + }; + }; + createStoragePolicy: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateStoragePolicyRequest"]; + }; + }; + responses: { + /** @description Policy created */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["StoragePolicy"]; }; }; }; }; - refreshOAuthProviderToken: { + deleteStoragePolicy: { parameters: { query?: never; header?: never; path: { - provider: "google" | "github" | "microsoft" | "apple"; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; + policyId: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Token refreshed successfully */ + /** @description Policy deleted */ 200: { headers: { [name: string]: unknown; }; - content: { - "application/json": { - message?: string; - provider?: string; - expires_in?: number; - }; - }; + content?: never; }; - /** @description No refresh token available or refresh failed */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + listStorageObjectsAdmin: { + parameters: { + query?: { + /** @description Filter by owner user ID */ + owner_id?: string; + /** @description Page number (1-based) */ + page?: number; + /** @description Items per page */ + limit?: number; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` + * — pages backward (the page immediately preceding this cursor). Mutually + * exclusive with `page` and `cursor`; combining them returns 400. `search` + * and `limit` must match the values bound to the cursor or the request + * returns 400. + */ + ending_before?: components["parameters"]["EndingBefore"]; + /** + * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or + * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then + * skip this many rows within. Used for numbered jump-to-page: from the + * current page, seek to its next/prev cursor and offset the remaining + * pages. Only honored on the cursor pagination path; ignored otherwise. + */ + offset?: components["parameters"]["Offset"]; + /** + * @description Case-insensitive substring match on the resource `name`. See the + * endpoint description for supported pagination modes. + */ + search?: components["parameters"]["Search"]; }; - /** @description Not authenticated */ - 401: { + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of storage objects */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": { + data?: components["schemas"]["StorageObjectWithBucket"][]; + page?: number; + limit?: number; + total?: number; + has_more?: boolean; + /** @description Opaque cursor for the next page (cursor pagination only) */ + next_cursor?: string; + /** @description Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. */ + prev_cursor?: string; + }; }; }; - /** @description Provider not linked */ - 404: { + }; + }; + getStorageStats: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Storage statistics */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["StorageStats"]; }; }; }; }; - getOAuthProviderToken: { + getRealtimeConfig: { parameters: { query?: never; header?: never; path: { - provider: "google" | "github" | "microsoft" | "apple"; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Current access token */ + /** @description Realtime configuration */ 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - message?: string; - provider?: string; - expires_in?: number; - }; + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["RealtimeConfig"]; }; }; - /** @description Not authenticated */ + /** @description Unauthorized */ 401: { headers: { [name: string]: unknown; @@ -21006,7 +22404,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Provider not linked */ + /** @description Project not found */ 404: { headers: { [name: string]: unknown; @@ -21017,60 +22415,32 @@ export interface operations { }; }; }; - callOAuthProviderAPI: { + updateRealtimeConfig: { parameters: { query?: never; header?: never; path: { - provider: "google" | "github" | "microsoft" | "apple"; + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; cookie?: never; }; requestBody: { content: { - "application/json": { - /** - * @description Relative path on the provider's API, beginning with `/`. It is - * joined with the provider's fixed base URL; it must not contain a - * scheme, host, userinfo, or a leading `//`. - * @example /user/repos - */ - endpoint: string; - /** - * @description HTTP method to use - * @default GET - * @enum {string} - */ - method?: "GET" | "POST"; - /** @description Request body for POST requests */ - body?: { - [key: string]: unknown; - }; - }; + "application/json": components["schemas"]["UpdateRealtimeConfigRequest"]; }; }; responses: { - /** @description Provider API response */ + /** @description Updated realtime configuration */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - /** @enum {string} */ - provider: "google" | "github" | "microsoft" | "apple"; - endpoint: string; - status_code: number; - /** @description Raw provider JSON value, or null when the provider returns no body */ - data: unknown; - }; + "application/json": components["schemas"]["RealtimeConfig"]; }; }; - /** - * @description Invalid request (for example: missing `endpoint`, an `endpoint` that is - * not a relative path, or an unsupported HTTP method), or a provider - * redirect to another origin. - */ + /** @description Invalid configuration values */ 400: { headers: { [name: string]: unknown; @@ -21079,7 +22449,7 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Not authenticated */ + /** @description Unauthorized */ 401: { headers: { [name: string]: unknown; @@ -21088,26 +22458,31 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description OAuth provider configuration not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + }; + }; + getRealtimeStats: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Project ID */ + id: components["parameters"]["ProjectId"]; }; - /** @description Failed to create the provider API request */ - 500: { + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Realtime statistics */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["RealtimeStats"]; }; }; - /** @description Provider transport failure, invalid JSON, or response body larger than 8 MiB */ - 502: { + /** @description Unauthorized */ + 401: { headers: { [name: string]: unknown; }; @@ -21117,207 +22492,214 @@ export interface operations { }; }; }; - listAnonKeys: { + listStorageObjects: { parameters: { query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - search?: components["parameters"]["Search"]; + /** @description Filter objects by path prefix */ + prefix?: string; + /** @description Maximum objects to return */ + limit?: number; + /** @description Pagination cursor */ + cursor?: string; }; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description List of anon keys */ + /** @description List of objects */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": { - data?: components["schemas"]["AnonKey"][]; - /** @description Total number of items matching the query (so the UI can render numbered pages). */ - total?: number; - /** @description Whether a next page exists. */ - has_more?: boolean; - /** @description Opaque cursor for the next page (cursor pagination only) */ - next_cursor?: string; - /** @description Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. */ - prev_cursor?: string; - }; + "application/json": components["schemas"]["StorageListResponse"]; + }; + }; + /** @description Access denied by storage policy */ + 403: { + headers: { + [name: string]: unknown; }; + content?: never; }; + 429: components["responses"]["BandwidthCapExceeded"]; }; }; - createAnonKey: { + acquireProjectLock: { parameters: { query?: never; - header?: never; + header: { + /** @description Opaque UUID generated once by the caller and retained for the lease lifetime. */ + "X-Volcano-Lock-Token": components["parameters"]["LockToken"]; + /** + * @description UUID correlating this request across client and server logs. Repeat safety comes from + * the lock token, so a retry under a reused request ID still counts against the quota. + */ + "X-Volcano-Request-Id": components["parameters"]["LockRequestId"]; + }; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description Project-local lock name. */ + key: components["parameters"]["LockKey"]; }; cookie?: never; }; requestBody: { content: { - "application/json": { - /** - * @description Key name for identification. - * Can only contain letters, numbers, underscores, and hyphens. - * @example frontend-app - */ - name: string; - /** - * @description Optional list of permissions for this key. - * If not provided, defaults to auth-only permissions: auth.signup, auth.signin, auth.refresh, auth.logout, auth.password_reset, auth.confirm_email, auth.resend_confirmation. - * Storage, realtime, and functions permissions must be explicitly added if needed. - * @example [ - * "auth.signup", - * "auth.signin", - * "auth.refresh", - * "auth.logout" - * ] - */ - permissions?: ("auth.signup" | "auth.signin" | "auth.refresh" | "auth.logout" | "auth.password_reset" | "auth.confirm_email" | "auth.resend_confirmation" | "storage.upload" | "storage.download" | "storage.list" | "storage.delete" | "realtime.connect" | "realtime.subscribe" | "realtime.publish" | "functions.invoke")[]; - }; + "application/json": components["schemas"]["ProjectLockLeaseRequest"]; }; }; responses: { - /** @description Anon key created */ + /** @description Lease acquired */ 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AnonKey"]; + "application/json": components["schemas"]["ProjectLockLease"]; }; }; - }; - }; - getAnonKey: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - keyId: string; + /** @description Invalid lock key, token, or TTL */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Anon key details */ - 200: { + /** @description Missing or invalid credentials */ + 401: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AnonKey"]; + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description A non-service credential was supplied or the service key lacks `locks.manage` */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** + * @description The lock is held by another live lease (`lock_held`), or the caller's own lease + * lapsed and is not yet reclaimable (`lock_ownership_lost`). + */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Project lock request limit exceeded */ + 429: { + headers: { + /** @description Seconds until the current fixed-minute window ends. */ + "Retry-After"?: number; + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; }; }; - /** @description Key not found */ - 404: { + /** @description Lock service unavailable */ + 503: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - revokeAnonKey: { + releaseProjectLock: { parameters: { query?: never; - header?: never; + header: { + /** @description Opaque UUID generated once by the caller and retained for the lease lifetime. */ + "X-Volcano-Lock-Token": components["parameters"]["LockToken"]; + /** + * @description UUID correlating this request across client and server logs. Repeat safety comes from + * the lock token, so a retry under a reused request ID still counts against the quota. + */ + "X-Volcano-Request-Id": components["parameters"]["LockRequestId"]; + }; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - keyId: string; + /** @description Project-local lock name. */ + key: components["parameters"]["LockKey"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Key revoked */ + /** @description Lease released */ 204: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Unauthorized */ + /** @description Invalid lock key or token */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Missing or invalid credentials */ 401: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Forbidden */ + /** @description A non-service credential was supplied or the service key lacks `locks.manage` */ 403: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Key not found */ - 404: { + /** @description The lease is owned by another token */ + 409: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Cannot delete the project's default anon key */ - 409: { + /** @description Project lock request limit exceeded */ + 429: { headers: { + /** @description Seconds until the current fixed-minute window ends. */ + "Retry-After"?: number; [name: string]: unknown; }; content: { "application/json": components["schemas"]["Error"]; }; }; - /** @description Internal server error */ - 500: { + /** @description Lock service unavailable */ + 503: { headers: { [name: string]: unknown; }; @@ -21327,430 +22709,252 @@ export interface operations { }; }; }; - regenerateAnonKey: { + renewProjectLock: { parameters: { query?: never; - header?: never; + header: { + /** @description Opaque UUID generated once by the caller and retained for the lease lifetime. */ + "X-Volcano-Lock-Token": components["parameters"]["LockToken"]; + /** + * @description UUID correlating this request across client and server logs. Repeat safety comes from + * the lock token, so a retry under a reused request ID still counts against the quota. + */ + "X-Volcano-Request-Id": components["parameters"]["LockRequestId"]; + }; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - keyId: string; + /** @description Project-local lock name. */ + key: components["parameters"]["LockKey"]; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["ProjectLockLeaseRequest"]; + }; + }; responses: { - /** @description Key regenerated */ + /** @description Lease renewed */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AnonKey"]; + "application/json": components["schemas"]["ProjectLockLease"]; }; }; - }; - }; - setDefaultAnonKey: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - keyId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Key set as default */ - 200: { + /** @description Invalid lock key, token, or TTL */ + 400: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["AnonKey"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Unauthorized */ + /** @description Missing or invalid credentials */ 401: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Forbidden */ + /** @description A non-service credential was supplied or the service key lacks `locks.manage` */ 403: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Anon key not found */ - 404: { + /** @description The lease expired or is owned by another token */ + 409: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - /** @description Internal server error */ - 500: { + /** @description Project lock request limit exceeded */ + 429: { headers: { + /** @description Seconds until the current fixed-minute window ends. */ + "Retry-After"?: number; [name: string]: unknown; }; content: { "application/json": components["schemas"]["Error"]; }; }; - }; - }; - listServiceKeys: { - parameters: { - query?: { - /** - * @description Page number (1-indexed) for offset pagination. Declares no schema - * default so the request validator does not inject one: handlers that omit - * `page` see it unset (nil) and default to 1 in code, while cursor-first - * endpoints (e.g. the project deployments feed) can detect its absence to - * stay in keyset/search mode. Supplying `page` selects offset pagination. - */ - page?: components["parameters"]["Page"]; - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; - /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. - */ - search?: components["parameters"]["Search"]; - }; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Paginated list of service keys */ - 200: { + /** @description Lock service unavailable */ + 503: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["PaginatedServiceKeys"]; + "application/json": components["schemas"]["Error"]; }; }; }; }; - createServiceKey: { + getProjectLock: { parameters: { query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - /** - * @description Descriptive name for the key (e.g., "admin-dashboard", "background-jobs"). - * Can only contain letters, numbers, underscores, and hyphens. - * @example admin-dashboard - */ - name: string; - /** - * @description Optional least-privilege scope for the key. When omitted, empty, or - * containing only blank strings, the key is granted full access (["*"]) - * for backward compatibility. Provide an explicit list (e.g. - * ["functions.invoke", "locks.manage"]) to restrict the key; "*" - * grants everything. Scope enforcement applies to function invocation, - * storage object operations, and project locks. - * @example [ - * "functions.invoke", - * "locks.manage" - * ] - */ - permissions?: string[]; - }; - }; - }; - responses: { - /** @description Service key created - save the key_value immediately! */ - 201: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ServiceKey"]; - }; - }; - /** @description Key with this name already exists */ - 409: { - headers: { - [name: string]: unknown; - }; - content?: never; + header: { + /** + * @description UUID correlating this request across client and server logs. Repeat safety comes from + * the lock token, so a retry under a reused request ID still counts against the quota. + */ + "X-Volcano-Request-Id": components["parameters"]["LockRequestId"]; }; - }; - }; - getServiceKey: { - parameters: { - query?: never; - header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - keyId: string; + /** @description Project-local lock name. */ + key: components["parameters"]["LockKey"]; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Service key details */ + /** @description Current lock state */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ServiceKey"]; + "application/json": components["schemas"]["ProjectLockState"]; }; }; - /** @description Key not found */ - 404: { + /** @description Invalid lock key */ + 400: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - }; - }; - deleteServiceKey: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - keyId: string; + /** @description Missing or invalid credentials */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Key deleted */ - 204: { + /** @description A non-service credential was supplied or the service key lacks `locks.manage` */ + 403: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - }; - }; - regenerateServiceKey: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - keyId: string; + /** @description Project lock request limit exceeded */ + 429: { + headers: { + /** @description Seconds until the current fixed-minute window ends. */ + "Retry-After"?: number; + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Key regenerated - save the new key_value immediately! */ - 200: { + /** @description Lock service unavailable */ + 503: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ServiceKey"]; + "application/json": components["schemas"]["Error"]; }; }; }; }; - listStorageBuckets: { + forceReleaseProjectLock: { parameters: { - query?: { - /** @description Number of items per page (max 100) */ - limit?: components["parameters"]["Limit"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; + query?: never; + header: { /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. + * @description UUID correlating this request across client and server logs. Repeat safety comes from + * the lock token, so a retry under a reused request ID still counts against the quota. */ - search?: components["parameters"]["Search"]; + "X-Volcano-Request-Id": components["parameters"]["LockRequestId"]; }; - header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description Project-local lock name. */ + key: components["parameters"]["LockKey"]; }; cookie?: never; }; requestBody?: never; responses: { - /** - * @description Either the full bucket list (bare array, legacy) or a paginated - * envelope when cursor pagination is requested. - */ - 200: { + /** @description Lock released */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["StorageBucket"][] | components["schemas"]["PaginatedStorageBuckets"]; - }; - }; - }; - }; - createStorageBucket: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["CreateStorageBucketRequest"]; + content?: never; }; - }; - responses: { - /** @description Bucket created */ - 201: { + /** @description Invalid lock key */ + 400: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["StorageBucket"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Bucket already exists */ - 409: { + /** @description Missing or invalid credentials */ + 401: { headers: { [name: string]: unknown; }; - content?: never; - }; - }; - }; - getStorageBucket: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Bucket details */ - 200: { + /** @description A non-service credential was supplied or the service key lacks `locks.manage` */ + 403: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["StorageBucket"]; + "application/json": components["schemas"]["Error"]; }; }; - /** @description Bucket not found */ - 404: { + /** @description Project lock request limit exceeded */ + 429: { headers: { + /** @description Seconds until the current fixed-minute window ends. */ + "Retry-After"?: number; [name: string]: unknown; }; - content?: never; - }; - }; - }; - deleteStorageBucket: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Bucket deleted */ - 200: { + /** @description Lock service unavailable */ + 503: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - updateStorageBucket: { + moveStorageObject: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Storage bucket name */ bucketName: components["parameters"]["BucketName"]; }; @@ -21758,53 +22962,34 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["UpdateStorageBucketRequest"]; + "application/json": components["schemas"]["StorageMoveRequest"]; }; }; responses: { - /** @description Bucket updated */ + /** @description Object moved */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["StorageBucket"]; + "application/json": components["schemas"]["StorageObject"]; }; }; - }; - }; - listStoragePolicies: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description List of policies */ - 200: { + /** @description Access denied by storage policy */ + 403: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["StoragePolicy"][]; - }; + content?: never; }; + 429: components["responses"]["BandwidthCapExceeded"]; }; }; - createStoragePolicy: { + copyStorageObject: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; /** @description Storage bucket name */ bucketName: components["parameters"]["BucketName"]; }; @@ -21812,281 +22997,263 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["CreateStoragePolicyRequest"]; + "application/json": components["schemas"]["StorageCopyRequest"]; }; }; responses: { - /** @description Policy created */ + /** @description Object copied */ 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["StoragePolicy"]; + "application/json": components["schemas"]["StorageObject"]; }; }; - }; - }; - deleteStoragePolicy: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; - policyId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Policy deleted */ - 200: { + /** @description Access denied by storage policy */ + 403: { headers: { [name: string]: unknown; }; content?: never; }; + 429: components["responses"]["BandwidthCapExceeded"]; }; }; - listStorageObjectsAdmin: { + downloadStorageObject: { parameters: { - query?: { - /** @description Filter by owner user ID */ - owner_id?: string; - /** @description Page number (1-based) */ - page?: number; - /** @description Items per page */ - limit?: number; - /** - * @description Opaque keyset pagination cursor from a previous response's `next_cursor` - * — pages forward. Mutually exclusive with `page` and `ending_before`; - * combining them returns 400. When supplied, the request's `search` and - * `limit` must match the values bound to the cursor or the request returns 400. - */ - cursor?: components["parameters"]["Cursor"]; - /** - * @description Opaque keyset pagination cursor from a previous response's `prev_cursor` - * — pages backward (the page immediately preceding this cursor). Mutually - * exclusive with `page` and `cursor`; combining them returns 400. `search` - * and `limit` must match the values bound to the cursor or the request - * returns 400. - */ - ending_before?: components["parameters"]["EndingBefore"]; - /** - * @description Bounded row offset past the keyset anchor named by `cursor` (forward) or - * `ending_before` (backward) — the hybrid jump. Seek to the anchor, then - * skip this many rows within. Used for numbered jump-to-page: from the - * current page, seek to its next/prev cursor and offset the remaining - * pages. Only honored on the cursor pagination path; ignored otherwise. - */ - offset?: components["parameters"]["Offset"]; + query?: never; + header?: { /** - * @description Case-insensitive substring match on the resource `name`. See the - * endpoint description for supported pagination modes. + * @description HTTP Range header for partial downloads. + * Format: bytes=start-end or bytes=start- + * Examples: bytes=0-1023, bytes=1000- */ - search?: components["parameters"]["Search"]; + Range?: string; + /** @description Upload session ID (to get session status instead of downloading) */ + "X-Upload-Session"?: string; }; - header?: never; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; + /** @description Object path within bucket */ + path: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Paginated list of storage objects */ + /** @description File content or session status */ 200: { headers: { + "Content-Type"?: string; + "Content-Length"?: number; + ETag?: string; [name: string]: unknown; }; content: { - "application/json": { - data?: components["schemas"]["StorageObjectWithBucket"][]; - page?: number; - limit?: number; - total?: number; - has_more?: boolean; - /** @description Opaque cursor for the next page (cursor pagination only) */ - next_cursor?: string; - /** @description Opaque cursor for the previous page (cursor pagination only). Send as `ending_before`. */ - prev_cursor?: string; - }; + "application/octet-stream": string; + "application/json": components["schemas"]["UploadSessionStatusResponse"]; }; }; - }; - }; - getStorageStats: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description Partial content (range request) */ + 206: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Storage statistics */ - 200: { + /** @description Invalid Range header format */ + 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["StorageStats"]; + content?: never; + }; + /** @description Access denied by storage policy */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Object or session not found, or session not owned by this credential */ + 404: { + headers: { + [name: string]: unknown; }; + content?: never; }; + 429: components["responses"]["BandwidthCapExceeded"]; }; }; - getRealtimeConfig: { + uploadPart: { parameters: { query?: never; - header?: never; + header: { + /** @description Upload session ID */ + "X-Upload-Session": string; + /** @description Part number (1 to 10000) */ + "X-Part-Number": number; + }; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; + /** @description Object path within bucket */ + path: string; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/octet-stream": string; + }; + }; responses: { - /** @description Realtime configuration */ + /** @description Part uploaded */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["RealtimeConfig"]; + "application/json": components["schemas"]["UploadSessionPart"]; }; }; - /** @description Unauthorized */ - 401: { + /** @description Invalid part number or part data */ + 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; + content?: never; + }; + /** @description Access denied */ + 403: { + headers: { + [name: string]: unknown; }; + content?: never; }; - /** @description Project not found */ + /** @description Session not found or not owned by this credential */ 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - updateRealtimeConfig: { + uploadStorageObject: { parameters: { query?: never; - header?: never; + header?: { + /** @description Upload session ID (for completing resumable uploads) */ + "X-Upload-Session"?: string; + /** @description Set to "true" to complete a resumable upload session */ + "X-Upload-Complete"?: "true"; + }; path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; + /** @description Object path within bucket */ + path: string; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["UpdateRealtimeConfigRequest"]; + "multipart/form-data": { + /** + * Format: binary + * @description File to upload (simple upload) + */ + file: string; + }; + "application/json": components["schemas"]["CreateUploadSessionRequest"]; }; }; responses: { - /** @description Updated realtime configuration */ + /** @description Resumable upload completed (when X-Upload-Complete=true) */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["RealtimeConfig"]; + "application/json": components["schemas"]["CompleteUploadSessionResponse"]; }; }; - /** @description Invalid configuration values */ - 400: { + /** @description File uploaded or session created */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["StorageObject"] | components["schemas"]["CreateUploadSessionResponse"]; }; }; - /** @description Unauthorized */ - 401: { + /** + * @description Bad request. This can occur when: + * - MIME type is not in the bucket's allowed_mime_types list + * - File exceeds the bucket's configured file_size_limit + * - File exceeds the global maximum upload size (5GB) + * - Invalid request body or missing required fields + */ + 400: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - }; - }; - getRealtimeStats: { - parameters: { - query?: never; - header?: never; - path: { - /** @description Project ID */ - id: components["parameters"]["ProjectId"]; + content?: never; }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Realtime statistics */ - 200: { + /** @description Access denied by storage policy */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Resumable upload session not found or not owned by this credential */ + 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["RealtimeStats"]; - }; + content?: never; }; - /** @description Unauthorized */ - 401: { + /** + * @description File size exceeds plan-based limits. This occurs when: + * - File exceeds the plan-based maximum file size (HOBBY or SUPERAGENT tier) + * - Upload would exceed the project's total storage quota + */ + 413: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; + 429: components["responses"]["BandwidthCapExceeded"]; }; }; - listStorageObjects: { + deleteStorageObject: { parameters: { - query?: { - /** @description Filter objects by path prefix */ - prefix?: string; - /** @description Maximum objects to return */ - limit?: number; - /** @description Pagination cursor */ - cursor?: string; + query?: never; + header?: { + /** @description Upload session ID (to abort session instead of deleting file) */ + "X-Upload-Session"?: string; }; - header?: never; path: { /** @description Storage bucket name */ bucketName: components["parameters"]["BucketName"]; + /** @description Object path within bucket */ + path: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description List of objects */ + /** @description Object deleted or session aborted */ 200: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["StorageListResponse"]; - }; + content?: never; }; /** @description Access denied by storage policy */ 403: { @@ -22095,179 +23262,141 @@ export interface operations { }; content?: never; }; + /** @description Object or session not found, or session not owned by this credential */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; 429: components["responses"]["BandwidthCapExceeded"]; }; }; - acquireProjectLock: { + updateStorageObjectVisibility: { parameters: { query?: never; - header: { - /** @description Opaque UUID generated once by the caller and retained for the lease lifetime. */ - "X-Volcano-Lock-Token": components["parameters"]["LockToken"]; - /** - * @description UUID correlating this request across client and server logs. Repeat safety comes from - * the lock token, so a retry under a reused request ID still counts against the quota. - */ - "X-Volcano-Request-Id": components["parameters"]["LockRequestId"]; - }; + header?: never; path: { - /** @description Project-local lock name. */ - key: components["parameters"]["LockKey"]; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; + /** @description Object path within bucket */ + path: string; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["ProjectLockLeaseRequest"]; + "application/json": components["schemas"]["StorageVisibilityRequest"]; }; }; responses: { - /** @description Lease acquired */ - 201: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ProjectLockLease"]; - }; - }; - /** @description Invalid lock key, token, or TTL */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Missing or invalid credentials */ - 401: { + /** @description Visibility updated */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["StorageObject"]; }; }; - /** @description A non-service credential was supplied or the service key lacks `locks.manage` */ + /** @description Not the file owner or denied by the bucket's UPDATE policies */ 403: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** - * @description The lock is held by another live lease (`lock_held`), or the caller's own lease - * lapsed and is not yet reclaimable (`lock_ownership_lost`). - */ - 409: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; - }; - /** @description Project lock request limit exceeded */ - 429: { - headers: { - /** @description Seconds until the current fixed-minute window ends. */ - "Retry-After"?: number; - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description Lock service unavailable */ - 503: { + /** @description Object not found */ + 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; }; }; - releaseProjectLock: { + downloadPublicFile: { parameters: { query?: never; - header: { - /** @description Opaque UUID generated once by the caller and retained for the lease lifetime. */ - "X-Volcano-Lock-Token": components["parameters"]["LockToken"]; - /** - * @description UUID correlating this request across client and server logs. Repeat safety comes from - * the lock token, so a retry under a reused request ID still counts against the quota. - */ - "X-Volcano-Request-Id": components["parameters"]["LockRequestId"]; - }; + header?: never; path: { - /** @description Project-local lock name. */ - key: components["parameters"]["LockKey"]; + /** @description Project ID */ + projectId: string; + /** @description Storage bucket name */ + bucketName: components["parameters"]["BucketName"]; + /** @description Object path within bucket */ + path: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Lease released */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Invalid lock key or token */ - 400: { + /** @description File content */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "*/*": string; }; }; - /** @description Missing or invalid credentials */ - 401: { + /** @description Partial content (range request) */ + 206: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description A non-service credential was supplied or the service key lacks `locks.manage` */ - 403: { + /** @description Not found (file doesn't exist or is not public) */ + 404: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["Error"]; - }; + content?: never; }; - /** @description The lease is owned by another token */ - 409: { + 429: components["responses"]["BandwidthCapExceeded"]; + }; + }; + healthCheck: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Server is healthy */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "text/plain": string; }; }; - /** @description Project lock request limit exceeded */ - 429: { + }; + }; + listSandboxPresets: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List available sandbox presets */ + 200: { headers: { - /** @description Seconds until the current fixed-minute window ends. */ - "Retry-After"?: number; [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["SandboxPresetList"]; }; }; - /** @description Lock service unavailable */ - 503: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; @@ -22277,50 +23406,38 @@ export interface operations { }; }; }; - renewProjectLock: { + listSandboxes: { parameters: { - query?: never; - header: { - /** @description Opaque UUID generated once by the caller and retained for the lease lifetime. */ - "X-Volcano-Lock-Token": components["parameters"]["LockToken"]; + query?: { + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; /** - * @description UUID correlating this request across client and server logs. Repeat safety comes from - * the lock token, so a retry under a reused request ID still counts against the quota. + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. */ - "X-Volcano-Request-Id": components["parameters"]["LockRequestId"]; + cursor?: components["parameters"]["Cursor"]; }; + header?: never; path: { - /** @description Project-local lock name. */ - key: components["parameters"]["LockKey"]; + id: string; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["ProjectLockLeaseRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Lease renewed */ + /** @description List sandbox templates */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ProjectLockLease"]; - }; - }; - /** @description Invalid lock key, token, or TTL */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["SandboxTemplatePage"]; }; }; - /** @description Missing or invalid credentials */ - 401: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; @@ -22328,17 +23445,36 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description A non-service credential was supplied or the service key lacks `locks.manage` */ - 403: { + }; + }; + createSandbox: { + parameters: { + query?: never; + header: { + "Idempotency-Key": string; + }; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateSandboxTemplateRequest"]; + }; + }; + responses: { + /** @description Create a sandbox template from a verified preset */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["SandboxTemplate"]; }; }; - /** @description The lease expired or is owned by another token */ - 409: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; @@ -22346,19 +23482,31 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project lock request limit exceeded */ - 429: { + }; + }; + getSandbox: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + sandboxId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Get a sandbox template */ + 200: { headers: { - /** @description Seconds until the current fixed-minute window ends. */ - "Retry-After"?: number; [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["SandboxTemplate"]; }; }; - /** @description Lock service unavailable */ - 503: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; @@ -22368,35 +23516,27 @@ export interface operations { }; }; }; - getProjectLock: { + deleteSandbox: { parameters: { query?: never; - header: { - /** - * @description UUID correlating this request across client and server logs. Repeat safety comes from - * the lock token, so a retry under a reused request ID still counts against the quota. - */ - "X-Volcano-Request-Id": components["parameters"]["LockRequestId"]; - }; + header?: never; path: { - /** @description Project-local lock name. */ - key: components["parameters"]["LockKey"]; + id: string; + sandboxId: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Current lock state */ - 200: { + /** @description Retire a template and terminate its sessions */ + 202: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["ProjectLockState"]; - }; + content?: never; }; - /** @description Invalid lock key */ - 400: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; @@ -22404,17 +23544,35 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Missing or invalid credentials */ - 401: { + }; + }; + updateSandbox: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + sandboxId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateSandboxTemplateRequest"]; + }; + }; + responses: { + /** @description Rename a sandbox template */ + 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["SandboxTemplate"]; }; }; - /** @description A non-service credential was supplied or the service key lacks `locks.manage` */ - 403: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; @@ -22422,19 +23580,41 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project lock request limit exceeded */ - 429: { + }; + }; + listSandboxDeployments: { + parameters: { + query?: { + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; + /** + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. + */ + cursor?: components["parameters"]["Cursor"]; + }; + header?: never; + path: { + id: string; + sandboxId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List sandbox deployment history */ + 200: { headers: { - /** @description Seconds until the current fixed-minute window ends. */ - "Retry-After"?: number; [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["SandboxDeploymentPage"]; }; }; - /** @description Lock service unavailable */ - 503: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; @@ -22444,33 +23624,38 @@ export interface operations { }; }; }; - forceReleaseProjectLock: { + listSandboxSessions: { parameters: { - query?: never; - header: { + query?: { + /** @description Number of items per page (max 100) */ + limit?: components["parameters"]["Limit"]; /** - * @description UUID correlating this request across client and server logs. Repeat safety comes from - * the lock token, so a retry under a reused request ID still counts against the quota. + * @description Opaque keyset pagination cursor from a previous response's `next_cursor` + * — pages forward. Mutually exclusive with `page` and `ending_before`; + * combining them returns 400. When supplied, the request's `search` and + * `limit` must match the values bound to the cursor or the request returns 400. */ - "X-Volcano-Request-Id": components["parameters"]["LockRequestId"]; + cursor?: components["parameters"]["Cursor"]; }; + header?: never; path: { - /** @description Project-local lock name. */ - key: components["parameters"]["LockKey"]; + id: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description Lock released */ - 204: { + /** @description List project sandbox sessions */ + 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["SandboxSessionPage"]; + }; }; - /** @description Invalid lock key */ - 400: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; @@ -22478,17 +23663,36 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Missing or invalid credentials */ - 401: { + }; + }; + createSandboxSession: { + parameters: { + query?: never; + header: { + "Idempotency-Key": string; + }; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateSandboxSessionRequest"]; + }; + }; + responses: { + /** @description Start a sandbox session */ + 201: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["SandboxSession"]; }; }; - /** @description A non-service credential was supplied or the service key lacks `locks.manage` */ - 403: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; @@ -22496,19 +23700,36 @@ export interface operations { "application/json": components["schemas"]["Error"]; }; }; - /** @description Project lock request limit exceeded */ - 429: { + }; + }; + executeSandbox: { + parameters: { + query?: never; + header: { + "Idempotency-Key": string; + }; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["SandboxExecutionRequest"]; + }; + }; + responses: { + /** @description Execute once and return after confirmed termination */ + 200: { headers: { - /** @description Seconds until the current fixed-minute window ends. */ - "Retry-After"?: number; [name: string]: unknown; }; content: { - "application/json": components["schemas"]["Error"]; + "application/json": components["schemas"]["SandboxExecutionResult"]; }; }; - /** @description Lock service unavailable */ - 503: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; @@ -22518,429 +23739,330 @@ export interface operations { }; }; }; - moveStorageObject: { + getSandboxSession: { parameters: { query?: never; header?: never; path: { - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; + sessionId: string; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["StorageMoveRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Object moved */ + /** @description Get a sandbox session */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["StorageObject"]; + "application/json": components["schemas"]["SandboxSession"]; }; }; - /** @description Access denied by storage policy */ - 403: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - 429: components["responses"]["BandwidthCapExceeded"]; }; }; - copyStorageObject: { + terminateSandboxSession: { parameters: { query?: never; header?: never; path: { - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; + sessionId: string; }; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["StorageCopyRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Object copied */ - 201: { + /** @description Request sandbox termination */ + 202: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["StorageObject"]; + "application/json": components["schemas"]["SandboxSession"]; }; }; - /** @description Access denied by storage policy */ - 403: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - 429: components["responses"]["BandwidthCapExceeded"]; }; }; - downloadStorageObject: { + suspendSandboxSession: { parameters: { - query?: never; - header?: { - /** - * @description HTTP Range header for partial downloads. - * Format: bytes=start-end or bytes=start- - * Examples: bytes=0-1023, bytes=1000- - */ - Range?: string; - /** @description Upload session ID (to get session status instead of downloading) */ - "X-Upload-Session"?: string; - }; - path: { - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; - /** @description Object path within bucket */ - path: string; + query?: never; + header?: never; + path: { + sessionId: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description File content or session status */ - 200: { + /** @description Suspend a sandbox session */ + 202: { headers: { - "Content-Type"?: string; - "Content-Length"?: number; - ETag?: string; [name: string]: unknown; }; content: { - "application/octet-stream": string; - "application/json": components["schemas"]["UploadSessionStatusResponse"]; + "application/json": components["schemas"]["SandboxSession"]; }; }; - /** @description Partial content (range request) */ - 206: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; - content?: never; - }; - /** @description Invalid Range header format */ - 400: { - headers: { - [name: string]: unknown; + content: { + "application/json": components["schemas"]["Error"]; }; - content?: never; }; - /** @description Access denied by storage policy */ - 403: { + }; + }; + resumeSandboxSession: { + parameters: { + query?: never; + header?: never; + path: { + sessionId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Resume a sandbox session */ + 202: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["SandboxSession"]; + }; }; - /** @description Object or session not found, or session not owned by this credential */ - 404: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - 429: components["responses"]["BandwidthCapExceeded"]; }; }; - uploadPart: { + executeSandboxSession: { parameters: { query?: never; header: { - /** @description Upload session ID */ - "X-Upload-Session": string; - /** @description Part number (1 to 10000) */ - "X-Part-Number": number; + "Idempotency-Key": string; }; path: { - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; - /** @description Object path within bucket */ - path: string; + sessionId: string; }; cookie?: never; }; requestBody: { content: { - "application/octet-stream": string; + "application/json": components["schemas"]["SandboxCommandRequest"]; }; }; responses: { - /** @description Part uploaded */ + /** @description Execute a command within a session */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["UploadSessionPart"]; + "application/json": components["schemas"]["SandboxCommandResult"]; }; }; - /** @description Invalid part number or part data */ - 400: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Access denied */ - 403: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; - content?: never; - }; - /** @description Session not found or not owned by this credential */ - 404: { - headers: { - [name: string]: unknown; + content: { + "application/json": components["schemas"]["Error"]; }; - content?: never; }; }; }; - uploadStorageObject: { + readSandboxSessionFile: { parameters: { query?: never; - header?: { - /** @description Upload session ID (for completing resumable uploads) */ - "X-Upload-Session"?: string; - /** @description Set to "true" to complete a resumable upload session */ - "X-Upload-Complete"?: "true"; - }; + header?: never; path: { - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; - /** @description Object path within bucket */ - path: string; + sessionId: string; }; cookie?: never; }; requestBody: { content: { - "multipart/form-data": { - /** - * Format: binary - * @description File to upload (simple upload) - */ - file: string; - }; - "application/json": components["schemas"]["CreateUploadSessionRequest"]; + "application/json": components["schemas"]["SandboxFileReadRequest"]; }; }; responses: { - /** @description Resumable upload completed (when X-Upload-Complete=true) */ + /** @description Read a workspace file */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["CompleteUploadSessionResponse"]; + "application/json": components["schemas"]["SandboxFileResult"]; }; }; - /** @description File uploaded or session created */ - 201: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["StorageObject"] | components["schemas"]["CreateUploadSessionResponse"]; - }; - }; - /** - * @description Bad request. This can occur when: - * - MIME type is not in the bucket's allowed_mime_types list - * - File exceeds the bucket's configured file_size_limit - * - File exceeds the global maximum upload size (5GB) - * - Invalid request body or missing required fields - */ - 400: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Access denied by storage policy */ - 403: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Resumable upload session not found or not owned by this credential */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** - * @description File size exceeds plan-based limits. This occurs when: - * - File exceeds the plan-based maximum file size (HOBBY or SUPERAGENT tier) - * - Upload would exceed the project's total storage quota - */ - 413: { - headers: { - [name: string]: unknown; + "application/json": components["schemas"]["Error"]; }; - content?: never; }; - 429: components["responses"]["BandwidthCapExceeded"]; }; }; - deleteStorageObject: { + writeSandboxSessionFile: { parameters: { query?: never; - header?: { - /** @description Upload session ID (to abort session instead of deleting file) */ - "X-Upload-Session"?: string; - }; + header?: never; path: { - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; - /** @description Object path within bucket */ - path: string; + sessionId: string; }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["SandboxFileWriteRequest"]; + }; + }; responses: { - /** @description Object deleted or session aborted */ - 200: { + /** @description Write a workspace file */ + 204: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Access denied by storage policy */ - 403: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; - content?: never; - }; - /** @description Object or session not found, or session not owned by this credential */ - 404: { - headers: { - [name: string]: unknown; + content: { + "application/json": components["schemas"]["Error"]; }; - content?: never; }; - 429: components["responses"]["BandwidthCapExceeded"]; }; }; - updateStorageObjectVisibility: { + grantSandboxSession: { parameters: { query?: never; header?: never; path: { - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; - /** @description Object path within bucket */ - path: string; + sessionId: string; + subjectId: string; }; cookie?: never; }; requestBody: { content: { - "application/json": components["schemas"]["StorageVisibilityRequest"]; + "application/json": components["schemas"]["SandboxSubjectGrantRequest"]; }; }; responses: { - /** @description Visibility updated */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["StorageObject"]; - }; - }; - /** @description Not the file owner or denied by the bucket's UPDATE policies */ - 403: { + /** @description Authorize an authenticated project user for this session */ + 204: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Object not found */ - 404: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; }; }; - downloadPublicFile: { + revokeSandboxSession: { parameters: { query?: never; header?: never; path: { - /** @description Project ID */ - projectId: string; - /** @description Storage bucket name */ - bucketName: components["parameters"]["BucketName"]; - /** @description Object path within bucket */ - path: string; + sessionId: string; + subjectId: string; }; cookie?: never; }; requestBody?: never; responses: { - /** @description File content */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "*/*": string; - }; - }; - /** @description Partial content (range request) */ - 206: { + /** @description Revoke a project user session grant */ + 204: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Not found (file doesn't exist or is not public) */ - 404: { + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["Error"]; + }; }; - 429: components["responses"]["BandwidthCapExceeded"]; }; }; - healthCheck: { + createSandboxSessionAccess: { parameters: { query?: never; header?: never; - path?: never; + path: { + sessionId: string; + }; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["SandboxAccessRequest"]; + }; + }; responses: { - /** @description Server is healthy */ + /** @description Issue a short-lived port-scoped access credential */ 200: { headers: { [name: string]: unknown; }; content: { - "text/plain": string; + "application/json": components["schemas"]["SandboxAccess"]; + }; + }; + /** @description Request refused or unavailable. Errors include invalid input (400), unauthenticated (401), forbidden (403), not found (404), conflicting retry (409), capacity exhausted (429), and disabled or unavailable (503). */ + default: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Error"]; }; }; }; diff --git a/src/sandbox-request.ts b/src/sandbox-request.ts new file mode 100644 index 00000000..7172a31e --- /dev/null +++ b/src/sandbox-request.ts @@ -0,0 +1,79 @@ +import type { executeSandbox } from './generated/client.ts'; +import type { SandboxCommandOptions, SandboxReplayOptions, SandboxResult } from './index.ts'; + +type TransportOptions = NonNullable[2]>; +export interface SandboxClient { + readonly timeout: number; + _completeOAuthExchange(): Promise; + _generatedOptions( + mode: 'anon' | 'session', + headers?: Record, + responseType?: 'blob', + timeoutMs?: number, + ): TransportOptions; +} +export function pathId(value: string): string { + if (!/^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/i.test(value)) { + throw new TypeError('A Sandbox resource ID must be a UUID'); + } + return encodeURIComponent(value); +} +export function requestOptions( + client: SandboxClient, + options: SandboxReplayOptions = {}, + mode?: 'anon' | 'session' | 'replayable', + timeoutMs?: number, +): TransportOptions { + const result = client._generatedOptions( + mode === 'anon' ? 'anon' : 'session', + mutationHeaders(options, mode === 'replayable'), + undefined, + timeoutMs, + ); + if (options.signal !== undefined) { + result.signal = options.signal; + } + return result; +} +function mutationHeaders(options: SandboxReplayOptions, mutating: boolean): Record { + if (!mutating) { + return {}; + } + const id = options.requestId ?? crypto.randomUUID(); + pathId(id); + return { 'Idempotency-Key': id }; +} + +export function commandRequest( + command: string, + options: SandboxCommandOptions, +): import('./generated/model/sandboxCommandRequest.ts').SandboxCommandRequest { + return { + command, + ...(options.timeoutSeconds === undefined ? {} : { timeout_seconds: options.timeoutSeconds }), + ...(options.environment === undefined ? {} : { environment: options.environment }), + }; +} +export async function sandboxResult(operation: () => Promise): Promise> { + try { + return { data: await operation(), error: null }; + } catch (error) { + return { + data: null, + error: error instanceof Error ? error : new Error('Sandbox request failed'), + }; + } +} + +export async function responseData(request: Promise<{ data: unknown }>): Promise { + const response = await request; + return response.data; +} + +export function executionRequestOptions( + client: SandboxClient, + options: SandboxCommandOptions, +): TransportOptions { + const timeoutMs = Math.max(client.timeout, ((options.timeoutSeconds ?? 60) + 120) * 1000); + return requestOptions(client, options, 'replayable', timeoutMs); +} diff --git a/src/sandbox-session.ts b/src/sandbox-session.ts new file mode 100644 index 00000000..10b4c72e --- /dev/null +++ b/src/sandbox-session.ts @@ -0,0 +1,157 @@ +import { + createSandboxSessionAccess, + executeSandboxSession, + getSandboxSession, + readSandboxSessionFile, + resumeSandboxSession, + suspendSandboxSession, + terminateSandboxSession, + writeSandboxSessionFile, +} from './generated/client.ts'; +import type { + SandboxCommandOptions, + SandboxRequestOptions, + SandboxSession, + SandboxState, +} from './index.ts'; +import { + commandRequest, + executionRequestOptions, + pathId, + requestOptions, + responseData, + type SandboxClient, + sandboxResult, +} from './sandbox-request.ts'; +import { + accessResult, + commandResult, + decodeBytes, + encodeBytes, + record, + sessionState, + text, +} from './sandbox-wire.ts'; + +export class SandboxSessionHandle implements SandboxSession { + readonly id: string; + readonly projectId: string; + readonly region: string; + state: SandboxState; + expiresAt: string; + readonly files; + constructor( + private readonly client: SandboxClient, + value: unknown, + ) { + const data = record(value); + this.id = text(data['id']); + this.projectId = text(data['project_id']); + this.region = text(data['region']); + this.state = sessionState(data['state']); + this.expiresAt = text(data['expires_at']); + this.files = { read: this.read.bind(this), write: this.write.bind(this) }; + } + private update(value: unknown): this { + const data = record(value); + if (data['id'] !== this.id) { + throw new TypeError('Sandbox session identity changed'); + } + this.state = sessionState(data['state']); + this.expiresAt = text(data['expires_at']); + return this; + } + refresh(options: SandboxRequestOptions = {}): ReturnType { + return sandboxResult(async () => + this.update( + await responseData( + getSandboxSession(pathId(this.id), requestOptions(this.client, options)), + ), + ), + ); + } + exec(command: string, options: SandboxCommandOptions = {}): ReturnType { + return sandboxResult(async () => + commandResult( + await responseData( + executeSandboxSession( + pathId(this.id), + commandRequest(command, options), + executionRequestOptions(this.client, options), + ), + ), + ), + ); + } + suspend(options: SandboxRequestOptions = {}): ReturnType { + return sandboxResult(async () => + this.update( + await responseData( + suspendSandboxSession(pathId(this.id), requestOptions(this.client, options)), + ), + ), + ); + } + resume(options: SandboxRequestOptions = {}): ReturnType { + return sandboxResult(async () => + this.update( + await responseData( + resumeSandboxSession(pathId(this.id), requestOptions(this.client, options)), + ), + ), + ); + } + terminate(options: SandboxRequestOptions = {}): ReturnType { + return sandboxResult(async () => + this.update( + await responseData( + terminateSandboxSession(pathId(this.id), requestOptions(this.client, options)), + ), + ), + ); + } + access(port: number, options: SandboxRequestOptions = {}): ReturnType { + return sandboxResult(async () => + accessResult( + await responseData( + createSandboxSessionAccess( + pathId(this.id), + { port }, + requestOptions(this.client, options), + ), + ), + ), + ); + } + async [Symbol.asyncDispose](): Promise { + if (this.state === 'terminated' || this.state === 'terminating') { + return; + } + const result = await this.terminate(); + if (result.error !== null && !isMissingSession(result.error)) { + throw result.error; + } + } + private read(path: string, options: SandboxRequestOptions = {}) { + return sandboxResult(async () => + decodeBytes( + await responseData( + readSandboxSessionFile(pathId(this.id), { path }, requestOptions(this.client, options)), + ), + ), + ); + } + private write(path: string, data: Uint8Array, options: SandboxRequestOptions = {}) { + return sandboxResult(async () => { + await writeSandboxSessionFile( + pathId(this.id), + { path, data: encodeBytes(data) }, + requestOptions(this.client, options), + ); + }); + } +} + +function isMissingSession(error: Error): boolean { + return 'status' in error && error.status === 404; +} diff --git a/src/sandbox-wire.ts b/src/sandbox-wire.ts new file mode 100644 index 00000000..7b2a9e21 --- /dev/null +++ b/src/sandbox-wire.ts @@ -0,0 +1,150 @@ +import type { + SandboxAccess, + SandboxCommandResult, + SandboxCreateOptions, + SandboxExecutionResult, + SandboxPreset, + SandboxState, +} from './index.ts'; + +export function record(value: unknown): Record { + if (!isRecord(value)) { + throw new TypeError('Invalid Sandbox response'); + } + return value; +} +export function text(value: unknown): string { + if (typeof value !== 'string') { + throw new TypeError('Invalid Sandbox text field'); + } + return value; +} +function number(value: unknown): number { + if (!Number.isFinite(value)) { + throw new TypeError('Invalid Sandbox numeric field'); + } + return Number(value); +} +function flag(value: unknown): boolean { + if (typeof value !== 'boolean') { + throw new TypeError('Invalid Sandbox flag'); + } + return value; +} +export function commandResult(value: unknown): SandboxCommandResult { + const data = record(value); + return { + stdout: text(data['stdout']), + stderr: text(data['stderr']), + exitCode: number(data['exit_code']), + timedOut: flag(data['timed_out']), + stdoutTruncated: flag(data['stdout_truncated']), + stderrTruncated: flag(data['stderr_truncated']), + }; +} +export function executionResult(value: unknown): SandboxExecutionResult { + const data = record(value); + return { + ...commandResult(data), + sessionId: text(data['session_id']), + region: text(data['region']), + durationMs: number(data['duration_ms']), + }; +} +const states: readonly SandboxState[] = [ + 'starting', + 'running', + 'suspending', + 'suspended', + 'resuming', + 'terminating', + 'terminated', + 'unknown', +]; +export function sessionState(value: unknown): SandboxState { + const result = states.find((state) => state === value); + if (result === undefined) { + throw new TypeError('Invalid Sandbox state'); + } + return result; +} +export function createRequest( + options: SandboxCreateOptions, +): import('./generated/model/createSandboxSessionRequest.ts').CreateSandboxSessionRequest { + if ((options.preset === undefined) === (options.sandboxId === undefined)) { + throw new TypeError('Choose exactly one preset or sandboxId'); + } + return { + region: options.region, + ...(options.preset === undefined ? {} : { preset: options.preset }), + ...(options.sandboxId === undefined ? {} : { sandbox_id: options.sandboxId }), + ...(options.memoryMB === undefined ? {} : { memory_mb: presetMemory(options.memoryMB) }), + }; +} +export function accessResult(value: unknown): SandboxAccess { + const data = record(value); + const access = { + url: text(data['url']), + token: text(data['token']), + expiresAt: text(data['expires_at']), + }; + Object.defineProperty(access, 'token', { enumerable: false }); + return access; +} +export function presetsResult(value: unknown): SandboxPreset[] { + const data = record(value); + if (!Array.isArray(data['data'])) { + throw new TypeError('Invalid Sandbox preset catalog'); + } + return data['data'].map((value: unknown) => { + const preset = record(value); + if (!Array.isArray(preset['regions'])) { + throw new TypeError('Invalid Sandbox regions'); + } + return { + id: text(preset['id']), + memoryMB: number(preset['memory_mb']), + regions: preset['regions'].map((region: unknown) => text(region)), + }; + }); +} +export function decodeBytes(value: unknown): Uint8Array { + return Uint8Array.from(atob(text(record(value)['data'])), (character) => + Number(character.codePointAt(0)), + ); +} +export function encodeBytes(data: Uint8Array): string { + if (data.byteLength > 8 * 1024 * 1024) { + throw new RangeError('Sandbox files are limited to 8 MiB'); + } + let binary = ''; + for (const byte of data) { + binary += String.fromCodePoint(byte); + } + return btoa(binary); +} + +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +export function sessionRequest( + options: SandboxCreateOptions, +): import('./generated/model/createSandboxSessionRequest.ts').CreateSandboxSessionRequest { + return { + ...createRequest(options), + ...(options.maxDurationSeconds === undefined + ? {} + : { max_duration_seconds: options.maxDurationSeconds }), + ...(options.idleTimeoutSeconds === undefined + ? {} + : { idle_timeout_seconds: options.idleTimeoutSeconds }), + }; +} + +function presetMemory(value: number): 1024 | 2048 { + if (value !== 1024 && value !== 2048) { + throw new RangeError('Sandbox memory must be 1024 or 2048 MB'); + } + return value; +} diff --git a/src/sandboxes.ts b/src/sandboxes.ts new file mode 100644 index 00000000..15ecf5f5 --- /dev/null +++ b/src/sandboxes.ts @@ -0,0 +1,102 @@ +import { + createSandboxSession, + executeSandbox, + getSandboxSession, + grantSandboxSession, + listSandboxPresets, + revokeSandboxSession, +} from './generated/client.ts'; +import type { + SandboxCreateOptions, + Sandboxes, + SandboxExecOptions, + SandboxRequestOptions, +} from './index.ts'; +import { + commandRequest, + executionRequestOptions, + pathId, + requestOptions, + responseData, + type SandboxClient, + sandboxResult, +} from './sandbox-request.ts'; +import { SandboxSessionHandle } from './sandbox-session.ts'; +import { createRequest, executionResult, presetsResult, sessionRequest } from './sandbox-wire.ts'; + +export class SandboxesApi implements Sandboxes { + constructor(private readonly client: SandboxClient) {} + presets(options: SandboxRequestOptions = {}): ReturnType { + return sandboxResult(async () => + presetsResult( + await responseData(listSandboxPresets(requestOptions(this.client, options, 'anon'))), + ), + ); + } + exec( + projectId: string, + command: string, + options: SandboxExecOptions, + ): ReturnType { + return sandboxResult(async () => { + await this.client._completeOAuthExchange(); + const response = await executeSandbox( + pathId(projectId), + { ...createRequest(options), ...commandRequest(command, options) }, + executionRequestOptions(this.client, options), + ); + return executionResult(response.data); + }); + } + create(projectId: string, options: SandboxCreateOptions): ReturnType { + return sandboxResult(async () => { + await this.client._completeOAuthExchange(); + const body = sessionRequest(options); + const response = await createSandboxSession( + pathId(projectId), + body, + requestOptions(this.client, options, 'replayable'), + ); + return new SandboxSessionHandle(this.client, response.data); + }); + } + get(sessionId: string, options: SandboxRequestOptions = {}): ReturnType { + return sandboxResult( + async () => + new SandboxSessionHandle( + this.client, + await responseData( + getSandboxSession(pathId(sessionId), requestOptions(this.client, options)), + ), + ), + ); + } + grant( + sessionId: string, + authUserId: string, + expiresAt: string, + options: SandboxRequestOptions = {}, + ): ReturnType { + return sandboxResult(async () => { + await grantSandboxSession( + pathId(sessionId), + pathId(authUserId), + { expires_at: expiresAt }, + requestOptions(this.client, options), + ); + }); + } + revoke( + sessionId: string, + authUserId: string, + options: SandboxRequestOptions = {}, + ): ReturnType { + return sandboxResult(async () => { + await revokeSandboxSession( + pathId(sessionId), + pathId(authUserId), + requestOptions(this.client, options), + ); + }); + } +} diff --git a/src/sdk-public-types.ts b/src/sdk-public-types.ts index b7759c29..f2a0fd56 100644 --- a/src/sdk-public-types.ts +++ b/src/sdk-public-types.ts @@ -1,3 +1,4 @@ +/// import type { FilterValue } from './database-filters'; import type { FunctionInvokeResponse } from './function-invoke.ts'; export type { FilterValue } from './database-filters'; @@ -21,6 +22,8 @@ export type PaginatedDurableExecutions = GeneratedComponents['schemas']['PaginatedDurableExecutions']; export interface VolcanoAuthConfig { + /** HTTP request timeout in milliseconds. Sandbox execution may extend this budget. */ + timeout?: number; /** * Your Volcano API base URL. * Defaults to 'https://api.volcano.dev' if not specified. @@ -1063,3 +1066,106 @@ export interface RealtimeModule { VolcanoRealtime: typeof import('./realtime').VolcanoRealtime; RealtimeChannel: typeof import('./realtime').RealtimeChannel; } + +export type SandboxResult = { data: T; error: null } | { data: null; error: Error }; +export interface SandboxRequestOptions { + signal?: AbortSignal; +} +export interface SandboxReplayOptions extends SandboxRequestOptions { + requestId?: string; +} +export interface SandboxSelectionOptions extends SandboxReplayOptions { + preset?: string; + sandboxId?: string; + region: string; + memoryMB?: number; +} +export interface SandboxCreateOptions extends SandboxSelectionOptions { + maxDurationSeconds?: number; + idleTimeoutSeconds?: number; +} +export interface SandboxExecOptions extends SandboxSelectionOptions { + timeoutSeconds?: number; + environment?: Record; +} +export interface SandboxCommandOptions extends SandboxReplayOptions { + timeoutSeconds?: number; + environment?: Record; +} +export interface SandboxCommandResult { + stdout: string; + stderr: string; + exitCode: number; + timedOut: boolean; + stdoutTruncated: boolean; + stderrTruncated: boolean; +} +export interface SandboxExecutionResult extends SandboxCommandResult { + sessionId: string; + region: string; + durationMs: number; +} +export type SandboxState = + | 'starting' + | 'running' + | 'suspending' + | 'suspended' + | 'resuming' + | 'terminating' + | 'terminated' + | 'unknown'; +export interface SandboxAccess { + url: string; + token: string; + expiresAt: string; +} +export interface SandboxSession extends AsyncDisposable { + readonly id: string; + readonly projectId: string; + readonly region: string; + readonly state: SandboxState; + readonly expiresAt: string; + refresh(options?: SandboxRequestOptions): Promise>; + exec( + command: string, + options?: SandboxCommandOptions, + ): Promise>; + suspend(options?: SandboxRequestOptions): Promise>; + resume(options?: SandboxRequestOptions): Promise>; + terminate(options?: SandboxRequestOptions): Promise>; + access(port: number, options?: SandboxRequestOptions): Promise>; + files: { + read(path: string, options?: SandboxRequestOptions): Promise>; + write( + path: string, + data: Uint8Array, + options?: SandboxRequestOptions, + ): Promise>; + }; +} +export interface SandboxPreset { + id: string; + memoryMB: number; + regions: string[]; +} +export interface Sandboxes { + presets(options?: SandboxRequestOptions): Promise>; + exec( + projectId: string, + command: string, + options: SandboxExecOptions, + ): Promise>; + create(projectId: string, options: SandboxCreateOptions): Promise>; + get(sessionId: string, options?: SandboxRequestOptions): Promise>; + grant( + sessionId: string, + authUserId: string, + expiresAt: string, + options?: SandboxRequestOptions, + ): Promise>; + revoke( + sessionId: string, + authUserId: string, + options?: SandboxRequestOptions, + ): Promise>; +} diff --git a/src/volcano-auth.ts b/src/volcano-auth.ts index 3ba45bde..1932a737 100644 --- a/src/volcano-auth.ts +++ b/src/volcano-auth.ts @@ -127,6 +127,7 @@ import { import { isBrowser } from './next/request.ts'; import { ProjectLocksApi } from './project-locks.ts'; import { logActivityResult, logSearchResult } from './project-logs.ts'; +import { SandboxesApi } from './sandboxes.ts'; import type { Auth, Durable, @@ -136,6 +137,7 @@ import type { MutationBuilder as PublicMutationBuilder, ProjectLocks, QueryBuilder as PublicQueryBuilder, + Sandboxes, Storage, StorageFileApi as PublicStorageFileApi, User, @@ -280,6 +282,7 @@ class VolcanoAuth { logs: Logs; storage: Storage; locks: ProjectLocks; + sandboxes: Sandboxes; constructor(config: VolcanoAuthConfig); constructor( @@ -388,6 +391,7 @@ class VolcanoAuth { }; this.locks = new ProjectLocksApi(this); + this.sandboxes = new SandboxesApi(this); } /** @internal */ @@ -508,17 +512,20 @@ class VolcanoAuth { volcanoAuthorization: 'anon' | 'session', headers?: Record, responseType?: 'blob', + timeoutMs?: number, ): { volcanoAuthorization: 'anon' | 'session'; volcanoClient: VolcanoAuth; headers?: Record; volcanoResponseType?: 'blob'; + volcanoTimeoutMs?: number; } { return { volcanoAuthorization, volcanoClient: this, ...(headers === undefined ? {} : { headers }), ...(responseType === undefined ? {} : { volcanoResponseType: responseType }), + ...(timeoutMs === undefined ? {} : { volcanoTimeoutMs: timeoutMs }), }; } @@ -527,6 +534,7 @@ class VolcanoAuth { path: string, options: RequestInit, authorization: 'anon' | 'session', + timeoutMs = this.timeout, ): Promise { const url = `${this.apiUrl}${path}`; if (authorization === 'anon') { @@ -540,11 +548,11 @@ class VolcanoAuth { ...options, headers, }, - this.timeout, + timeoutMs, ); } - return fetchWithAuthRetry(this, url, options); + return fetchWithAuthRetry(this, url, options, timeoutMs); } /** @internal */ diff --git a/src/volcano-fetch.ts b/src/volcano-fetch.ts index fad17c6b..37d1c624 100644 --- a/src/volcano-fetch.ts +++ b/src/volcano-fetch.ts @@ -5,6 +5,7 @@ interface GeneratedTransportClient { path: string, options: RequestInit, authorization: GeneratedAuthorization, + timeoutMs?: number, ): Promise; } @@ -12,6 +13,7 @@ export interface VolcanoRequestInit extends RequestInit { volcanoAuthorization?: GeneratedAuthorization; volcanoClient?: GeneratedTransportClient; volcanoResponseType?: 'blob'; + volcanoTimeoutMs?: number; } async function readBody(response: Response): Promise { @@ -75,11 +77,17 @@ function errorMessage(status: number, data: unknown): string { } export async function volcanoFetch(path: string, options: VolcanoRequestInit): Promise { - const { volcanoAuthorization, volcanoClient, volcanoResponseType, ...request } = options; + const { volcanoAuthorization, volcanoClient, volcanoResponseType, volcanoTimeoutMs, ...request } = + options; if (volcanoClient === undefined || volcanoAuthorization === undefined) { throw new Error('Generated transport requires a Volcano client and authorization mode'); } - const response = await volcanoClient._generatedFetch(path, request, volcanoAuthorization); + const response = await volcanoClient._generatedFetch( + path, + request, + volcanoAuthorization, + volcanoTimeoutMs, + ); const data = await responseData(response, volcanoResponseType); if (!response.ok) { diff --git a/test/fixtures/published-api.d.ts b/test/fixtures/published-api.d.ts index 8281ae0d..aa1559d0 100644 --- a/test/fixtures/published-api.d.ts +++ b/test/fixtures/published-api.d.ts @@ -1,4 +1,4 @@ -// Frozen main 3ec5cf3 API with the nine human-approved return-type corrections. +// Main 3ec5cf3 API with the nine approved return-type corrections and the additive Sandbox facade. import type { FilterValue } from '../../dist/database-filters'; export type { FilterValue } from '../../dist/database-filters'; export type { @@ -12,6 +12,8 @@ export type DurableExecutionStatus = GeneratedComponents['schemas']['DurableExec export type PaginatedDurableExecutions = GeneratedComponents['schemas']['PaginatedDurableExecutions']; export interface VolcanoAuthConfig { + /** HTTP request timeout in milliseconds. Sandbox execution may extend this budget. */ + timeout?: number; apiUrl?: string; anonKey: string; accessToken?: string; @@ -684,6 +686,7 @@ export class VolcanoAuth { logs: Logs; storage: Storage; locks: ProjectLocks; + sandboxes: Sandboxes; database(databaseName: string): VolcanoAuth; from>(table: string): QueryBuilder; insert>( @@ -709,3 +712,106 @@ export { databaseConnectionString, type DatabaseConnectionStringOptions, } from '../../dist/database-connection-string'; + +export type SandboxResult = { data: T; error: null } | { data: null; error: Error }; +export interface SandboxRequestOptions { + signal?: AbortSignal; +} +export interface SandboxReplayOptions extends SandboxRequestOptions { + requestId?: string; +} +export interface SandboxSelectionOptions extends SandboxReplayOptions { + preset?: string; + sandboxId?: string; + region: string; + memoryMB?: number; +} +export interface SandboxCreateOptions extends SandboxSelectionOptions { + maxDurationSeconds?: number; + idleTimeoutSeconds?: number; +} +export interface SandboxExecOptions extends SandboxSelectionOptions { + timeoutSeconds?: number; + environment?: Record; +} +export interface SandboxCommandOptions extends SandboxReplayOptions { + timeoutSeconds?: number; + environment?: Record; +} +export interface SandboxCommandResult { + stdout: string; + stderr: string; + exitCode: number; + timedOut: boolean; + stdoutTruncated: boolean; + stderrTruncated: boolean; +} +export interface SandboxExecutionResult extends SandboxCommandResult { + sessionId: string; + region: string; + durationMs: number; +} +export type SandboxState = + | 'starting' + | 'running' + | 'suspending' + | 'suspended' + | 'resuming' + | 'terminating' + | 'terminated' + | 'unknown'; +export interface SandboxAccess { + url: string; + token: string; + expiresAt: string; +} +export interface SandboxSession extends AsyncDisposable { + readonly id: string; + readonly projectId: string; + readonly region: string; + readonly state: SandboxState; + readonly expiresAt: string; + refresh(options?: SandboxRequestOptions): Promise>; + exec( + command: string, + options?: SandboxCommandOptions, + ): Promise>; + suspend(options?: SandboxRequestOptions): Promise>; + resume(options?: SandboxRequestOptions): Promise>; + terminate(options?: SandboxRequestOptions): Promise>; + access(port: number, options?: SandboxRequestOptions): Promise>; + files: { + read(path: string, options?: SandboxRequestOptions): Promise>; + write( + path: string, + data: Uint8Array, + options?: SandboxRequestOptions, + ): Promise>; + }; +} +export interface SandboxPreset { + id: string; + memoryMB: number; + regions: string[]; +} +export interface Sandboxes { + presets(options?: SandboxRequestOptions): Promise>; + exec( + projectId: string, + command: string, + options: SandboxExecOptions, + ): Promise>; + create(projectId: string, options: SandboxCreateOptions): Promise>; + get(sessionId: string, options?: SandboxRequestOptions): Promise>; + grant( + sessionId: string, + authUserId: string, + expiresAt: string, + options?: SandboxRequestOptions, + ): Promise>; + revoke( + sessionId: string, + authUserId: string, + options?: SandboxRequestOptions, + ): Promise>; +} diff --git a/test/types/package-auth-surface.ts b/test/types/package-auth-surface.ts index 2d3c5476..57cef664 100644 --- a/test/types/package-auth-surface.ts +++ b/test/types/package-auth-surface.ts @@ -13,6 +13,7 @@ type PublishedMember = | 'logs' | 'storage' | 'locks' + | 'sandboxes' | 'database' | 'from' | 'insert' diff --git a/test/types/package-sandbox.ts b/test/types/package-sandbox.ts new file mode 100644 index 00000000..6c99d80b --- /dev/null +++ b/test/types/package-sandbox.ts @@ -0,0 +1,8 @@ +import { type SandboxPreset, VolcanoClient } from '../../dist/index.js'; +const client = new VolcanoClient({ anonKey: 'anonymous-key' }); +declare const preset: SandboxPreset; +export const created = client.sandboxes.create('project-id', { + preset: preset.id, + memoryMB: preset.memoryMB, + region: 'us-east-1', +}); diff --git a/test/types/sandbox-contract.ts b/test/types/sandbox-contract.ts new file mode 100644 index 00000000..ad9d1dae --- /dev/null +++ b/test/types/sandbox-contract.ts @@ -0,0 +1,62 @@ +import type { + SandboxCreateOptions, + Sandboxes, + SandboxExecOptions, + SandboxSession, +} from '../../src/index.ts'; + +export const sessionOptions: SandboxCreateOptions = { + preset: 'python3.12', + region: 'aws-us-east-1', + maxDurationSeconds: 300, + idleTimeoutSeconds: 60, +}; +export const executionOptions: SandboxExecOptions = { + preset: 'python3.12', + region: 'aws-us-east-1', + timeoutSeconds: 30, +}; +export const invalidExecutionLifetime: SandboxExecOptions = { + region: 'aws-us-east-1', + // @ts-expect-error Session lifetime does not apply to one-shot execution. + maxDurationSeconds: 300, +}; +export const invalidExecutionIdle: SandboxExecOptions = { + region: 'aws-us-east-1', + // @ts-expect-error Idle timeout does not apply to one-shot execution. + idleTimeoutSeconds: 60, +}; +declare const session: SandboxSession; +export const disposable: AsyncDisposable = session; + +declare const sandboxes: Sandboxes; +const requestId = '33333333-3333-4333-8333-333333333333'; +export const replayableRequests = [ + sandboxes.create('project', { ...sessionOptions, requestId }), + sandboxes.exec('project', 'true', { ...executionOptions, requestId }), + session.exec('true', { requestId }), +]; +export const nonReplayableRequests = [ + // @ts-expect-error The public catalog does not support idempotency keys. + sandboxes.presets({ requestId }), + // @ts-expect-error Session lookup does not support idempotency keys. + sandboxes.get('session', { requestId }), + // @ts-expect-error Refresh does not support idempotency keys. + session.refresh({ requestId }), + // @ts-expect-error Suspend does not support idempotency keys. + session.suspend({ requestId }), + // @ts-expect-error Resume does not support idempotency keys. + session.resume({ requestId }), + // @ts-expect-error Termination does not support idempotency keys. + session.terminate({ requestId }), + // @ts-expect-error Access credentials do not support idempotency keys. + session.access(8080, { requestId }), + // @ts-expect-error File reads do not support idempotency keys. + session.files.read('/workspace/file', { requestId }), + // @ts-expect-error File writes do not support idempotency keys. + session.files.write('/workspace/file', new Uint8Array(), { requestId }), + // @ts-expect-error Grants do not support idempotency keys. + sandboxes.grant('session', 'user', '2026-10-06T00:00:00Z', { requestId }), + // @ts-expect-error Revocation does not support idempotency keys. + sandboxes.revoke('session', 'user', { requestId }), +]; diff --git a/tsconfig.consumer-sandbox.json b/tsconfig.consumer-sandbox.json new file mode 100644 index 00000000..12159560 --- /dev/null +++ b/tsconfig.consumer-sandbox.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.consumer.json", + "compilerOptions": { "target": "ES2022", "lib": ["ES2022", "DOM"], "types": [] }, + "include": ["test/types/package-sandbox.ts"] +}