@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.
Files changed (49) hide show
  1. package/README.md +164 -14
  2. package/dist/index.d.ts +1807 -878
  3. package/dist/index.js +9153 -4076
  4. package/index.ts +61 -7152
  5. package/package.json +10 -3
  6. package/query-types.ts +83 -2
  7. package/scripts/smoke-types.ts +145 -5
  8. package/src/client.ts +1507 -0
  9. package/src/internal/auth.ts +35 -0
  10. package/src/internal/deprecation.ts +11 -0
  11. package/src/internal/error.ts +90 -0
  12. package/src/internal/paths.ts +456 -0
  13. package/src/internal/queryGuard.ts +21 -0
  14. package/src/managers/allowedDomains.ts +90 -0
  15. package/src/managers/anomalyInsights.ts +215 -0
  16. package/src/managers/auditLog.ts +105 -0
  17. package/src/managers/collections.ts +197 -0
  18. package/src/managers/files.ts +182 -0
  19. package/src/managers/functionRuns.ts +229 -0
  20. package/src/managers/functions.ts +171 -0
  21. package/src/managers/orchestrationRuns.ts +122 -0
  22. package/src/managers/orchestrations.ts +297 -0
  23. package/src/managers/query.ts +199 -0
  24. package/src/managers/records.ts +186 -0
  25. package/src/managers/smartQueries.ts +374 -0
  26. package/src/managers/structures.ts +205 -0
  27. package/src/managers/triggers.ts +349 -0
  28. package/src/managers/validation.ts +303 -0
  29. package/src/managers/webhookSubscriptions.ts +206 -0
  30. package/src/realtime/manager.ts +292 -0
  31. package/src/types/allowedDomains.ts +29 -0
  32. package/src/types/auth.ts +83 -0
  33. package/src/types/common.ts +57 -0
  34. package/src/types/compute.ts +145 -0
  35. package/src/types/insights.ts +113 -0
  36. package/src/types/orchestrations.ts +460 -0
  37. package/src/types/realtime.ts +403 -0
  38. package/src/types/records.ts +261 -0
  39. package/src/types/search.ts +44 -0
  40. package/src/types/smartQueries.ts +303 -0
  41. package/src/types/structures.ts +203 -0
  42. package/src/types/triggers.ts +122 -0
  43. package/src/types/validation.ts +167 -0
  44. package/src/types/webhooks.ts +114 -0
  45. package/src/urls.ts +33 -0
  46. package/dist/query-types.d.ts +0 -187
  47. package/dist/query-types.js +0 -137
  48. package/dist/scripts/smoke-types.d.ts +0 -12
  49. package/dist/scripts/smoke-types.js +0 -102
