@centrali-io/centrali-sdk 5.5.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +164 -14
- package/dist/index.d.ts +1807 -878
- package/dist/index.js +9153 -4076
- package/index.ts +61 -7152
- package/package.json +10 -3
- package/query-types.ts +83 -2
- package/scripts/smoke-types.ts +145 -5
- package/src/client.ts +1507 -0
- package/src/internal/auth.ts +35 -0
- package/src/internal/deprecation.ts +11 -0
- package/src/internal/error.ts +90 -0
- package/src/internal/paths.ts +456 -0
- package/src/internal/queryGuard.ts +21 -0
- package/src/managers/allowedDomains.ts +90 -0
- package/src/managers/anomalyInsights.ts +215 -0
- package/src/managers/auditLog.ts +105 -0
- package/src/managers/collections.ts +197 -0
- package/src/managers/files.ts +182 -0
- package/src/managers/functionRuns.ts +229 -0
- package/src/managers/functions.ts +171 -0
- package/src/managers/orchestrationRuns.ts +122 -0
- package/src/managers/orchestrations.ts +297 -0
- package/src/managers/query.ts +199 -0
- package/src/managers/records.ts +186 -0
- package/src/managers/smartQueries.ts +374 -0
- package/src/managers/structures.ts +205 -0
- package/src/managers/triggers.ts +349 -0
- package/src/managers/validation.ts +303 -0
- package/src/managers/webhookSubscriptions.ts +206 -0
- package/src/realtime/manager.ts +292 -0
- package/src/types/allowedDomains.ts +29 -0
- package/src/types/auth.ts +83 -0
- package/src/types/common.ts +57 -0
- package/src/types/compute.ts +145 -0
- package/src/types/insights.ts +113 -0
- package/src/types/orchestrations.ts +460 -0
- package/src/types/realtime.ts +403 -0
- package/src/types/records.ts +261 -0
- package/src/types/search.ts +44 -0
- package/src/types/smartQueries.ts +303 -0
- package/src/types/structures.ts +203 -0
- package/src/types/triggers.ts +122 -0
- package/src/types/validation.ts +167 -0
- package/src/types/webhooks.ts +114 -0
- package/src/urls.ts +33 -0
- package/dist/query-types.d.ts +0 -187
- package/dist/query-types.js +0 -137
- package/dist/scripts/smoke-types.d.ts +0 -12
- package/dist/scripts/smoke-types.js +0 -102
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// =====================================================
|
|
2
|
+
// Files Manager (CEN-1218 / Phase 3)
|
|
3
|
+
// =====================================================
|
|
4
|
+
|
|
5
|
+
import type { Method } from 'axios';
|
|
6
|
+
import type { ApiResponse } from '../types/common';
|
|
7
|
+
import type { QueryDefinition, QueryResult } from '../../query-types';
|
|
8
|
+
import { getFilesCanonicalApiPath } from '../internal/paths';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Canonical shape returned by `client.files.query()`. Mirrors the
|
|
13
|
+
* `filesquery` executor's canonical projection in the storage service —
|
|
14
|
+
* camelCase keys, snake_case never leaks. The truly internal blob-routing
|
|
15
|
+
* attributes (`storageAddress`, `uniqueName`) are intentionally not on
|
|
16
|
+
* the canonical surface. `renderId` IS exposed so callers can pass it to
|
|
17
|
+
* {@link CentraliCli.getFileRenderUrl} / {@link CentraliCli.getFileDownloadUrl}
|
|
18
|
+
* after discovering files via query.
|
|
19
|
+
*
|
|
20
|
+
* Optional fields are absent when unset on the row OR when not requested
|
|
21
|
+
* via `select.fields`.
|
|
22
|
+
*/
|
|
23
|
+
export interface FileMetadata {
|
|
24
|
+
/** UUID. Always present. */
|
|
25
|
+
id: string;
|
|
26
|
+
/** Original filename. */
|
|
27
|
+
name?: string;
|
|
28
|
+
/** Absolute storage path (e.g. `/root/shared/logo.png`). */
|
|
29
|
+
path?: string;
|
|
30
|
+
/** Parent folder display path. */
|
|
31
|
+
location?: string;
|
|
32
|
+
/** Workspace slug — pinned by the executor. */
|
|
33
|
+
workspaceSlug?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Render token. Pass to {@link CentraliCli.getFileRenderUrl} to display
|
|
36
|
+
* a file inline (e.g. images), or {@link CentraliCli.getFileDownloadUrl}
|
|
37
|
+
* for an attachment-style download link.
|
|
38
|
+
*/
|
|
39
|
+
renderId?: string;
|
|
40
|
+
/** MIME type (e.g. `image/png`). */
|
|
41
|
+
contentType?: string;
|
|
42
|
+
/** High-level file kind (image, video, document, …). */
|
|
43
|
+
fileType?: string;
|
|
44
|
+
/** Byte size. */
|
|
45
|
+
size?: number;
|
|
46
|
+
/** Parent folder UUID; null/absent for files at the root. */
|
|
47
|
+
folderId?: string | null;
|
|
48
|
+
/** User ID of the uploader. */
|
|
49
|
+
createdBy?: string;
|
|
50
|
+
/** ISO timestamp. */
|
|
51
|
+
createdAt?: string;
|
|
52
|
+
/** ISO timestamp. */
|
|
53
|
+
updatedAt?: string;
|
|
54
|
+
/** Whether the file is publicly accessible without auth. */
|
|
55
|
+
isPublic?: boolean;
|
|
56
|
+
/** Structure slug when this file is attached to a record (otherwise null). */
|
|
57
|
+
recordSlug?: string | null;
|
|
58
|
+
/** Authorization context: `general`, `record`, `avatar`, `support`, … */
|
|
59
|
+
fileContext?: string;
|
|
60
|
+
/** Soft-delete timestamp (null when active). */
|
|
61
|
+
deletedAt?: string | null;
|
|
62
|
+
/** Tags array; supports `hasAny` / `hasAll` operators in queries. */
|
|
63
|
+
tags?: string[];
|
|
64
|
+
/** Media duration in seconds (audio/video only). */
|
|
65
|
+
duration?: number | null;
|
|
66
|
+
/** Pixel width (image/video). */
|
|
67
|
+
width?: number | null;
|
|
68
|
+
/** Pixel height (image/video). */
|
|
69
|
+
height?: number | null;
|
|
70
|
+
/** Primary codec (e.g. `opus`, `h264`). */
|
|
71
|
+
codec?: string | null;
|
|
72
|
+
/** Bitrate in bits per second. */
|
|
73
|
+
bitrate?: number | null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* FilesManager exposes the canonical files query surface (CEN-1218,
|
|
78
|
+
* Phase 3 of the Query Foundation). Mirrors `client.orchestrationRuns`
|
|
79
|
+
* and `client.functionRuns`: a thin wrapper over
|
|
80
|
+
* `POST /files/query` and `/query/test`.
|
|
81
|
+
*
|
|
82
|
+
* Existing helpers (`client.uploadFile`, `client.getFileRenderUrl`,
|
|
83
|
+
* `client.createFolder`, …) stay where they are — those are workflow
|
|
84
|
+
* helpers, not query primitives.
|
|
85
|
+
*
|
|
86
|
+
* Access via `client.files`.
|
|
87
|
+
*/
|
|
88
|
+
export class FilesManager {
|
|
89
|
+
private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
|
|
90
|
+
private workspaceId: string;
|
|
91
|
+
|
|
92
|
+
constructor(
|
|
93
|
+
workspaceId: string,
|
|
94
|
+
requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
|
|
95
|
+
) {
|
|
96
|
+
this.workspaceId = workspaceId;
|
|
97
|
+
this.requestFn = requestFn;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Run a canonical query against `POST /storage/ws/<ws>/api/v1/files/query`.
|
|
102
|
+
*
|
|
103
|
+
* The body **is** a `QueryDefinition`. `resource` is forced to
|
|
104
|
+
* `"files"` — the storage executor rejects anything else. Returns the
|
|
105
|
+
* canonical `{ data, meta }` envelope.
|
|
106
|
+
*
|
|
107
|
+
* Queryable fields (canonical camelCase): `id`, `name`, `path`,
|
|
108
|
+
* `location`, `renderId`, `contentType`, `fileType`, `size`,
|
|
109
|
+
* `folderId`, `createdBy`, `createdAt`, `updatedAt`, `isPublic`,
|
|
110
|
+
* `recordSlug`, `fileContext`, `deletedAt`, `tags`, `duration`,
|
|
111
|
+
* `width`, `height`, `codec`, `bitrate`. Internal blob-routing
|
|
112
|
+
* columns (`storageAddress`, `uniqueName`) are intentionally not
|
|
113
|
+
* exposed.
|
|
114
|
+
*
|
|
115
|
+
* `tags` is a varchar array column — `hasAny` (overlap) and `hasAll`
|
|
116
|
+
* (contains) work; range operators don't.
|
|
117
|
+
*
|
|
118
|
+
* Authorization: a `where` that pins `id.eq` (in a flat AND-of-scalar-eq
|
|
119
|
+
* shape) routes through file-context-aware ABAC server-side, including
|
|
120
|
+
* record-backed files (`records:retrieve`) and path-keyed user / avatar
|
|
121
|
+
* / support policies. Non-scoped queries use `files:list`.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* // Recent images uploaded in the last 7 days
|
|
126
|
+
* const recent = await client.files.query({
|
|
127
|
+
* resource: 'files',
|
|
128
|
+
* where: {
|
|
129
|
+
* and: [
|
|
130
|
+
* { fileType: { eq: 'image' } },
|
|
131
|
+
* { createdAt: { gte: '2026-04-24T00:00:00Z' } },
|
|
132
|
+
* ],
|
|
133
|
+
* },
|
|
134
|
+
* sort: [{ field: 'createdAt', direction: 'desc' }],
|
|
135
|
+
* page: { limit: 50 },
|
|
136
|
+
* });
|
|
137
|
+
*
|
|
138
|
+
* // Files in a folder, narrowed projection for a list UI
|
|
139
|
+
* const items = await client.files.query({
|
|
140
|
+
* resource: 'files',
|
|
141
|
+
* where: { folderId: { eq: 'folder-uuid' } },
|
|
142
|
+
* select: { fields: ['name', 'contentType', 'size', 'createdAt'] },
|
|
143
|
+
* page: { limit: 100 },
|
|
144
|
+
* });
|
|
145
|
+
*
|
|
146
|
+
* // Files tagged "draft" or "review"
|
|
147
|
+
* const drafts = await client.files.query({
|
|
148
|
+
* resource: 'files',
|
|
149
|
+
* where: { tags: { hasAny: ['draft', 'review'] } },
|
|
150
|
+
* });
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
public async query<T = FileMetadata>(
|
|
154
|
+
definition: Omit<QueryDefinition, 'resource'> & { resource?: string }
|
|
155
|
+
): Promise<QueryResult<T>> {
|
|
156
|
+
const path = getFilesCanonicalApiPath(this.workspaceId, 'query');
|
|
157
|
+
const body: QueryDefinition = { ...definition, resource: 'files' };
|
|
158
|
+
const resp = await this.requestFn<T[]>('POST', path, body);
|
|
159
|
+
return resp as unknown as QueryResult<T>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Authoring-time dry-run against `POST /files/query/test`.
|
|
164
|
+
*
|
|
165
|
+
* Same input shape as {@link FilesManager.query | query}. Returns a
|
|
166
|
+
* plan summary on success or structured `QueryError`s on failure,
|
|
167
|
+
* without executing the query. Use from query builders to surface
|
|
168
|
+
* precise errors before saving / running.
|
|
169
|
+
*
|
|
170
|
+
* The `/query/test` response is `{ ok, plan }` (NOT a `{ data }`
|
|
171
|
+
* envelope), so we return `resp.data` to unwrap the request layer's
|
|
172
|
+
* coercion — same convention as `client.orchestrationRuns.test`.
|
|
173
|
+
*/
|
|
174
|
+
public async test(
|
|
175
|
+
definition: Omit<QueryDefinition, 'resource'> & { resource?: string }
|
|
176
|
+
): Promise<{ ok: true; plan: { executor: string; resource: string; mode: string; hasUnreadableField: boolean } }> {
|
|
177
|
+
const path = getFilesCanonicalApiPath(this.workspaceId, 'query/test');
|
|
178
|
+
const body: QueryDefinition = { ...definition, resource: 'files' };
|
|
179
|
+
const resp = await this.requestFn<{ ok: true; plan: { executor: string; resource: string; mode: string; hasUnreadableField: boolean } }>('POST', path, body);
|
|
180
|
+
return resp.data;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// =====================================================
|
|
2
|
+
// Function Runs Manager
|
|
3
|
+
// =====================================================
|
|
4
|
+
|
|
5
|
+
import type { Method } from 'axios';
|
|
6
|
+
import type { ApiResponse, PaginatedResponse } from '../types/common';
|
|
7
|
+
import type {
|
|
8
|
+
FunctionRun,
|
|
9
|
+
ListFunctionRunsOptions,
|
|
10
|
+
ComputeJobStatusResponse,
|
|
11
|
+
} from '../types/compute';
|
|
12
|
+
import type { QueryDefinition, QueryResult } from '../../query-types';
|
|
13
|
+
import {
|
|
14
|
+
getFunctionRunsApiPath,
|
|
15
|
+
getFunctionRunsByTriggerApiPath,
|
|
16
|
+
getFunctionRunsByFunctionApiPath,
|
|
17
|
+
getComputeJobStatusApiPath,
|
|
18
|
+
} from '../internal/paths';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Manager for querying function execution runs.
|
|
22
|
+
*
|
|
23
|
+
* Provides read access to function run history — useful for checking
|
|
24
|
+
* whether jobs completed, inspecting outputs, and monitoring trigger activity.
|
|
25
|
+
*
|
|
26
|
+
* - {@link FunctionRunsManager.query | query} — canonical `POST /function-runs/query`
|
|
27
|
+
* (CEN-1216). Use for nested boolean trees, `select` projection, paging.
|
|
28
|
+
* - {@link FunctionRunsManager.test | test} — authoring dry-run against
|
|
29
|
+
* `/function-runs/query/test`. Validates and plans without executing.
|
|
30
|
+
* - {@link FunctionRunsManager.listByTrigger | listByTrigger} /
|
|
31
|
+
* {@link FunctionRunsManager.listByFunction | listByFunction} — legacy GET
|
|
32
|
+
* surfaces, retained for back-compat. Prefer `query()` for new code.
|
|
33
|
+
*
|
|
34
|
+
* Access via `client.functionRuns` (canonical, CEN-1227). The legacy
|
|
35
|
+
* `client.runs` accessor remains as a deprecated alias.
|
|
36
|
+
*/
|
|
37
|
+
export class FunctionRunsManager {
|
|
38
|
+
private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
|
|
39
|
+
private workspaceId: string;
|
|
40
|
+
|
|
41
|
+
constructor(
|
|
42
|
+
workspaceId: string,
|
|
43
|
+
requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
|
|
44
|
+
) {
|
|
45
|
+
this.workspaceId = workspaceId;
|
|
46
|
+
this.requestFn = requestFn;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get a function run by ID.
|
|
51
|
+
*
|
|
52
|
+
* @param runId - The function run UUID
|
|
53
|
+
* @returns The function run details
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* const run = await client.functionRuns.get('run-uuid');
|
|
58
|
+
* console.log('Status:', run.data.status);
|
|
59
|
+
* console.log('Duration:', run.data.endedAt ? Date.parse(run.data.endedAt) - Date.parse(run.data.startedAt) : 'still running');
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
public get(runId: string): Promise<ApiResponse<FunctionRun>> {
|
|
63
|
+
const path = getFunctionRunsApiPath(this.workspaceId, runId);
|
|
64
|
+
return this.requestFn<FunctionRun>('GET', path);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* List runs for a specific trigger.
|
|
69
|
+
*
|
|
70
|
+
* @param triggerId - The trigger UUID
|
|
71
|
+
* @param options - Optional pagination and status filter
|
|
72
|
+
* @returns Paginated list of function runs
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* // List recent runs for a trigger
|
|
77
|
+
* const runs = await client.functionRuns.listByTrigger('trigger-uuid');
|
|
78
|
+
*
|
|
79
|
+
* // Filter to only failed runs
|
|
80
|
+
* const failed = await client.functionRuns.listByTrigger('trigger-uuid', {
|
|
81
|
+
* status: 'failure'
|
|
82
|
+
* });
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
public listByTrigger(triggerId: string, options?: ListFunctionRunsOptions): Promise<ApiResponse<PaginatedResponse<FunctionRun>>> {
|
|
86
|
+
const path = getFunctionRunsByTriggerApiPath(this.workspaceId, triggerId);
|
|
87
|
+
const queryParams: Record<string, any> = {};
|
|
88
|
+
if (options?.page) queryParams.page = options.page;
|
|
89
|
+
if (options?.limit) queryParams.limit = options.limit;
|
|
90
|
+
if (options?.status) queryParams.status = options.status;
|
|
91
|
+
return this.requestFn<PaginatedResponse<FunctionRun>>('GET', path, null, queryParams);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* List runs for a specific compute function.
|
|
96
|
+
*
|
|
97
|
+
* @param functionId - The compute function UUID
|
|
98
|
+
* @param options - Optional pagination and status filter
|
|
99
|
+
* @returns Paginated list of function runs
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* // List recent runs for a function
|
|
104
|
+
* const runs = await client.functionRuns.listByFunction('function-uuid');
|
|
105
|
+
*
|
|
106
|
+
* // Only completed runs, page 2
|
|
107
|
+
* const completed = await client.functionRuns.listByFunction('function-uuid', {
|
|
108
|
+
* status: 'completed',
|
|
109
|
+
* page: 2
|
|
110
|
+
* });
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
public listByFunction(functionId: string, options?: ListFunctionRunsOptions): Promise<ApiResponse<PaginatedResponse<FunctionRun>>> {
|
|
114
|
+
const path = getFunctionRunsByFunctionApiPath(this.workspaceId, functionId);
|
|
115
|
+
const queryParams: Record<string, any> = {};
|
|
116
|
+
if (options?.page) queryParams.page = options.page;
|
|
117
|
+
if (options?.limit) queryParams.limit = options.limit;
|
|
118
|
+
if (options?.status) queryParams.status = options.status;
|
|
119
|
+
return this.requestFn<PaginatedResponse<FunctionRun>>('GET', path, null, queryParams);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get the status of a compute job by job ID.
|
|
124
|
+
*
|
|
125
|
+
* This is the primary way to poll for the result of an async trigger
|
|
126
|
+
* invocation. The job ID is returned by `client.triggers.invoke()`.
|
|
127
|
+
*
|
|
128
|
+
* @param jobId - The job ID returned by invoke
|
|
129
|
+
* @returns Job status including returnValue (on success) or failedReason (on failure)
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* // Invoke a trigger and poll for the result
|
|
134
|
+
* const { data: jobId } = await client.triggers.invoke('trigger-uuid');
|
|
135
|
+
*
|
|
136
|
+
* // Poll until complete
|
|
137
|
+
* let job;
|
|
138
|
+
* do {
|
|
139
|
+
* await new Promise(r => setTimeout(r, 1000));
|
|
140
|
+
* job = await client.functionRuns.getJobStatus(jobId);
|
|
141
|
+
* } while (job.data.status === 'queued' || job.data.status === 'running');
|
|
142
|
+
*
|
|
143
|
+
* if (job.data.status === 'completed') {
|
|
144
|
+
* console.log('Result:', job.data.returnValue);
|
|
145
|
+
* } else {
|
|
146
|
+
* console.error('Failed:', job.data.failedReason);
|
|
147
|
+
* }
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
public getJobStatus(jobId: string): Promise<ApiResponse<ComputeJobStatusResponse>> {
|
|
151
|
+
const path = getComputeJobStatusApiPath(this.workspaceId, jobId);
|
|
152
|
+
return this.requestFn<ComputeJobStatusResponse>('GET', path);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Run a canonical query against `POST /workspace/<ws>/api/v1/function-runs/query`.
|
|
157
|
+
*
|
|
158
|
+
* Phase 3 of the query foundation (CEN-1216). The body **is** a
|
|
159
|
+
* `QueryDefinition`. `resource` is forced to `"function-runs"` — the
|
|
160
|
+
* data-service executor rejects anything else. Returns the canonical
|
|
161
|
+
* `{ data, meta }` envelope.
|
|
162
|
+
*
|
|
163
|
+
* Queryable fields are the fixed-schema columns: `id`, `functionId`,
|
|
164
|
+
* `triggerId`, `status`, `startedAt`, `endedAt`, `executionSource`,
|
|
165
|
+
* `errorCode`, `errorMessage`, etc. The `runData` and `executionContext`
|
|
166
|
+
* JSONB columns are intentionally not queryable — fetch a specific run
|
|
167
|
+
* via `client.functionRuns.get(runId)` if you need its payload.
|
|
168
|
+
*
|
|
169
|
+
* The `where` clause that pins `functionId.eq` or `triggerId.eq` (in a
|
|
170
|
+
* pure AND-of-scalar-eq shape) uses `function_runs:retrieve` server-side;
|
|
171
|
+
* everything else uses `function_runs:list`. Retrieve-only roles can
|
|
172
|
+
* still query a specific function or trigger's run history this way.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```ts
|
|
176
|
+
* // Recent failures for a function
|
|
177
|
+
* const failures = await client.functionRuns.query({
|
|
178
|
+
* resource: 'function-runs',
|
|
179
|
+
* where: {
|
|
180
|
+
* and: [
|
|
181
|
+
* { functionId: { eq: 'fn-123' } },
|
|
182
|
+
* { status: { eq: 'failure' } },
|
|
183
|
+
* ],
|
|
184
|
+
* },
|
|
185
|
+
* sort: [{ field: 'startedAt', direction: 'desc' }],
|
|
186
|
+
* page: { limit: 50 },
|
|
187
|
+
* });
|
|
188
|
+
*
|
|
189
|
+
* // Workspace-wide run activity in a date window with field projection
|
|
190
|
+
* const activity = await client.functionRuns.query({
|
|
191
|
+
* resource: 'function-runs',
|
|
192
|
+
* where: {
|
|
193
|
+
* and: [
|
|
194
|
+
* { startedAt: { gte: '2026-04-01' } },
|
|
195
|
+
* { startedAt: { lt: '2026-05-01' } },
|
|
196
|
+
* ],
|
|
197
|
+
* },
|
|
198
|
+
* sort: [{ field: 'startedAt', direction: 'desc' }],
|
|
199
|
+
* page: { limit: 100 },
|
|
200
|
+
* select: { fields: ['id', 'functionId', 'status', 'startedAt', 'endedAt', 'errorCode'] },
|
|
201
|
+
* });
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
public async query<T = FunctionRun>(
|
|
205
|
+
definition: Omit<QueryDefinition, 'resource'> & { resource?: string }
|
|
206
|
+
): Promise<QueryResult<T>> {
|
|
207
|
+
const path = `data/workspace/${this.workspaceId}/api/v1/function-runs/query`;
|
|
208
|
+
const body: QueryDefinition = { ...definition, resource: 'function-runs' };
|
|
209
|
+
const resp = await this.requestFn<T[]>('POST', path, body);
|
|
210
|
+
return resp as unknown as QueryResult<T>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Authoring-time dry-run against `POST /function-runs/query/test`.
|
|
215
|
+
*
|
|
216
|
+
* Same input shape as {@link FunctionRunsManager.query | query}. Returns
|
|
217
|
+
* a plan summary on success or structured `QueryError`s on failure,
|
|
218
|
+
* without executing the query. Use from query builders to surface precise
|
|
219
|
+
* errors before saving / running.
|
|
220
|
+
*/
|
|
221
|
+
public async test(
|
|
222
|
+
definition: Omit<QueryDefinition, 'resource'> & { resource?: string }
|
|
223
|
+
): Promise<{ ok: true; plan: { executor: string; resource: string; mode: string; hasUnreadableField: boolean } }> {
|
|
224
|
+
const path = `data/workspace/${this.workspaceId}/api/v1/function-runs/query/test`;
|
|
225
|
+
const body: QueryDefinition = { ...definition, resource: 'function-runs' };
|
|
226
|
+
const resp = await this.requestFn<{ ok: true; plan: { executor: string; resource: string; mode: string; hasUnreadableField: boolean } }>('POST', path, body);
|
|
227
|
+
return resp.data;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// =====================================================
|
|
2
|
+
// Compute Functions Manager (Configuration-as-Code)
|
|
3
|
+
// =====================================================
|
|
4
|
+
|
|
5
|
+
import type { Method } from 'axios';
|
|
6
|
+
import type { ApiResponse } from '../types/common';
|
|
7
|
+
import type {
|
|
8
|
+
ComputeFunction,
|
|
9
|
+
CreateComputeFunctionInput,
|
|
10
|
+
UpdateComputeFunctionInput,
|
|
11
|
+
ListComputeFunctionsOptions,
|
|
12
|
+
TestComputeFunctionInput,
|
|
13
|
+
TestComputeFunctionResult,
|
|
14
|
+
} from '../types/compute';
|
|
15
|
+
import {
|
|
16
|
+
getComputeFunctionsApiPath,
|
|
17
|
+
getComputeFunctionTestApiPath,
|
|
18
|
+
} from '../internal/paths';
|
|
19
|
+
|
|
20
|
+
// =====================================================
|
|
21
|
+
// Compute Functions Manager (Configuration-as-Code)
|
|
22
|
+
// =====================================================
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* ComputeFunctionsManager provides methods for managing compute functions.
|
|
26
|
+
* Compute functions are JavaScript code blocks that can be executed on triggers,
|
|
27
|
+
* schedules, or on-demand.
|
|
28
|
+
* Access via `client.functions`.
|
|
29
|
+
*
|
|
30
|
+
* Usage:
|
|
31
|
+
* ```ts
|
|
32
|
+
* // List all compute functions
|
|
33
|
+
* const fns = await client.functions.list();
|
|
34
|
+
*
|
|
35
|
+
* // Create a new function
|
|
36
|
+
* const fn = await client.functions.create({
|
|
37
|
+
* name: 'Process Order',
|
|
38
|
+
* code: 'async function run() { return { processed: true }; }'
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* // Test execute code without saving
|
|
42
|
+
* const result = await client.functions.testExecute({
|
|
43
|
+
* code: 'async function run() { return executionParams; }',
|
|
44
|
+
* params: { orderId: '123' }
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export class ComputeFunctionsManager {
|
|
49
|
+
private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
|
|
50
|
+
private workspaceId: string;
|
|
51
|
+
|
|
52
|
+
constructor(
|
|
53
|
+
workspaceId: string,
|
|
54
|
+
requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
|
|
55
|
+
) {
|
|
56
|
+
this.workspaceId = workspaceId;
|
|
57
|
+
this.requestFn = requestFn;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* List all compute functions in the workspace.
|
|
62
|
+
*
|
|
63
|
+
* @param options - Optional list parameters (pagination, search)
|
|
64
|
+
* @returns List of compute functions
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const fns = await client.functions.list();
|
|
69
|
+
* const searched = await client.functions.list({ search: 'order', limit: 10 });
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
public list(options?: ListComputeFunctionsOptions): Promise<ApiResponse<ComputeFunction[]>> {
|
|
73
|
+
const path = getComputeFunctionsApiPath(this.workspaceId);
|
|
74
|
+
return this.requestFn<ComputeFunction[]>('GET', path, null, options);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get a compute function by ID.
|
|
79
|
+
*
|
|
80
|
+
* @param functionId - The compute function UUID
|
|
81
|
+
* @returns The compute function details
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* const fn = await client.functions.get('function-uuid');
|
|
86
|
+
* console.log('Function name:', fn.data.name);
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
public get(functionId: string): Promise<ApiResponse<ComputeFunction>> {
|
|
90
|
+
const path = getComputeFunctionsApiPath(this.workspaceId, functionId);
|
|
91
|
+
return this.requestFn<ComputeFunction>('GET', path);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Create a new compute function.
|
|
96
|
+
*
|
|
97
|
+
* @param input - The function definition
|
|
98
|
+
* @returns The created compute function
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* const fn = await client.functions.create({
|
|
103
|
+
* name: 'Process Order',
|
|
104
|
+
* code: 'async function run() { return { processed: true }; }',
|
|
105
|
+
* description: 'Processes incoming orders',
|
|
106
|
+
* timeoutMs: 60000
|
|
107
|
+
* });
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
public create(input: CreateComputeFunctionInput): Promise<ApiResponse<ComputeFunction>> {
|
|
111
|
+
const path = getComputeFunctionsApiPath(this.workspaceId);
|
|
112
|
+
return this.requestFn<ComputeFunction>('POST', path, input);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Update an existing compute function.
|
|
117
|
+
*
|
|
118
|
+
* @param functionId - The compute function UUID
|
|
119
|
+
* @param input - The fields to update
|
|
120
|
+
* @returns The updated compute function
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* const updated = await client.functions.update('function-uuid', {
|
|
125
|
+
* code: 'async function run() { return { v2: true }; }',
|
|
126
|
+
* timeoutMs: 120000
|
|
127
|
+
* });
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
public update(functionId: string, input: UpdateComputeFunctionInput): Promise<ApiResponse<ComputeFunction>> {
|
|
131
|
+
const path = getComputeFunctionsApiPath(this.workspaceId, functionId);
|
|
132
|
+
return this.requestFn<ComputeFunction>('PUT', path, input);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Delete a compute function.
|
|
137
|
+
*
|
|
138
|
+
* @param functionId - The compute function UUID
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* await client.functions.delete('function-uuid');
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
public delete(functionId: string): Promise<ApiResponse<void>> {
|
|
146
|
+
const path = getComputeFunctionsApiPath(this.workspaceId, functionId);
|
|
147
|
+
return this.requestFn<void>('DELETE', path);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Test execute code without saving it as a function.
|
|
152
|
+
* Useful for validating function code before creating/updating.
|
|
153
|
+
*
|
|
154
|
+
* @param input - The code to test and optional input data
|
|
155
|
+
* @returns Test execution result including output, duration, and logs
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* const result = await client.functions.testExecute({
|
|
160
|
+
* code: 'async function run() { return { sum: executionParams.a + executionParams.b }; }',
|
|
161
|
+
* params: { a: 1, b: 2 }
|
|
162
|
+
* });
|
|
163
|
+
* console.log('Output:', result.data.output); // { sum: 3 }
|
|
164
|
+
* console.log('Duration:', result.data.duration_ms, 'ms');
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
public testExecute(input: TestComputeFunctionInput): Promise<ApiResponse<TestComputeFunctionResult>> {
|
|
168
|
+
const path = getComputeFunctionTestApiPath(this.workspaceId);
|
|
169
|
+
return this.requestFn<TestComputeFunctionResult>('POST', path, input);
|
|
170
|
+
}
|
|
171
|
+
}
|