@secondlayer/sdk 0.10.3 → 1.0.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 +1 -22
- package/dist/index.d.ts +168 -56
- package/dist/index.js +137 -90
- package/dist/index.js.map +9 -10
- package/dist/marketplace/index.d.ts +3 -0
- package/dist/marketplace/index.js +22 -4
- package/dist/marketplace/index.js.map +4 -4
- package/dist/subgraphs/index.d.ts +148 -47
- package/dist/subgraphs/index.js +128 -81
- package/dist/subgraphs/index.js.map +8 -9
- package/dist/workflows/index.d.ts +125 -5
- package/dist/workflows/index.js +130 -5
- package/dist/workflows/index.js.map +5 -5
- package/package.json +4 -8
- package/dist/streams/index.d.ts +0 -57
- package/dist/streams/index.js +0 -160
- package/dist/streams/index.js.map +0 -12
package/README.md
CHANGED
|
@@ -19,27 +19,6 @@ const sl = new SecondLayer({
|
|
|
19
19
|
});
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
## Streams
|
|
23
|
-
|
|
24
|
-
Manage real-time event streams with endpoint delivery.
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
// Create
|
|
28
|
-
const { stream, signingSecret } = await sl.streams.create({
|
|
29
|
-
name: "my-stream",
|
|
30
|
-
endpointUrl: "https://example.com/receive",
|
|
31
|
-
filters: { type: "contract_call", contract_id: "SP...token" },
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// List
|
|
35
|
-
const { streams, total } = await sl.streams.list({ status: "active" });
|
|
36
|
-
|
|
37
|
-
// Get / Update / Delete
|
|
38
|
-
const stream = await sl.streams.get("stream-id");
|
|
39
|
-
await sl.streams.update("stream-id", { name: "renamed" });
|
|
40
|
-
await sl.streams.delete("stream-id");
|
|
41
|
-
```
|
|
42
|
-
|
|
43
22
|
## Subgraphs
|
|
44
23
|
|
|
45
24
|
Deploy and query subgraphs (custom indexers).
|
|
@@ -101,7 +80,7 @@ const run = await sl.workflows.getRun("run-id");
|
|
|
101
80
|
import { ApiError } from "@secondlayer/sdk";
|
|
102
81
|
|
|
103
82
|
try {
|
|
104
|
-
await sl.
|
|
83
|
+
await sl.subgraphs.get("nonexistent");
|
|
105
84
|
} catch (err) {
|
|
106
85
|
if (err instanceof ApiError) {
|
|
107
86
|
console.log(err.status); // 404
|
package/dist/index.d.ts
CHANGED
|
@@ -4,10 +4,13 @@ interface SecondLayerOptions {
|
|
|
4
4
|
baseUrl: string;
|
|
5
5
|
/** Bearer token for authenticated requests. */
|
|
6
6
|
apiKey?: string;
|
|
7
|
+
/** Deploy origin label sent as `x-sl-origin` (telemetry). Defaults to `cli`. */
|
|
8
|
+
origin?: "cli" | "mcp" | "session";
|
|
7
9
|
}
|
|
8
10
|
declare abstract class BaseClient {
|
|
9
11
|
protected baseUrl: string;
|
|
10
12
|
protected apiKey?: string;
|
|
13
|
+
protected origin: "cli" | "mcp" | "session";
|
|
11
14
|
constructor(options?: Partial<SecondLayerOptions>);
|
|
12
15
|
static authHeaders(apiKey?: string): Record<string, string>;
|
|
13
16
|
protected request<T>(method: string, path: string, body?: unknown): Promise<T>;
|
|
@@ -45,52 +48,28 @@ declare class Marketplace extends BaseClient {
|
|
|
45
48
|
}
|
|
46
49
|
}>;
|
|
47
50
|
}
|
|
48
|
-
import { BulkPauseResponse, BulkResumeResponse, CreateStream, CreateStreamResponse, ListStreamsResponse, StreamResponse, UpdateStream } from "@secondlayer/shared/schemas";
|
|
49
|
-
interface DeliverySummary {
|
|
50
|
-
id: string;
|
|
51
|
-
blockHeight: number;
|
|
52
|
-
status: string;
|
|
53
|
-
statusCode: number | null;
|
|
54
|
-
responseTimeMs: number | null;
|
|
55
|
-
attempts: number;
|
|
56
|
-
error: string | null;
|
|
57
|
-
createdAt: string;
|
|
58
|
-
}
|
|
59
|
-
interface DeliveryDetail extends DeliverySummary {
|
|
60
|
-
payload: unknown;
|
|
61
|
-
}
|
|
62
|
-
interface DeliveriesResponse {
|
|
63
|
-
deliveries: DeliverySummary[];
|
|
64
|
-
}
|
|
65
|
-
declare class Streams extends BaseClient {
|
|
66
|
-
private requestWithStreamId;
|
|
67
|
-
resolveStreamId(partialId: string): Promise<string>;
|
|
68
|
-
create(data: CreateStream): Promise<CreateStreamResponse>;
|
|
69
|
-
update(id: string, data: UpdateStream): Promise<StreamResponse>;
|
|
70
|
-
updateByName(name: string, data: CreateStream): Promise<StreamResponse>;
|
|
71
|
-
list(params?: {
|
|
72
|
-
status?: string
|
|
73
|
-
}): Promise<ListStreamsResponse>;
|
|
74
|
-
get(id: string): Promise<StreamResponse>;
|
|
75
|
-
delete(id: string): Promise<void>;
|
|
76
|
-
enable(id: string): Promise<StreamResponse>;
|
|
77
|
-
disable(id: string): Promise<StreamResponse>;
|
|
78
|
-
rotateSecret(id: string): Promise<{
|
|
79
|
-
secret: string
|
|
80
|
-
}>;
|
|
81
|
-
/** List recent deliveries for a stream. */
|
|
82
|
-
listDeliveries(id: string, params?: {
|
|
83
|
-
limit?: number
|
|
84
|
-
status?: string
|
|
85
|
-
}): Promise<DeliveriesResponse>;
|
|
86
|
-
/** Get a single delivery with full payload. */
|
|
87
|
-
getDelivery(streamId: string, deliveryId: string): Promise<DeliveryDetail>;
|
|
88
|
-
pauseAll(): Promise<BulkPauseResponse>;
|
|
89
|
-
resumeAll(): Promise<BulkResumeResponse>;
|
|
90
|
-
}
|
|
91
51
|
import { ReindexResponse, SubgraphDetail, SubgraphGapsResponse, SubgraphQueryParams as SubgraphQueryParams2, SubgraphSummary } from "@secondlayer/shared/schemas";
|
|
92
52
|
import { DeploySubgraphRequest, DeploySubgraphResponse } from "@secondlayer/shared/schemas/subgraphs";
|
|
93
53
|
import { InferSubgraphClient } from "@secondlayer/subgraphs";
|
|
54
|
+
interface SubgraphSource {
|
|
55
|
+
name: string;
|
|
56
|
+
version: string;
|
|
57
|
+
sourceCode: string | null;
|
|
58
|
+
readOnly: boolean;
|
|
59
|
+
reason?: string;
|
|
60
|
+
updatedAt: string;
|
|
61
|
+
}
|
|
62
|
+
interface BundleSubgraphResponse {
|
|
63
|
+
ok: true;
|
|
64
|
+
name: string;
|
|
65
|
+
version: string | null;
|
|
66
|
+
description: string | null;
|
|
67
|
+
sources: Record<string, Record<string, unknown>>;
|
|
68
|
+
schema: Record<string, unknown>;
|
|
69
|
+
handlerCode: string;
|
|
70
|
+
sourceCode: string;
|
|
71
|
+
bundleSize: number;
|
|
72
|
+
}
|
|
94
73
|
declare class Subgraphs extends BaseClient {
|
|
95
74
|
list(): Promise<{
|
|
96
75
|
data: SubgraphSummary[]
|
|
@@ -116,6 +95,14 @@ declare class Subgraphs extends BaseClient {
|
|
|
116
95
|
message: string
|
|
117
96
|
}>;
|
|
118
97
|
deploy(data: DeploySubgraphRequest): Promise<DeploySubgraphResponse>;
|
|
98
|
+
getSource(name: string): Promise<SubgraphSource>;
|
|
99
|
+
/**
|
|
100
|
+
* Bundle a TypeScript subgraph source on the server. Used by the web chat
|
|
101
|
+
* authoring loop so Vercel's serverless runtime doesn't have to run esbuild.
|
|
102
|
+
*/
|
|
103
|
+
bundle(data: {
|
|
104
|
+
code: string
|
|
105
|
+
}): Promise<BundleSubgraphResponse>;
|
|
119
106
|
queryTable(name: string, table: string, params?: SubgraphQueryParams2): Promise<unknown[]>;
|
|
120
107
|
queryTableCount(name: string, table: string, params?: SubgraphQueryParams2): Promise<{
|
|
121
108
|
count: number
|
|
@@ -139,12 +126,78 @@ declare class Subgraphs extends BaseClient {
|
|
|
139
126
|
private createTableClient;
|
|
140
127
|
}
|
|
141
128
|
import { InferSubgraphClient as InferSubgraphClient2 } from "@secondlayer/subgraphs";
|
|
142
|
-
import { QueueStats } from "@secondlayer/shared/types";
|
|
143
129
|
import { WorkflowRun, WorkflowRunStatus } from "@secondlayer/workflows";
|
|
130
|
+
interface WorkflowSource {
|
|
131
|
+
name: string;
|
|
132
|
+
version: string;
|
|
133
|
+
sourceCode: string | null;
|
|
134
|
+
readOnly: boolean;
|
|
135
|
+
reason?: string;
|
|
136
|
+
updatedAt: string;
|
|
137
|
+
}
|
|
138
|
+
interface WorkflowStepEvent {
|
|
139
|
+
id: string;
|
|
140
|
+
stepIndex: number;
|
|
141
|
+
stepId: string;
|
|
142
|
+
stepType: string;
|
|
143
|
+
status: string;
|
|
144
|
+
output?: unknown;
|
|
145
|
+
error: string | null;
|
|
146
|
+
retryCount: number;
|
|
147
|
+
aiTokensUsed: number;
|
|
148
|
+
startedAt: string | null;
|
|
149
|
+
completedAt: string | null;
|
|
150
|
+
durationMs: number | null;
|
|
151
|
+
ts: string;
|
|
152
|
+
}
|
|
153
|
+
interface WorkflowRunDoneEvent {
|
|
154
|
+
runId: string;
|
|
155
|
+
status: string;
|
|
156
|
+
error?: string | null;
|
|
157
|
+
completedAt?: string | null;
|
|
158
|
+
}
|
|
159
|
+
type WorkflowTailEvent = {
|
|
160
|
+
type: "step"
|
|
161
|
+
step: WorkflowStepEvent
|
|
162
|
+
} | {
|
|
163
|
+
type: "done"
|
|
164
|
+
done: WorkflowRunDoneEvent
|
|
165
|
+
} | {
|
|
166
|
+
type: "heartbeat"
|
|
167
|
+
ts: string
|
|
168
|
+
} | {
|
|
169
|
+
type: "timeout"
|
|
170
|
+
message: string
|
|
171
|
+
};
|
|
172
|
+
interface DeployDryRunResponse {
|
|
173
|
+
valid: boolean;
|
|
174
|
+
validation?: {
|
|
175
|
+
name: string
|
|
176
|
+
triggerType: string
|
|
177
|
+
};
|
|
178
|
+
bundleSize: number;
|
|
179
|
+
error?: string;
|
|
180
|
+
}
|
|
181
|
+
interface DeployResponse {
|
|
182
|
+
action: "created" | "updated";
|
|
183
|
+
workflowId: string;
|
|
184
|
+
version: string;
|
|
185
|
+
message: string;
|
|
186
|
+
}
|
|
187
|
+
interface BundleWorkflowResponse {
|
|
188
|
+
ok: true;
|
|
189
|
+
name: string;
|
|
190
|
+
trigger: Record<string, unknown>;
|
|
191
|
+
handlerCode: string;
|
|
192
|
+
sourceCode: string;
|
|
193
|
+
retries: Record<string, unknown> | null;
|
|
194
|
+
timeout: number | null;
|
|
195
|
+
bundleSize: number;
|
|
196
|
+
}
|
|
144
197
|
interface WorkflowSummary {
|
|
145
198
|
name: string;
|
|
146
199
|
status: "active" | "paused";
|
|
147
|
-
triggerType: "event" | "
|
|
200
|
+
triggerType: "event" | "schedule" | "manual";
|
|
148
201
|
createdAt: string;
|
|
149
202
|
updatedAt: string;
|
|
150
203
|
}
|
|
@@ -172,13 +225,63 @@ declare class Workflows extends BaseClient {
|
|
|
172
225
|
name: string
|
|
173
226
|
trigger: Record<string, unknown>
|
|
174
227
|
handlerCode: string
|
|
228
|
+
sourceCode?: string
|
|
229
|
+
expectedVersion?: string
|
|
175
230
|
retries?: Record<string, unknown>
|
|
176
231
|
timeout?: number
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
232
|
+
clientRequestId?: string
|
|
233
|
+
} & {
|
|
234
|
+
dryRun?: false
|
|
235
|
+
}): Promise<DeployResponse>;
|
|
236
|
+
deploy(data: {
|
|
237
|
+
name: string
|
|
238
|
+
trigger: Record<string, unknown>
|
|
239
|
+
handlerCode: string
|
|
240
|
+
sourceCode?: string
|
|
241
|
+
expectedVersion?: string
|
|
242
|
+
retries?: Record<string, unknown>
|
|
243
|
+
timeout?: number
|
|
244
|
+
dryRun: true
|
|
245
|
+
}): Promise<DeployDryRunResponse>;
|
|
246
|
+
getSource(name: string): Promise<WorkflowSource>;
|
|
247
|
+
/**
|
|
248
|
+
* Bundle a TypeScript workflow source on the server. Used by the web chat
|
|
249
|
+
* authoring loop so Vercel's serverless runtime doesn't have to run esbuild.
|
|
250
|
+
* CLI and MCP still bundle locally — this method is for clients that can't
|
|
251
|
+
* install `@secondlayer/bundler` directly (e.g. browser tooling, edge
|
|
252
|
+
* functions).
|
|
253
|
+
*/
|
|
254
|
+
bundle(data: {
|
|
255
|
+
code: string
|
|
256
|
+
}): Promise<BundleWorkflowResponse>;
|
|
257
|
+
pauseAll(): Promise<{
|
|
258
|
+
paused: number
|
|
259
|
+
workflows: Array<{
|
|
260
|
+
name: string
|
|
261
|
+
version: string
|
|
262
|
+
status: string
|
|
263
|
+
}>
|
|
181
264
|
}>;
|
|
265
|
+
cancelRun(runId: string): Promise<{
|
|
266
|
+
runId: string
|
|
267
|
+
status: string
|
|
268
|
+
cancelled: boolean
|
|
269
|
+
completedAt?: string
|
|
270
|
+
message?: string
|
|
271
|
+
}>;
|
|
272
|
+
rollback(name: string, toVersion?: string): Promise<{
|
|
273
|
+
action: "rolled-back"
|
|
274
|
+
name: string
|
|
275
|
+
fromVersion: string
|
|
276
|
+
restoredFromVersion: string
|
|
277
|
+
version: string
|
|
278
|
+
}>;
|
|
279
|
+
/**
|
|
280
|
+
* Subscribe to a workflow run's server-sent event stream. Resolves when the
|
|
281
|
+
* run completes, times out, or the signal is aborted. Throws on HTTP errors
|
|
282
|
+
* opening the stream.
|
|
283
|
+
*/
|
|
284
|
+
streamRun(name: string, runId: string, onEvent: (event: WorkflowTailEvent) => void, signal?: AbortSignal): Promise<void>;
|
|
182
285
|
list(): Promise<{
|
|
183
286
|
workflows: WorkflowSummary[]
|
|
184
287
|
}>;
|
|
@@ -198,12 +301,10 @@ declare class Workflows extends BaseClient {
|
|
|
198
301
|
getRun(runId: string): Promise<WorkflowRun>;
|
|
199
302
|
}
|
|
200
303
|
declare class SecondLayer extends BaseClient {
|
|
201
|
-
readonly streams: Streams;
|
|
202
304
|
readonly subgraphs: Subgraphs;
|
|
203
305
|
readonly marketplace: Marketplace;
|
|
204
306
|
readonly workflows: Workflows;
|
|
205
307
|
constructor(options?: Partial<SecondLayerOptions>);
|
|
206
|
-
getQueueStats(): Promise<QueueStats>;
|
|
207
308
|
}
|
|
208
309
|
/**
|
|
209
310
|
* Returns a typed client for a subgraph defined with `defineSubgraph()`.
|
|
@@ -230,10 +331,10 @@ declare function getSubgraph<T extends {
|
|
|
230
331
|
* @example
|
|
231
332
|
* ```ts
|
|
232
333
|
* try {
|
|
233
|
-
* await client.
|
|
334
|
+
* await client.subgraphs.get("my-subgraph");
|
|
234
335
|
* } catch (err) {
|
|
235
336
|
* if (err instanceof ApiError && err.status === 404) {
|
|
236
|
-
* console.log("
|
|
337
|
+
* console.log("Subgraph not found");
|
|
237
338
|
* }
|
|
238
339
|
* }
|
|
239
340
|
* ```
|
|
@@ -241,7 +342,18 @@ declare function getSubgraph<T extends {
|
|
|
241
342
|
declare class ApiError extends Error {
|
|
242
343
|
/** HTTP status code (0 for network errors). */
|
|
243
344
|
status: number;
|
|
244
|
-
|
|
345
|
+
/** Raw response body (parsed JSON if possible) — preserved for callers that need error details. */
|
|
346
|
+
body?: unknown;
|
|
347
|
+
constructor(status: number, message: string, body?: unknown);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Thrown by {@link Workflows.deploy} when the server rejects a deploy because the
|
|
351
|
+
* provided `expectedVersion` does not match the current stored version.
|
|
352
|
+
*/
|
|
353
|
+
declare class VersionConflictError extends ApiError {
|
|
354
|
+
currentVersion: string;
|
|
355
|
+
expectedVersion: string;
|
|
356
|
+
constructor(currentVersion: string, expectedVersion: string, message?: string);
|
|
245
357
|
}
|
|
246
358
|
/**
|
|
247
359
|
* Verify a webhook delivery signature from Secondlayer.
|
|
@@ -252,7 +364,7 @@ declare class ApiError extends Error {
|
|
|
252
364
|
*
|
|
253
365
|
* @param rawBody - The raw request body as a string (not parsed JSON)
|
|
254
366
|
* @param signatureHeader - The value of the `x-secondlayer-signature` header
|
|
255
|
-
* @param secret - Your
|
|
367
|
+
* @param secret - Your signing secret
|
|
256
368
|
* @param toleranceSeconds - Max age of signature in seconds (default 300)
|
|
257
369
|
* @returns true if the signature is valid
|
|
258
370
|
*
|
|
@@ -271,4 +383,4 @@ declare class ApiError extends Error {
|
|
|
271
383
|
* ```
|
|
272
384
|
*/
|
|
273
385
|
declare function verifyWebhookSignature(rawBody: string, signatureHeader: string, secret: string, toleranceSeconds?: number): boolean;
|
|
274
|
-
export { verifyWebhookSignature, getSubgraph,
|
|
386
|
+
export { verifyWebhookSignature, getSubgraph, VersionConflictError, Subgraphs, SecondLayerOptions, SecondLayer, Marketplace, ApiError };
|
package/dist/index.js
CHANGED
|
@@ -1,35 +1,51 @@
|
|
|
1
1
|
// src/errors.ts
|
|
2
2
|
class ApiError extends Error {
|
|
3
3
|
status;
|
|
4
|
-
|
|
4
|
+
body;
|
|
5
|
+
constructor(status, message, body) {
|
|
5
6
|
super(message);
|
|
6
7
|
this.status = status;
|
|
8
|
+
this.body = body;
|
|
7
9
|
this.name = "ApiError";
|
|
8
10
|
}
|
|
9
11
|
}
|
|
10
12
|
|
|
13
|
+
class VersionConflictError extends ApiError {
|
|
14
|
+
currentVersion;
|
|
15
|
+
expectedVersion;
|
|
16
|
+
constructor(currentVersion, expectedVersion, message = `Version conflict: expected ${expectedVersion}, current ${currentVersion}`) {
|
|
17
|
+
super(409, message, { currentVersion, expectedVersion });
|
|
18
|
+
this.currentVersion = currentVersion;
|
|
19
|
+
this.expectedVersion = expectedVersion;
|
|
20
|
+
this.name = "VersionConflictError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
11
24
|
// src/base.ts
|
|
12
25
|
var DEFAULT_BASE_URL = "https://api.secondlayer.tools";
|
|
13
26
|
|
|
14
27
|
class BaseClient {
|
|
15
28
|
baseUrl;
|
|
16
29
|
apiKey;
|
|
30
|
+
origin;
|
|
17
31
|
constructor(options = {}) {
|
|
18
32
|
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
19
33
|
this.apiKey = options.apiKey;
|
|
34
|
+
this.origin = options.origin ?? "cli";
|
|
20
35
|
}
|
|
21
36
|
static authHeaders(apiKey) {
|
|
22
37
|
const headers = {
|
|
23
38
|
"Content-Type": "application/json"
|
|
24
39
|
};
|
|
25
40
|
if (apiKey) {
|
|
26
|
-
headers
|
|
41
|
+
headers.Authorization = `Bearer ${apiKey}`;
|
|
27
42
|
}
|
|
28
43
|
return headers;
|
|
29
44
|
}
|
|
30
45
|
async request(method, path, body) {
|
|
31
46
|
const url = `${this.baseUrl}${path}`;
|
|
32
47
|
const headers = BaseClient.authHeaders(this.apiKey);
|
|
48
|
+
headers["x-sl-origin"] = this.origin;
|
|
33
49
|
let response;
|
|
34
50
|
try {
|
|
35
51
|
response = await fetch(url, {
|
|
@@ -54,8 +70,10 @@ class BaseClient {
|
|
|
54
70
|
}
|
|
55
71
|
const errorBody = await response.text();
|
|
56
72
|
let message = `HTTP ${response.status}`;
|
|
73
|
+
let parsedBody = errorBody;
|
|
57
74
|
try {
|
|
58
75
|
const json = JSON.parse(errorBody);
|
|
76
|
+
parsedBody = json;
|
|
59
77
|
const err = json.error ?? json.message;
|
|
60
78
|
if (typeof err === "string") {
|
|
61
79
|
message = err;
|
|
@@ -66,7 +84,7 @@ class BaseClient {
|
|
|
66
84
|
if (errorBody)
|
|
67
85
|
message = errorBody;
|
|
68
86
|
}
|
|
69
|
-
throw new ApiError(response.status, message);
|
|
87
|
+
throw new ApiError(response.status, message, parsedBody);
|
|
70
88
|
}
|
|
71
89
|
if (response.status === 204) {
|
|
72
90
|
return;
|
|
@@ -131,83 +149,6 @@ class Marketplace extends BaseClient {
|
|
|
131
149
|
return this.request("GET", `/api/marketplace/subgraphs/${name}/${table}${buildSubgraphQueryString(params)}`);
|
|
132
150
|
}
|
|
133
151
|
}
|
|
134
|
-
// src/streams/client.ts
|
|
135
|
-
class Streams extends BaseClient {
|
|
136
|
-
async requestWithStreamId(method, pathTemplate, id, body) {
|
|
137
|
-
const fullId = await this.resolveStreamId(id);
|
|
138
|
-
return this.request(method, pathTemplate(fullId), body);
|
|
139
|
-
}
|
|
140
|
-
async resolveStreamId(partialId) {
|
|
141
|
-
if (partialId.length === 36 && partialId.includes("-")) {
|
|
142
|
-
return partialId;
|
|
143
|
-
}
|
|
144
|
-
const { streams } = await this.list();
|
|
145
|
-
const matches = streams.filter((s) => s.id.startsWith(partialId));
|
|
146
|
-
if (matches.length === 0) {
|
|
147
|
-
throw new ApiError(404, `No stream found matching "${partialId}"`);
|
|
148
|
-
}
|
|
149
|
-
if (matches.length > 1) {
|
|
150
|
-
throw new ApiError(400, `Multiple streams match "${partialId}": ${matches.map((s) => s.id.slice(0, 8)).join(", ")}`);
|
|
151
|
-
}
|
|
152
|
-
return matches[0].id;
|
|
153
|
-
}
|
|
154
|
-
async create(data) {
|
|
155
|
-
return this.request("POST", "/api/streams", data);
|
|
156
|
-
}
|
|
157
|
-
async update(id, data) {
|
|
158
|
-
return this.requestWithStreamId("PATCH", (id2) => `/api/streams/${id2}`, id, data);
|
|
159
|
-
}
|
|
160
|
-
async updateByName(name, data) {
|
|
161
|
-
const { streams } = await this.list();
|
|
162
|
-
const existing = streams.find((s) => s.name === name);
|
|
163
|
-
if (!existing) {
|
|
164
|
-
throw new ApiError(404, `Stream with name "${name}" not found`);
|
|
165
|
-
}
|
|
166
|
-
return this.update(existing.id, data);
|
|
167
|
-
}
|
|
168
|
-
async list(params) {
|
|
169
|
-
const searchParams = new URLSearchParams;
|
|
170
|
-
if (params?.status)
|
|
171
|
-
searchParams.set("status", params.status);
|
|
172
|
-
const query = searchParams.toString();
|
|
173
|
-
const path = query ? `/api/streams?${query}` : "/api/streams";
|
|
174
|
-
return this.request("GET", path);
|
|
175
|
-
}
|
|
176
|
-
async get(id) {
|
|
177
|
-
return this.requestWithStreamId("GET", (id2) => `/api/streams/${id2}`, id);
|
|
178
|
-
}
|
|
179
|
-
async delete(id) {
|
|
180
|
-
return this.requestWithStreamId("DELETE", (id2) => `/api/streams/${id2}`, id);
|
|
181
|
-
}
|
|
182
|
-
async enable(id) {
|
|
183
|
-
return this.requestWithStreamId("POST", (id2) => `/api/streams/${id2}/enable`, id);
|
|
184
|
-
}
|
|
185
|
-
async disable(id) {
|
|
186
|
-
return this.requestWithStreamId("POST", (id2) => `/api/streams/${id2}/disable`, id);
|
|
187
|
-
}
|
|
188
|
-
async rotateSecret(id) {
|
|
189
|
-
return this.requestWithStreamId("POST", (id2) => `/api/streams/${id2}/rotate-secret`, id);
|
|
190
|
-
}
|
|
191
|
-
async listDeliveries(id, params) {
|
|
192
|
-
const qs = new URLSearchParams;
|
|
193
|
-
if (params?.limit !== undefined)
|
|
194
|
-
qs.set("limit", String(params.limit));
|
|
195
|
-
if (params?.status)
|
|
196
|
-
qs.set("status", params.status);
|
|
197
|
-
const query = qs.toString();
|
|
198
|
-
return this.requestWithStreamId("GET", (id2) => `/api/streams/${id2}/deliveries${query ? `?${query}` : ""}`, id);
|
|
199
|
-
}
|
|
200
|
-
async getDelivery(streamId, deliveryId) {
|
|
201
|
-
const fullId = await this.resolveStreamId(streamId);
|
|
202
|
-
return this.request("GET", `/api/streams/${fullId}/deliveries/${deliveryId}`);
|
|
203
|
-
}
|
|
204
|
-
async pauseAll() {
|
|
205
|
-
return this.request("POST", "/api/streams/pause");
|
|
206
|
-
}
|
|
207
|
-
async resumeAll() {
|
|
208
|
-
return this.request("POST", "/api/streams/resume");
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
152
|
// src/subgraphs/serialize.ts
|
|
212
153
|
var SYSTEM_COLUMN_MAP = {
|
|
213
154
|
_blockHeight: "_block_height",
|
|
@@ -304,6 +245,12 @@ class Subgraphs extends BaseClient {
|
|
|
304
245
|
async deploy(data) {
|
|
305
246
|
return this.request("POST", "/api/subgraphs", data);
|
|
306
247
|
}
|
|
248
|
+
async getSource(name) {
|
|
249
|
+
return this.request("GET", `/api/subgraphs/${name}/source`);
|
|
250
|
+
}
|
|
251
|
+
async bundle(data) {
|
|
252
|
+
return this.request("POST", "/api/subgraphs/bundle", data);
|
|
253
|
+
}
|
|
307
254
|
async queryTable(name, table, params = {}) {
|
|
308
255
|
const result = await this.request("GET", `/api/subgraphs/${name}/${table}${buildSubgraphQueryString2(params)}`);
|
|
309
256
|
return Array.isArray(result) ? result : result.data;
|
|
@@ -358,9 +305,116 @@ class Subgraphs extends BaseClient {
|
|
|
358
305
|
}
|
|
359
306
|
}
|
|
360
307
|
// src/workflows/client.ts
|
|
308
|
+
function parseSseChunk(raw) {
|
|
309
|
+
let event = "message";
|
|
310
|
+
const dataLines = [];
|
|
311
|
+
for (const line of raw.split(`
|
|
312
|
+
`)) {
|
|
313
|
+
if (line.startsWith("event:")) {
|
|
314
|
+
event = line.slice(6).trim();
|
|
315
|
+
} else if (line.startsWith("data:")) {
|
|
316
|
+
dataLines.push(line.slice(5).trimStart());
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (dataLines.length === 0)
|
|
320
|
+
return null;
|
|
321
|
+
const data = dataLines.join(`
|
|
322
|
+
`);
|
|
323
|
+
try {
|
|
324
|
+
const parsed = JSON.parse(data);
|
|
325
|
+
switch (event) {
|
|
326
|
+
case "step":
|
|
327
|
+
return { type: "step", step: parsed };
|
|
328
|
+
case "done":
|
|
329
|
+
return { type: "done", done: parsed };
|
|
330
|
+
case "heartbeat":
|
|
331
|
+
return {
|
|
332
|
+
type: "heartbeat",
|
|
333
|
+
ts: typeof parsed === "string" ? parsed : String(parsed)
|
|
334
|
+
};
|
|
335
|
+
case "timeout":
|
|
336
|
+
return {
|
|
337
|
+
type: "timeout",
|
|
338
|
+
message: parsed.message ?? "timeout"
|
|
339
|
+
};
|
|
340
|
+
default:
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
} catch {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
361
348
|
class Workflows extends BaseClient {
|
|
362
349
|
async deploy(data) {
|
|
363
|
-
|
|
350
|
+
try {
|
|
351
|
+
return await this.request("POST", "/api/workflows", data);
|
|
352
|
+
} catch (err) {
|
|
353
|
+
if (err instanceof ApiError && err.status === 409) {
|
|
354
|
+
const body = err.body;
|
|
355
|
+
if (body?.currentVersion && body.expectedVersion) {
|
|
356
|
+
throw new VersionConflictError(body.currentVersion, body.expectedVersion, err.message);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
throw err;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async getSource(name) {
|
|
363
|
+
return this.request("GET", `/api/workflows/${name}/source`);
|
|
364
|
+
}
|
|
365
|
+
async bundle(data) {
|
|
366
|
+
return this.request("POST", "/api/workflows/bundle", data);
|
|
367
|
+
}
|
|
368
|
+
async pauseAll() {
|
|
369
|
+
return this.request("POST", "/api/workflows/pause-all");
|
|
370
|
+
}
|
|
371
|
+
async cancelRun(runId) {
|
|
372
|
+
return this.request("POST", `/api/workflows/runs/${runId}/cancel`);
|
|
373
|
+
}
|
|
374
|
+
async rollback(name, toVersion) {
|
|
375
|
+
return this.request("POST", `/api/workflows/${name}/rollback`, toVersion ? { toVersion } : {});
|
|
376
|
+
}
|
|
377
|
+
async streamRun(name, runId, onEvent, signal) {
|
|
378
|
+
const url = `${this.baseUrl}/api/workflows/${name}/runs/${runId}/stream`;
|
|
379
|
+
const headers = {
|
|
380
|
+
Accept: "text/event-stream",
|
|
381
|
+
"x-sl-origin": this.origin
|
|
382
|
+
};
|
|
383
|
+
if (this.apiKey) {
|
|
384
|
+
headers.Authorization = `Bearer ${this.apiKey}`;
|
|
385
|
+
}
|
|
386
|
+
const res = await fetch(url, { headers, signal });
|
|
387
|
+
if (!res.ok || !res.body) {
|
|
388
|
+
throw new ApiError(res.status, `Failed to open workflow run stream (HTTP ${res.status})`);
|
|
389
|
+
}
|
|
390
|
+
const reader = res.body.pipeThrough(new TextDecoderStream).getReader();
|
|
391
|
+
let buffer = "";
|
|
392
|
+
while (true) {
|
|
393
|
+
const { value, done } = await reader.read();
|
|
394
|
+
if (done)
|
|
395
|
+
break;
|
|
396
|
+
buffer += value;
|
|
397
|
+
let sep = buffer.indexOf(`
|
|
398
|
+
|
|
399
|
+
`);
|
|
400
|
+
while (sep !== -1) {
|
|
401
|
+
const chunk = buffer.slice(0, sep);
|
|
402
|
+
buffer = buffer.slice(sep + 2);
|
|
403
|
+
const parsed = parseSseChunk(chunk);
|
|
404
|
+
if (parsed) {
|
|
405
|
+
onEvent(parsed);
|
|
406
|
+
if (parsed.type === "done" || parsed.type === "timeout") {
|
|
407
|
+
await reader.cancel().catch(() => {
|
|
408
|
+
return;
|
|
409
|
+
});
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
sep = buffer.indexOf(`
|
|
414
|
+
|
|
415
|
+
`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
364
418
|
}
|
|
365
419
|
async list() {
|
|
366
420
|
return this.request("GET", "/api/workflows");
|
|
@@ -396,21 +450,15 @@ class Workflows extends BaseClient {
|
|
|
396
450
|
|
|
397
451
|
// src/client.ts
|
|
398
452
|
class SecondLayer extends BaseClient {
|
|
399
|
-
streams;
|
|
400
453
|
subgraphs;
|
|
401
454
|
marketplace;
|
|
402
455
|
workflows;
|
|
403
456
|
constructor(options = {}) {
|
|
404
457
|
super(options);
|
|
405
|
-
this.streams = new Streams(options);
|
|
406
458
|
this.subgraphs = new Subgraphs(options);
|
|
407
459
|
this.marketplace = new Marketplace(options);
|
|
408
460
|
this.workflows = new Workflows(options);
|
|
409
461
|
}
|
|
410
|
-
async getQueueStats() {
|
|
411
|
-
const status = await this.request("GET", "/status");
|
|
412
|
-
return status.queue;
|
|
413
|
-
}
|
|
414
462
|
}
|
|
415
463
|
|
|
416
464
|
// src/subgraphs/get-subgraph.ts
|
|
@@ -431,13 +479,12 @@ function verifyWebhookSignature(rawBody, signatureHeader, secret, toleranceSecon
|
|
|
431
479
|
export {
|
|
432
480
|
verifyWebhookSignature,
|
|
433
481
|
getSubgraph,
|
|
434
|
-
|
|
482
|
+
VersionConflictError,
|
|
435
483
|
Subgraphs,
|
|
436
|
-
Streams,
|
|
437
484
|
SecondLayer,
|
|
438
485
|
Marketplace,
|
|
439
486
|
ApiError
|
|
440
487
|
};
|
|
441
488
|
|
|
442
|
-
//# debugId=
|
|
489
|
+
//# debugId=E50F894A60802FF364756E2164756E21
|
|
443
490
|
//# sourceMappingURL=index.js.map
|