@@ -0,0 +1,90 @@
1
+ // =====================================================
2
+ // Allowed Domains Manager
3
+ // =====================================================
4
+
5
+ import type { Method } from 'axios';
6
+ import type { ApiResponse } from '../types/common';
7
+ import type { AllowedDomain, AddAllowedDomainOptions } from '../types/allowedDomains';
8
+ import { getAllowedDomainsApiPath } from '../internal/paths';
9
+
10
+ // =====================================================
11
+ // Allowed Domains Manager
12
+ // =====================================================
13
+
14
+ /**
15
+ * AllowedDomainsManager provides methods for managing allowed domains for compute function external calls.
16
+ * Access via `client.allowedDomains`.
17
+ *
18
+ * Usage:
19
+ * ```ts
20
+ * // List all allowed domains
21
+ * const domains = await client.allowedDomains.list();
22
+ *
23
+ * // Add a new domain
24
+ * const domain = await client.allowedDomains.add({ domain: 'api.example.com' });
25
+ *
26
+ * // Remove a domain
27
+ * await client.allowedDomains.remove('domain-id');
28
+ * ```
29
+ */
30
+ export class AllowedDomainsManager {
31
+ private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
32
+ private workspaceId: string;
33
+
34
+ constructor(
35
+ workspaceId: string,
36
+ requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
37
+ ) {
38
+ this.workspaceId = workspaceId;
39
+ this.requestFn = requestFn;
40
+ }
41
+
42
+ /**
43
+ * List all allowed domains in the workspace.
44
+ *
45
+ * @returns List of allowed domains with total count
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const result = await client.allowedDomains.list();
50
+ * console.log('Total domains:', result.meta.total);
51
+ * result.data.forEach(d => console.log(d.domain));
52
+ * ```
53
+ */
54
+ public list(): Promise<ApiResponse<AllowedDomain[]>> {
55
+ const path = getAllowedDomainsApiPath(this.workspaceId);
56
+ return this.requestFn<AllowedDomain[]>('GET', path);
57
+ }
58
+
59
+ /**
60
+ * Add a new allowed domain.
61
+ *
62
+ * @param options - The domain to add
63
+ * @returns The created allowed domain entry
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const result = await client.allowedDomains.add({ domain: 'api.stripe.com' });
68
+ * console.log('Added:', result.data.domain, result.data.id);
69
+ * ```
70
+ */
71
+ public add(options: AddAllowedDomainOptions): Promise<ApiResponse<AllowedDomain>> {
72
+ const path = getAllowedDomainsApiPath(this.workspaceId);
73
+ return this.requestFn<AllowedDomain>('POST', path, { domain: options.domain });
74
+ }
75
+
76
+ /**
77
+ * Remove an allowed domain by ID.
78
+ *
79
+ * @param domainId - The ID of the domain to remove
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * await client.allowedDomains.remove('domain-id-123');
84
+ * ```
85
+ */
86
+ public remove(domainId: string): Promise<ApiResponse<void>> {
87
+ const path = getAllowedDomainsApiPath(this.workspaceId, domainId);
88
+ return this.requestFn<void>('DELETE', path);
89
+ }
90
+ }
@@ -0,0 +1,215 @@
1
+ // =====================================================
2
+ // Anomaly Insights Manager
3
+ // =====================================================
4
+
5
+ import type { Method } from 'axios';
6
+ import type { ApiResponse } from '../types/common';
7
+ import type {
8
+ AnomalyInsight,
9
+ ListInsightsOptions,
10
+ AnomalyAnalysisResult,
11
+ InsightsSummary,
12
+ } from '../types/insights';
13
+ import {
14
+ getAnomalyInsightsApiPath,
15
+ getStructureInsightsApiPath,
16
+ getAnomalyInsightAcknowledgeApiPath,
17
+ getAnomalyInsightDismissApiPath,
18
+ getAnomalyInsightsBulkAcknowledgeApiPath,
19
+ getAnomalyInsightsSummaryApiPath,
20
+ getAnomalyAnalysisTriggerApiPath,
21
+ } from '../internal/paths';
22
+
23
+ // =====================================================
24
+ // Anomaly Insights Manager
25
+ // =====================================================
26
+
27
+ /**
28
+ * AnomalyInsightsManager provides methods for querying and managing AI-generated anomaly insights.
29
+ * Access via `client.anomalyInsights`.
30
+ *
31
+ * Usage:
32
+ * ```ts
33
+ * // List all active insights
34
+ * const insights = await client.anomalyInsights.list({ status: 'active' });
35
+ *
36
+ * // Get insights for a specific structure
37
+ * const orderInsights = await client.anomalyInsights.listByStructure('orders');
38
+ *
39
+ * // Get insight summary
40
+ * const summary = await client.anomalyInsights.getSummary();
41
+ *
42
+ * // Acknowledge an insight
43
+ * await client.anomalyInsights.acknowledge('insight-id');
44
+ *
45
+ * // Dismiss an insight
46
+ * await client.anomalyInsights.dismiss('insight-id');
47
+ * ```
48
+ */
49
+ export class AnomalyInsightsManager {
50
+ private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
51
+ private workspaceId: string;
52
+
53
+ constructor(
54
+ workspaceId: string,
55
+ requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
56
+ ) {
57
+ this.workspaceId = workspaceId;
58
+ this.requestFn = requestFn;
59
+ }
60
+
61
+ /**
62
+ * List anomaly insights with optional filters.
63
+ *
64
+ * @param options - Optional filter and pagination options
65
+ * @returns List of anomaly insights
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * // List all active critical insights
70
+ * const insights = await client.anomalyInsights.list({
71
+ * status: 'active',
72
+ * severity: 'critical'
73
+ * });
74
+ *
75
+ * // List insights for a specific structure
76
+ * const orderInsights = await client.anomalyInsights.list({
77
+ * structureSlug: 'orders'
78
+ * });
79
+ * ```
80
+ */
81
+ public list(options?: ListInsightsOptions): Promise<ApiResponse<AnomalyInsight[]>> {
82
+ const path = getAnomalyInsightsApiPath(this.workspaceId);
83
+ return this.requestFn<AnomalyInsight[]>('GET', path, null, options);
84
+ }
85
+
86
+ /**
87
+ * List insights for a specific structure.
88
+ *
89
+ * @param structureSlug - The structure's record slug
90
+ * @param options - Optional filter options
91
+ * @returns List of insights for the structure
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * const insights = await client.anomalyInsights.listByStructure('orders');
96
+ * ```
97
+ */
98
+ public listByStructure(
99
+ structureSlug: string,
100
+ options?: Omit<ListInsightsOptions, 'structureSlug'>
101
+ ): Promise<ApiResponse<AnomalyInsight[]>> {
102
+ const path = getStructureInsightsApiPath(this.workspaceId, structureSlug);
103
+ return this.requestFn<AnomalyInsight[]>('GET', path, null, options);
104
+ }
105
+
106
+ /**
107
+ * Get a single insight by ID.
108
+ *
109
+ * @param insightId - The insight UUID
110
+ * @returns The insight details
111
+ *
112
+ * @example
113
+ * ```ts
114
+ * const insight = await client.anomalyInsights.get('insight-id');
115
+ * console.log('Insight:', insight.data.title);
116
+ * ```
117
+ */
118
+ public get(insightId: string): Promise<ApiResponse<AnomalyInsight>> {
119
+ const path = getAnomalyInsightsApiPath(this.workspaceId, insightId);
120
+ return this.requestFn<AnomalyInsight>('GET', path);
121
+ }
122
+
123
+ /**
124
+ * Acknowledge an insight.
125
+ * Marks the insight as reviewed/handled.
126
+ *
127
+ * @param insightId - The insight UUID
128
+ * @returns The updated insight
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * await client.anomalyInsights.acknowledge('insight-id');
133
+ * ```
134
+ */
135
+ public acknowledge(insightId: string): Promise<ApiResponse<AnomalyInsight>> {
136
+ const path = getAnomalyInsightAcknowledgeApiPath(this.workspaceId, insightId);
137
+ return this.requestFn<AnomalyInsight>('POST', path);
138
+ }
139
+
140
+ /**
141
+ * Dismiss an insight.
142
+ * Marks the insight as not relevant/false positive.
143
+ *
144
+ * @param insightId - The insight UUID
145
+ * @returns The updated insight
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * await client.anomalyInsights.dismiss('insight-id');
150
+ * ```
151
+ */
152
+ public dismiss(insightId: string): Promise<ApiResponse<AnomalyInsight>> {
153
+ const path = getAnomalyInsightDismissApiPath(this.workspaceId, insightId);
154
+ return this.requestFn<AnomalyInsight>('POST', path);
155
+ }
156
+
157
+ /**
158
+ * Bulk acknowledge multiple insights.
159
+ *
160
+ * @param ids - Array of insight IDs to acknowledge
161
+ * @returns Result with count of updated insights
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * const result = await client.anomalyInsights.bulkAcknowledge(['id1', 'id2']);
166
+ * console.log('Acknowledged:', result.data.updated);
167
+ * ```
168
+ */
169
+ public bulkAcknowledge(ids: string[]): Promise<ApiResponse<{ updated: number; message: string }>> {
170
+ const path = getAnomalyInsightsBulkAcknowledgeApiPath(this.workspaceId);
171
+ return this.requestFn<{ updated: number; message: string }>('POST', path, { ids });
172
+ }
173
+
174
+ /**
175
+ * Get insights summary/statistics.
176
+ *
177
+ * @param structureSlug - Optional structure to filter summary
178
+ * @returns Summary of insights by status and severity
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * // Get overall summary
183
+ * const summary = await client.anomalyInsights.getSummary();
184
+ * console.log('Critical insights:', summary.data.bySeverity.critical);
185
+ *
186
+ * // Get summary for a specific structure
187
+ * const orderSummary = await client.anomalyInsights.getSummary('orders');
188
+ * ```
189
+ */
190
+ public getSummary(structureSlug?: string): Promise<ApiResponse<InsightsSummary>> {
191
+ const path = getAnomalyInsightsSummaryApiPath(this.workspaceId);
192
+ const params = structureSlug ? { structureSlug } : undefined;
193
+ return this.requestFn<InsightsSummary>('GET', path, null, params);
194
+ }
195
+
196
+ /**
197
+ * Trigger anomaly analysis for a structure.
198
+ * Starts an AI-powered analysis to detect anomalies in the structure's data.
199
+ *
200
+ * @param structureSlug - The structure's record slug to analyze
201
+ * @returns Result indicating if analysis was triggered and the batch ID
202
+ *
203
+ * @example
204
+ * ```ts
205
+ * const result = await client.anomalyInsights.triggerAnalysis('orders');
206
+ * if (result.data.success) {
207
+ * console.log('Analysis started:', result.data.batchId);
208
+ * }
209
+ * ```
210
+ */
211
+ public triggerAnalysis(structureSlug: string): Promise<ApiResponse<AnomalyAnalysisResult>> {
212
+ const path = getAnomalyAnalysisTriggerApiPath(this.workspaceId);
213
+ return this.requestFn<AnomalyAnalysisResult>('POST', path, { structureSlug });
214
+ }
215
+ }
@@ -0,0 +1,105 @@
1
+ // =====================================================
2
+ // Audit Log Manager (canonical query surface — CEN-1215)
3
+ // =====================================================
4
+
5
+ import type { Method } from 'axios';
6
+ import type { ApiResponse } from '../types/common';
7
+ import type { QueryDefinition, QueryResult } from '../../query-types';
8
+
9
+
10
+ /**
11
+ * AuditLogManager exposes the canonical query surface for the audit log.
12
+ *
13
+ * Phase 3 of the query foundation (CEN-1214 epic). Workspace-service backed,
14
+ * not data-service — the audit log is a workspace concern. The shape mirrors
15
+ * `RecordsManager` so a caller writing audit-log queries uses the same
16
+ * vocabulary they already know from records.
17
+ *
18
+ * - {@link AuditLogManager.query | query} — full POST `/audit/query`. Use for
19
+ * nested boolean trees, `select` projection, paging.
20
+ * - {@link AuditLogManager.test | test} — authoring dry-run against
21
+ * `/audit/query/test`. Validates and plans without executing.
22
+ *
23
+ * Access via `client.auditLog`.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * // Per-resource history (canonical equivalent of legacy GET /audit/.../history).
28
+ * const history = await client.auditLog.query({
29
+ * resource: 'audit-log',
30
+ * where: {
31
+ * and: [
32
+ * { resourceType: { eq: 'structure' } },
33
+ * { resourceId: { eq: 'r-123' } },
34
+ * ],
35
+ * },
36
+ * sort: [{ field: 'createdAt', direction: 'desc' }],
37
+ * page: { limit: 50 },
38
+ * });
39
+ *
40
+ * // Workspace-wide activity feed in a date range, projecting only the columns
41
+ * // the table needs (drops the heavy `changes` JSONB).
42
+ * const activity = await client.auditLog.query({
43
+ * resource: 'audit-log',
44
+ * where: {
45
+ * and: [
46
+ * { createdAt: { gte: '2026-04-01' } },
47
+ * { createdAt: { lt: '2026-05-01' } },
48
+ * ],
49
+ * },
50
+ * sort: [{ field: 'createdAt', direction: 'desc' }],
51
+ * page: { limit: 100 },
52
+ * select: { fields: ['type', 'resourceType', 'resourceId', 'actorId', 'summary', 'createdAt'] },
53
+ * });
54
+ * ```
55
+ */
56
+ export class AuditLogManager {
57
+ private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
58
+ private workspaceId: string;
59
+
60
+ constructor(
61
+ workspaceId: string,
62
+ requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
63
+ ) {
64
+ this.workspaceId = workspaceId;
65
+ this.requestFn = requestFn;
66
+ }
67
+
68
+ /**
69
+ * Run a canonical query against `POST /workspace/<ws>/api/v1/audit/query`.
70
+ *
71
+ * The body **is** a `QueryDefinition`. `resource` is forced to `"audit-log"`
72
+ * — the workspace executor rejects anything else. Returns the canonical
73
+ * `{ data, meta }` envelope.
74
+ *
75
+ * The `where` clause that pins both `resourceType.eq` and `resourceId.eq`
76
+ * uses `audit_logs:retrieve` server-side; everything else uses
77
+ * `audit_logs:list`. Retrieve-only roles can still query their own
78
+ * resource's history this way.
79
+ */
80
+ public async query<T = any>(
81
+ definition: Omit<QueryDefinition, 'resource'> & { resource?: string }
82
+ ): Promise<QueryResult<T>> {
83
+ const path = `workspace/api/v1/${this.workspaceId}/audit/query`;
84
+ const body: QueryDefinition = { ...definition, resource: 'audit-log' };
85
+ const resp = await this.requestFn<T[]>('POST', path, body);
86
+ return resp as unknown as QueryResult<T>;
87
+ }
88
+
89
+ /**
90
+ * Authoring-time dry-run against `POST /audit/query/test`.
91
+ *
92
+ * Same input shape as {@link AuditLogManager.query | query}. Returns a
93
+ * plan summary on success or structured `QueryError`s on failure, without
94
+ * executing the query. Use from query builders to surface precise errors
95
+ * before saving / running.
96
+ */
97
+ public async test(
98
+ definition: Omit<QueryDefinition, 'resource'> & { resource?: string }
99
+ ): Promise<{ ok: true; plan: { executor: string; resource: string; mode: string; hasUnreadableField: boolean } }> {
100
+ const path = `workspace/api/v1/${this.workspaceId}/audit/query/test`;
101
+ const body: QueryDefinition = { ...definition, resource: 'audit-log' };
102
+ const resp = await this.requestFn<{ ok: true; plan: { executor: string; resource: string; mode: string; hasUnreadableField: boolean } }>('POST', path, body);
103
+ return resp.data;
104
+ }
105
+ }
@@ -0,0 +1,197 @@
1
+ // =====================================================
2
+ // Collections Manager (Configuration-as-Code)
3
+ // =====================================================
4
+
5
+ import type { Method } from 'axios';
6
+ import type { ApiResponse } from '../types/common';
7
+ import type {
8
+ Structure,
9
+ CreateStructureInput,
10
+ UpdateStructureInput,
11
+ ListCollectionsOptions,
12
+ ValidateStructureInput,
13
+ } from '../types/structures';
14
+ import {
15
+ getCollectionsApiPath,
16
+ getCollectionBySlugApiPath,
17
+ getCollectionValidateApiPath,
18
+ } from '../internal/paths';
19
+
20
+ // =====================================================
21
+ // Collections Manager (Configuration-as-Code)
22
+ // =====================================================
23
+
24
+ /**
25
+ * CollectionsManager provides methods for managing data collections (schemas).
26
+ * Collections define the shape of records including properties, validation rules,
27
+ * and schema discovery modes.
28
+ * Access via `client.collections`.
29
+ *
30
+ * Usage:
31
+ * ```ts
32
+ * // List all collections
33
+ * const collections = await client.collections.list();
34
+ *
35
+ * // Create a new collection
36
+ * const collection = await client.collections.create({
37
+ * name: 'Orders',
38
+ * recordSlug: 'orders',
39
+ * properties: [
40
+ * { name: 'title', type: 'string', required: true },
41
+ * { name: 'amount', type: 'number', minimum: 0 }
42
+ * ]
43
+ * });
44
+ *
45
+ * // Validate before creating
46
+ * const validation = await client.collections.validate({ recordSlug: 'orders' });
47
+ * ```
48
+ */
49
+ export class CollectionsManager {
50
+ private requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>;
51
+ private workspaceId: string;
52
+
53
+ constructor(
54
+ workspaceId: string,
55
+ requestFn: <T>(method: Method, path: string, data?: any, queryParams?: Record<string, any>) => Promise<ApiResponse<T>>
56
+ ) {
57
+ this.workspaceId = workspaceId;
58
+ this.requestFn = requestFn;
59
+ }
60
+
61
+ /**
62
+ * List all collections in the workspace.
63
+ *
64
+ * @param options - Optional list parameters (pagination)
65
+ * @returns List of collections
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const collections = await client.collections.list();
70
+ * const page2 = await client.collections.list({ page: 2, limit: 10 });
71
+ * ```
72
+ */
73
+ public list(options?: ListCollectionsOptions): Promise<ApiResponse<Structure[]>> {
74
+ const path = getCollectionsApiPath(this.workspaceId);
75
+ return this.requestFn<Structure[]>('GET', path, null, options);
76
+ }
77
+
78
+ /**
79
+ * Get a collection by ID.
80
+ *
81
+ * @param collectionId - The collection UUID
82
+ * @returns The collection details
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const collection = await client.collections.get('collection-uuid');
87
+ * console.log('Properties:', collection.data.properties.length);
88
+ * ```
89
+ */
90
+ public get(collectionId: string): Promise<ApiResponse<Structure>> {
91
+ const path = getCollectionsApiPath(this.workspaceId, collectionId);
92
+ return this.requestFn<Structure>('GET', path);
93
+ }
94
+
95
+ /**
96
+ * Get a collection by its record slug.
97
+ *
98
+ * @param recordSlug - The collection's record slug (e.g., "orders")
99
+ * @returns The collection details
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * const collection = await client.collections.getBySlug('orders');
104
+ * console.log('Collection name:', collection.data.name);
105
+ * ```
106
+ */
107
+ public getBySlug(recordSlug: string): Promise<ApiResponse<Structure>> {
108
+ const path = getCollectionBySlugApiPath(this.workspaceId, recordSlug);
109
+ return this.requestFn<Structure>('GET', path);
110
+ }
111
+
112
+ /**
113
+ * Create a new collection.
114
+ *
115
+ * @param input - The collection definition
116
+ * @returns The created collection
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * const collection = await client.collections.create({
121
+ * name: 'Orders',
122
+ * recordSlug: 'orders',
123
+ * description: 'Customer orders',
124
+ * properties: [
125
+ * { name: 'title', type: 'string', required: true },
126
+ * { name: 'amount', type: 'number', minimum: 0 },
127
+ * { name: 'status', type: 'string', enum: ['pending', 'completed'] }
128
+ * ],
129
+ * enableVersioning: true,
130
+ * schemaDiscoveryMode: 'strict'
131
+ * });
132
+ * ```
133
+ */
134
+ public create(input: CreateStructureInput): Promise<ApiResponse<Structure>> {
135
+ const path = getCollectionsApiPath(this.workspaceId);
136
+ return this.requestFn<Structure>('POST', path, input);
137
+ }
138
+
139
+ /**
140
+ * Update an existing collection.
141
+ *
142
+ * @param collectionId - The collection UUID
143
+ * @param input - The fields to update
144
+ * @returns The updated collection
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * const updated = await client.collections.update('collection-uuid', {
149
+ * name: 'Updated Orders',
150
+ * properties: [
151
+ * { name: 'title', type: 'string', required: true },
152
+ * { name: 'amount', type: 'number', minimum: 0 },
153
+ * { name: 'priority', type: 'number' }
154
+ * ]
155
+ * });
156
+ * ```
157
+ */
158
+ public update(collectionId: string, input: UpdateStructureInput): Promise<ApiResponse<Structure>> {
159
+ const path = getCollectionsApiPath(this.workspaceId, collectionId);
160
+ return this.requestFn<Structure>('PUT', path, input);
161
+ }
162
+
163
+ /**
164
+ * Delete a collection.
165
+ *
166
+ * @param collectionId - The collection UUID
167
+ *
168
+ * @example
169
+ * ```ts
170
+ * await client.collections.delete('collection-uuid');
171
+ * ```
172
+ */
173
+ public delete(collectionId: string): Promise<ApiResponse<void>> {
174
+ const path = getCollectionsApiPath(this.workspaceId, collectionId);
175
+ return this.requestFn<void>('DELETE', path);
176
+ }
177
+
178
+ /**
179
+ * Validate a collection definition without creating it.
180
+ * Useful for checking slug uniqueness and property validity before creation.
181
+ *
182
+ * @param input - The collection definition to validate
183
+ * @returns Validation result
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * const result = await client.collections.validate({
188
+ * slug: 'orders',
189
+ * properties: [{ name: 'title', type: 'string' }]
190
+ * });
191
+ * ```
192
+ */
193
+ public validate(input: ValidateStructureInput): Promise<ApiResponse<any>> {
194
+ const path = getCollectionValidateApiPath(this.workspaceId);
195
+ return this.requestFn<any>('POST', path, input);
196
+ }
197
+ }