@centrali-io/centrali-sdk 5.5.1 → 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,292 @@
|
|
|
1
|
+
import { EventSource as EventSourcePolyfill } from 'eventsource';
|
|
2
|
+
import { getRealtimeUrl } from '../urls';
|
|
3
|
+
import { emitDeprecationWarning } from '../internal/deprecation';
|
|
4
|
+
import type {
|
|
5
|
+
RealtimeSubscribeOptions,
|
|
6
|
+
RealtimeSubscription,
|
|
7
|
+
RealtimeRecordEvent,
|
|
8
|
+
RealtimeCloseEvent,
|
|
9
|
+
} from '../types/realtime';
|
|
10
|
+
|
|
11
|
+
// Use native EventSource in browser, polyfill in Node.js
|
|
12
|
+
const EventSourceImpl: typeof EventSource = typeof EventSource !== 'undefined'
|
|
13
|
+
? EventSource
|
|
14
|
+
: EventSourcePolyfill as unknown as typeof EventSource;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate the SSE endpoint path for a workspace.
|
|
18
|
+
* Matches: services/backend/realtime/internal/sse/handler.go ServeHTTP route
|
|
19
|
+
*/
|
|
20
|
+
function getRealtimeEventPath(workspaceSlug: string): string {
|
|
21
|
+
return `/workspace/${workspaceSlug}/events`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Internal configuration for realtime connections.
|
|
26
|
+
*/
|
|
27
|
+
interface RealtimeConfig {
|
|
28
|
+
/** Maximum reconnection attempts (default: 10) */
|
|
29
|
+
maxReconnectAttempts: number;
|
|
30
|
+
/** Initial reconnect delay in ms (default: 1000) */
|
|
31
|
+
initialReconnectDelayMs: number;
|
|
32
|
+
/** Maximum reconnect delay in ms (default: 30000) */
|
|
33
|
+
maxReconnectDelayMs: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Default realtime configuration.
|
|
38
|
+
*/
|
|
39
|
+
const DEFAULT_REALTIME_CONFIG: RealtimeConfig = {
|
|
40
|
+
maxReconnectAttempts: 10,
|
|
41
|
+
initialReconnectDelayMs: 1000,
|
|
42
|
+
maxReconnectDelayMs: 30000,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* RealtimeManager handles SSE connections to the Centrali Realtime Service.
|
|
47
|
+
* Provides automatic reconnection with exponential backoff.
|
|
48
|
+
*
|
|
49
|
+
* Usage:
|
|
50
|
+
* ```ts
|
|
51
|
+
* const realtime = new RealtimeManager(baseUrl, workspaceSlug, () => client.getToken());
|
|
52
|
+
* const sub = realtime.subscribe({
|
|
53
|
+
* structures: ['order'],
|
|
54
|
+
* events: ['record_created', 'record_updated'],
|
|
55
|
+
* onEvent: (event) => console.log(event),
|
|
56
|
+
* onError: (error) => console.error(error),
|
|
57
|
+
* });
|
|
58
|
+
* // Later: sub.unsubscribe();
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export class RealtimeManager {
|
|
62
|
+
private baseUrl: string;
|
|
63
|
+
private workspaceSlug: string;
|
|
64
|
+
private getToken: () => string | null | Promise<string | null>;
|
|
65
|
+
private config: RealtimeConfig;
|
|
66
|
+
|
|
67
|
+
constructor(
|
|
68
|
+
baseUrl: string,
|
|
69
|
+
workspaceSlug: string,
|
|
70
|
+
getToken: () => string | null | Promise<string | null>,
|
|
71
|
+
config?: Partial<RealtimeConfig>
|
|
72
|
+
) {
|
|
73
|
+
this.baseUrl = baseUrl;
|
|
74
|
+
this.workspaceSlug = workspaceSlug;
|
|
75
|
+
this.getToken = getToken;
|
|
76
|
+
this.config = { ...DEFAULT_REALTIME_CONFIG, ...config };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Subscribe to realtime events for the workspace.
|
|
81
|
+
*
|
|
82
|
+
* IMPORTANT: Initial Sync Pattern
|
|
83
|
+
* Realtime delivers only new events after connection. For dashboards and lists:
|
|
84
|
+
* 1. Fetch current records first
|
|
85
|
+
* 2. Subscribe to realtime
|
|
86
|
+
* 3. Apply diffs while UI shows the snapshot
|
|
87
|
+
*
|
|
88
|
+
* @param options - Subscription options
|
|
89
|
+
* @returns Subscription handle with unsubscribe() method
|
|
90
|
+
*/
|
|
91
|
+
public subscribe(options: RealtimeSubscribeOptions): RealtimeSubscription {
|
|
92
|
+
let eventSource: EventSource | null = null;
|
|
93
|
+
let unsubscribed = false;
|
|
94
|
+
let connected = false;
|
|
95
|
+
let reconnectAttempt = 0;
|
|
96
|
+
let reconnectTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
97
|
+
|
|
98
|
+
const connect = async () => {
|
|
99
|
+
// Zombie loop prevention: don't reconnect if unsubscribed
|
|
100
|
+
if (unsubscribed) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
// Get token (may be async for client credentials flow)
|
|
106
|
+
const token = await Promise.resolve(this.getToken());
|
|
107
|
+
if (!token) {
|
|
108
|
+
options.onError?.({
|
|
109
|
+
code: 'MISSING_TOKEN',
|
|
110
|
+
message: 'No authentication token available',
|
|
111
|
+
recoverable: false,
|
|
112
|
+
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Build SSE URL with query params
|
|
117
|
+
const realtimeBaseUrl = getRealtimeUrl(this.baseUrl);
|
|
118
|
+
const path = getRealtimeEventPath(this.workspaceSlug);
|
|
119
|
+
const url = new URL(`${realtimeBaseUrl}${path}`);
|
|
120
|
+
|
|
121
|
+
// Add access token
|
|
122
|
+
url.searchParams.set('access_token', token);
|
|
123
|
+
|
|
124
|
+
// Add collection filter
|
|
125
|
+
if (options.collections?.length) {
|
|
126
|
+
url.searchParams.set('collections', options.collections.join(','));
|
|
127
|
+
} else if (options.structures?.length) {
|
|
128
|
+
emitDeprecationWarning("The 'structures' filter option is deprecated. Use 'collections' instead.");
|
|
129
|
+
url.searchParams.set('collections', options.structures.join(','));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Add event type filter
|
|
133
|
+
if (options.events?.length) {
|
|
134
|
+
url.searchParams.set('events', options.events.join(','));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Add CFL filter
|
|
138
|
+
if (options.filter) {
|
|
139
|
+
url.searchParams.set('filter', options.filter);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Add compute function filters
|
|
143
|
+
if (options.jobId) {
|
|
144
|
+
url.searchParams.set('jobId', options.jobId);
|
|
145
|
+
}
|
|
146
|
+
if (options.triggerType) {
|
|
147
|
+
url.searchParams.set('triggerType', options.triggerType);
|
|
148
|
+
}
|
|
149
|
+
if (options.functionId) {
|
|
150
|
+
url.searchParams.set('functionId', options.functionId);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Add orchestration filters
|
|
154
|
+
if (options.orchestrationId) {
|
|
155
|
+
url.searchParams.set('orchestrationId', options.orchestrationId);
|
|
156
|
+
}
|
|
157
|
+
if (options.runId) {
|
|
158
|
+
url.searchParams.set('runId', options.runId);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Create EventSource (uses polyfill in Node.js)
|
|
162
|
+
eventSource = new EventSourceImpl(url.toString());
|
|
163
|
+
|
|
164
|
+
// Handle connection open
|
|
165
|
+
eventSource.onopen = () => {
|
|
166
|
+
if (unsubscribed) {
|
|
167
|
+
eventSource?.close();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
connected = true;
|
|
171
|
+
reconnectAttempt = 0;
|
|
172
|
+
options.onConnected?.();
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// Handle record events - server sends all record events as 'message' type
|
|
176
|
+
// The event.event field inside the payload contains the actual type
|
|
177
|
+
// (record_created, record_updated, record_deleted)
|
|
178
|
+
eventSource.addEventListener('message', (e: MessageEvent) => {
|
|
179
|
+
if (unsubscribed) return;
|
|
180
|
+
try {
|
|
181
|
+
const event = JSON.parse(e.data) as RealtimeRecordEvent;
|
|
182
|
+
options.onEvent(event);
|
|
183
|
+
} catch (err) {
|
|
184
|
+
options.onError?.({
|
|
185
|
+
code: 'PARSE_ERROR',
|
|
186
|
+
message: `Failed to parse event: ${err}`,
|
|
187
|
+
recoverable: true,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Handle close event from server
|
|
193
|
+
eventSource.addEventListener('close', (e: MessageEvent) => {
|
|
194
|
+
if (unsubscribed) return;
|
|
195
|
+
try {
|
|
196
|
+
const closeEvent = JSON.parse(e.data) as RealtimeCloseEvent;
|
|
197
|
+
connected = false;
|
|
198
|
+
options.onDisconnected?.(closeEvent.reason);
|
|
199
|
+
|
|
200
|
+
// Reconnect if server says to
|
|
201
|
+
if (closeEvent.reconnect && !unsubscribed) {
|
|
202
|
+
scheduleReconnect();
|
|
203
|
+
}
|
|
204
|
+
} catch {
|
|
205
|
+
// Ignore parse errors for close events
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Handle errors
|
|
210
|
+
eventSource.onerror = () => {
|
|
211
|
+
if (unsubscribed) {
|
|
212
|
+
eventSource?.close();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
connected = false;
|
|
217
|
+
eventSource?.close();
|
|
218
|
+
eventSource = null;
|
|
219
|
+
|
|
220
|
+
// EventSource error events don't provide much detail
|
|
221
|
+
// The connection will be closed, so we notify and potentially reconnect
|
|
222
|
+
options.onDisconnected?.('connection_error');
|
|
223
|
+
options.onError?.({
|
|
224
|
+
code: 'CONNECTION_ERROR',
|
|
225
|
+
message: 'Connection to realtime service failed',
|
|
226
|
+
recoverable: true,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
scheduleReconnect();
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
} catch (err) {
|
|
233
|
+
options.onError?.({
|
|
234
|
+
code: 'CONNECTION_ERROR',
|
|
235
|
+
message: `Failed to connect: ${err}`,
|
|
236
|
+
recoverable: true,
|
|
237
|
+
});
|
|
238
|
+
scheduleReconnect();
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const scheduleReconnect = () => {
|
|
243
|
+
// Zombie loop prevention
|
|
244
|
+
if (unsubscribed) return;
|
|
245
|
+
|
|
246
|
+
reconnectAttempt++;
|
|
247
|
+
if (reconnectAttempt > this.config.maxReconnectAttempts) {
|
|
248
|
+
options.onError?.({
|
|
249
|
+
code: 'CONNECTION_ERROR',
|
|
250
|
+
message: `Max reconnection attempts (${this.config.maxReconnectAttempts}) exceeded`,
|
|
251
|
+
recoverable: false,
|
|
252
|
+
});
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Exponential backoff with jitter
|
|
257
|
+
const delay = Math.min(
|
|
258
|
+
this.config.initialReconnectDelayMs * Math.pow(2, reconnectAttempt - 1),
|
|
259
|
+
this.config.maxReconnectDelayMs
|
|
260
|
+
);
|
|
261
|
+
const jitter = Math.random() * 0.3 * delay; // 0-30% jitter
|
|
262
|
+
|
|
263
|
+
reconnectTimeout = setTimeout(() => {
|
|
264
|
+
if (!unsubscribed) {
|
|
265
|
+
connect();
|
|
266
|
+
}
|
|
267
|
+
}, delay + jitter);
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
// Start connection
|
|
271
|
+
connect();
|
|
272
|
+
|
|
273
|
+
// Return subscription handle
|
|
274
|
+
return {
|
|
275
|
+
unsubscribe: () => {
|
|
276
|
+
unsubscribed = true;
|
|
277
|
+
connected = false;
|
|
278
|
+
if (reconnectTimeout) {
|
|
279
|
+
clearTimeout(reconnectTimeout);
|
|
280
|
+
reconnectTimeout = null;
|
|
281
|
+
}
|
|
282
|
+
if (eventSource) {
|
|
283
|
+
eventSource.close();
|
|
284
|
+
eventSource = null;
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
get connected() {
|
|
288
|
+
return connected;
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// =====================================================
|
|
2
|
+
// Allowed Domains Types
|
|
3
|
+
// =====================================================
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An allowed domain entry for compute function external calls.
|
|
7
|
+
*/
|
|
8
|
+
export interface AllowedDomain {
|
|
9
|
+
id: string;
|
|
10
|
+
domain: string;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
createdBy: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Response from listing allowed domains.
|
|
17
|
+
*/
|
|
18
|
+
export interface AllowedDomainsListResponse {
|
|
19
|
+
data: AllowedDomain[];
|
|
20
|
+
meta: { total: number };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Options for adding an allowed domain.
|
|
25
|
+
*/
|
|
26
|
+
export interface AddAllowedDomainOptions {
|
|
27
|
+
/** The domain to allow (e.g., 'api.example.com'). No protocol prefix. */
|
|
28
|
+
domain: string;
|
|
29
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// =====================================================
|
|
2
|
+
// Authorization Types (BYOT - Bring Your Own Token)
|
|
3
|
+
// =====================================================
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Resource category for authorization.
|
|
7
|
+
* - 'workspace': Workspace-level resources (e.g., settings, members)
|
|
8
|
+
* - 'structure': Structure-level resources (e.g., specific records)
|
|
9
|
+
* - 'custom': Custom resources defined by the user for AuthZ-as-a-Service
|
|
10
|
+
*/
|
|
11
|
+
export type ResourceCategory = 'workspace' | 'structure' | 'custom';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Options for authorization check.
|
|
15
|
+
* Use this when authorizing access using an external IdP token (BYOT).
|
|
16
|
+
*/
|
|
17
|
+
export interface CheckAuthorizationOptions {
|
|
18
|
+
/**
|
|
19
|
+
* The JWT token from your external identity provider (e.g., Clerk, Auth0, Okta).
|
|
20
|
+
* The token will be validated against the configured external auth provider.
|
|
21
|
+
*/
|
|
22
|
+
token: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The resource being accessed.
|
|
26
|
+
* Can be a Centrali system resource (e.g., 'records', 'files') or a custom
|
|
27
|
+
* resource you've defined for AuthZ-as-a-Service (e.g., 'orders', 'invoices').
|
|
28
|
+
*/
|
|
29
|
+
resource: string;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The action being performed on the resource.
|
|
33
|
+
* Common actions: 'create', 'read', 'update', 'delete', 'admin'
|
|
34
|
+
* You can also define custom actions (e.g., 'approve', 'publish').
|
|
35
|
+
*/
|
|
36
|
+
action: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Resource category for authorization evaluation.
|
|
40
|
+
* - 'workspace': Workspace-level resources
|
|
41
|
+
* - 'structure': Structure-level resources
|
|
42
|
+
* - 'custom': Custom resources for AuthZ-as-a-Service
|
|
43
|
+
* @default 'custom'
|
|
44
|
+
*/
|
|
45
|
+
resourceCategory?: ResourceCategory;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Optional context data for policy evaluation.
|
|
49
|
+
* This data becomes available as `request_metadata` in policies.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // Policy can reference: request_metadata.orderId, request_metadata.amount
|
|
53
|
+
* context: {
|
|
54
|
+
* orderId: 'order-123',
|
|
55
|
+
* amount: 50000,
|
|
56
|
+
* department: 'sales'
|
|
57
|
+
* }
|
|
58
|
+
*/
|
|
59
|
+
context?: Record<string, unknown>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Result of an authorization check.
|
|
64
|
+
*/
|
|
65
|
+
export interface AuthorizationResult {
|
|
66
|
+
/**
|
|
67
|
+
* Whether the action is allowed.
|
|
68
|
+
*/
|
|
69
|
+
allowed: boolean;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The decision from the policy evaluator.
|
|
73
|
+
* - 'allow': Access granted
|
|
74
|
+
* - 'deny': Access denied
|
|
75
|
+
* - 'not_applicable': No matching policy found
|
|
76
|
+
*/
|
|
77
|
+
decision: 'allow' | 'deny' | 'not_applicable';
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Human-readable message explaining the decision.
|
|
81
|
+
*/
|
|
82
|
+
message?: string;
|
|
83
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { AxiosRequestConfig } from 'axios';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Options for initializing the Centrali SDK client.
|
|
5
|
+
*/
|
|
6
|
+
export interface CentraliSDKOptions {
|
|
7
|
+
/** Base URL of Centrali (e.g. https://centrali.io). The SDK automatically uses api.centrali.io for API calls. */
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
workspaceId: string;
|
|
10
|
+
|
|
11
|
+
// Auth path 1: Publishable key (frontend apps — safe to expose in browser code)
|
|
12
|
+
/** Publishable key for frontend access. Sent as x-api-key header. No token refresh needed. */
|
|
13
|
+
publishableKey?: string;
|
|
14
|
+
|
|
15
|
+
// Auth path 2: Bearer token (existing) + dynamic token callback (new)
|
|
16
|
+
/** Optional initial bearer token for authentication */
|
|
17
|
+
token?: string;
|
|
18
|
+
/** Optional callback to dynamically fetch a fresh token before each request (e.g., for Clerk, Auth0) */
|
|
19
|
+
getToken?: () => Promise<string>;
|
|
20
|
+
|
|
21
|
+
// Auth path 3: Service account (server-side only — never use in browser)
|
|
22
|
+
/** Optional OAuth2 client credentials */
|
|
23
|
+
clientId?: string;
|
|
24
|
+
clientSecret?: string;
|
|
25
|
+
|
|
26
|
+
/** Optional custom axios config */
|
|
27
|
+
axiosConfig?: AxiosRequestConfig;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Generic API response wrapper.
|
|
32
|
+
*/
|
|
33
|
+
export interface ApiResponse<T> {
|
|
34
|
+
data: T;
|
|
35
|
+
meta?: Record<string, any>;
|
|
36
|
+
error?: any
|
|
37
|
+
id?: string;
|
|
38
|
+
createdAt?: string;
|
|
39
|
+
updatedAt?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Paginated API response wrapper.
|
|
44
|
+
*/
|
|
45
|
+
export interface PaginatedResponse<T> {
|
|
46
|
+
/** Data items */
|
|
47
|
+
data: T[];
|
|
48
|
+
/** Pagination metadata */
|
|
49
|
+
meta: {
|
|
50
|
+
/** Total number of items */
|
|
51
|
+
total: number;
|
|
52
|
+
/** Current page number */
|
|
53
|
+
page: number;
|
|
54
|
+
/** Items per page */
|
|
55
|
+
pageSize: number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// =====================================================
|
|
2
|
+
// Compute Function Types (Configuration-as-Code)
|
|
3
|
+
// =====================================================
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Compute function definition.
|
|
7
|
+
*/
|
|
8
|
+
export interface ComputeFunction {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
code: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
workspaceSlug: string;
|
|
14
|
+
createdBy: string;
|
|
15
|
+
updatedBy?: string;
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Input for creating a new compute function.
|
|
23
|
+
*/
|
|
24
|
+
export interface CreateComputeFunctionInput {
|
|
25
|
+
name: string;
|
|
26
|
+
code: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
timeoutMs?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Input for updating an existing compute function.
|
|
33
|
+
*/
|
|
34
|
+
export interface UpdateComputeFunctionInput {
|
|
35
|
+
name?: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
code?: string;
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Options for listing compute functions.
|
|
43
|
+
*/
|
|
44
|
+
export interface ListComputeFunctionsOptions {
|
|
45
|
+
page?: number;
|
|
46
|
+
limit?: number;
|
|
47
|
+
search?: string;
|
|
48
|
+
searchField?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Input for test-executing a compute function without saving.
|
|
53
|
+
*/
|
|
54
|
+
export interface TestComputeFunctionInput {
|
|
55
|
+
code: string;
|
|
56
|
+
params?: Record<string, any>;
|
|
57
|
+
timeoutMs?: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Result from test-executing a compute function.
|
|
62
|
+
*/
|
|
63
|
+
export interface TestComputeFunctionResult {
|
|
64
|
+
success: boolean;
|
|
65
|
+
output?: any;
|
|
66
|
+
duration_ms?: number;
|
|
67
|
+
logs?: string[];
|
|
68
|
+
error?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// =====================================================
|
|
72
|
+
// Function Run Types
|
|
73
|
+
// =====================================================
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Execution source for a function run.
|
|
77
|
+
*/
|
|
78
|
+
export type FunctionRunExecutionSource = 'trigger' | 'rerun' | 'manual' | 'scheduled' | 'http-trigger' | 'orchestration' | 'endpoint';
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Status of a function run.
|
|
82
|
+
*/
|
|
83
|
+
export type FunctionRunStatus = 'pending' | 'running' | 'completed' | 'failure' | 'timeout';
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* A function run record representing a single execution of a compute function.
|
|
87
|
+
*/
|
|
88
|
+
export interface FunctionRun {
|
|
89
|
+
id: string;
|
|
90
|
+
createdBy: string;
|
|
91
|
+
functionId: string;
|
|
92
|
+
workspaceSlug: string;
|
|
93
|
+
jobId: string;
|
|
94
|
+
status: FunctionRunStatus;
|
|
95
|
+
runData: any | null;
|
|
96
|
+
startedAt: string;
|
|
97
|
+
endedAt?: string | null;
|
|
98
|
+
createdAt?: string;
|
|
99
|
+
updatedAt?: string;
|
|
100
|
+
executionId: string;
|
|
101
|
+
triggerId?: string | null;
|
|
102
|
+
triggerType?: string | null;
|
|
103
|
+
orchestrationRunId?: string | null;
|
|
104
|
+
orchestrationStepId?: string | null;
|
|
105
|
+
originalRunId?: string | null;
|
|
106
|
+
isRerun: boolean;
|
|
107
|
+
rerunCount: number;
|
|
108
|
+
rerunBy?: string | null;
|
|
109
|
+
rerunReason?: string | null;
|
|
110
|
+
functionCodeHash?: string | null;
|
|
111
|
+
functionVersion?: string | null;
|
|
112
|
+
executionSource: FunctionRunExecutionSource;
|
|
113
|
+
memoryUsageBytes?: number | null;
|
|
114
|
+
cpuUsageSeconds?: number | null;
|
|
115
|
+
errorCode?: string | null;
|
|
116
|
+
errorMessage?: string | null;
|
|
117
|
+
dataStrippedAt?: string | null;
|
|
118
|
+
archiveStorageAddress?: string | null;
|
|
119
|
+
archivedAt?: string | null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Options for listing function runs by trigger or function.
|
|
124
|
+
*/
|
|
125
|
+
export interface ListFunctionRunsOptions {
|
|
126
|
+
page?: number;
|
|
127
|
+
limit?: number;
|
|
128
|
+
status?: FunctionRunStatus;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Status of a compute job in the execution pipeline.
|
|
133
|
+
*/
|
|
134
|
+
export type ComputeJobStatus = 'queued' | 'running' | 'completed' | 'failed';
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* A compute job status response from the job status endpoint.
|
|
138
|
+
* Represents the state of an async compute execution.
|
|
139
|
+
*/
|
|
140
|
+
export interface ComputeJobStatusResponse {
|
|
141
|
+
jobId: string;
|
|
142
|
+
status: ComputeJobStatus;
|
|
143
|
+
returnValue?: any;
|
|
144
|
+
failedReason?: string | null;
|
|
145
|
+
}
|