@driftgate/sdk 0.1.0-rc.1
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 +32 -0
- package/dist/index.d.ts +4167 -0
- package/dist/index.js +765 -0
- package/dist/index.js.map +1 -0
- package/examples/full.ts +19 -0
- package/examples/hello-world.ts +5 -0
- package/package.json +41 -0
- package/src/index.ts +1065 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { setTimeout as sleep } from "timers/promises";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import {
|
|
5
|
+
CanonicalPolicyRefSchema,
|
|
6
|
+
CanonicalRiskMetaSchema,
|
|
7
|
+
CanonicalRouteRefSchema,
|
|
8
|
+
DataBoundaryDecisionSchema,
|
|
9
|
+
EdgeInterceptorRegistrationSchema,
|
|
10
|
+
EdgeInterceptorStatusSchema,
|
|
11
|
+
FirewallEventsResponseSchema,
|
|
12
|
+
FirewallInspectRequestSchema,
|
|
13
|
+
FirewallInspectResponseSchema,
|
|
14
|
+
FirewallInspectResultSchema,
|
|
15
|
+
RunStateSchema,
|
|
16
|
+
V4ExecutionRequestSchema,
|
|
17
|
+
V4SessionResourceSchema,
|
|
18
|
+
V4SessionStartRequestSchema,
|
|
19
|
+
WorkflowVersionSchema
|
|
20
|
+
} from "@driftgate/contracts";
|
|
21
|
+
var HeadlessErrorEnvelopeSchema = z.object({
|
|
22
|
+
code: z.string(),
|
|
23
|
+
message: z.string(),
|
|
24
|
+
correlation_id: z.string().optional(),
|
|
25
|
+
details: z.unknown().optional()
|
|
26
|
+
});
|
|
27
|
+
var LegacyErrorEnvelopeSchema = z.object({
|
|
28
|
+
error: z.string(),
|
|
29
|
+
message: z.string(),
|
|
30
|
+
issues: z.unknown().optional()
|
|
31
|
+
});
|
|
32
|
+
var CanonicalTimingMsSchema = z.object({
|
|
33
|
+
total: z.number(),
|
|
34
|
+
policy: z.number().optional(),
|
|
35
|
+
route: z.number().optional(),
|
|
36
|
+
tool: z.number().optional()
|
|
37
|
+
});
|
|
38
|
+
var CanonicalMetaSchema = z.object({
|
|
39
|
+
requestId: z.string(),
|
|
40
|
+
sessionId: z.string().optional(),
|
|
41
|
+
executionId: z.string().optional(),
|
|
42
|
+
lineageId: z.string().optional(),
|
|
43
|
+
policy: CanonicalPolicyRefSchema.optional(),
|
|
44
|
+
route: CanonicalRouteRefSchema.optional(),
|
|
45
|
+
risk: CanonicalRiskMetaSchema.optional(),
|
|
46
|
+
timingMs: CanonicalTimingMsSchema
|
|
47
|
+
});
|
|
48
|
+
var CanonicalErrorSchema = z.object({
|
|
49
|
+
code: z.string(),
|
|
50
|
+
message: z.string(),
|
|
51
|
+
status: z.number(),
|
|
52
|
+
retryable: z.boolean(),
|
|
53
|
+
details: z.record(z.unknown()).optional()
|
|
54
|
+
});
|
|
55
|
+
var RunRecordSchema = z.object({
|
|
56
|
+
id: z.string(),
|
|
57
|
+
workspaceId: z.string(),
|
|
58
|
+
workflowVersionId: z.string(),
|
|
59
|
+
state: RunStateSchema,
|
|
60
|
+
correlationId: z.string(),
|
|
61
|
+
idempotencyKey: z.string().nullable().optional(),
|
|
62
|
+
triggerSource: z.enum(["ui", "api", "sdk", "cli", "hosted", "webhook"]),
|
|
63
|
+
requestedBy: z.string(),
|
|
64
|
+
requestedAt: z.string(),
|
|
65
|
+
startedAt: z.string().nullable().optional(),
|
|
66
|
+
completedAt: z.string().nullable().optional(),
|
|
67
|
+
slaPolicyId: z.string().nullable().optional(),
|
|
68
|
+
slaDueAt: z.string().nullable().optional(),
|
|
69
|
+
slaViolatedAt: z.string().nullable().optional()
|
|
70
|
+
});
|
|
71
|
+
var ApprovalSchema = z.object({
|
|
72
|
+
id: z.string(),
|
|
73
|
+
runId: z.string(),
|
|
74
|
+
requiredRole: z.string(),
|
|
75
|
+
status: z.enum(["pending", "approved", "denied"]),
|
|
76
|
+
createdAt: z.string(),
|
|
77
|
+
decidedAt: z.string().nullable().optional(),
|
|
78
|
+
decidedBy: z.string().nullable().optional()
|
|
79
|
+
});
|
|
80
|
+
var RunResponseSchema = z.object({
|
|
81
|
+
run: RunRecordSchema,
|
|
82
|
+
approval: ApprovalSchema.nullable().optional(),
|
|
83
|
+
blocked: z.boolean().optional(),
|
|
84
|
+
policyDecisions: z.array(
|
|
85
|
+
z.object({
|
|
86
|
+
mode: z.enum(["monitor", "enforce"]),
|
|
87
|
+
decision: z.enum(["allow", "deny"]),
|
|
88
|
+
policyId: z.string(),
|
|
89
|
+
ruleId: z.string(),
|
|
90
|
+
reasonCode: z.string(),
|
|
91
|
+
reasonText: z.string(),
|
|
92
|
+
correlationId: z.string(),
|
|
93
|
+
trace: z.record(z.unknown())
|
|
94
|
+
})
|
|
95
|
+
).optional(),
|
|
96
|
+
entitlementDecision: z.object({
|
|
97
|
+
id: z.string(),
|
|
98
|
+
reasonCode: z.string(),
|
|
99
|
+
reasonText: z.string(),
|
|
100
|
+
entitled: z.boolean()
|
|
101
|
+
}).optional(),
|
|
102
|
+
usageEntry: z.object({
|
|
103
|
+
id: z.string(),
|
|
104
|
+
quantity: z.number()
|
|
105
|
+
}).optional(),
|
|
106
|
+
boundaryDecision: DataBoundaryDecisionSchema.nullable().optional(),
|
|
107
|
+
firewallDecision: FirewallInspectResultSchema.nullable().optional()
|
|
108
|
+
});
|
|
109
|
+
var V4SessionStartDataSchema = z.object({
|
|
110
|
+
session: V4SessionResourceSchema
|
|
111
|
+
});
|
|
112
|
+
var CanonicalEnvelopeSchema = (dataSchema) => z.object({
|
|
113
|
+
ok: z.boolean(),
|
|
114
|
+
data: dataSchema.nullable(),
|
|
115
|
+
meta: CanonicalMetaSchema,
|
|
116
|
+
error: CanonicalErrorSchema.nullable()
|
|
117
|
+
});
|
|
118
|
+
var V4SessionStartResponseSchema = CanonicalEnvelopeSchema(V4SessionStartDataSchema);
|
|
119
|
+
var V4ExecutionResponseSchema = CanonicalEnvelopeSchema(RunResponseSchema);
|
|
120
|
+
var V4EphemeralExecuteRequestBodySchema = V4SessionStartRequestSchema.extend({
|
|
121
|
+
input: z.record(z.unknown())
|
|
122
|
+
});
|
|
123
|
+
var V4EphemeralExecuteDataSchema = z.object({
|
|
124
|
+
session: V4SessionResourceSchema,
|
|
125
|
+
execution: RunResponseSchema
|
|
126
|
+
});
|
|
127
|
+
var V4EphemeralExecutionResponseSchema = CanonicalEnvelopeSchema(V4EphemeralExecuteDataSchema);
|
|
128
|
+
var CanonicalErrorEnvelopeSchema = z.object({
|
|
129
|
+
ok: z.literal(false),
|
|
130
|
+
data: z.null(),
|
|
131
|
+
meta: CanonicalMetaSchema,
|
|
132
|
+
error: CanonicalErrorSchema
|
|
133
|
+
});
|
|
134
|
+
var RunEventsResponseSchema = z.object({
|
|
135
|
+
events: z.array(
|
|
136
|
+
z.object({
|
|
137
|
+
id: z.string(),
|
|
138
|
+
runId: z.string(),
|
|
139
|
+
type: z.string(),
|
|
140
|
+
payload: z.record(z.unknown()),
|
|
141
|
+
createdAt: z.string()
|
|
142
|
+
})
|
|
143
|
+
)
|
|
144
|
+
});
|
|
145
|
+
var ApprovalsListSchema = z.object({
|
|
146
|
+
approvals: z.array(
|
|
147
|
+
z.object({
|
|
148
|
+
approval: ApprovalSchema,
|
|
149
|
+
run: RunRecordSchema
|
|
150
|
+
})
|
|
151
|
+
)
|
|
152
|
+
});
|
|
153
|
+
var DeployResponseSchema = z.object({
|
|
154
|
+
project: z.object({
|
|
155
|
+
id: z.string(),
|
|
156
|
+
workspaceId: z.string(),
|
|
157
|
+
name: z.string(),
|
|
158
|
+
createdBy: z.string(),
|
|
159
|
+
createdAt: z.string(),
|
|
160
|
+
updatedAt: z.string()
|
|
161
|
+
}),
|
|
162
|
+
workflow: z.object({
|
|
163
|
+
id: z.string(),
|
|
164
|
+
projectId: z.string(),
|
|
165
|
+
workspaceId: z.string(),
|
|
166
|
+
name: z.string(),
|
|
167
|
+
status: z.enum(["draft", "published", "archived"]),
|
|
168
|
+
createdBy: z.string(),
|
|
169
|
+
createdAt: z.string(),
|
|
170
|
+
updatedAt: z.string()
|
|
171
|
+
}),
|
|
172
|
+
draft: z.object({
|
|
173
|
+
workflowId: z.string(),
|
|
174
|
+
workspaceId: z.string(),
|
|
175
|
+
version: z.number(),
|
|
176
|
+
nodes: z.array(z.unknown()),
|
|
177
|
+
edges: z.array(z.unknown()),
|
|
178
|
+
viewport: z.object({ x: z.number(), y: z.number(), zoom: z.number() }),
|
|
179
|
+
updatedAt: z.string()
|
|
180
|
+
}),
|
|
181
|
+
compile: z.object({
|
|
182
|
+
checksum: z.string(),
|
|
183
|
+
mutationNodeIds: z.array(z.string()),
|
|
184
|
+
compiledPlan: z.record(z.unknown())
|
|
185
|
+
})
|
|
186
|
+
});
|
|
187
|
+
var PublishResponseSchema = z.object({
|
|
188
|
+
version: WorkflowVersionSchema
|
|
189
|
+
});
|
|
190
|
+
var ConnectorRecordSchema = z.object({
|
|
191
|
+
id: z.string(),
|
|
192
|
+
workspaceId: z.string(),
|
|
193
|
+
name: z.string(),
|
|
194
|
+
connectorType: z.string(),
|
|
195
|
+
status: z.enum(["active", "disabled"]),
|
|
196
|
+
config: z.record(z.unknown()),
|
|
197
|
+
createdBy: z.string(),
|
|
198
|
+
createdAt: z.string(),
|
|
199
|
+
updatedAt: z.string()
|
|
200
|
+
});
|
|
201
|
+
var WorkspaceSecretRecordSchema = z.object({
|
|
202
|
+
id: z.string(),
|
|
203
|
+
workspaceId: z.string(),
|
|
204
|
+
connectorId: z.string().nullable(),
|
|
205
|
+
name: z.string(),
|
|
206
|
+
keyVersion: z.string(),
|
|
207
|
+
metadata: z.record(z.unknown()),
|
|
208
|
+
createdBy: z.string(),
|
|
209
|
+
createdAt: z.string(),
|
|
210
|
+
rotatedAt: z.string().nullable(),
|
|
211
|
+
revokedAt: z.string().nullable(),
|
|
212
|
+
maskedValue: z.string()
|
|
213
|
+
});
|
|
214
|
+
var WorkspaceWebhookRecordSchema = z.object({
|
|
215
|
+
id: z.string(),
|
|
216
|
+
workspaceId: z.string(),
|
|
217
|
+
connectorId: z.string().nullable(),
|
|
218
|
+
name: z.string(),
|
|
219
|
+
path: z.string(),
|
|
220
|
+
targetWorkflowId: z.string(),
|
|
221
|
+
status: z.enum(["active", "disabled"]),
|
|
222
|
+
eventFilter: z.record(z.unknown()),
|
|
223
|
+
createdBy: z.string(),
|
|
224
|
+
createdAt: z.string(),
|
|
225
|
+
updatedAt: z.string(),
|
|
226
|
+
lastReceivedAt: z.string().nullable(),
|
|
227
|
+
revokedAt: z.string().nullable(),
|
|
228
|
+
signingSecretConfigured: z.boolean()
|
|
229
|
+
});
|
|
230
|
+
var ConnectorListSchema = z.object({
|
|
231
|
+
connectors: z.array(ConnectorRecordSchema)
|
|
232
|
+
});
|
|
233
|
+
var ConnectorMutationSchema = z.object({
|
|
234
|
+
connector: ConnectorRecordSchema
|
|
235
|
+
});
|
|
236
|
+
var SecretListSchema = z.object({
|
|
237
|
+
secrets: z.array(WorkspaceSecretRecordSchema)
|
|
238
|
+
});
|
|
239
|
+
var SecretMutationSchema = z.object({
|
|
240
|
+
secret: WorkspaceSecretRecordSchema
|
|
241
|
+
});
|
|
242
|
+
var WebhookListSchema = z.object({
|
|
243
|
+
webhooks: z.array(WorkspaceWebhookRecordSchema)
|
|
244
|
+
});
|
|
245
|
+
var WebhookMutationSchema = z.object({
|
|
246
|
+
webhook: WorkspaceWebhookRecordSchema
|
|
247
|
+
});
|
|
248
|
+
var EdgeInterceptorListSchema = z.object({
|
|
249
|
+
registrations: z.array(EdgeInterceptorRegistrationSchema)
|
|
250
|
+
});
|
|
251
|
+
var EdgeInterceptorMutationSchema = z.object({
|
|
252
|
+
registration: EdgeInterceptorRegistrationSchema
|
|
253
|
+
});
|
|
254
|
+
var FirewallInspectBodySchema = FirewallInspectRequestSchema.omit({
|
|
255
|
+
workspaceId: true
|
|
256
|
+
});
|
|
257
|
+
var DriftGateError = class extends Error {
|
|
258
|
+
constructor(code, message, status, correlationId, details) {
|
|
259
|
+
super(message);
|
|
260
|
+
this.code = code;
|
|
261
|
+
this.status = status;
|
|
262
|
+
this.correlationId = correlationId;
|
|
263
|
+
this.details = details;
|
|
264
|
+
this.name = "DriftGateError";
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
var DriftGateSessionHandle = class {
|
|
268
|
+
constructor(client, session, startEnvelope) {
|
|
269
|
+
this.client = client;
|
|
270
|
+
this.session = session;
|
|
271
|
+
this.startEnvelope = startEnvelope;
|
|
272
|
+
}
|
|
273
|
+
get sessionId() {
|
|
274
|
+
return this.session.sessionId;
|
|
275
|
+
}
|
|
276
|
+
get rawEnvelope() {
|
|
277
|
+
return this.startEnvelope.raw;
|
|
278
|
+
}
|
|
279
|
+
async execute(input) {
|
|
280
|
+
return this.client.executeSession(this.session.sessionId, input);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
function isTerminalState(state) {
|
|
284
|
+
return ["succeeded", "failed", "denied", "timed_out", "canceled", "aborted"].includes(state);
|
|
285
|
+
}
|
|
286
|
+
var DriftGateClient = class {
|
|
287
|
+
baseUrl;
|
|
288
|
+
sessionToken;
|
|
289
|
+
apiKey;
|
|
290
|
+
fetchImpl;
|
|
291
|
+
edgeInterceptorState = null;
|
|
292
|
+
session;
|
|
293
|
+
approvals;
|
|
294
|
+
connectors;
|
|
295
|
+
secrets;
|
|
296
|
+
webhooks;
|
|
297
|
+
edgeInterceptors;
|
|
298
|
+
firewall;
|
|
299
|
+
constructor(options) {
|
|
300
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
301
|
+
this.sessionToken = options.sessionToken;
|
|
302
|
+
this.apiKey = options.apiKey;
|
|
303
|
+
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
304
|
+
this.session = {
|
|
305
|
+
start: async (input) => {
|
|
306
|
+
const payload = V4SessionStartRequestSchema.parse(input);
|
|
307
|
+
const raw = await this.request("/v4/sessions.start", {
|
|
308
|
+
method: "POST",
|
|
309
|
+
body: JSON.stringify(payload)
|
|
310
|
+
});
|
|
311
|
+
const parsed = V4SessionStartResponseSchema.parse(raw);
|
|
312
|
+
if (!parsed.ok || !parsed.data) {
|
|
313
|
+
const canonicalCode = parsed.error?.code ?? "INTERNAL";
|
|
314
|
+
throw new DriftGateError(
|
|
315
|
+
canonicalCode,
|
|
316
|
+
parsed.error?.message ?? "session.start failed",
|
|
317
|
+
parsed.error?.status ?? 500,
|
|
318
|
+
parsed.meta.requestId,
|
|
319
|
+
parsed.error?.details
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
const envelope = {
|
|
323
|
+
ok: parsed.ok,
|
|
324
|
+
data: parsed.data,
|
|
325
|
+
meta: parsed.meta,
|
|
326
|
+
error: parsed.error,
|
|
327
|
+
raw
|
|
328
|
+
};
|
|
329
|
+
return new DriftGateSessionHandle(this, parsed.data.session, envelope);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
this.approvals = {
|
|
333
|
+
list: async (workspaceId, status) => {
|
|
334
|
+
const query = status ? `?status=${encodeURIComponent(status)}` : "";
|
|
335
|
+
const response = await this.request(`/v1/headless/workspaces/${encodeURIComponent(workspaceId)}/approvals${query}`);
|
|
336
|
+
return ApprovalsListSchema.parse(response).approvals;
|
|
337
|
+
},
|
|
338
|
+
approve: async (approvalId) => {
|
|
339
|
+
const response = await this.request(`/v1/headless/approvals/${encodeURIComponent(approvalId)}/approve`, {
|
|
340
|
+
method: "POST"
|
|
341
|
+
});
|
|
342
|
+
return RunResponseSchema.parse(response);
|
|
343
|
+
},
|
|
344
|
+
deny: async (approvalId) => {
|
|
345
|
+
const response = await this.request(`/v1/headless/approvals/${encodeURIComponent(approvalId)}/deny`, {
|
|
346
|
+
method: "POST"
|
|
347
|
+
});
|
|
348
|
+
return RunResponseSchema.parse(response);
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
this.connectors = {
|
|
352
|
+
list: async (workspaceId) => {
|
|
353
|
+
const response = await this.request(
|
|
354
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/connectors`
|
|
355
|
+
);
|
|
356
|
+
return ConnectorListSchema.parse(response).connectors;
|
|
357
|
+
},
|
|
358
|
+
create: async (workspaceId, input) => {
|
|
359
|
+
const response = await this.request(
|
|
360
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/connectors`,
|
|
361
|
+
{
|
|
362
|
+
method: "POST",
|
|
363
|
+
body: JSON.stringify(input)
|
|
364
|
+
}
|
|
365
|
+
);
|
|
366
|
+
return ConnectorMutationSchema.parse(response).connector;
|
|
367
|
+
},
|
|
368
|
+
update: async (workspaceId, connectorId, input) => {
|
|
369
|
+
const response = await this.request(
|
|
370
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/connectors/${encodeURIComponent(
|
|
371
|
+
connectorId
|
|
372
|
+
)}`,
|
|
373
|
+
{
|
|
374
|
+
method: "PATCH",
|
|
375
|
+
body: JSON.stringify(input)
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
return ConnectorMutationSchema.parse(response).connector;
|
|
379
|
+
},
|
|
380
|
+
delete: async (workspaceId, connectorId) => {
|
|
381
|
+
const response = await this.request(
|
|
382
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/connectors/${encodeURIComponent(
|
|
383
|
+
connectorId
|
|
384
|
+
)}`,
|
|
385
|
+
{
|
|
386
|
+
method: "DELETE"
|
|
387
|
+
}
|
|
388
|
+
);
|
|
389
|
+
return ConnectorMutationSchema.parse(response).connector;
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
this.secrets = {
|
|
393
|
+
list: async (workspaceId) => {
|
|
394
|
+
const response = await this.request(
|
|
395
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/secrets`
|
|
396
|
+
);
|
|
397
|
+
return SecretListSchema.parse(response).secrets;
|
|
398
|
+
},
|
|
399
|
+
create: async (workspaceId, input) => {
|
|
400
|
+
const response = await this.request(
|
|
401
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/secrets`,
|
|
402
|
+
{
|
|
403
|
+
method: "POST",
|
|
404
|
+
body: JSON.stringify(input)
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
return SecretMutationSchema.parse(response).secret;
|
|
408
|
+
},
|
|
409
|
+
update: async (workspaceId, secretId, input) => {
|
|
410
|
+
const response = await this.request(
|
|
411
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/secrets/${encodeURIComponent(secretId)}`,
|
|
412
|
+
{
|
|
413
|
+
method: "PATCH",
|
|
414
|
+
body: JSON.stringify(input)
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
return SecretMutationSchema.parse(response).secret;
|
|
418
|
+
},
|
|
419
|
+
delete: async (workspaceId, secretId) => {
|
|
420
|
+
const response = await this.request(
|
|
421
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/secrets/${encodeURIComponent(secretId)}`,
|
|
422
|
+
{
|
|
423
|
+
method: "DELETE"
|
|
424
|
+
}
|
|
425
|
+
);
|
|
426
|
+
return SecretMutationSchema.parse(response).secret;
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
this.webhooks = {
|
|
430
|
+
list: async (workspaceId) => {
|
|
431
|
+
const response = await this.request(
|
|
432
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/webhooks`
|
|
433
|
+
);
|
|
434
|
+
return WebhookListSchema.parse(response).webhooks;
|
|
435
|
+
},
|
|
436
|
+
create: async (workspaceId, input) => {
|
|
437
|
+
const response = await this.request(
|
|
438
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/webhooks`,
|
|
439
|
+
{
|
|
440
|
+
method: "POST",
|
|
441
|
+
body: JSON.stringify(input)
|
|
442
|
+
}
|
|
443
|
+
);
|
|
444
|
+
return WebhookMutationSchema.parse(response).webhook;
|
|
445
|
+
},
|
|
446
|
+
update: async (workspaceId, webhookId, input) => {
|
|
447
|
+
const response = await this.request(
|
|
448
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/webhooks/${encodeURIComponent(
|
|
449
|
+
webhookId
|
|
450
|
+
)}`,
|
|
451
|
+
{
|
|
452
|
+
method: "PATCH",
|
|
453
|
+
body: JSON.stringify(input)
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
return WebhookMutationSchema.parse(response).webhook;
|
|
457
|
+
},
|
|
458
|
+
delete: async (workspaceId, webhookId) => {
|
|
459
|
+
const response = await this.request(
|
|
460
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/webhooks/${encodeURIComponent(
|
|
461
|
+
webhookId
|
|
462
|
+
)}`,
|
|
463
|
+
{
|
|
464
|
+
method: "DELETE"
|
|
465
|
+
}
|
|
466
|
+
);
|
|
467
|
+
return WebhookMutationSchema.parse(response).webhook;
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
this.edgeInterceptors = {
|
|
471
|
+
list: async (workspaceId) => {
|
|
472
|
+
const response = await this.request(
|
|
473
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/edge/interceptors`
|
|
474
|
+
);
|
|
475
|
+
return EdgeInterceptorListSchema.parse(response).registrations;
|
|
476
|
+
},
|
|
477
|
+
register: async (workspaceId, input) => {
|
|
478
|
+
const response = await this.request(
|
|
479
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/edge/interceptors`,
|
|
480
|
+
{
|
|
481
|
+
method: "POST",
|
|
482
|
+
body: JSON.stringify({
|
|
483
|
+
...input,
|
|
484
|
+
workspaceId
|
|
485
|
+
})
|
|
486
|
+
}
|
|
487
|
+
);
|
|
488
|
+
return EdgeInterceptorMutationSchema.parse(response).registration;
|
|
489
|
+
},
|
|
490
|
+
setStatus: async (workspaceId, registrationId, status) => {
|
|
491
|
+
const parsedStatus = EdgeInterceptorStatusSchema.parse(status);
|
|
492
|
+
const response = await this.request(
|
|
493
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/edge/interceptors/${encodeURIComponent(
|
|
494
|
+
registrationId
|
|
495
|
+
)}/status`,
|
|
496
|
+
{
|
|
497
|
+
method: "PATCH",
|
|
498
|
+
body: JSON.stringify({ status: parsedStatus })
|
|
499
|
+
}
|
|
500
|
+
);
|
|
501
|
+
return EdgeInterceptorMutationSchema.parse(response).registration;
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
this.firewall = {
|
|
505
|
+
inspect: async (workspaceId, input) => {
|
|
506
|
+
const parsedInput = FirewallInspectBodySchema.parse(input);
|
|
507
|
+
const response = await this.request(
|
|
508
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/firewall/inspect`,
|
|
509
|
+
{
|
|
510
|
+
method: "POST",
|
|
511
|
+
body: JSON.stringify(parsedInput)
|
|
512
|
+
}
|
|
513
|
+
);
|
|
514
|
+
return FirewallInspectResponseSchema.parse(response);
|
|
515
|
+
},
|
|
516
|
+
events: async (workspaceId) => {
|
|
517
|
+
const response = await this.request(
|
|
518
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/firewall/events`
|
|
519
|
+
);
|
|
520
|
+
return FirewallEventsResponseSchema.parse(response).events;
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
async executeSession(sessionId, input) {
|
|
525
|
+
const payload = V4ExecutionRequestSchema.parse(input);
|
|
526
|
+
const raw = await this.request(`/v4/sessions/${encodeURIComponent(sessionId)}/executions.execute`, {
|
|
527
|
+
method: "POST",
|
|
528
|
+
body: JSON.stringify(payload)
|
|
529
|
+
});
|
|
530
|
+
const parsed = V4ExecutionResponseSchema.parse(raw);
|
|
531
|
+
if (!parsed.ok || !parsed.data) {
|
|
532
|
+
const canonicalCode = parsed.error?.code ?? "INTERNAL";
|
|
533
|
+
throw new DriftGateError(
|
|
534
|
+
canonicalCode,
|
|
535
|
+
parsed.error?.message ?? "session.execute failed",
|
|
536
|
+
parsed.error?.status ?? 500,
|
|
537
|
+
parsed.meta.requestId,
|
|
538
|
+
parsed.error?.details
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
return {
|
|
542
|
+
ok: parsed.ok,
|
|
543
|
+
data: parsed.data,
|
|
544
|
+
meta: parsed.meta,
|
|
545
|
+
error: parsed.error,
|
|
546
|
+
raw
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
async execute(input) {
|
|
550
|
+
const payload = V4EphemeralExecuteRequestBodySchema.parse(input);
|
|
551
|
+
const raw = await this.request("/v4/execute", {
|
|
552
|
+
method: "POST",
|
|
553
|
+
body: JSON.stringify(payload)
|
|
554
|
+
});
|
|
555
|
+
const parsed = V4EphemeralExecutionResponseSchema.parse(raw);
|
|
556
|
+
if (!parsed.ok || !parsed.data) {
|
|
557
|
+
const canonicalCode = parsed.error?.code ?? "INTERNAL";
|
|
558
|
+
throw new DriftGateError(
|
|
559
|
+
canonicalCode,
|
|
560
|
+
parsed.error?.message ?? "execute failed",
|
|
561
|
+
parsed.error?.status ?? 500,
|
|
562
|
+
parsed.meta.requestId,
|
|
563
|
+
parsed.error?.details
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
return {
|
|
567
|
+
ok: parsed.ok,
|
|
568
|
+
data: parsed.data,
|
|
569
|
+
meta: parsed.meta,
|
|
570
|
+
error: parsed.error,
|
|
571
|
+
raw
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
async enableEdgeMode(input) {
|
|
575
|
+
const registration = await this.edgeInterceptors.register(input.workspaceId, input.registration);
|
|
576
|
+
this.edgeInterceptorState = {
|
|
577
|
+
workspaceId: input.workspaceId,
|
|
578
|
+
registration,
|
|
579
|
+
enforcement: input.enforcement ?? "monitor",
|
|
580
|
+
hooks: input.hooks
|
|
581
|
+
};
|
|
582
|
+
return registration;
|
|
583
|
+
}
|
|
584
|
+
disableEdgeMode() {
|
|
585
|
+
this.edgeInterceptorState = null;
|
|
586
|
+
}
|
|
587
|
+
async run(input) {
|
|
588
|
+
const edgeDecision = this.evaluateEdgeDecision(input);
|
|
589
|
+
const edgeState = this.edgeInterceptorState;
|
|
590
|
+
if (edgeDecision && edgeState?.hooks?.beforeRun) {
|
|
591
|
+
await edgeState.hooks.beforeRun(input, edgeDecision);
|
|
592
|
+
}
|
|
593
|
+
if (edgeDecision && !edgeDecision.allowed) {
|
|
594
|
+
if (edgeState?.hooks?.onBlocked) {
|
|
595
|
+
await edgeState.hooks.onBlocked(input, edgeDecision);
|
|
596
|
+
}
|
|
597
|
+
if (edgeState?.enforcement === "enforce") {
|
|
598
|
+
throw new DriftGateError(
|
|
599
|
+
"edge_interceptor_denied",
|
|
600
|
+
edgeDecision.reasonText,
|
|
601
|
+
403,
|
|
602
|
+
void 0,
|
|
603
|
+
{
|
|
604
|
+
reasonCode: edgeDecision.reasonCode,
|
|
605
|
+
requiredCapabilities: edgeDecision.requiredCapabilities,
|
|
606
|
+
grantedCapabilities: edgeDecision.grantedCapabilities,
|
|
607
|
+
registrationId: edgeState.registration.registrationId
|
|
608
|
+
}
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
const response = await this.request("/v1/headless/runs", {
|
|
613
|
+
method: "POST",
|
|
614
|
+
body: JSON.stringify(input)
|
|
615
|
+
});
|
|
616
|
+
const parsed = RunResponseSchema.parse(response);
|
|
617
|
+
if (edgeDecision && edgeState?.hooks?.afterRun) {
|
|
618
|
+
await edgeState.hooks.afterRun(input, edgeDecision, parsed);
|
|
619
|
+
}
|
|
620
|
+
return parsed;
|
|
621
|
+
}
|
|
622
|
+
async status(runId) {
|
|
623
|
+
const response = await this.request(`/v1/headless/runs/${encodeURIComponent(runId)}`);
|
|
624
|
+
return RunResponseSchema.parse(response);
|
|
625
|
+
}
|
|
626
|
+
async events(runId) {
|
|
627
|
+
const response = await this.request(`/v1/headless/runs/${encodeURIComponent(runId)}/events`);
|
|
628
|
+
return RunEventsResponseSchema.parse(response).events;
|
|
629
|
+
}
|
|
630
|
+
async waitForTerminal(runId, options = {}) {
|
|
631
|
+
const intervalMs = options.intervalMs ?? 1500;
|
|
632
|
+
const timeoutMs = options.timeoutMs ?? 12e4;
|
|
633
|
+
const startedAt = Date.now();
|
|
634
|
+
while (true) {
|
|
635
|
+
const current = await this.status(runId);
|
|
636
|
+
if (isTerminalState(current.run.state)) {
|
|
637
|
+
return current;
|
|
638
|
+
}
|
|
639
|
+
if (Date.now() - startedAt >= timeoutMs) {
|
|
640
|
+
throw new DriftGateError("timeout", `run ${runId} did not reach terminal state before timeout`, 408);
|
|
641
|
+
}
|
|
642
|
+
await sleep(intervalMs);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
async deployWorkflow(input) {
|
|
646
|
+
const response = await this.request("/v1/headless/workflows/deploy", {
|
|
647
|
+
method: "POST",
|
|
648
|
+
body: JSON.stringify(input)
|
|
649
|
+
});
|
|
650
|
+
return DeployResponseSchema.parse(response);
|
|
651
|
+
}
|
|
652
|
+
async publishWorkflow(workflowId, workflowYaml) {
|
|
653
|
+
const response = await this.request(`/v1/headless/workflows/${encodeURIComponent(workflowId)}/publish`, {
|
|
654
|
+
method: "POST",
|
|
655
|
+
body: JSON.stringify(workflowYaml ? { workflowYaml } : {})
|
|
656
|
+
});
|
|
657
|
+
const parsed = PublishResponseSchema.parse(response);
|
|
658
|
+
return parsed.version;
|
|
659
|
+
}
|
|
660
|
+
evaluateEdgeDecision(input) {
|
|
661
|
+
const state = this.edgeInterceptorState;
|
|
662
|
+
if (!state || state.workspaceId !== input.workspaceId) {
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
if (state.registration.status !== "active") {
|
|
666
|
+
return {
|
|
667
|
+
allowed: true,
|
|
668
|
+
reasonCode: "edge.interceptor.disabled",
|
|
669
|
+
reasonText: "Edge interceptor registration is disabled; enforcement skipped.",
|
|
670
|
+
requiredCapabilities: [],
|
|
671
|
+
grantedCapabilities: state.registration.capabilities
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
const requiredCapabilities = ["runs:create"];
|
|
675
|
+
const grantedCapabilities = state.registration.capabilities;
|
|
676
|
+
const grantedSet = new Set(grantedCapabilities);
|
|
677
|
+
const missingCapabilities = requiredCapabilities.filter(
|
|
678
|
+
(capability) => !grantedSet.has(capability)
|
|
679
|
+
);
|
|
680
|
+
if (missingCapabilities.length === 0) {
|
|
681
|
+
return {
|
|
682
|
+
allowed: true,
|
|
683
|
+
reasonCode: "edge.interceptor.allow",
|
|
684
|
+
reasonText: "Edge interceptor capability checks passed.",
|
|
685
|
+
requiredCapabilities,
|
|
686
|
+
grantedCapabilities
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
return {
|
|
690
|
+
allowed: false,
|
|
691
|
+
reasonCode: "edge.interceptor.denied.missing_capability",
|
|
692
|
+
reasonText: `Missing required edge capabilities: ${missingCapabilities.join(", ")}`,
|
|
693
|
+
requiredCapabilities,
|
|
694
|
+
grantedCapabilities
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
async request(path, init = {}) {
|
|
698
|
+
const headers = new Headers(init.headers ?? {});
|
|
699
|
+
if (!headers.has("content-type") && init.body) {
|
|
700
|
+
headers.set("content-type", "application/json");
|
|
701
|
+
}
|
|
702
|
+
if (this.apiKey) {
|
|
703
|
+
headers.set("x-driftgate-api-key", this.apiKey);
|
|
704
|
+
} else if (this.sessionToken) {
|
|
705
|
+
headers.set("authorization", `Bearer ${this.sessionToken}`);
|
|
706
|
+
}
|
|
707
|
+
const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
708
|
+
...init,
|
|
709
|
+
headers
|
|
710
|
+
});
|
|
711
|
+
const rawText = await response.text();
|
|
712
|
+
const body = rawText.length > 0 ? safelyParseJson(rawText) : null;
|
|
713
|
+
if (!response.ok) {
|
|
714
|
+
const canonicalEnvelope = CanonicalErrorEnvelopeSchema.safeParse(body);
|
|
715
|
+
if (canonicalEnvelope.success) {
|
|
716
|
+
throw new DriftGateError(
|
|
717
|
+
canonicalEnvelope.data.error.code,
|
|
718
|
+
canonicalEnvelope.data.error.message,
|
|
719
|
+
canonicalEnvelope.data.error.status,
|
|
720
|
+
canonicalEnvelope.data.meta.requestId,
|
|
721
|
+
canonicalEnvelope.data.error.details
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
const envelope = HeadlessErrorEnvelopeSchema.safeParse(body);
|
|
725
|
+
if (envelope.success) {
|
|
726
|
+
throw new DriftGateError(
|
|
727
|
+
envelope.data.code,
|
|
728
|
+
envelope.data.message,
|
|
729
|
+
response.status,
|
|
730
|
+
envelope.data.correlation_id,
|
|
731
|
+
envelope.data.details
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
const legacyEnvelope = LegacyErrorEnvelopeSchema.safeParse(body);
|
|
735
|
+
if (legacyEnvelope.success) {
|
|
736
|
+
throw new DriftGateError(
|
|
737
|
+
legacyEnvelope.data.error,
|
|
738
|
+
legacyEnvelope.data.message,
|
|
739
|
+
response.status,
|
|
740
|
+
void 0,
|
|
741
|
+
legacyEnvelope.data.issues
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
throw new DriftGateError(
|
|
745
|
+
"http_error",
|
|
746
|
+
`request failed (${response.status})${rawText ? `: ${rawText}` : ""}`,
|
|
747
|
+
response.status
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
return body;
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
function safelyParseJson(input) {
|
|
754
|
+
try {
|
|
755
|
+
return JSON.parse(input);
|
|
756
|
+
} catch {
|
|
757
|
+
return { raw: input };
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
export {
|
|
761
|
+
DriftGateClient,
|
|
762
|
+
DriftGateError,
|
|
763
|
+
DriftGateSessionHandle
|
|
764
|
+
};
|
|
765
|
+
//# sourceMappingURL=index.js.map
|