refactor(console): canonical /v1 surface — drop /api/ prefix and nested /v2
- next.config: one V1_PASS_THROUGH + V1_FROM_V2 table drives both /v1->/api rewrites and inverse /api->/v1 (307) redirects; /v1/prompts,/v1/scores map to the v2 handlers (no /v1/v2). CSP/headers treat /v1 as API surface. - relocate App-Router routes (chatCompletion,in-app-agent,billing) app/api->app/v1 and pages/api/trpc->pages/v1/trpc (depth-preserving; imports unaffected). - emitters speak /v1 directly: tRPC client, @hanzo/console-js SDK (/v1/prompts), Fern base-paths (32 files, zero /v1/v2), client fetches, probe paths. - Dockerfile HEALTHCHECK -> /v1/ready (was /api/health 404; /health hangs).
This commit is contained in:
+2
-2
@@ -130,7 +130,7 @@ ENV PORT=3000
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD node -e "const http = require('http'); \
|
||||
const req = http.request({hostname: 'localhost', port: 3000, path: '/api/health', method: 'GET'}, \
|
||||
const req = http.request({hostname: 'localhost', port: 3000, path: '/v1/ready', method: 'GET'}, \
|
||||
(res) => process.exit(res.statusCode === 200 ? 0 : 1)); \
|
||||
req.on('error', () => process.exit(1)); \
|
||||
req.end();" || exit 1
|
||||
@@ -170,7 +170,7 @@ ENV PRISMA_QUERY_ENGINE_LIBRARY=/app/web/.prisma/client/libquery_engine-linux-mu
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD node -e "const http = require('http'); \
|
||||
const req = http.request({hostname: 'localhost', port: 3000, path: '/api/health', method: 'GET'}, \
|
||||
const req = http.request({hostname: 'localhost', port: 3000, path: '/v1/ready', method: 'GET'}, \
|
||||
(res) => process.exit(res.statusCode === 200 ? 0 : 1)); \
|
||||
req.on('error', () => process.exit(1)); \
|
||||
req.end();" || exit 1
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
create:
|
||||
docs: Add a score to the database, upserts on id
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/admin
|
||||
base-path: /v1/admin
|
||||
endpoints:
|
||||
getAll:
|
||||
docs: Get all organizations
|
||||
|
||||
@@ -5,7 +5,7 @@ imports:
|
||||
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
listQueues:
|
||||
docs: Get all annotation queues
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public/integrations/blob-storage
|
||||
base-path: /v1/integrations/blob-storage
|
||||
endpoints:
|
||||
getBlobStorageIntegrations:
|
||||
docs: Get all blob storage integrations for the organization (requires organization-scoped API key)
|
||||
@@ -65,7 +65,7 @@ types:
|
||||
docs: |
|
||||
What data the integration exports.
|
||||
- `LEGACY_TRACES_OBSERVATIONS`: traces, observations, and scores tables with a fixed column set. The `exportFieldGroups` field is not applicable.
|
||||
- `OBSERVATIONS_V2`: same data model as the `/api/public/v2/observations` endpoint, plus scores. Columns are controlled by `exportFieldGroups`.
|
||||
- `OBSERVATIONS_V2`: same data model as the `/v1/observations` endpoint, plus scores. Columns are controlled by `exportFieldGroups`.
|
||||
- `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS`: both sets. For the `OBSERVATIONS_V2` portion, columns are controlled by `exportFieldGroups`.
|
||||
|
||||
**Note:** `OBSERVATIONS_V2` and the enriched-observations portion of `LEGACY_TRACES_AND_ENRICHED_OBSERVATIONS` rely on the enriched observations table (Langfuse Fast Preview / v4), which is currently available on Langfuse Cloud only. See https://langfuse.com/docs/v4.
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
commons: ./commons.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
create:
|
||||
docs: Create a comment. Comments may be attached to different object types (trace, observation, session, prompt).
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
pagination: ./utils/pagination.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
create:
|
||||
method: POST
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
pagination: ./utils/pagination.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
create:
|
||||
method: POST
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
pagination: ./utils/pagination.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
list:
|
||||
method: GET
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/fern-api/fern/main/fern.schema.json
|
||||
service:
|
||||
auth: false
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
health:
|
||||
docs: Check health of API and database
|
||||
|
||||
@@ -4,16 +4,16 @@ imports:
|
||||
commons: ./commons.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
batch:
|
||||
availability:
|
||||
status: deprecated
|
||||
message: "Use the OpenTelemetry endpoint at /api/public/otel/v1/traces instead. Learn more: https://hanzo.com/integrations/native/opentelemetry"
|
||||
message: "Use the OpenTelemetry endpoint at /v1/otel/v1/traces instead. Learn more: https://hanzo.com/integrations/native/opentelemetry"
|
||||
docs: |
|
||||
**Legacy endpoint for batch ingestion for Hanzo Observability.**
|
||||
|
||||
-> Please use the OpenTelemetry endpoint (`/api/public/otel/v1/traces`). Learn more: https://hanzo.com/integrations/native/opentelemetry
|
||||
-> Please use the OpenTelemetry endpoint (`/v1/otel/v1/traces`). Learn more: https://hanzo.com/integrations/native/opentelemetry
|
||||
|
||||
Within each batch, there can be multiple events.
|
||||
Each event has a type, an id, a timestamp, metadata and a body.
|
||||
|
||||
@@ -4,13 +4,13 @@ imports:
|
||||
commons: ../commons.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
metrics:
|
||||
docs: |
|
||||
Get metrics from the Langfuse project using a query object.
|
||||
|
||||
Consider using the [v2 metrics endpoint](/api-reference#tag/metricsv2/GET/api/public/v2/metrics) for better performance.
|
||||
Consider using the [v2 metrics endpoint](/api-reference#tag/metricsv2/GET/v1/metrics) for better performance.
|
||||
|
||||
For more details, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api).
|
||||
method: GET
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
pagination: ../utils/pagination.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
get:
|
||||
docs: Get a observation
|
||||
@@ -19,7 +19,7 @@ service:
|
||||
docs: |
|
||||
Get a list of observations.
|
||||
|
||||
Consider using the [v2 observations endpoint](/api-reference#tag/observationsv2/GET/api/public/v2/observations) for cursor-based pagination and field selection.
|
||||
Consider using the [v2 observations endpoint](/api-reference#tag/observationsv2/GET/v1/observations) for cursor-based pagination and field selection.
|
||||
method: GET
|
||||
path: /observations
|
||||
request:
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
commons: ../commons.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
create:
|
||||
docs: Create a score (supports both trace and session scores)
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
pagination: ./utils/pagination.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
list:
|
||||
method: GET
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
get:
|
||||
docs: Get a media record
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
commons: ./commons.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
metrics:
|
||||
docs: |
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
pagination: ./utils/pagination.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
create:
|
||||
method: POST
|
||||
|
||||
@@ -3,7 +3,7 @@ imports:
|
||||
commons: ./commons.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
get:
|
||||
docs: Get a observation
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/fern-api/fern/main/fern.schema.json
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
exportTraces:
|
||||
docs: |
|
||||
|
||||
@@ -5,7 +5,7 @@ imports:
|
||||
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
getOrganizationMemberships:
|
||||
docs: Get all memberships for the organization associated with the API key (requires organization-scoped API key)
|
||||
|
||||
@@ -4,10 +4,10 @@ imports:
|
||||
pagination: ./utils/pagination.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
get:
|
||||
docs: Get Project associated with API key (requires project-scoped API key). You can use GET /api/public/organizations/projects to get all projects with an organization-scoped key.
|
||||
docs: Get Project associated with API key (requires project-scoped API key). You can use GET /v1/organizations/projects to get all projects with an organization-scoped key.
|
||||
method: GET
|
||||
path: /projects
|
||||
response: Projects
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
pagination: ./utils/pagination.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public/v2
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
update:
|
||||
docs: Update labels for a specific prompt version
|
||||
|
||||
@@ -5,7 +5,7 @@ imports:
|
||||
scim: ./scim.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public/v2
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
get:
|
||||
docs: Get a prompt
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public/scim
|
||||
base-path: /v1/scim
|
||||
endpoints:
|
||||
getServiceProviderConfig:
|
||||
docs: Get SCIM Service Provider Configuration (requires organization-scoped API key)
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
commons: ./commons.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
create:
|
||||
docs: Create a score configuration (config). Score configs are used to define the structure of scores
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
commons: ./commons.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public/v2
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
get-many:
|
||||
docs: Get a list of scores (supports both trace and session scores)
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
commons: ./commons.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
list:
|
||||
docs: Get sessions
|
||||
@@ -31,7 +31,7 @@ service:
|
||||
docs: Optional filter for sessions where the environment is one of the provided values.
|
||||
response: PaginatedSessions
|
||||
get:
|
||||
docs: Get a session. Please note that `traces` on this endpoint are not paginated, if you plan to fetch large sessions, consider `GET /api/public/traces?sessionId=<sessionId>`
|
||||
docs: Get a session. Please note that `traces` on this endpoint are not paginated, if you plan to fetch large sessions, consider `GET /v1/traces?sessionId=<sessionId>`
|
||||
method: GET
|
||||
path: /sessions/{sessionId}
|
||||
path-parameters:
|
||||
|
||||
@@ -4,7 +4,7 @@ imports:
|
||||
commons: ./commons.yml
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public
|
||||
base-path: /v1
|
||||
endpoints:
|
||||
get:
|
||||
docs: Get a specific trace
|
||||
|
||||
@@ -27,7 +27,7 @@ types:
|
||||
It supports mapping from `input`, `output`, and `metadata`.
|
||||
- `experiment` evaluates live experiment executions and can additionally map `expected_output` and `experiment_item_metadata`.
|
||||
It currently supports filtering by `datasetId`.
|
||||
Discover valid dataset IDs with `GET /api/public/v2/datasets`, then use the returned dataset `id` values in your filter.
|
||||
Discover valid dataset IDs with `GET /v1/datasets`, then use the returned dataset `id` values in your filter.
|
||||
enum:
|
||||
- observation
|
||||
- experiment
|
||||
@@ -74,7 +74,7 @@ types:
|
||||
If omitted, Langfuse uses the project's default evaluation model.
|
||||
If provided, the model must be available to the project when the evaluator or evaluation rule is enabled.
|
||||
|
||||
To discover valid configured `provider` values for a project, call `GET /api/public/llm-connections` and read the `provider` field from the returned connections.
|
||||
To discover valid configured `provider` values for a project, call `GET /v1/llm-connections` and read the `provider` field from the returned connections.
|
||||
Use a `provider` value that matches one of the connections already configured in the same project.
|
||||
|
||||
Recovery guidance:
|
||||
@@ -85,7 +85,7 @@ types:
|
||||
docs: |
|
||||
Provider identifier to use for this evaluator, for example `openai` or `anthropic`.
|
||||
|
||||
To discover valid values for the current project, call `GET /api/public/llm-connections` and use one of the returned `provider` values.
|
||||
To discover valid values for the current project, call `GET /v1/llm-connections` and use one of the returned `provider` values.
|
||||
model:
|
||||
type: string
|
||||
docs: Model identifier exposed by the provider, for example `gpt-4.1-mini`.
|
||||
@@ -502,12 +502,12 @@ types:
|
||||
- `toolCalls`: `number`
|
||||
- `target=experiment`
|
||||
- `datasetId`: `stringOptions`, operators `any of` / `none of`
|
||||
Use dataset `id` values from `GET /api/public/v2/datasets`, not dataset names.
|
||||
Use dataset `id` values from `GET /v1/datasets`, not dataset names.
|
||||
|
||||
Recovery guidance:
|
||||
- `invalid_filter_value` with `details.column` but no `invalidValues`: the selected `column` is not supported for the chosen `target`
|
||||
- `invalid_filter_value` with `details.invalidValues`: the selected values are not allowed for that column. Replace them with one of `details.allowedValues` when provided.
|
||||
- `invalid_filter_value` for `column=datasetId`: call `GET /api/public/v2/datasets`, then retry with dataset `id` values from that response.
|
||||
- `invalid_filter_value` for `column=datasetId`: call `GET /v1/datasets`, then retry with dataset `id` values from that response.
|
||||
discriminant: type
|
||||
union:
|
||||
"datetime":
|
||||
|
||||
@@ -169,7 +169,7 @@ types:
|
||||
value: "$["
|
||||
- name: NameConflict
|
||||
value:
|
||||
message: 'An evaluation rule named "answer-quality-live" already exists in this project. Use PATCH /api/public/unstable/evaluation-rules/erule_123 to update it instead of creating a duplicate.'
|
||||
message: 'An evaluation rule named "answer-quality-live" already exists in this project. Use PATCH /v1/unstable/evaluation-rules/erule_123 to update it instead of creating a duplicate.'
|
||||
code: name_conflict
|
||||
details:
|
||||
field: name
|
||||
@@ -203,7 +203,7 @@ errors:
|
||||
Recovery guidance:
|
||||
- read `details.issues` for malformed bodies or queries
|
||||
- read `details.column`, `details.invalidValues`, and `details.allowedValues` for filter problems
|
||||
- for `details.column=datasetId`, call `GET /api/public/v2/datasets` and retry with dataset `id` values from that response
|
||||
- for `details.column=datasetId`, call `GET /v1/datasets` and retry with dataset `id` values from that response
|
||||
- read `details.variable` or `details.variables` for mapping problems
|
||||
status-code: 400
|
||||
type: PublicApiError
|
||||
|
||||
@@ -6,7 +6,7 @@ imports:
|
||||
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public/unstable
|
||||
base-path: /v1/unstable
|
||||
endpoints:
|
||||
create:
|
||||
docs: |
|
||||
@@ -21,14 +21,14 @@ service:
|
||||
- `target` must be `observation` or `experiment`
|
||||
- `evaluator.name` + `evaluator.scope` must identify an existing evaluator family returned by the evaluator endpoints
|
||||
- Langfuse resolves that family to its latest version before saving the evaluation rule
|
||||
- for `target=experiment`, use dataset `id` values from `GET /api/public/v2/datasets` when filtering by `datasetId`
|
||||
- for `target=experiment`, use dataset `id` values from `GET /v1/datasets` when filtering by `datasetId`
|
||||
- every evaluator prompt variable must be mapped exactly once
|
||||
- `expected_output` and `experiment_item_metadata` mappings are only valid for `target=experiment`
|
||||
- if `enabled=true`, Langfuse validates that the referenced evaluator can currently run
|
||||
- at most 50 evaluation rules can be effectively active in one project at the same time
|
||||
|
||||
If an evaluation rule with the same `name` already exists in the project, the API returns `409`.
|
||||
In that case, update the existing resource with `PATCH /api/public/unstable/evaluation-rules/{evaluationRuleId}` instead of creating a second one.
|
||||
In that case, update the existing resource with `PATCH /v1/unstable/evaluation-rules/{evaluationRuleId}` instead of creating a second one.
|
||||
|
||||
If enabling this resource would exceed the 50-active limit, the API also returns `409`.
|
||||
In that case, disable or pause another active evaluation rule before enabling a new one.
|
||||
@@ -39,7 +39,7 @@ service:
|
||||
|
||||
Recovery guidance:
|
||||
- `400 invalid_filter_value`: fix the filter `column` or `value` using `details.column`, `details.invalidValues`, and `details.allowedValues`
|
||||
- `400 invalid_filter_value` with `details.column=datasetId`: call `GET /api/public/v2/datasets`, then retry with dataset `id` values from that response
|
||||
- `400 invalid_filter_value` with `details.column=datasetId`: call `GET /v1/datasets`, then retry with dataset `id` values from that response
|
||||
- `400 missing_variable_mapping`: fetch the evaluator again and make sure every variable in `variables` appears exactly once in `mapping`
|
||||
- `400 duplicate_variable_mapping`: remove repeated mappings for the same variable
|
||||
- `400 invalid_variable_mapping`: switch to a valid `source` for the selected `target`, or fix the variable name
|
||||
@@ -109,7 +109,7 @@ service:
|
||||
createdAt: "2026-03-30T09:20:00.000Z"
|
||||
updatedAt: "2026-03-30T09:20:00.000Z"
|
||||
- name: CreateExperimentEvaluationRule
|
||||
docs: Deploy an evaluator to compare experiment outputs against expected outputs. Discover valid dataset IDs with `GET /api/public/v2/datasets` first.
|
||||
docs: Deploy an evaluator to compare experiment outputs against expected outputs. Discover valid dataset IDs with `GET /v1/datasets` first.
|
||||
request:
|
||||
name: experiment-expected-output-match
|
||||
evaluator:
|
||||
@@ -375,7 +375,7 @@ types:
|
||||
Checklist for agents and SDK clients:
|
||||
- reference an existing evaluator family by `evaluator.name` and `evaluator.scope`
|
||||
- choose `target=observation` or `target=experiment`
|
||||
- if `target=experiment` and you want a dataset filter, call `GET /api/public/v2/datasets` first and use dataset `id` values in `filter[].value`
|
||||
- if `target=experiment` and you want a dataset filter, call `GET /v1/datasets` first and use dataset `id` values in `filter[].value`
|
||||
- fetch or inspect the evaluator first, then provide a complete variable mapping for every evaluator variable listed in `variables`
|
||||
- optionally narrow execution with `filter`
|
||||
- set `enabled=true` only when you want live execution immediately
|
||||
@@ -406,7 +406,7 @@ types:
|
||||
|
||||
Omit or pass an empty list to evaluate all matching targets for the selected `target`.
|
||||
Each filter object must use a column that is valid for that `target`.
|
||||
For `target=experiment`, `column=datasetId` expects dataset `id` values from `GET /api/public/v2/datasets`, not dataset names.
|
||||
For `target=experiment`, `column=datasetId` expects dataset `id` values from `GET /v1/datasets`, not dataset names.
|
||||
mapping:
|
||||
type: list<commons.EvaluationRuleMapping>
|
||||
docs: |
|
||||
@@ -426,7 +426,7 @@ types:
|
||||
- If you only want to rename the rule or change sampling, send just those fields.
|
||||
- If you change `evaluator`, send a fresh `mapping` unless you are certain the existing mapping still matches the evaluator variables.
|
||||
- If you change `target`, usually send both `filter` and `mapping` in the same request.
|
||||
- If you change an experiment `datasetId` filter, call `GET /api/public/v2/datasets` and use dataset `id` values from that response.
|
||||
- If you change an experiment `datasetId` filter, call `GET /v1/datasets` and use dataset `id` values from that response.
|
||||
properties:
|
||||
name:
|
||||
type: optional<string>
|
||||
@@ -451,7 +451,7 @@ types:
|
||||
docs: |
|
||||
Updated filter list.
|
||||
|
||||
For `target=experiment`, `column=datasetId` expects dataset `id` values from `GET /api/public/v2/datasets`, not dataset names.
|
||||
For `target=experiment`, `column=datasetId` expects dataset `id` values from `GET /v1/datasets`, not dataset names.
|
||||
mapping:
|
||||
type: optional<list<commons.EvaluationRuleMapping>>
|
||||
docs: Updated variable mappings.
|
||||
|
||||
@@ -6,7 +6,7 @@ imports:
|
||||
|
||||
service:
|
||||
auth: true
|
||||
base-path: /api/public/unstable
|
||||
base-path: /v1/unstable
|
||||
endpoints:
|
||||
create:
|
||||
docs: |
|
||||
|
||||
@@ -44,7 +44,7 @@ export class Hanzo {
|
||||
* Fetches a prompt from the Hanzo prompt management service.
|
||||
*/
|
||||
async getPrompt(name: string, version?: number, options?: PromptOptions): Promise<PromptResponse> {
|
||||
const url = new URL(`/api/public/v2/prompts/${encodeURIComponent(name)}`, this.baseUrl);
|
||||
const url = new URL(`/v1/prompts/${encodeURIComponent(name)}`, this.baseUrl);
|
||||
if (version !== undefined) {
|
||||
url.searchParams.set("version", String(version));
|
||||
}
|
||||
|
||||
@@ -2544,7 +2544,7 @@ export const getEventsForAnalyticsIntegrations = async function* (
|
||||
},
|
||||
});
|
||||
|
||||
const baseUrl = env.NEXTAUTH_URL?.replace("/api/auth", "");
|
||||
const baseUrl = env.NEXTAUTH_URL?.replace("/v1/auth", "");
|
||||
for await (const record of records) {
|
||||
yield {
|
||||
timestamp: record.start_time,
|
||||
|
||||
@@ -1744,7 +1744,7 @@ export const getGenerationsForAnalyticsIntegrations = async function* (
|
||||
},
|
||||
});
|
||||
|
||||
const baseUrl = env.NEXTAUTH_URL?.replace("/api/auth", "");
|
||||
const baseUrl = env.NEXTAUTH_URL?.replace("/v1/auth", "");
|
||||
for await (const record of records) {
|
||||
yield {
|
||||
timestamp: record.start_time,
|
||||
|
||||
@@ -1733,7 +1733,7 @@ export const getScoresForAnalyticsIntegrations = async function* (
|
||||
},
|
||||
});
|
||||
|
||||
const baseUrl = env.NEXTAUTH_URL?.replace("/api/auth", "");
|
||||
const baseUrl = env.NEXTAUTH_URL?.replace("/v1/auth", "");
|
||||
for await (const record of records) {
|
||||
// Determine the effective session_id based on score attachment
|
||||
const effectiveSessionId = record.score_session_id || record.trace_session_id;
|
||||
|
||||
@@ -1360,7 +1360,7 @@ export const getTracesForAnalyticsIntegrations = async function* (
|
||||
},
|
||||
});
|
||||
|
||||
const baseUrl = env.NEXTAUTH_URL?.replace("/api/auth", "");
|
||||
const baseUrl = env.NEXTAUTH_URL?.replace("/v1/auth", "");
|
||||
|
||||
for await (const record of records) {
|
||||
yield {
|
||||
|
||||
+104
-33
@@ -52,6 +52,35 @@ const sharedAlias = {
|
||||
"@/src/features/query": path.join(sharedSrc, "features/query"),
|
||||
};
|
||||
|
||||
// Canonical URL surface (single source of truth). Every console HTTP path is
|
||||
// published at /v1/*; the Pages Router keeps handler files under pages/api/, so
|
||||
// /v1/* is rewritten onto them and every legacy /api/* is 307-forwarded back to
|
||||
// /v1/*. Both directions are derived from this one list (DRY) — segment name is
|
||||
// preserved (/v1/<seg>/* ↔ /api/<seg>/*). The public SDK API is handled
|
||||
// separately by collapsing /api/public/* ↔ /v1/* (the redundant `public` drops).
|
||||
const V1_PASS_THROUGH = [
|
||||
"auth", // NextAuth (basePath is /v1/auth)
|
||||
"trpc", // tRPC web RPC
|
||||
"admin",
|
||||
"agents",
|
||||
"billing",
|
||||
"compute",
|
||||
"dashboard",
|
||||
"feedback",
|
||||
"kms",
|
||||
"observe",
|
||||
"start-cron",
|
||||
"support",
|
||||
"zap",
|
||||
"chatCompletion",
|
||||
"in-app-agent",
|
||||
];
|
||||
|
||||
// Resources whose current version is Langfuse-internal "v2". There is NO /v1/v2
|
||||
// in the published surface — these are served at /v1/<resource> and routed onto
|
||||
// the v2 handler file. (House rule: one version segment, /v1, never a nested v2.)
|
||||
const V1_FROM_V2 = ["prompts", "scores"];
|
||||
|
||||
/**
|
||||
* CSP headers
|
||||
* img-src https to allow loading images from SSO providers
|
||||
@@ -157,38 +186,80 @@ const nextConfig = {
|
||||
},
|
||||
output: "standalone",
|
||||
|
||||
// Two purposes:
|
||||
// 1. /v1/* → /api/* — Pages Router forces API files under `pages/api/`, but
|
||||
// the canonical published URL surface is /v1/*. This rewrite exposes the
|
||||
// Hanzo-owned (non-upstream) internal routes at /v1/*. Internal callers
|
||||
// in code (components, hooks, services) must reference /v1/* paths.
|
||||
// The Langfuse upstream surfaces (/api/public/*, /api/auth/*, /api/trpc/*,
|
||||
// /api/observe/*) keep their /api/* shapes because external SDKs and
|
||||
// NextAuth/tRPC libraries hardcode those.
|
||||
// 2. Frontend-only mode proxies API calls to a production console.
|
||||
// Canonical URL surface — exactly one way: /v1/*. The Pages Router forces
|
||||
// handler files under pages/api/, so /v1/* is rewritten onto them. rewrites()
|
||||
// and redirects() are BOTH derived from V1_PASS_THROUGH (above) so the two
|
||||
// directions can never drift. A specific rule (internal trace export) is
|
||||
// listed before the public-API catch-all so it wins by order.
|
||||
async rewrites() {
|
||||
const v1ToApi = [
|
||||
"admin",
|
||||
"agents",
|
||||
"billing",
|
||||
"compute",
|
||||
"feedback",
|
||||
"kms",
|
||||
"start-cron",
|
||||
"zap",
|
||||
].map((seg) => ({
|
||||
source: `/v1/${seg}/:path*`,
|
||||
destination: `/api/${seg}/:path*`,
|
||||
}));
|
||||
// Top-level feedback / start-cron without /:path*
|
||||
v1ToApi.push({ source: "/v1/feedback", destination: "/api/feedback" });
|
||||
v1ToApi.push({ source: "/v1/start-cron", destination: "/api/start-cron" });
|
||||
|
||||
if (process.env.SKIP_ENV_VALIDATION !== "1") return v1ToApi;
|
||||
const target = process.env.CONSOLE_API_URL || "https://console.hanzo.ai";
|
||||
// Frontend-only mode: proxy BOTH surfaces to a live console, no local API.
|
||||
if (process.env.SKIP_ENV_VALIDATION === "1") {
|
||||
const target = process.env.CONSOLE_API_URL || "https://console.hanzo.ai";
|
||||
return [
|
||||
{ source: "/v1/:path*", destination: `${target}/v1/:path*` },
|
||||
{ source: "/api/:path*", destination: `${target}/api/:path*` },
|
||||
];
|
||||
}
|
||||
const passThrough = V1_PASS_THROUGH.flatMap((seg) => [
|
||||
{ source: `/v1/${seg}/:path*`, destination: `/api/${seg}/:path*` },
|
||||
{ source: `/v1/${seg}`, destination: `/api/${seg}` },
|
||||
]);
|
||||
const v2Rewrites = V1_FROM_V2.flatMap((seg) => [
|
||||
{ source: `/v1/${seg}/:path*`, destination: `/api/public/v2/${seg}/:path*` },
|
||||
{ source: `/v1/${seg}`, destination: `/api/public/v2/${seg}` },
|
||||
]);
|
||||
return [
|
||||
...v1ToApi,
|
||||
{ source: "/api/:path*", destination: `${target}/api/:path*` },
|
||||
// internal trace export must win over the public-API catch-all below
|
||||
{
|
||||
source: "/v1/traces/:traceId/download",
|
||||
destination: "/api/traces/:traceId/download",
|
||||
},
|
||||
...passThrough,
|
||||
// v2-current resources at /v1/<resource> (no /v1/v2) — precede catch-all
|
||||
...v2Rewrites,
|
||||
// public SDK API — the redundant /api/public segment is dropped
|
||||
{ source: "/v1/:path*", destination: "/api/public/:path*" },
|
||||
];
|
||||
},
|
||||
|
||||
// Inverse of rewrites(): every legacy /api/* 307s to canonical /v1/*. 307
|
||||
// (not 308) keeps a rollback from sticking in browser caches.
|
||||
async redirects() {
|
||||
if (process.env.SKIP_ENV_VALIDATION === "1") return [];
|
||||
const passThrough = V1_PASS_THROUGH.flatMap((seg) => [
|
||||
{
|
||||
source: `/api/${seg}/:path*`,
|
||||
destination: `/v1/${seg}/:path*`,
|
||||
permanent: false,
|
||||
},
|
||||
{ source: `/api/${seg}`, destination: `/v1/${seg}`, permanent: false },
|
||||
]);
|
||||
const v2Redirects = V1_FROM_V2.flatMap((seg) => [
|
||||
{
|
||||
source: `/api/public/v2/${seg}/:path*`,
|
||||
destination: `/v1/${seg}/:path*`,
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
source: `/api/public/v2/${seg}`,
|
||||
destination: `/v1/${seg}`,
|
||||
permanent: false,
|
||||
},
|
||||
]);
|
||||
return [
|
||||
{
|
||||
source: "/api/traces/:traceId/download",
|
||||
destination: "/v1/traces/:traceId/download",
|
||||
permanent: false,
|
||||
},
|
||||
...passThrough,
|
||||
// /api/public/v2/<resource> → /v1/<resource> (precede the general rule)
|
||||
...v2Redirects,
|
||||
{
|
||||
source: "/api/public/:path*",
|
||||
destination: "/v1/:path*",
|
||||
permanent: false,
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
@@ -240,9 +311,9 @@ const nextConfig = {
|
||||
value: host,
|
||||
})),
|
||||
},
|
||||
// CSP header
|
||||
// CSP header (skip the API surface — both /api/* and the canonical /v1/*)
|
||||
{
|
||||
source: "/:path((?!api).*)*",
|
||||
source: "/:path((?!api|v1).*)*",
|
||||
headers: [
|
||||
{
|
||||
key: "Content-Security-Policy",
|
||||
@@ -259,7 +330,7 @@ const nextConfig = {
|
||||
...(env.NEXT_PUBLIC_HANZO_CLOUD_REGION !== undefined
|
||||
? [
|
||||
{
|
||||
source: "/api/auth/session",
|
||||
source: "/v1/auth/session",
|
||||
headers: [
|
||||
{
|
||||
key: "Access-Control-Allow-Origin",
|
||||
|
||||
@@ -323,7 +323,7 @@ function SsoConfigDialog({
|
||||
|
||||
const callbackUrl = useMemo(() => {
|
||||
if (typeof window === "undefined") return "";
|
||||
return `${window.location.origin}/api/auth/callback/${domain}.${selectedProvider}`;
|
||||
return `${window.location.origin}/v1/auth/callback/${domain}.${selectedProvider}`;
|
||||
}, [domain, selectedProvider]);
|
||||
|
||||
const saveMutation = api.ssoConfig.save.useMutation({
|
||||
|
||||
@@ -28,7 +28,7 @@ function generateCurlCommand(execution: WorkflowExecution): string {
|
||||
// Use the correct API format: nodeid.reasonerid
|
||||
const baseUrl = window.location.origin;
|
||||
const target = `${execution.agent_node_id}.${execution.reasoner_id}`;
|
||||
const apiUrl = `${baseUrl}/api/agents/v1/execute/${target}`;
|
||||
const apiUrl = `${baseUrl}/v1/agents/v1/execute/${target}`;
|
||||
|
||||
const payload = {
|
||||
input: execution.input_data || {}
|
||||
@@ -46,7 +46,7 @@ function generateCurlCommand(execution: WorkflowExecution): string {
|
||||
function generatePythonCode(execution: WorkflowExecution): string {
|
||||
const baseUrl = window.location.origin;
|
||||
const target = `${execution.agent_node_id}.${execution.reasoner_id}`;
|
||||
const apiUrl = `${baseUrl}/api/agents/v1/execute/${target}`;
|
||||
const apiUrl = `${baseUrl}/v1/agents/v1/execute/${target}`;
|
||||
|
||||
const payload = {
|
||||
input: execution.input_data || {}
|
||||
@@ -112,7 +112,7 @@ export function ExecutionRetryPanel({ execution }: ExecutionRetryPanelProps) {
|
||||
// Use the correct API format: nodeid.reasonerid
|
||||
const baseUrl = window.location.origin;
|
||||
const target = `${execution.agent_node_id}.${execution.reasoner_id}`;
|
||||
const apiUrl = `${baseUrl}/api/agents/v1/execute/${target}`;
|
||||
const apiUrl = `${baseUrl}/v1/agents/v1/execute/${target}`;
|
||||
|
||||
const payload = {
|
||||
input: execution.input_data || {}
|
||||
|
||||
@@ -27,7 +27,7 @@ import type {
|
||||
let API_BASE_URL =
|
||||
(typeof process !== "undefined" && process.env?.NEXT_PUBLIC_AGENTS_URL) ||
|
||||
(typeof window !== "undefined" && (window as any).__VITE_API_BASE_URL__) ||
|
||||
"/api/agents/ui/v1";
|
||||
"/v1/agents/ui/v1";
|
||||
|
||||
/** Override the API base URL at runtime (called by AgentsProvider). */
|
||||
export function setBaseUrl(url: string) {
|
||||
@@ -611,7 +611,7 @@ export async function registerServerlessAgent(invocationUrl: string): Promise<{
|
||||
}> {
|
||||
// Use /api/agents/v1 base for this endpoint (not /api/agents/ui/v1).
|
||||
// Routes through the Console proxy which forwards to AGENTS_API_URL.
|
||||
const API_V1_BASE = "/api/agents/v1";
|
||||
const API_V1_BASE = "/v1/agents/v1";
|
||||
const timeout = 15000;
|
||||
|
||||
// Create AbortController for timeout
|
||||
|
||||
@@ -78,7 +78,7 @@ export interface CasvisorSession {
|
||||
// Base URL / fetch helper
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const PROXY_BASE = "/api/compute";
|
||||
const PROXY_BASE = "/v1/compute";
|
||||
|
||||
async function casvisorFetch<T>(
|
||||
path: string,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { getGlobalApiKey } from "./api";
|
||||
// Must go through the console agents proxy (/api/agents/ui/v1 → backend
|
||||
// /api/v1). A raw '/api/v1' base hits the console Next.js app, which has no
|
||||
// such route, and 404s.
|
||||
const API_BASE = "/api/agents/ui/v1";
|
||||
const API_BASE = "/v1/agents/ui/v1";
|
||||
|
||||
export class ObservabilityWebhookApiError extends Error {
|
||||
public status?: number;
|
||||
|
||||
@@ -14,7 +14,7 @@ import type {
|
||||
} from "../types/execution";
|
||||
import { getGlobalApiKey } from "./api";
|
||||
|
||||
const API_BASE_URL = "/api/agents/ui/v1";
|
||||
const API_BASE_URL = "/v1/agents/ui/v1";
|
||||
const withAuthHeaders = (headers?: HeadersInit) => {
|
||||
const merged = new Headers(headers || {});
|
||||
const apiKey = getGlobalApiKey();
|
||||
@@ -212,7 +212,7 @@ export const reasonersApi = {
|
||||
): Promise<ExecutionResponse> => {
|
||||
// Must go through the console agents proxy; a raw /api/v1 base hits the
|
||||
// console app (no such route) and 404s. /api/agents/v1 → backend /api/v1.
|
||||
const url = `/api/agents/v1/execute/${encodeURIComponent(reasonerId)}`;
|
||||
const url = `/v1/agents/v1/execute/${encodeURIComponent(reasonerId)}`;
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
@@ -274,7 +274,7 @@ export const reasonersApi = {
|
||||
reasonerId: string,
|
||||
request: ExecutionRequest,
|
||||
): Promise<AsyncExecuteResponse> => {
|
||||
const url = `/api/agents/v1/execute/async/${encodeURIComponent(reasonerId)}`;
|
||||
const url = `/v1/agents/v1/execute/async/${encodeURIComponent(reasonerId)}`;
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
@@ -329,7 +329,7 @@ export const reasonersApi = {
|
||||
getExecutionStatus: async (
|
||||
executionId: string,
|
||||
): Promise<ExecutionStatusResponse> => {
|
||||
const url = `/api/agents/v1/executions/${encodeURIComponent(executionId)}`;
|
||||
const url = `/v1/agents/v1/executions/${encodeURIComponent(executionId)}`;
|
||||
|
||||
try {
|
||||
const response = await fetch(url, { headers: withAuthHeaders() });
|
||||
|
||||
@@ -65,7 +65,7 @@ export function RequestResetPasswordEmailButton({
|
||||
const formattedEmail = encodeURIComponent(email.toLowerCase().trim());
|
||||
const formattedCode = encodeURIComponent(code.trim());
|
||||
const callback = encodeURIComponent(`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/auth/reset-password`);
|
||||
const url = `${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/auth/callback/email?email=${formattedEmail}&token=${formattedCode}&callbackUrl=${callback}`;
|
||||
const url = `${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/auth/callback/email?email=${formattedEmail}&token=${formattedCode}&callbackUrl=${callback}`;
|
||||
window.location.href = url;
|
||||
} catch (error) {
|
||||
console.error("Error verifying code:", error);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { env } from "@/src/env.mjs";
|
||||
* console code can use `useIam()` for IAM-native session/login/logout. IAM is
|
||||
* the native identity; the BrowserIamSdk drives OIDC discovery + PKCE against
|
||||
* `NEXT_PUBLIC_IAM_SERVER_URL` and proxies token/userinfo through console's own
|
||||
* `/api/auth/iam/*` routes to avoid cross-origin issues.
|
||||
* `/v1/auth/iam/*` routes to avoid cross-origin issues.
|
||||
*
|
||||
* When the client IAM env is not configured this is a transparent pass-through,
|
||||
* so the app shell is unaffected on instances that have not enabled IAM-native
|
||||
@@ -32,7 +32,7 @@ export function IamSessionProvider({ children }: { children: ReactNode }) {
|
||||
scope: "openid profile email",
|
||||
// Route token/userinfo through console so the browser never hits IAM
|
||||
// cross-origin (and so console can bridge the IAM token into a session).
|
||||
proxyBaseUrl: `${origin}${basePath}/api/auth/iam`,
|
||||
proxyBaseUrl: `${origin}${basePath}/v1/auth/iam`,
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ export function DeveloperToolsSettings() {
|
||||
<CodeBlock
|
||||
language="shell"
|
||||
value={`claude mcp add --transport http langfuse \\
|
||||
https://cloud.langfuse.com/api/public/mcp \\
|
||||
https://cloud.hanzo.ai/v1/mcp \\
|
||||
--header "Authorization: Basic {your-base64-token}"`}
|
||||
/>
|
||||
<div className="mt-4 flex items-center gap-2">
|
||||
|
||||
@@ -239,7 +239,7 @@ function InAppAiAgentProviderInner({
|
||||
agent.abortRun();
|
||||
|
||||
const freshAgent = new HttpAgent({
|
||||
url: `${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/in-app-agent`,
|
||||
url: `${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/in-app-agent`,
|
||||
threadId: agent.threadId,
|
||||
initialMessages: agent.messages.filter(
|
||||
isAgentConversationMessage,
|
||||
@@ -292,7 +292,7 @@ function InAppAiAgentProviderInner({
|
||||
// Create the agent if none exists
|
||||
if (!agentRef.current) {
|
||||
agentRef.current = new HttpAgent({
|
||||
url: `${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/in-app-agent`,
|
||||
url: `${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/in-app-agent`,
|
||||
threadId: restoredSession.threadId,
|
||||
initialMessages: restoredMessages,
|
||||
initialState: restoredSession.state,
|
||||
|
||||
@@ -192,10 +192,10 @@ export default async function handler(request: Request) {
|
||||
}
|
||||
|
||||
function getLangfuseMcpUrl(): string {
|
||||
const rawUrl = env.NEXTAUTH_URL.replace(/\/api\/auth\/?$/, "");
|
||||
const rawUrl = env.NEXTAUTH_URL.replace(/\/v1\/auth\/?$/, "");
|
||||
const baseUrl = new URL(rawUrl);
|
||||
|
||||
baseUrl.pathname = `${baseUrl.pathname.replace(/\/$/, "")}/api/public/mcp`;
|
||||
baseUrl.pathname = `${baseUrl.pathname.replace(/\/$/, "")}/v1/mcp`;
|
||||
baseUrl.search = "";
|
||||
baseUrl.hash = "";
|
||||
|
||||
|
||||
@@ -736,7 +736,7 @@ async function getChatCompletionWithTools(
|
||||
});
|
||||
|
||||
const result = await fetch(
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/chatCompletion`,
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/chatCompletion`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -781,7 +781,7 @@ async function getChatCompletionWithStructuredOutput(
|
||||
});
|
||||
|
||||
const result = await fetch(
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/chatCompletion`,
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/chatCompletion`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -829,7 +829,7 @@ async function* getChatCompletionStream(
|
||||
});
|
||||
|
||||
const result = await fetch(
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/chatCompletion`,
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/chatCompletion`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -889,7 +889,7 @@ async function getChatCompletionNonStreaming(
|
||||
});
|
||||
|
||||
const result = await fetch(
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/chatCompletion`,
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/chatCompletion`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
|
||||
@@ -32,7 +32,7 @@ export const slackRouter = createTRPCRouter({
|
||||
isConnected: false,
|
||||
teamId: null,
|
||||
teamName: null,
|
||||
installUrl: `/api/public/slack/install?projectId=${input.projectId}`,
|
||||
installUrl: `/v1/slack/install?projectId=${input.projectId}`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ export const slackRouter = createTRPCRouter({
|
||||
isConnected: false,
|
||||
teamId: integration.teamId,
|
||||
teamName: integration.teamName,
|
||||
installUrl: `/api/public/slack/install?projectId=${input.projectId}`,
|
||||
installUrl: `/v1/slack/install?projectId=${input.projectId}`,
|
||||
error:
|
||||
"Integration is invalid. Please reconnect your Slack workspace.",
|
||||
};
|
||||
@@ -77,7 +77,7 @@ export const slackRouter = createTRPCRouter({
|
||||
isConnected: false,
|
||||
teamId: integration.teamId,
|
||||
teamName: integration.teamName,
|
||||
installUrl: `/api/public/slack/install?projectId=${input.projectId}`,
|
||||
installUrl: `/v1/slack/install?projectId=${input.projectId}`,
|
||||
error:
|
||||
"Failed to validate integration. Please reconnect your Slack workspace.",
|
||||
};
|
||||
|
||||
@@ -214,7 +214,7 @@ export function SupportFormSection({ onCancel, onSuccess }: { onCancel: () => vo
|
||||
}),
|
||||
);
|
||||
|
||||
const res = await fetch("/api/support/upload-attachments", {
|
||||
const res = await fetch("/v1/support/upload-attachments", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ files: filePayloads }),
|
||||
|
||||
@@ -139,7 +139,7 @@ const MyApp: AppType<{ session: Session | null }> = ({
|
||||
session={session}
|
||||
refetchOnWindowFocus={true}
|
||||
refetchInterval={5 * 60} // 5 minutes
|
||||
basePath={`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/auth`}
|
||||
basePath={`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/auth`}
|
||||
>
|
||||
<IamSessionProvider>
|
||||
<DetailPageListsProvider>
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function EnterpriseSsoRequiredPage() {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/auth/check-sso`, {
|
||||
const response = await fetch(`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/auth/check-sso`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ domain }),
|
||||
|
||||
@@ -17,8 +17,8 @@ type PageProps = {
|
||||
};
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<PageProps> = async () => {
|
||||
// remove /api/auth from the URL as it needs to be added for custom base url
|
||||
const deploymentDomain = env.NEXTAUTH_URL?.replace("/api/auth", "");
|
||||
// remove /v1/auth from the URL as it needs to be added for custom base url
|
||||
const deploymentDomain = env.NEXTAUTH_URL?.replace("/v1/auth", "");
|
||||
return {
|
||||
props: {
|
||||
deploymentDomain,
|
||||
|
||||
@@ -177,7 +177,7 @@ export const getServerSideProps: GetServerSideProps<PageProps> = async () => {
|
||||
},
|
||||
signUpDisabled: env.AUTH_DISABLE_SIGNUP === "true",
|
||||
runningOnHuggingFaceSpaces: env.NEXTAUTH_URL?.replace(
|
||||
"/api/auth",
|
||||
"/v1/auth",
|
||||
"",
|
||||
).endsWith(".hf.space"),
|
||||
},
|
||||
@@ -685,7 +685,7 @@ export default function SignIn({
|
||||
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/auth/check-sso`,
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/auth/check-sso`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
|
||||
@@ -111,7 +111,7 @@ export default function SignIn({
|
||||
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/auth/check-sso`,
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/auth/check-sso`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -158,7 +158,7 @@ export default function SignIn({
|
||||
try {
|
||||
setFormError(null);
|
||||
const res = await fetch(
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/api/auth/signup`,
|
||||
`${env.NEXT_PUBLIC_BASE_PATH ?? ""}/v1/auth/signup`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
|
||||
@@ -184,12 +184,12 @@ export const api = createTRPCNext<AppRouter>({
|
||||
},
|
||||
// when condition is true, use normal request
|
||||
true: httpLink({
|
||||
url: `${getBaseUrl()}/api/trpc`,
|
||||
url: `${getBaseUrl()}/v1/trpc`,
|
||||
transformer: superjson,
|
||||
}),
|
||||
// when condition is false, use batching
|
||||
false: httpBatchLink({
|
||||
url: `${getBaseUrl()}/api/trpc`,
|
||||
url: `${getBaseUrl()}/v1/trpc`,
|
||||
transformer: superjson,
|
||||
maxURLLength: 2083, // avoid too large batches
|
||||
}),
|
||||
@@ -237,7 +237,7 @@ export const directApi = createTRPCProxyClient<AppRouter>({
|
||||
enabled: () => process.env.NODE_ENV === "development",
|
||||
}),
|
||||
httpBatchLink({
|
||||
url: `${getBaseUrl()}/api/trpc`,
|
||||
url: `${getBaseUrl()}/v1/trpc`,
|
||||
transformer: superjson,
|
||||
maxURLLength: 2083, // avoid too large batches
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user