mirror of
https://github.com/hanzoai/flow.git
synced 2026-10-17 01:29:18 +00:00
Call flow's API at /v1 from every client
The frontend drops its v2 base and getURL's version switch; lfx, the SDK, template validation and the OpenAPI token URL name /v1. Claude-Session: https://claude.ai/code/session_011i2AG9nwpiKUCVxAdDzYuU
This commit is contained in:
@@ -42,7 +42,7 @@ services:
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.constraint-label-stack=${TRAEFIK_TAG?Variable not set}
|
||||
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=PathPrefix(`/v1`) || PathPrefix(`/v2`) || PathPrefix(`/docs`) || PathPrefix(`/health`)
|
||||
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=PathPrefix(`/v1`) || PathPrefix(`/docs`) || PathPrefix(`/health`)
|
||||
- traefik.http.services.${STACK_NAME?Variable not set}-backend.loadbalancer.server.port=7860
|
||||
|
||||
frontend:
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.constraint-label-stack=${TRAEFIK_TAG?Variable not set}
|
||||
- traefik.http.routers.${STACK_NAME?Variable not set}-celeryworker-http.rule=PathPrefix(`/v1`) || PathPrefix(`/v2`) || PathPrefix(`/docs`) || PathPrefix(`/health`)
|
||||
- traefik.http.routers.${STACK_NAME?Variable not set}-celeryworker-http.rule=PathPrefix(`/v1`) || PathPrefix(`/docs`) || PathPrefix(`/health`)
|
||||
- traefik.http.services.${STACK_NAME?Variable not set}-celeryworker.loadbalancer.server.port=7860
|
||||
|
||||
networks:
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ services:
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.constraint-label-stack=${TRAEFIK_TAG?Variable not set}
|
||||
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=PathPrefix(`/v1`) || PathPrefix(`/v2`) || PathPrefix(`/docs`) || PathPrefix(`/health`)
|
||||
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=PathPrefix(`/v1`) || PathPrefix(`/docs`) || PathPrefix(`/health`)
|
||||
- traefik.http.services.${STACK_NAME?Variable not set}-backend.loadbalancer.server.port=7860
|
||||
|
||||
db:
|
||||
|
||||
@@ -92,7 +92,6 @@ export class Web extends Construct {
|
||||
defaultBehavior: { origin: s3SpaOrigin },
|
||||
additionalBehaviors: {
|
||||
'/v1/*': albBehaviorOptions,
|
||||
'/v2/*': albBehaviorOptions,
|
||||
'/health' : albBehaviorOptions,
|
||||
},
|
||||
enableLogging: true, // ログ出力設定
|
||||
|
||||
@@ -1024,7 +1024,7 @@ async def create_upload_file(
|
||||
Authorization is handled by the ``get_flow`` dependency, which requires an
|
||||
authenticated user and verifies flow ownership. Mirrors the
|
||||
``max_file_size_upload`` guard on the non-deprecated twin at
|
||||
``/api/v1/files/upload/{flow_id}`` so authenticated callers can't fill
|
||||
``/v1/files/upload/{flow_id}`` so authenticated callers can't fill
|
||||
disk through this route either.
|
||||
"""
|
||||
try:
|
||||
|
||||
@@ -138,7 +138,7 @@ async def handle_list_resources(project_id=None):
|
||||
####################################################
|
||||
# When a user uploads a file inside a flow
|
||||
# (e.g., via the File Read component),
|
||||
# it hits /v2/files (POST),
|
||||
# it hits /v1/files (POST),
|
||||
# which saves files at the user-level.
|
||||
# So the above query for flow files is not enough.
|
||||
# So we list all user files for the current user.
|
||||
@@ -226,7 +226,7 @@ async def handle_read_resource(uri: str, project_id: UUID | str | None = None) -
|
||||
|
||||
if flow is None:
|
||||
# The namespace segment may refer to the user's own bucket (user-level
|
||||
# files uploaded via /api/v2/files) rather than a flow id.
|
||||
# files uploaded via /v1/files) rather than a flow id.
|
||||
if str(current_user.id) != str(namespace_id):
|
||||
msg = "Resource not found or access denied"
|
||||
raise ValueError(msg)
|
||||
|
||||
@@ -54,7 +54,7 @@ class OAuth2PasswordBearerCookie(OAuth2PasswordBearer):
|
||||
return None
|
||||
|
||||
|
||||
oauth2_login = OAuth2PasswordBearerCookie(tokenUrl="api/v1/login", auto_error=False)
|
||||
oauth2_login = OAuth2PasswordBearerCookie(tokenUrl="v1/login", auto_error=False)
|
||||
|
||||
API_KEY_NAME = "x-api-key"
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ async def validate_flow_execution(
|
||||
|
||||
try:
|
||||
# Create a flow from the template with timeout
|
||||
create_response = await client.post("api/v1/flows/", json=template_data, headers=headers, timeout=10)
|
||||
create_response = await client.post("v1/flows/", json=template_data, headers=headers, timeout=10)
|
||||
|
||||
if create_response.status_code != 201: # noqa: PLR2004
|
||||
errors.append(f"{filename}: Failed to create flow: {create_response.status_code}")
|
||||
@@ -165,7 +165,7 @@ async def validate_flow_execution(
|
||||
|
||||
try:
|
||||
# Build the flow with timeout
|
||||
build_response = await client.post(f"api/v1/build/{flow_id}/flow", json={}, headers=headers, timeout=10)
|
||||
build_response = await client.post(f"v1/build/{flow_id}/flow", json={}, headers=headers, timeout=10)
|
||||
|
||||
if build_response.status_code != 200: # noqa: PLR2004
|
||||
errors.append(f"{filename}: Failed to build flow: {build_response.status_code}")
|
||||
@@ -175,7 +175,7 @@ async def validate_flow_execution(
|
||||
|
||||
# Get build events to validate execution
|
||||
events_headers = {**headers, "Accept": "application/x-ndjson"}
|
||||
events_response = await client.get(f"api/v1/build/{job_id}/events", headers=events_headers, timeout=10)
|
||||
events_response = await client.get(f"v1/build/{job_id}/events", headers=events_headers, timeout=10)
|
||||
|
||||
if events_response.status_code != 200: # noqa: PLR2004
|
||||
errors.append(f"{filename}: Failed to get build events: {events_response.status_code}")
|
||||
@@ -187,7 +187,7 @@ async def validate_flow_execution(
|
||||
finally:
|
||||
# Clean up the flow with timeout
|
||||
try: # noqa: SIM105
|
||||
await client.delete(f"api/v1/flows/{flow_id}", headers=headers, timeout=10)
|
||||
await client.delete(f"v1/flows/{flow_id}", headers=headers, timeout=10)
|
||||
except asyncio.TimeoutError:
|
||||
# Log but don't fail if cleanup times out
|
||||
pass
|
||||
|
||||
+5
-5
@@ -381,7 +381,7 @@ Use strict equality `autoLogin === false` instead of `!autoLogin`. Treat `null`
|
||||
|
||||
### 6.2 API Contracts
|
||||
|
||||
#### GET /api/v1/monitor/messages/shared/sessions
|
||||
#### GET /v1/monitor/messages/shared/sessions
|
||||
|
||||
**Purpose**: List session IDs for a shared flow, scoped to the authenticated user.
|
||||
|
||||
@@ -397,7 +397,7 @@ source_flow_id: UUID (required) — The original public flow ID from the URL
|
||||
|
||||
---
|
||||
|
||||
#### GET /api/v1/monitor/messages/shared
|
||||
#### GET /v1/monitor/messages/shared
|
||||
|
||||
**Purpose**: Get messages for a shared flow, scoped to the authenticated user.
|
||||
|
||||
@@ -430,7 +430,7 @@ order_by: string (optional, default: "timestamp") — Allowed: timestamp, sender
|
||||
|
||||
---
|
||||
|
||||
#### PUT /api/v1/monitor/messages/shared/{message_id}
|
||||
#### PUT /v1/monitor/messages/shared/{message_id}
|
||||
|
||||
**Purpose**: Update a message on a shared flow (e.g., persist `build_duration`).
|
||||
|
||||
@@ -443,7 +443,7 @@ order_by: string (optional, default: "timestamp") — Allowed: timestamp, sender
|
||||
|
||||
---
|
||||
|
||||
#### DELETE /api/v1/monitor/messages/shared/session/{session_id}
|
||||
#### DELETE /v1/monitor/messages/shared/session/{session_id}
|
||||
|
||||
**Purpose**: Delete all messages in a session on a shared flow.
|
||||
|
||||
@@ -453,7 +453,7 @@ order_by: string (optional, default: "timestamp") — Allowed: timestamp, sender
|
||||
|
||||
---
|
||||
|
||||
#### PATCH /api/v1/monitor/messages/shared/session/{old_session_id}
|
||||
#### PATCH /v1/monitor/messages/shared/session/{old_session_id}
|
||||
|
||||
**Purpose**: Rename a session on a shared flow.
|
||||
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ jest
|
||||
});
|
||||
|
||||
jest.mock("@/customization/config-constants", () => ({
|
||||
BASE_URL_API: "http://localhost:7860/api/v1/",
|
||||
BASE_URL_API: "http://localhost:7860/v1/",
|
||||
}));
|
||||
|
||||
// Mocking the customization layer for the user avatar is how we prove the
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ export default function ModelInputComponent({
|
||||
// This ensures importing a flow shows the importing user's full enabled
|
||||
// list rather than the intersection of the two sets.
|
||||
//
|
||||
// Cross-type guard: `providersData` from ``GET /api/v1/models`` is NOT
|
||||
// Cross-type guard: `providersData` from ``GET /v1/models`` is NOT
|
||||
// filtered by ``model_type`` (the hook doesn't pass one), and the merged
|
||||
// ``enabled_models`` map treats llm + embeddings as a single flat
|
||||
// provider→name→bool record. Without this check, text-embedding models
|
||||
|
||||
+1
-1
@@ -266,7 +266,7 @@ describe("file-utils", () => {
|
||||
it("should_not_treat_flow_substrings_as_special_path_segments", () => {
|
||||
const windowsPath = "C:\\temp\\flow-report\\flow123\\image.png";
|
||||
const expected =
|
||||
"http://localhost:3000/api/v1/files/images/C%3A/temp/flow-report/flow123/image.png";
|
||||
"http://localhost:3000/v1/files/images/C%3A/temp/flow-report/flow123/image.png";
|
||||
|
||||
expect(getFilePreviewUrl(windowsPath)).toBe(expected);
|
||||
});
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// src/constants/constants.ts
|
||||
|
||||
import {
|
||||
BASE_URL_API as CUSTOM_BASE_URL_API,
|
||||
BASE_URL_API_V2 as CUSTOM_BASE_URL_API_V2,
|
||||
} from "../customization/config-constants";
|
||||
import { BASE_URL_API as CUSTOM_BASE_URL_API } from "../customization/config-constants";
|
||||
import { customDefaultShortcuts } from "../customization/constants";
|
||||
import type { languageMap } from "../types/components";
|
||||
|
||||
@@ -607,8 +604,6 @@ export const ADMIN_HEADER_DESCRIPTION =
|
||||
|
||||
export const BASE_URL_API = CUSTOM_BASE_URL_API || "/v1/";
|
||||
|
||||
export const BASE_URL_API_V2 = CUSTOM_BASE_URL_API_V2 || "/v2/";
|
||||
|
||||
/**
|
||||
* URLs excluded from error retries.
|
||||
* @constant
|
||||
|
||||
+4
-4
@@ -10,7 +10,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: (key: string) => `api/v1/${key.toLowerCase()}`,
|
||||
getURL: (key: string) => `v1/${key.toLowerCase()}`,
|
||||
}));
|
||||
|
||||
jest.mock("@/modals/IOModal/helpers/playground-auth", () => ({
|
||||
@@ -60,7 +60,7 @@ describe("persistMessageProperties", () => {
|
||||
|
||||
expect(mockPut).toHaveBeenCalledTimes(1);
|
||||
expect(mockPut).toHaveBeenCalledWith(
|
||||
`api/v1/messages/${MESSAGE_ID}`,
|
||||
`v1/messages/${MESSAGE_ID}`,
|
||||
PAYLOAD,
|
||||
);
|
||||
});
|
||||
@@ -73,7 +73,7 @@ describe("persistMessageProperties", () => {
|
||||
|
||||
expect(mockPut).toHaveBeenCalledTimes(1);
|
||||
expect(mockPut).toHaveBeenCalledWith(
|
||||
`api/v1/messages/shared/${MESSAGE_ID}`,
|
||||
`v1/messages/shared/${MESSAGE_ID}`,
|
||||
PAYLOAD,
|
||||
{ params: { source_flow_id: "real-flow-id-123" } },
|
||||
);
|
||||
@@ -122,7 +122,7 @@ describe("persistMessageProperties", () => {
|
||||
persistMessageProperties(MESSAGE_ID, complexPayload);
|
||||
|
||||
expect(mockPut).toHaveBeenCalledWith(
|
||||
`api/v1/messages/${MESSAGE_ID}`,
|
||||
`v1/messages/${MESSAGE_ID}`,
|
||||
complexPayload,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { getBaseUrl } from "@/customization/utils/urls";
|
||||
import { BASE_URL_API_V2 } from "../../../constants/constants";
|
||||
|
||||
export const URLs = {
|
||||
TRANSACTIONS: `monitor/transactions`,
|
||||
@@ -50,13 +49,12 @@ export const URLs = {
|
||||
export function getURL(
|
||||
key: keyof typeof URLs,
|
||||
params: Record<string, unknown> = {},
|
||||
v2: boolean = false,
|
||||
) {
|
||||
let url = URLs[key];
|
||||
for (const paramKey of Object.keys(params)) {
|
||||
url += `/${params[paramKey]}`;
|
||||
}
|
||||
return `${v2 ? BASE_URL_API_V2 : getBaseUrl()}${url}`;
|
||||
return `${getBaseUrl()}${url}`;
|
||||
}
|
||||
|
||||
export type URLsType = typeof URLs;
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import type {
|
||||
|
||||
// Mock getURL before importing the module under test
|
||||
jest.mock("../../../helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "http://localhost/api/v1/agentic/assist/stream"),
|
||||
getURL: jest.fn(() => "http://localhost/v1/agentic/assist/stream"),
|
||||
}));
|
||||
|
||||
import { postAssistStream } from "../use-post-assist-stream";
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments/providers"),
|
||||
getURL: jest.fn(() => "/v1/deployments/providers"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -40,7 +40,7 @@ describe("useDeleteProviderAccount", () => {
|
||||
await mutation.mutate({ provider_id: "prov-1" });
|
||||
|
||||
expect(mockApiDelete).toHaveBeenCalledWith(
|
||||
"/api/v1/deployments/providers/prov-1",
|
||||
"/v1/deployments/providers/prov-1",
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
+3
-3
@@ -19,7 +19,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments/providers"),
|
||||
getURL: jest.fn(() => "/v1/deployments/providers"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -42,7 +42,7 @@ describe("useGetProviderAccounts", () => {
|
||||
useGetProviderAccounts({});
|
||||
await flushPromises();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments/providers", {
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments/providers", {
|
||||
params: { page: 1, size: 20 },
|
||||
});
|
||||
});
|
||||
@@ -55,7 +55,7 @@ describe("useGetProviderAccounts", () => {
|
||||
useGetProviderAccounts({ page: 2, size: 10 });
|
||||
await flushPromises();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments/providers", {
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments/providers", {
|
||||
params: { page: 2, size: 10 },
|
||||
});
|
||||
});
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments/providers"),
|
||||
getURL: jest.fn(() => "/v1/deployments/providers"),
|
||||
}));
|
||||
|
||||
const mockMutate = jest.fn(
|
||||
@@ -56,7 +56,7 @@ describe("usePostProviderAccount", () => {
|
||||
await mutation.mutate(validPayload);
|
||||
|
||||
expect(mockApiPost).toHaveBeenCalledWith(
|
||||
"/api/v1/deployments/providers",
|
||||
"/v1/deployments/providers",
|
||||
validPayload,
|
||||
);
|
||||
});
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -47,7 +47,7 @@ describe("useCheckToolNames", () => {
|
||||
expect(capturedQueryFn).not.toBeNull();
|
||||
capturedQueryFn!();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments/snapshots", {
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments/snapshots", {
|
||||
params: {
|
||||
provider_id: "prov-1",
|
||||
names: ["my_tool", "other_tool"],
|
||||
@@ -67,7 +67,7 @@ describe("useCheckToolNames", () => {
|
||||
|
||||
const calledUrl = mockApiGet.mock.calls[0][0];
|
||||
expect(calledUrl).not.toContain("check-names");
|
||||
expect(calledUrl).toBe("/api/v1/deployments/snapshots");
|
||||
expect(calledUrl).toBe("/v1/deployments/snapshots");
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -39,7 +39,7 @@ describe("useDeleteDeployment", () => {
|
||||
const mutation = useDeleteDeployment();
|
||||
await mutation.mutate({ deployment_id: "dep-1" });
|
||||
|
||||
expect(mockApiDelete).toHaveBeenCalledWith("/api/v1/deployments/dep-1");
|
||||
expect(mockApiDelete).toHaveBeenCalledWith("/v1/deployments/dep-1");
|
||||
});
|
||||
|
||||
it("refetches useGetDeployments on success", async () => {
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -42,7 +42,7 @@ describe("useGetDeploymentAttachments", () => {
|
||||
useGetDeploymentAttachments({ deploymentId: "dep-1" });
|
||||
await flushPromises();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments/dep-1/flows", {
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments/dep-1/flows", {
|
||||
params: { size: 50 },
|
||||
paramsSerializer: { indexes: null },
|
||||
});
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -42,7 +42,7 @@ describe("useGetDeploymentConfigs", () => {
|
||||
useGetDeploymentConfigs({ providerId: "prov-1" });
|
||||
await flushPromises();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments/configs", {
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments/configs", {
|
||||
params: { provider_id: "prov-1", size: 10000 },
|
||||
});
|
||||
});
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -42,7 +42,7 @@ describe("useGetDeploymentLlms", () => {
|
||||
useGetDeploymentLlms({ providerId: "prov-1" });
|
||||
await flushPromises();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments/llms", {
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments/llms", {
|
||||
params: { provider_id: "prov-1" },
|
||||
});
|
||||
});
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -42,7 +42,7 @@ describe("useGetDeploymentRun", () => {
|
||||
});
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith(
|
||||
"/api/v1/deployments/dep-1/runs/exec-1",
|
||||
"/v1/deployments/dep-1/runs/exec-1",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ describe("useGetDeploymentRun", () => {
|
||||
});
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith(
|
||||
"/api/v1/deployments/dep-1/runs/exec%2Fwith%20spaces",
|
||||
"/v1/deployments/dep-1/runs/exec%2Fwith%20spaces",
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -40,7 +40,7 @@ describe("useGetDeployment", () => {
|
||||
useGetDeployment({ deploymentId: "dep-1" });
|
||||
await flushPromises();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments/dep-1");
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments/dep-1");
|
||||
});
|
||||
|
||||
it("uses correct query key", () => {
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
// Capture the config passed to useQueries so we can test combine and queryFn
|
||||
@@ -66,7 +66,7 @@ describe("useGetDeploymentsByProviders", () => {
|
||||
useGetDeploymentsByProviders(["prov-1"]);
|
||||
await capturedConfig.queries[0].queryFn();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments", {
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments", {
|
||||
params: { provider_id: "prov-1", page: 1, size: 20 },
|
||||
});
|
||||
});
|
||||
@@ -79,7 +79,7 @@ describe("useGetDeploymentsByProviders", () => {
|
||||
useGetDeploymentsByProviders(["prov-1"], "folder-1");
|
||||
await capturedConfig.queries[0].queryFn();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments", {
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments", {
|
||||
params: {
|
||||
provider_id: "prov-1",
|
||||
project_id: "folder-1",
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -44,7 +44,7 @@ describe("useGetDeployments", () => {
|
||||
useGetDeployments({ provider_id: "prov-1" });
|
||||
await flushPromises();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments", {
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments", {
|
||||
params: {
|
||||
provider_id: "prov-1",
|
||||
page: 1,
|
||||
@@ -67,7 +67,7 @@ describe("useGetDeployments", () => {
|
||||
});
|
||||
await flushPromises();
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/api/v1/deployments", {
|
||||
expect(mockApiGet).toHaveBeenCalledWith("/v1/deployments", {
|
||||
params: {
|
||||
provider_id: "prov-1",
|
||||
flow_ids: ["f1", "f2"],
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -49,7 +49,7 @@ describe("usePatchDeployment", () => {
|
||||
});
|
||||
|
||||
expect(mockApiPatch).toHaveBeenCalledWith(
|
||||
"/api/v1/deployments/dep-42",
|
||||
"/v1/deployments/dep-42",
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -45,7 +45,7 @@ describe("usePatchSnapshot", () => {
|
||||
});
|
||||
|
||||
expect(mockApiPatch).toHaveBeenCalledWith(
|
||||
"/api/v1/deployments/snapshots/snap-abc",
|
||||
"/v1/deployments/snapshots/snap-abc",
|
||||
{ flow_version_id: "fv-1" },
|
||||
);
|
||||
});
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -46,7 +46,7 @@ describe("usePostDeploymentRun", () => {
|
||||
const mutation = usePostDeploymentRun();
|
||||
await mutation.mutate(payload);
|
||||
|
||||
expect(mockApiPost).toHaveBeenCalledWith("/api/v1/deployments/dep-1/runs", {
|
||||
expect(mockApiPost).toHaveBeenCalledWith("/v1/deployments/dep-1/runs", {
|
||||
provider_data: { input: "Hello agent" },
|
||||
});
|
||||
});
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/deployments"),
|
||||
getURL: jest.fn(() => "/v1/deployments"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -64,7 +64,7 @@ describe("usePostDeployment", () => {
|
||||
await mutation.mutate(validPayload);
|
||||
|
||||
expect(mockApiPost).toHaveBeenCalledWith(
|
||||
"/api/v1/deployments",
|
||||
"/v1/deployments",
|
||||
validPayload,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ export const useDeleteFileV2: useMutationFunctionType<IDeleteFile, void> = (
|
||||
|
||||
const deleteFileFn = async (): Promise<any> => {
|
||||
const response = await api.delete<any>(
|
||||
`${getURL("FILE_MANAGEMENT", { id: params.id }, true)}`,
|
||||
`${getURL("FILE_MANAGEMENT", { id: params.id })}`,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
|
||||
@@ -16,7 +16,7 @@ export const useDeleteFilesV2: useMutationFunctionType<
|
||||
|
||||
const deleteFileFn = async (params): Promise<any> => {
|
||||
const response = await api.delete<any>(
|
||||
`${getURL("FILE_MANAGEMENT", { mode: "batch/" }, true)}`,
|
||||
`${getURL("FILE_MANAGEMENT", { mode: "batch/" })}`,
|
||||
{
|
||||
data: params.ids,
|
||||
},
|
||||
|
||||
@@ -20,7 +20,7 @@ export const useDuplicateFileV2: useMutationFunctionType<
|
||||
const duplicateFileFn = async (): Promise<any> => {
|
||||
// First download the file
|
||||
const response = await fetch(
|
||||
`${getURL("FILE_MANAGEMENT", { id: params.id }, true)}`,
|
||||
`${getURL("FILE_MANAGEMENT", { id: params.id })}`,
|
||||
{
|
||||
headers: {
|
||||
Accept: "*/*",
|
||||
@@ -40,7 +40,7 @@ export const useDuplicateFileV2: useMutationFunctionType<
|
||||
formData.append("file", file);
|
||||
|
||||
const uploadResponse = await api.post<any>(
|
||||
`${getURL("FILE_MANAGEMENT", {}, true)}/`,
|
||||
`${getURL("FILE_MANAGEMENT")}/`,
|
||||
formData,
|
||||
);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export const useGetDownloadFileV2: useMutationFunctionType<
|
||||
if (!params) return;
|
||||
// need to use fetch because axios convert blob data to string, and this convertion can corrupt the file
|
||||
const response = await fetch(
|
||||
`${getURL("FILE_MANAGEMENT", { id: params.id }, true)}`,
|
||||
`${getURL("FILE_MANAGEMENT", { id: params.id })}`,
|
||||
{
|
||||
headers: {
|
||||
Accept: "*/*",
|
||||
|
||||
@@ -19,7 +19,7 @@ export const useGetDownloadFilesV2: useMutationFunctionType<
|
||||
let response;
|
||||
if (params.ids.length === 1) {
|
||||
response = await fetch(
|
||||
`${getURL("FILE_MANAGEMENT", { id: params.ids[0] }, true)}`,
|
||||
`${getURL("FILE_MANAGEMENT", { id: params.ids[0] })}`,
|
||||
{
|
||||
headers: {
|
||||
Accept: "*/*",
|
||||
@@ -29,7 +29,7 @@ export const useGetDownloadFilesV2: useMutationFunctionType<
|
||||
);
|
||||
} else {
|
||||
response = await fetch(
|
||||
`${getURL("FILE_MANAGEMENT", { mode: "batch/" }, true)}`,
|
||||
`${getURL("FILE_MANAGEMENT", { mode: "batch/" })}`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(params.ids),
|
||||
|
||||
@@ -14,7 +14,7 @@ export const useGetFilesV2: useQueryFunctionType<undefined, FilesResponse> = (
|
||||
|
||||
const getFilesFn = async () => {
|
||||
const response = await api.get<FilesResponse>(
|
||||
`${getURL("FILE_MANAGEMENT", {}, true)}`,
|
||||
`${getURL("FILE_MANAGEMENT")}`,
|
||||
);
|
||||
return response["data"] ?? [];
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@ export const usePostUploadFileV2: useMutationFunctionType<
|
||||
|
||||
try {
|
||||
const response = await api.post<any>(
|
||||
`${getURL("FILE_MANAGEMENT", {}, true)}`,
|
||||
`${getURL("FILE_MANAGEMENT")}`,
|
||||
formData,
|
||||
{
|
||||
onUploadProgress: (progressEvent) => {
|
||||
|
||||
@@ -17,7 +17,7 @@ export const usePostRenameFileV2: useMutationFunctionType<
|
||||
|
||||
const postRenameFileFn = async (payload: IPostRenameFile): Promise<any> => {
|
||||
const response = await api.put<any>(
|
||||
`${getURL("FILE_MANAGEMENT", { id: payload.id }, true)}?name=${encodeURI(payload.name)}`,
|
||||
`${getURL("FILE_MANAGEMENT", { id: payload.id })}?name=${encodeURI(payload.name)}`,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
|
||||
@@ -22,7 +22,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn((key) => `/api/v1/${key.toLowerCase()}`),
|
||||
getURL: jest.fn((key) => `/v1/${key.toLowerCase()}`),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn((key: string) => `/api/v1/${key.toLowerCase()}`),
|
||||
getURL: jest.fn((key: string) => `/v1/${key.toLowerCase()}`),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
|
||||
@@ -40,7 +40,7 @@ export const useAddMCPServer: useMutationFunctionType<
|
||||
}
|
||||
|
||||
const res = await api.post(
|
||||
`${getURL("MCP_SERVERS", undefined, true)}/${body.name}`,
|
||||
`${getURL("MCP_SERVERS")}/${body.name}`,
|
||||
payload,
|
||||
);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ export const useDeleteMCPServer: useMutationFunctionType<
|
||||
): Promise<DeleteMCPServerResponse> {
|
||||
try {
|
||||
const res = await api.delete(
|
||||
`${getURL("MCP_SERVERS", undefined, true)}/${payload.name}`,
|
||||
`${getURL("MCP_SERVERS")}/${payload.name}`,
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -19,7 +19,7 @@ export const useGetMCPServer: useMutationFunctionType<
|
||||
|
||||
const responseFn = async (params: IGetMCPServer) => {
|
||||
const { data } = await api.get<Omit<getMCPServerResponse, "name">>(
|
||||
`${getURL("MCP_SERVERS", undefined, true)}/${params.name}`,
|
||||
`${getURL("MCP_SERVERS")}/${params.name}`,
|
||||
);
|
||||
|
||||
return { ...data, name: params.name };
|
||||
|
||||
@@ -22,7 +22,7 @@ export const useGetMCPServers: useQueryFunctionType<
|
||||
const responseFn = async () => {
|
||||
try {
|
||||
const { data } = await api.get<getMCPServersResponse>(
|
||||
`${getURL("MCP_SERVERS", undefined, true)}?action_count=false`,
|
||||
`${getURL("MCP_SERVERS")}?action_count=false`,
|
||||
);
|
||||
// Merge with cached data to preserve non-null mode/toolsCount
|
||||
const cachedData = queryClient.getQueryData(["useGetMCPServers"]) as
|
||||
@@ -56,7 +56,7 @@ export const useGetMCPServers: useQueryFunctionType<
|
||||
const fetchWithCounts = async () => {
|
||||
try {
|
||||
const { data } = await api.get<getMCPServersResponse>(
|
||||
`${getURL("MCP_SERVERS", undefined, true)}?action_count=true`,
|
||||
`${getURL("MCP_SERVERS")}?action_count=true`,
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
|
||||
@@ -41,7 +41,7 @@ export const usePatchMCPServer: useMutationFunctionType<
|
||||
}
|
||||
|
||||
const res = await api.patch(
|
||||
`${getURL("MCP_SERVERS", undefined, true)}/${body.name}`,
|
||||
`${getURL("MCP_SERVERS")}/${body.name}`,
|
||||
payload,
|
||||
);
|
||||
|
||||
|
||||
+3
-3
@@ -56,7 +56,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: (key: string) => `api/v1/${key.toLowerCase()}`,
|
||||
getURL: (key: string) => `v1/${key.toLowerCase()}`,
|
||||
}));
|
||||
|
||||
jest.mock("@/utils/utils", () => ({
|
||||
@@ -101,7 +101,7 @@ describe("useGetMessagesQuery - Routing Logic", () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith(
|
||||
"api/v1/messages",
|
||||
"v1/messages",
|
||||
expect.objectContaining({
|
||||
params: expect.objectContaining({ flow_id: FLOW_ID }),
|
||||
}),
|
||||
@@ -117,7 +117,7 @@ describe("useGetMessagesQuery - Routing Logic", () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith(
|
||||
"api/v1/messages/shared",
|
||||
"v1/messages/shared",
|
||||
expect.objectContaining({ params: { source_flow_id: SOURCE_FLOW_ID } }),
|
||||
);
|
||||
});
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: (key: string) => `api/v1/${key.toLowerCase()}`,
|
||||
getURL: (key: string) => `v1/${key.toLowerCase()}`,
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -67,7 +67,7 @@ describe("useGetSessionsFromFlowQuery - Routing Logic", () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
expect(mockApiGet).toHaveBeenCalledWith(
|
||||
"api/v1/messages/shared/sessions",
|
||||
"v1/messages/shared/sessions",
|
||||
expect.objectContaining({ params: { source_flow_id: SOURCE_FLOW_ID } }),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ export const useGetRegistration: useQueryFunctionType<
|
||||
const { query } = UseRequestProcessor();
|
||||
|
||||
const getRegistration = async (): Promise<RegistrationInfo> => {
|
||||
const res = await api.get(`${getURL("REGISTRATION", {}, true)}/`);
|
||||
const res = await api.get(`${getURL("REGISTRATION")}/`);
|
||||
return res.data;
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export const usePostRegistration: useMutationFunctionType<
|
||||
const postRegistrationFn = async (
|
||||
payload: IRegistrationRequest,
|
||||
): Promise<IRegistrationResponse> => {
|
||||
const response = await api.post(`${getURL("REGISTRATION", {}, true)}/`, {
|
||||
const response = await api.post(`${getURL("REGISTRATION")}/`, {
|
||||
email: payload.email,
|
||||
});
|
||||
return response.data;
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: jest.fn(() => "/api/v1/variables"),
|
||||
getURL: jest.fn(() => "/v1/variables"),
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/services/request-processor", () => ({
|
||||
@@ -43,7 +43,7 @@ describe("usePostDetectEnvVars", () => {
|
||||
await mutation.mutate(payload);
|
||||
|
||||
expect(mockApiPost).toHaveBeenCalledWith(
|
||||
"/api/v1/variables/detections",
|
||||
"/v1/variables/detections",
|
||||
payload,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
export const BASENAME = "";
|
||||
export const PORT = 3000;
|
||||
export const PROXY_TARGET = "http://localhost:7860";
|
||||
export const API_ROUTES = ["^/v1/", "^/v2/", "/health"];
|
||||
export const API_ROUTES = ["^/v1/", "/health"];
|
||||
export const BASE_URL_API = "/v1/";
|
||||
export const BASE_URL_API_V2 = "/v2/";
|
||||
export const HEALTH_CHECK_URL = "/health_check";
|
||||
export const DOCS_LINK = "https://docs.hanzo.ai/flow";
|
||||
|
||||
@@ -14,6 +13,5 @@ export default {
|
||||
PROXY_TARGET,
|
||||
API_ROUTES,
|
||||
BASE_URL_API,
|
||||
BASE_URL_API_V2,
|
||||
HEALTH_CHECK_URL,
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ describe("customGetMCPUrl", () => {
|
||||
const url = customGetMCPUrl("proj-1");
|
||||
|
||||
expect(url).toBe(
|
||||
"https://custom.example.com/api/v1/mcp/project/proj-1/streamable",
|
||||
"https://custom.example.com/v1/mcp/project/proj-1/streamable",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ describe("customGetMCPUrl", () => {
|
||||
const url = customGetMCPUrl("proj-1");
|
||||
|
||||
expect(url).toBe(
|
||||
"https://override.example.com/api/v1/mcp/project/proj-1/streamable",
|
||||
"https://override.example.com/v1/mcp/project/proj-1/streamable",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ describe("customGetMCPUrl", () => {
|
||||
const url = customGetMCPUrl("proj-1");
|
||||
|
||||
expect(url).toBe(
|
||||
"https://api-default.example.com/api/v1/mcp/project/proj-1/streamable",
|
||||
"https://api-default.example.com/v1/mcp/project/proj-1/streamable",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -50,7 +50,7 @@ describe("customGetMCPUrl", () => {
|
||||
const url = customGetMCPUrl("proj-1");
|
||||
|
||||
expect(url).toBe(
|
||||
`${window.location.origin}/api/v1/mcp/project/proj-1/streamable`,
|
||||
`${window.location.origin}/v1/mcp/project/proj-1/streamable`,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ describe("customGetMCPUrl", () => {
|
||||
const url = customGetMCPUrl("proj-1");
|
||||
|
||||
expect(url).toBe(
|
||||
"https://example.com/api/v1/mcp/project/proj-1/streamable",
|
||||
"https://example.com/v1/mcp/project/proj-1/streamable",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -70,7 +70,7 @@ describe("customGetMCPUrl", () => {
|
||||
const url = customGetMCPUrl("proj-1");
|
||||
|
||||
expect(url).toBe(
|
||||
"https://example.com/api/v1/mcp/project/proj-1/streamable",
|
||||
"https://example.com/v1/mcp/project/proj-1/streamable",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -79,7 +79,7 @@ describe("customGetMCPUrl", () => {
|
||||
|
||||
const url = customGetMCPUrl("proj-1", {}, "sse");
|
||||
|
||||
expect(url).toBe("https://example.com/api/v1/mcp/project/proj-1/sse");
|
||||
expect(url).toBe("https://example.com/v1/mcp/project/proj-1/sse");
|
||||
});
|
||||
|
||||
it("returns composer URL when useComposer is true and streamableHttpUrl is set", () => {
|
||||
|
||||
@@ -7,7 +7,7 @@ jest.mock("@/controllers/API/api", () => ({
|
||||
}));
|
||||
|
||||
jest.mock("@/controllers/API/helpers/constants", () => ({
|
||||
getURL: (key: string) => `http://localhost/api/v1/${key.toLowerCase()}`,
|
||||
getURL: (key: string) => `http://localhost/v1/${key.toLowerCase()}`,
|
||||
}));
|
||||
|
||||
import { useFlowEvents } from "../use-flow-events";
|
||||
|
||||
@@ -156,7 +156,7 @@ describe("API Snippet Generation Utilities", () => {
|
||||
|
||||
// Check for file upload steps
|
||||
expect(code).toContain("/v1/files/upload/");
|
||||
expect(code).toContain("/v2/files");
|
||||
expect(code).toContain("/v1/files");
|
||||
expect(code).toContain("with open");
|
||||
expect(code).toContain('files={"file": f}');
|
||||
});
|
||||
@@ -180,7 +180,7 @@ describe("API Snippet Generation Utilities", () => {
|
||||
|
||||
// Check for file upload steps
|
||||
expect(code).toContain("/v1/files/upload/");
|
||||
expect(code).toContain("/v2/files");
|
||||
expect(code).toContain("/v1/files");
|
||||
expect(code).toContain("with open");
|
||||
expect(code).toContain('files={"file": f}');
|
||||
});
|
||||
@@ -245,7 +245,7 @@ describe("API Snippet Generation Utilities", () => {
|
||||
|
||||
// Check for upload steps
|
||||
expect(code).toContain("/v1/files/upload/");
|
||||
expect(code).toContain("/v2/files");
|
||||
expect(code).toContain("/v1/files");
|
||||
});
|
||||
|
||||
it("should generate multi-step code for file uploads without authentication", () => {
|
||||
@@ -277,7 +277,7 @@ describe("API Snippet Generation Utilities", () => {
|
||||
|
||||
// Check for upload steps
|
||||
expect(code).toContain("/v1/files/upload/");
|
||||
expect(code).toContain("/v2/files");
|
||||
expect(code).toContain("/v1/files");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -364,7 +364,7 @@ describe("API Snippet Generation Utilities", () => {
|
||||
expect(result.steps[0].title).toContain("Upload files");
|
||||
expect(result.steps[0]).toHaveProperty("code");
|
||||
expect(result.steps[0].code).toContain("/v1/files/upload/");
|
||||
expect(result.steps[0].code).toContain("/v2/files");
|
||||
expect(result.steps[0].code).toContain("/v1/files");
|
||||
expect(result.steps[0].code).toContain('--form "file=@');
|
||||
expect(result.steps[0].code).toContain("x-api-key: YOUR_API_KEY_HERE");
|
||||
|
||||
@@ -403,7 +403,7 @@ describe("API Snippet Generation Utilities", () => {
|
||||
expect(result.steps[0].title).toContain("Upload files");
|
||||
expect(result.steps[0]).toHaveProperty("code");
|
||||
expect(result.steps[0].code).toContain("/v1/files/upload/");
|
||||
expect(result.steps[0].code).toContain("/v2/files");
|
||||
expect(result.steps[0].code).toContain("/v1/files");
|
||||
expect(result.steps[0].code).toContain('--form "file=@');
|
||||
expect(result.steps[0].code).not.toContain(
|
||||
"x-api-key: YOUR_API_KEY_HERE",
|
||||
|
||||
@@ -312,7 +312,7 @@ describe("getNewCurlCode", () => {
|
||||
expect(result.steps).toHaveLength(2);
|
||||
|
||||
// Check upload step
|
||||
expect(result.steps[0].code).toContain("/v2/files");
|
||||
expect(result.steps[0].code).toContain("/v1/files");
|
||||
expect(result.steps[0].code).toContain('--form "file=@your_file_1.pdf"');
|
||||
|
||||
// Check execute step
|
||||
@@ -336,7 +336,7 @@ describe("getNewCurlCode", () => {
|
||||
expect(result.steps).toHaveLength(2);
|
||||
|
||||
// Check upload step
|
||||
expect(result.steps[0].code).toContain("/v2/files");
|
||||
expect(result.steps[0].code).toContain("/v1/files");
|
||||
expect(result.steps[0].code).toContain('--form "file=@your_file_1.pdf"');
|
||||
});
|
||||
|
||||
@@ -358,7 +358,7 @@ describe("getNewCurlCode", () => {
|
||||
// Check both uploads
|
||||
expect(result.steps[0].code).toContain("your_file_1.pdf");
|
||||
expect(result.steps[0].code).toContain("your_file_2.pdf");
|
||||
expect(result.steps[0].code).toContain("/v2/files");
|
||||
expect(result.steps[0].code).toContain("/v1/files");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -405,7 +405,7 @@ describe("getNewCurlCode", () => {
|
||||
|
||||
// Check upload step
|
||||
expect(result.steps[0].code).toContain("curl.exe --request POST");
|
||||
expect(result.steps[0].code).toContain("/v2/files");
|
||||
expect(result.steps[0].code).toContain("/v1/files");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -428,7 +428,7 @@ describe("getNewCurlCode", () => {
|
||||
|
||||
// Check for both v1 and v2 API uploads
|
||||
expect(result.steps[0].code).toContain("/v1/files/upload/");
|
||||
expect(result.steps[0].code).toContain("/v2/files");
|
||||
expect(result.steps[0].code).toContain("/v1/files");
|
||||
|
||||
// Check all upload counter placeholders
|
||||
expect(result.steps[1].code).toContain(
|
||||
|
||||
@@ -159,7 +159,7 @@ describe("getNewJsApiCode", () => {
|
||||
"// Step 1: Upload file for File/VideoFile fileNode1",
|
||||
);
|
||||
expect(code).toContain("createFormData('your_file_1.pdf')");
|
||||
expect(code).toContain("/v2/files");
|
||||
expect(code).toContain("/v1/files");
|
||||
expect(code).toContain("filePath1");
|
||||
});
|
||||
|
||||
@@ -179,7 +179,7 @@ describe("getNewJsApiCode", () => {
|
||||
"// Step 1: Upload file for File/VideoFile videoNode1",
|
||||
);
|
||||
expect(code).toContain("createFormData('your_file_1.pdf')");
|
||||
expect(code).toContain("/v2/files");
|
||||
expect(code).toContain("/v1/files");
|
||||
expect(code).toContain("filePath1");
|
||||
});
|
||||
|
||||
@@ -232,7 +232,7 @@ describe("getNewJsApiCode", () => {
|
||||
expect(code).toContain(
|
||||
"// Step 3: Upload file for File/VideoFile videoNode1",
|
||||
);
|
||||
expect(code).toContain("/v2/files");
|
||||
expect(code).toContain("/v1/files");
|
||||
|
||||
// Check for flow execution step
|
||||
expect(code).toContain("// Step 4: Execute flow with all file paths");
|
||||
|
||||
@@ -185,7 +185,7 @@ describe("getNewPythonApiCode", () => {
|
||||
"# Step 1: Upload file for File/VideoFile fileNode1",
|
||||
);
|
||||
expect(code).toContain('with open("your_file_1.pdf", "rb") as f:');
|
||||
expect(code).toContain('f"{base_url}/v2/files"');
|
||||
expect(code).toContain('f"{base_url}/v1/files"');
|
||||
expect(code).toContain('file_path_1 = response.json()["path"]');
|
||||
|
||||
// Check for flow execution step
|
||||
@@ -209,7 +209,7 @@ describe("getNewPythonApiCode", () => {
|
||||
"# Step 1: Upload file for File/VideoFile videoNode1",
|
||||
);
|
||||
expect(code).toContain('with open("your_file_1.pdf", "rb") as f:');
|
||||
expect(code).toContain('f"{base_url}/v2/files"');
|
||||
expect(code).toContain('f"{base_url}/v1/files"');
|
||||
expect(code).toContain('file_path_1 = response.json()["path"]');
|
||||
|
||||
// Check for flow execution step
|
||||
@@ -268,7 +268,7 @@ describe("getNewPythonApiCode", () => {
|
||||
expect(code).toContain(
|
||||
"# Step 3: Upload file for File/VideoFile videoNode1",
|
||||
);
|
||||
expect(code).toContain("/v2/files");
|
||||
expect(code).toContain("/v1/files");
|
||||
|
||||
// Check for flow execution step
|
||||
expect(code).toContain("# Step 4: Execute flow with all file paths");
|
||||
|
||||
@@ -169,14 +169,14 @@ ${getApiSampleHeaders("curl")}
|
||||
if (detectedPlatform === "powershell") {
|
||||
uploadCommands.push(
|
||||
`curl.exe --request POST \`
|
||||
--url "${baseUrl}/v2/files" \`
|
||||
--url "${baseUrl}/v1/files" \`
|
||||
${shouldDisplayApiKey ? '--header "x-api-key: YOUR_API_KEY_HERE" \\' : getApiSampleHeaders("curl")}
|
||||
--form "file=@your_file_${uploadCounter}.pdf"`,
|
||||
);
|
||||
} else {
|
||||
uploadCommands.push(
|
||||
`curl --request POST \\
|
||||
--url "${baseUrl}/v2/files" \\
|
||||
--url "${baseUrl}/v1/files" \\
|
||||
${shouldDisplayApiKey ? '--header "x-api-key: YOUR_API_KEY_HERE" \\' : getApiSampleHeaders("curl")}
|
||||
--form "file=@your_file_${uploadCounter}.pdf"`,
|
||||
);
|
||||
|
||||
@@ -154,7 +154,7 @@ const authHeaders = { 'x-api-key': apiKey };`
|
||||
const fileUploadOptions${index + 1} = {
|
||||
hostname: '${hostname}',
|
||||
port: ${port},
|
||||
path: '/v2/files',
|
||||
path: '/v1/files',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': \`multipart/form-data; boundary=\${fileBoundary${
|
||||
|
||||
@@ -125,7 +125,7 @@ except ValueError as e:
|
||||
uploadSteps.length + 1
|
||||
}: Upload file for File/VideoFile ${nodeId}\nwith open(\"your_file_${
|
||||
index + 1
|
||||
}.pdf\", \"rb\") as f:\n response = requests.post(\n f\"{base_url}/v2/files\",\n headers=headers,\n files={\"file\": f}\n )\n response.raise_for_status()\n file_path_${
|
||||
}.pdf\", \"rb\") as f:\n response = requests.post(\n f\"{base_url}/v1/files\",\n headers=headers,\n files={\"file\": f}\n )\n response.raise_for_status()\n file_path_${
|
||||
index + 1
|
||||
} = response.json()[\"path\"]`,
|
||||
);
|
||||
|
||||
@@ -80,7 +80,7 @@ def get_llm(
|
||||
# ``get_language_model_options``, does not inject ``model_class`` into
|
||||
# each model's metadata). This happens for example immediately after a
|
||||
# user configures a provider and the frontend augments its dropdown from
|
||||
# ``/api/v1/models`` before the backend has repopulated
|
||||
# ``/v1/models`` before the backend has repopulated
|
||||
# ``template[model]["options"]``; the resulting stored selection only
|
||||
# carries the raw ``create_model_metadata`` fields, so we have to derive
|
||||
# ``model_class`` from the provider mapping that
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""lfx push -- push normalized flow JSON to a remote Flow instance.
|
||||
|
||||
Uses stable flow IDs for upsert (PUT /api/v1/flows/{id}), so repeated pushes
|
||||
Uses stable flow IDs for upsert (PUT /v1/flows/{id}), so repeated pushes
|
||||
are idempotent: the first push creates the flow, subsequent ones update it in
|
||||
place without changing its ID on the remote instance.
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ class FlowClient:
|
||||
return headers
|
||||
|
||||
def _url(self, path: str) -> str:
|
||||
return f"{self.server_url}/api/v1{path}"
|
||||
return f"{self.server_url}/v1{path}"
|
||||
|
||||
async def get(self, path: str, **kwargs: Any) -> Any:
|
||||
url = self._url(path)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Component registry cache — fetches and searches component types.
|
||||
|
||||
Loads the full component catalog from /api/v1/all and provides
|
||||
Loads the full component catalog from /v1/all and provides
|
||||
pure search/describe functions.
|
||||
"""
|
||||
|
||||
|
||||
@@ -130,8 +130,8 @@ class WorkflowJobResponse(BaseModel):
|
||||
"""Automatically populate links for the client."""
|
||||
if not self.links:
|
||||
self.links = {
|
||||
"status": f"/v2/workflows?job_id={self.job_id!s}",
|
||||
"stop": "/v2/workflows/stop",
|
||||
"status": f"/v1/workflows?job_id={self.job_id!s}",
|
||||
"stop": "/v1/workflows/stop",
|
||||
}
|
||||
return self
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ class AsyncFlowClient(_ClientCommon):
|
||||
) -> list[Flow]:
|
||||
resp = await self._request(
|
||||
"GET",
|
||||
"/api/v1/flows/",
|
||||
"/v1/flows/",
|
||||
params=self._build_flow_list_params(
|
||||
folder_id=folder_id,
|
||||
remove_example_flows=remove_example_flows,
|
||||
@@ -144,17 +144,17 @@ class AsyncFlowClient(_ClientCommon):
|
||||
return self._validate_model_list(Flow, resp.json())
|
||||
|
||||
async def get_flow(self, flow_id: UUID | str) -> Flow:
|
||||
resp = await self._request("GET", f"/api/v1/flows/{flow_id}")
|
||||
resp = await self._request("GET", f"/v1/flows/{flow_id}")
|
||||
return self._validate_model(Flow, resp.json())
|
||||
|
||||
async def create_flow(self, flow: FlowCreate) -> Flow:
|
||||
resp = await self._request("POST", "/api/v1/flows/", json=self._model_payload(flow))
|
||||
resp = await self._request("POST", "/v1/flows/", json=self._model_payload(flow))
|
||||
return self._validate_model(Flow, resp.json())
|
||||
|
||||
async def update_flow(self, flow_id: UUID | str, update: FlowUpdate) -> Flow:
|
||||
resp = await self._request(
|
||||
"PATCH",
|
||||
f"/api/v1/flows/{flow_id}",
|
||||
f"/v1/flows/{flow_id}",
|
||||
json=self._model_payload(update),
|
||||
)
|
||||
return self._validate_model(Flow, resp.json())
|
||||
@@ -163,13 +163,13 @@ class AsyncFlowClient(_ClientCommon):
|
||||
"""Create-or-update by stable ID. Returns ``(flow, created)``."""
|
||||
resp = await self._request(
|
||||
"PUT",
|
||||
f"/api/v1/flows/{flow_id}",
|
||||
f"/v1/flows/{flow_id}",
|
||||
json=self._model_payload(flow),
|
||||
)
|
||||
return self._upsert_result(Flow, resp)
|
||||
|
||||
async def delete_flow(self, flow_id: UUID | str) -> None:
|
||||
await self._request("DELETE", f"/api/v1/flows/{flow_id}")
|
||||
await self._request("DELETE", f"/v1/flows/{flow_id}")
|
||||
|
||||
async def run_flow(
|
||||
self,
|
||||
@@ -178,7 +178,7 @@ class AsyncFlowClient(_ClientCommon):
|
||||
) -> RunResponse:
|
||||
resp = await self._request(
|
||||
"POST",
|
||||
f"/api/v1/run/{flow_id_or_endpoint}",
|
||||
f"/v1/run/{flow_id_or_endpoint}",
|
||||
json=self._model_payload(request),
|
||||
)
|
||||
return self._validate_model(RunResponse, resp.json())
|
||||
@@ -275,7 +275,7 @@ class AsyncFlowClient(_ClientCommon):
|
||||
response = chunk.final_response()
|
||||
"""
|
||||
return self._aiter_stream(
|
||||
f"/api/v1/run/{flow_id_or_endpoint}",
|
||||
f"/v1/run/{flow_id_or_endpoint}",
|
||||
self._build_stream_payload(
|
||||
input_value=input_value,
|
||||
input_type=input_type,
|
||||
@@ -306,27 +306,27 @@ class AsyncFlowClient(_ClientCommon):
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
async def list_projects(self) -> list[Project]:
|
||||
resp = await self._request("GET", "/api/v1/projects/")
|
||||
resp = await self._request("GET", "/v1/projects/")
|
||||
return self._validate_model_list(Project, resp.json())
|
||||
|
||||
async def get_project(self, project_id: UUID | str) -> ProjectWithFlows:
|
||||
resp = await self._request("GET", f"/api/v1/projects/{project_id}")
|
||||
resp = await self._request("GET", f"/v1/projects/{project_id}")
|
||||
return self._validate_model(ProjectWithFlows, resp.json())
|
||||
|
||||
async def create_project(self, project: ProjectCreate) -> Project:
|
||||
resp = await self._request("POST", "/api/v1/projects/", json=self._model_payload(project))
|
||||
resp = await self._request("POST", "/v1/projects/", json=self._model_payload(project))
|
||||
return self._validate_model(Project, resp.json())
|
||||
|
||||
async def update_project(self, project_id: UUID | str, update: ProjectUpdate) -> Project:
|
||||
resp = await self._request(
|
||||
"PATCH",
|
||||
f"/api/v1/projects/{project_id}",
|
||||
f"/v1/projects/{project_id}",
|
||||
json=self._model_payload(update),
|
||||
)
|
||||
return self._validate_model(Project, resp.json())
|
||||
|
||||
async def delete_project(self, project_id: UUID | str) -> None:
|
||||
await self._request("DELETE", f"/api/v1/projects/{project_id}")
|
||||
await self._request("DELETE", f"/v1/projects/{project_id}")
|
||||
|
||||
async def download_project(self, project_id: UUID | str) -> dict[str, bytes]:
|
||||
"""Download all flows in a project.
|
||||
@@ -334,13 +334,13 @@ class AsyncFlowClient(_ClientCommon):
|
||||
Raises :class:`ValueError` if the archive contains more than 500
|
||||
entries or any single entry exceeds 50 MB (zip-bomb protection).
|
||||
"""
|
||||
resp = await self._request("GET", f"/api/v1/projects/download/{project_id}")
|
||||
resp = await self._request("GET", f"/v1/projects/download/{project_id}")
|
||||
return self._extract_project_archive(resp.content)
|
||||
|
||||
async def upload_project(self, zip_bytes: bytes) -> list[Flow]:
|
||||
resp = await self._request(
|
||||
"POST",
|
||||
"/api/v1/projects/upload/",
|
||||
"/v1/projects/upload/",
|
||||
content=zip_bytes,
|
||||
headers={"Content-Type": "application/octet-stream"},
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Wraps an :class:`asyncio.Task` so callers can start a flow run and poll or
|
||||
await it without blocking the event loop. Mirrors the ``BackgroundJob`` API
|
||||
from flow-ai/sdk PR #1 (Janardan Singh Kavia, IBM Corp., Apache 2.0)
|
||||
adapted for the Flow V1 ``/api/v1/run/{id}`` endpoint.
|
||||
adapted for the Flow V1 ``/v1/run/{id}`` endpoint.
|
||||
|
||||
Typical usage::
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ class FlowClient(_ClientCommon):
|
||||
) -> list[Flow]:
|
||||
resp = self._request(
|
||||
"GET",
|
||||
"/api/v1/flows/",
|
||||
"/v1/flows/",
|
||||
params=self._build_flow_list_params(
|
||||
folder_id=folder_id,
|
||||
remove_example_flows=remove_example_flows,
|
||||
@@ -154,17 +154,17 @@ class FlowClient(_ClientCommon):
|
||||
return self._validate_model_list(Flow, resp.json())
|
||||
|
||||
def get_flow(self, flow_id: UUID | str) -> Flow:
|
||||
resp = self._request("GET", f"/api/v1/flows/{flow_id}")
|
||||
resp = self._request("GET", f"/v1/flows/{flow_id}")
|
||||
return self._validate_model(Flow, resp.json())
|
||||
|
||||
def create_flow(self, flow: FlowCreate) -> Flow:
|
||||
resp = self._request("POST", "/api/v1/flows/", json=self._model_payload(flow))
|
||||
resp = self._request("POST", "/v1/flows/", json=self._model_payload(flow))
|
||||
return self._validate_model(Flow, resp.json())
|
||||
|
||||
def update_flow(self, flow_id: UUID | str, update: FlowUpdate) -> Flow:
|
||||
resp = self._request(
|
||||
"PATCH",
|
||||
f"/api/v1/flows/{flow_id}",
|
||||
f"/v1/flows/{flow_id}",
|
||||
json=self._model_payload(update),
|
||||
)
|
||||
return self._validate_model(Flow, resp.json())
|
||||
@@ -177,13 +177,13 @@ class FlowClient(_ClientCommon):
|
||||
"""
|
||||
resp = self._request(
|
||||
"PUT",
|
||||
f"/api/v1/flows/{flow_id}",
|
||||
f"/v1/flows/{flow_id}",
|
||||
json=self._model_payload(flow),
|
||||
)
|
||||
return self._upsert_result(Flow, resp)
|
||||
|
||||
def delete_flow(self, flow_id: UUID | str) -> None:
|
||||
self._request("DELETE", f"/api/v1/flows/{flow_id}")
|
||||
self._request("DELETE", f"/v1/flows/{flow_id}")
|
||||
|
||||
def run_flow(
|
||||
self,
|
||||
@@ -192,7 +192,7 @@ class FlowClient(_ClientCommon):
|
||||
) -> RunResponse:
|
||||
resp = self._request(
|
||||
"POST",
|
||||
f"/api/v1/run/{flow_id_or_endpoint}",
|
||||
f"/v1/run/{flow_id_or_endpoint}",
|
||||
json=self._model_payload(request),
|
||||
)
|
||||
return self._validate_model(RunResponse, resp.json())
|
||||
@@ -244,7 +244,7 @@ class FlowClient(_ClientCommon):
|
||||
response = chunk.final_response()
|
||||
"""
|
||||
return self._iter_stream(
|
||||
f"/api/v1/run/{flow_id_or_endpoint}",
|
||||
f"/v1/run/{flow_id_or_endpoint}",
|
||||
self._build_stream_payload(
|
||||
input_value=input_value,
|
||||
input_type=input_type,
|
||||
@@ -275,27 +275,27 @@ class FlowClient(_ClientCommon):
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def list_projects(self) -> list[Project]:
|
||||
resp = self._request("GET", "/api/v1/projects/")
|
||||
resp = self._request("GET", "/v1/projects/")
|
||||
return self._validate_model_list(Project, resp.json())
|
||||
|
||||
def get_project(self, project_id: UUID | str) -> ProjectWithFlows:
|
||||
resp = self._request("GET", f"/api/v1/projects/{project_id}")
|
||||
resp = self._request("GET", f"/v1/projects/{project_id}")
|
||||
return self._validate_model(ProjectWithFlows, resp.json())
|
||||
|
||||
def create_project(self, project: ProjectCreate) -> Project:
|
||||
resp = self._request("POST", "/api/v1/projects/", json=self._model_payload(project))
|
||||
resp = self._request("POST", "/v1/projects/", json=self._model_payload(project))
|
||||
return self._validate_model(Project, resp.json())
|
||||
|
||||
def update_project(self, project_id: UUID | str, update: ProjectUpdate) -> Project:
|
||||
resp = self._request(
|
||||
"PATCH",
|
||||
f"/api/v1/projects/{project_id}",
|
||||
f"/v1/projects/{project_id}",
|
||||
json=self._model_payload(update),
|
||||
)
|
||||
return self._validate_model(Project, resp.json())
|
||||
|
||||
def delete_project(self, project_id: UUID | str) -> None:
|
||||
self._request("DELETE", f"/api/v1/projects/{project_id}")
|
||||
self._request("DELETE", f"/v1/projects/{project_id}")
|
||||
|
||||
def download_project(self, project_id: UUID | str) -> dict[str, bytes]:
|
||||
"""Download all flows in a project.
|
||||
@@ -306,14 +306,14 @@ class FlowClient(_ClientCommon):
|
||||
Raises :class:`ValueError` if the archive contains more than 500
|
||||
entries or any single entry exceeds 50 MB (zip-bomb protection).
|
||||
"""
|
||||
resp = self._request("GET", f"/api/v1/projects/download/{project_id}")
|
||||
resp = self._request("GET", f"/v1/projects/download/{project_id}")
|
||||
return self._extract_project_archive(resp.content)
|
||||
|
||||
def upload_project(self, zip_bytes: bytes) -> list[Flow]:
|
||||
"""Upload a project ZIP archive and return the created flows."""
|
||||
resp = self._request(
|
||||
"POST",
|
||||
"/api/v1/projects/upload/",
|
||||
"/v1/projects/upload/",
|
||||
content=zip_bytes,
|
||||
headers={"Content-Type": "application/octet-stream"},
|
||||
)
|
||||
@@ -327,7 +327,7 @@ class FlowClient(_ClientCommon):
|
||||
"""Upload or update a flow from a local JSON file.
|
||||
|
||||
The ``id`` field embedded in the file is used for upsert
|
||||
(create-or-update via ``PUT /api/v1/flows/{id}``).
|
||||
(create-or-update via ``PUT /v1/flows/{id}``).
|
||||
Returns ``(flow, created)`` where ``created`` is ``True`` when the
|
||||
flow was newly created and ``False`` when it was updated::
|
||||
|
||||
|
||||
Reference in New Issue
Block a user