@secondlayer/sdk 0.2.0 → 0.3.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/dist/index.d.ts CHANGED
@@ -1,52 +1,81 @@
1
- import { CreateStream, UpdateStream, StreamResponse, CreateStreamResponse, ListStreamsResponse, BulkPauseResponse, BulkResumeResponse, ViewSummary, ViewDetail, ViewQueryParams, ReindexResponse } from "@secondlayer/shared/schemas";
2
- import { DeployViewRequest, DeployViewResponse } from "@secondlayer/shared/schemas/views";
3
- import { QueueStats } from "@secondlayer/shared/types";
4
- interface StreamsClientOptions {
1
+ import { CreateStream, UpdateStream, StreamResponse, CreateStreamResponse, ListStreamsResponse, BulkPauseResponse, BulkResumeResponse } from "@secondlayer/shared/schemas";
2
+ interface SecondLayerOptions {
3
+ /** Base URL of the Secondlayer API (trailing slashes are stripped). */
5
4
  baseUrl: string;
5
+ /** Bearer token for authenticated requests. */
6
6
  apiKey?: string;
7
7
  }
8
- declare class StreamsClient {
9
- private baseUrl;
10
- private apiKey?;
11
- constructor(options: StreamsClientOptions);
8
+ declare abstract class BaseClient {
9
+ protected baseUrl: string;
10
+ protected apiKey?: string;
11
+ constructor(options?: Partial<SecondLayerOptions>);
12
12
  static authHeaders(apiKey?: string): Record<string, string>;
13
- private request;
13
+ protected request<T>(method: string, path: string, body?: unknown): Promise<T>;
14
+ }
15
+ declare class Streams extends BaseClient {
16
+ private requestWithStreamId;
14
17
  resolveStreamId(partialId: string): Promise<string>;
15
- createStream(data: CreateStream): Promise<CreateStreamResponse>;
16
- updateStream(id: string, data: UpdateStream): Promise<StreamResponse>;
17
- updateStreamByName(name: string, data: CreateStream): Promise<StreamResponse>;
18
- listStreams(params?: {
18
+ create(data: CreateStream): Promise<CreateStreamResponse>;
19
+ update(id: string, data: UpdateStream): Promise<StreamResponse>;
20
+ updateByName(name: string, data: CreateStream): Promise<StreamResponse>;
21
+ list(params?: {
19
22
  status?: string
20
23
  }): Promise<ListStreamsResponse>;
21
- getStream(id: string): Promise<StreamResponse>;
22
- deleteStream(id: string): Promise<void>;
23
- enableStream(id: string): Promise<StreamResponse>;
24
- disableStream(id: string): Promise<StreamResponse>;
24
+ get(id: string): Promise<StreamResponse>;
25
+ delete(id: string): Promise<void>;
26
+ enable(id: string): Promise<StreamResponse>;
27
+ disable(id: string): Promise<StreamResponse>;
25
28
  rotateSecret(id: string): Promise<{
26
29
  secret: string
27
30
  }>;
28
31
  pauseAll(): Promise<BulkPauseResponse>;
29
32
  resumeAll(): Promise<BulkResumeResponse>;
30
- getQueueStats(): Promise<QueueStats>;
31
- listViews(): Promise<{
33
+ }
34
+ import { ViewSummary, ViewDetail, ViewQueryParams, ReindexResponse } from "@secondlayer/shared/schemas";
35
+ import { DeployViewRequest, DeployViewResponse } from "@secondlayer/shared/schemas/views";
36
+ declare class Views extends BaseClient {
37
+ list(): Promise<{
32
38
  data: ViewSummary[]
33
39
  }>;
34
- getView(name: string): Promise<ViewDetail>;
35
- reindexView(name: string, options?: {
40
+ get(name: string): Promise<ViewDetail>;
41
+ reindex(name: string, options?: {
36
42
  fromBlock?: number
37
43
  toBlock?: number
38
44
  }): Promise<ReindexResponse>;
39
- deleteView(name: string): Promise<{
45
+ delete(name: string): Promise<{
40
46
  message: string
41
47
  }>;
42
- deployView(data: DeployViewRequest): Promise<DeployViewResponse>;
48
+ deploy(data: DeployViewRequest): Promise<DeployViewResponse>;
43
49
  queryTable(name: string, table: string, params?: ViewQueryParams): Promise<unknown[]>;
44
50
  queryTableCount(name: string, table: string, params?: ViewQueryParams): Promise<{
45
51
  count: number
46
52
  }>;
47
53
  }
54
+ import { QueueStats } from "@secondlayer/shared/types";
55
+ declare class SecondLayer extends BaseClient {
56
+ readonly streams: Streams;
57
+ readonly views: Views;
58
+ constructor(options?: Partial<SecondLayerOptions>);
59
+ getQueueStats(): Promise<QueueStats>;
60
+ }
61
+ /**
62
+ * Error thrown by {@link SecondLayer} when an API request fails.
63
+ * Includes the HTTP status code for programmatic error handling.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * try {
68
+ * await client.streams.get("abc123");
69
+ * } catch (err) {
70
+ * if (err instanceof ApiError && err.status === 404) {
71
+ * console.log("Stream not found");
72
+ * }
73
+ * }
74
+ * ```
75
+ */
48
76
  declare class ApiError extends Error {
77
+ /** HTTP status code (0 for network errors). */
49
78
  status: number;
50
79
  constructor(status: number, message: string);
51
80
  }
52
- export { StreamsClientOptions, StreamsClient, ApiError };
81
+ export { Views, Streams, SecondLayerOptions, SecondLayer, ApiError };
package/dist/index.js CHANGED
@@ -8,12 +8,14 @@ class ApiError extends Error {
8
8
  }
9
9
  }
10
10
 
11
- // src/client.ts
12
- class StreamsClient {
11
+ // src/base.ts
12
+ var DEFAULT_BASE_URL = "https://api.secondlayer.tools";
13
+
14
+ class BaseClient {
13
15
  baseUrl;
14
16
  apiKey;
15
- constructor(options) {
16
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
17
+ constructor(options = {}) {
18
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
17
19
  this.apiKey = options.apiKey;
18
20
  }
19
21
  static authHeaders(apiKey) {
@@ -25,7 +27,7 @@ class StreamsClient {
25
27
  }
26
28
  async request(method, path, body) {
27
29
  const url = `${this.baseUrl}${path}`;
28
- const headers = StreamsClient.authHeaders(this.apiKey);
30
+ const headers = BaseClient.authHeaders(this.apiKey);
29
31
  let response;
30
32
  try {
31
33
  response = await fetch(url, {
@@ -64,12 +66,21 @@ class StreamsClient {
64
66
  }
65
67
  return response.json();
66
68
  }
69
+ }
70
+
71
+ // src/streams/client.ts
72
+ class Streams extends BaseClient {
73
+ async requestWithStreamId(method, pathTemplate, id, body) {
74
+ const fullId = await this.resolveStreamId(id);
75
+ return this.request(method, pathTemplate(fullId), body);
76
+ }
67
77
  async resolveStreamId(partialId) {
68
78
  if (partialId.length === 36 && partialId.includes("-")) {
69
79
  return partialId;
70
80
  }
71
- const { streams } = await this.listStreams();
72
- const matches = streams.filter((s) => s.id.startsWith(partialId));
81
+ const { streams } = await this.list();
82
+ const typedStreams = streams;
83
+ const matches = typedStreams.filter((s) => s.id.startsWith(partialId));
73
84
  if (matches.length === 0) {
74
85
  throw new ApiError(404, `No stream found matching "${partialId}"`);
75
86
  }
@@ -78,22 +89,22 @@ class StreamsClient {
78
89
  }
79
90
  return matches[0].id;
80
91
  }
81
- async createStream(data) {
92
+ async create(data) {
82
93
  return this.request("POST", "/api/streams", data);
83
94
  }
84
- async updateStream(id, data) {
85
- const fullId = await this.resolveStreamId(id);
86
- return this.request("PATCH", `/api/streams/${fullId}`, data);
95
+ async update(id, data) {
96
+ return this.requestWithStreamId("PATCH", (id2) => `/api/streams/${id2}`, id, data);
87
97
  }
88
- async updateStreamByName(name, data) {
89
- const { streams } = await this.listStreams();
90
- const existing = streams.find((s) => s.name === name);
98
+ async updateByName(name, data) {
99
+ const { streams } = await this.list();
100
+ const typedStreams = streams;
101
+ const existing = typedStreams.find((s) => s.name === name);
91
102
  if (!existing) {
92
103
  throw new ApiError(404, `Stream with name "${name}" not found`);
93
104
  }
94
- return this.updateStream(existing.id, data);
105
+ return this.update(existing.id, data);
95
106
  }
96
- async listStreams(params) {
107
+ async list(params) {
97
108
  const searchParams = new URLSearchParams;
98
109
  if (params?.status)
99
110
  searchParams.set("status", params.status);
@@ -101,25 +112,20 @@ class StreamsClient {
101
112
  const path = query ? `/api/streams?${query}` : "/api/streams";
102
113
  return this.request("GET", path);
103
114
  }
104
- async getStream(id) {
105
- const fullId = await this.resolveStreamId(id);
106
- return this.request("GET", `/api/streams/${fullId}`);
115
+ async get(id) {
116
+ return this.requestWithStreamId("GET", (id2) => `/api/streams/${id2}`, id);
107
117
  }
108
- async deleteStream(id) {
109
- const fullId = await this.resolveStreamId(id);
110
- return this.request("DELETE", `/api/streams/${fullId}`);
118
+ async delete(id) {
119
+ return this.requestWithStreamId("DELETE", (id2) => `/api/streams/${id2}`, id);
111
120
  }
112
- async enableStream(id) {
113
- const fullId = await this.resolveStreamId(id);
114
- return this.request("POST", `/api/streams/${fullId}/enable`);
121
+ async enable(id) {
122
+ return this.requestWithStreamId("POST", (id2) => `/api/streams/${id2}/enable`, id);
115
123
  }
116
- async disableStream(id) {
117
- const fullId = await this.resolveStreamId(id);
118
- return this.request("POST", `/api/streams/${fullId}/disable`);
124
+ async disable(id) {
125
+ return this.requestWithStreamId("POST", (id2) => `/api/streams/${id2}/disable`, id);
119
126
  }
120
127
  async rotateSecret(id) {
121
- const fullId = await this.resolveStreamId(id);
122
- return this.request("POST", `/api/streams/${fullId}/rotate-secret`);
128
+ return this.requestWithStreamId("POST", (id2) => `/api/streams/${id2}/rotate-secret`, id);
123
129
  }
124
130
  async pauseAll() {
125
131
  return this.request("POST", "/api/streams/pause");
@@ -127,32 +133,8 @@ class StreamsClient {
127
133
  async resumeAll() {
128
134
  return this.request("POST", "/api/streams/resume");
129
135
  }
130
- async getQueueStats() {
131
- const status = await this.request("GET", "/status");
132
- return status.queue;
133
- }
134
- async listViews() {
135
- return this.request("GET", "/api/views");
136
- }
137
- async getView(name) {
138
- return this.request("GET", `/api/views/${name}`);
139
- }
140
- async reindexView(name, options) {
141
- return this.request("POST", `/api/views/${name}/reindex`, options);
142
- }
143
- async deleteView(name) {
144
- return this.request("DELETE", `/api/views/${name}`);
145
- }
146
- async deployView(data) {
147
- return this.request("POST", "/api/views", data);
148
- }
149
- async queryTable(name, table, params = {}) {
150
- return this.request("GET", `/api/views/${name}/${table}${buildViewQueryString(params)}`);
151
- }
152
- async queryTableCount(name, table, params = {}) {
153
- return this.request("GET", `/api/views/${name}/${table}/count${buildViewQueryString(params)}`);
154
- }
155
136
  }
137
+ // src/views/client.ts
156
138
  function buildViewQueryString(params) {
157
139
  const qs = new URLSearchParams;
158
140
  if (params.sort)
@@ -173,10 +155,50 @@ function buildViewQueryString(params) {
173
155
  const str = qs.toString();
174
156
  return str ? `?${str}` : "";
175
157
  }
158
+
159
+ class Views extends BaseClient {
160
+ async list() {
161
+ return this.request("GET", "/api/views");
162
+ }
163
+ async get(name) {
164
+ return this.request("GET", `/api/views/${name}`);
165
+ }
166
+ async reindex(name, options) {
167
+ return this.request("POST", `/api/views/${name}/reindex`, options);
168
+ }
169
+ async delete(name) {
170
+ return this.request("DELETE", `/api/views/${name}`);
171
+ }
172
+ async deploy(data) {
173
+ return this.request("POST", "/api/views", data);
174
+ }
175
+ async queryTable(name, table, params = {}) {
176
+ return this.request("GET", `/api/views/${name}/${table}${buildViewQueryString(params)}`);
177
+ }
178
+ async queryTableCount(name, table, params = {}) {
179
+ return this.request("GET", `/api/views/${name}/${table}/count${buildViewQueryString(params)}`);
180
+ }
181
+ }
182
+ // src/client.ts
183
+ class SecondLayer extends BaseClient {
184
+ streams;
185
+ views;
186
+ constructor(options = {}) {
187
+ super(options);
188
+ this.streams = new Streams(options);
189
+ this.views = new Views(options);
190
+ }
191
+ async getQueueStats() {
192
+ const status = await this.request("GET", "/status");
193
+ return status.queue;
194
+ }
195
+ }
176
196
  export {
177
- StreamsClient,
197
+ Views,
198
+ Streams,
199
+ SecondLayer,
178
200
  ApiError
179
201
  };
180
202
 
181
- //# debugId=25305F1E09AEB0F664756E2164756E21
203
+ //# debugId=3185A873B53583DC64756E2164756E21
182
204
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/errors.ts", "../src/client.ts"],
3
+ "sources": ["../src/errors.ts", "../src/base.ts", "../src/streams/client.ts", "../src/views/client.ts", "../src/client.ts"],
4
4
  "sourcesContent": [
5
- "export class ApiError extends Error {\n constructor(\n public status: number,\n message: string\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n",
6
- "import type {\n CreateStream,\n UpdateStream,\n StreamResponse,\n CreateStreamResponse,\n ListStreamsResponse,\n BulkPauseResponse,\n BulkResumeResponse,\n ViewSummary,\n ViewDetail,\n ViewQueryParams,\n ReindexResponse,\n} from \"@secondlayer/shared/schemas\";\nimport type { DeployViewRequest, DeployViewResponse } from \"@secondlayer/shared/schemas/views\";\nimport type { QueueStats } from \"@secondlayer/shared/types\";\nimport { ApiError } from \"./errors.ts\";\n\nexport interface StreamsClientOptions {\n baseUrl: string;\n apiKey?: string;\n}\n\nexport class StreamsClient {\n private baseUrl: string;\n private apiKey?: string;\n\n constructor(options: StreamsClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n\n // ── Helpers ───────────────────────────────────────────────────────────\n\n static authHeaders(apiKey?: string): Record<string, string> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (apiKey) {\n headers[\"Authorization\"] = `Bearer ${apiKey}`;\n }\n return headers;\n }\n\n private async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers = StreamsClient.authHeaders(this.apiKey);\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch {\n throw new ApiError(0, `Cannot reach API at ${this.baseUrl}. Check your connection or try again.`);\n }\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new ApiError(401, \"API key invalid or expired.\");\n }\n\n if (response.status === 429) {\n const retryAfter = response.headers.get(\"Retry-After\");\n const msg = retryAfter\n ? `Rate limited. Wait ${retryAfter} seconds.`\n : \"Rate limited. Try again later.\";\n throw new ApiError(429, msg);\n }\n\n if (response.status >= 500) {\n throw new ApiError(response.status, `Server error. Try again or check status at ${this.baseUrl}/health`);\n }\n\n const errorBody = await response.text();\n let message = `HTTP ${response.status}`;\n try {\n const json = JSON.parse(errorBody);\n message = json.error || json.message || message;\n } catch {\n if (errorBody) message = errorBody;\n }\n throw new ApiError(response.status, message);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return response.json() as Promise<T>;\n }\n\n // ── Stream ID Resolution ──────────────────────────────────────────────\n\n async resolveStreamId(partialId: string): Promise<string> {\n if (partialId.length === 36 && partialId.includes(\"-\")) {\n return partialId;\n }\n\n const { streams } = await this.listStreams();\n const matches = streams.filter((s) => s.id.startsWith(partialId));\n\n if (matches.length === 0) {\n throw new ApiError(404, `No stream found matching \"${partialId}\"`);\n }\n if (matches.length > 1) {\n throw new ApiError(400, `Multiple streams match \"${partialId}\": ${matches.map((s) => s.id.slice(0, 8)).join(\", \")}`);\n }\n\n return matches[0]!.id;\n }\n\n // ── Streams ───────────────────────────────────────────────────────────\n\n async createStream(data: CreateStream): Promise<CreateStreamResponse> {\n return this.request<CreateStreamResponse>(\"POST\", \"/api/streams\", data);\n }\n\n async updateStream(id: string, data: UpdateStream): Promise<StreamResponse> {\n const fullId = await this.resolveStreamId(id);\n return this.request<StreamResponse>(\"PATCH\", `/api/streams/${fullId}`, data);\n }\n\n async updateStreamByName(name: string, data: CreateStream): Promise<StreamResponse> {\n const { streams } = await this.listStreams();\n const existing = streams.find((s) => s.name === name);\n if (!existing) {\n throw new ApiError(404, `Stream with name \"${name}\" not found`);\n }\n return this.updateStream(existing.id, data);\n }\n\n async listStreams(params?: { status?: string }): Promise<ListStreamsResponse> {\n const searchParams = new URLSearchParams();\n if (params?.status) searchParams.set(\"status\", params.status);\n const query = searchParams.toString();\n const path = query ? `/api/streams?${query}` : \"/api/streams\";\n return this.request<ListStreamsResponse>(\"GET\", path);\n }\n\n async getStream(id: string): Promise<StreamResponse> {\n const fullId = await this.resolveStreamId(id);\n return this.request<StreamResponse>(\"GET\", `/api/streams/${fullId}`);\n }\n\n async deleteStream(id: string): Promise<void> {\n const fullId = await this.resolveStreamId(id);\n return this.request<void>(\"DELETE\", `/api/streams/${fullId}`);\n }\n\n async enableStream(id: string): Promise<StreamResponse> {\n const fullId = await this.resolveStreamId(id);\n return this.request<StreamResponse>(\"POST\", `/api/streams/${fullId}/enable`);\n }\n\n async disableStream(id: string): Promise<StreamResponse> {\n const fullId = await this.resolveStreamId(id);\n return this.request<StreamResponse>(\"POST\", `/api/streams/${fullId}/disable`);\n }\n\n async rotateSecret(id: string): Promise<{ secret: string }> {\n const fullId = await this.resolveStreamId(id);\n return this.request<{ secret: string }>(\"POST\", `/api/streams/${fullId}/rotate-secret`);\n }\n\n async pauseAll(): Promise<BulkPauseResponse> {\n return this.request<BulkPauseResponse>(\"POST\", \"/api/streams/pause\");\n }\n\n async resumeAll(): Promise<BulkResumeResponse> {\n return this.request<BulkResumeResponse>(\"POST\", \"/api/streams/resume\");\n }\n\n // ── Queue ─────────────────────────────────────────────────────────────\n\n async getQueueStats(): Promise<QueueStats> {\n const status = await this.request<{ queue: QueueStats }>(\"GET\", \"/status\");\n return status.queue;\n }\n\n // ── Views ─────────────────────────────────────────────────────────────\n\n async listViews(): Promise<{ data: ViewSummary[] }> {\n return this.request<{ data: ViewSummary[] }>(\"GET\", \"/api/views\");\n }\n\n async getView(name: string): Promise<ViewDetail> {\n return this.request<ViewDetail>(\"GET\", `/api/views/${name}`);\n }\n\n async reindexView(name: string, options?: { fromBlock?: number; toBlock?: number }): Promise<ReindexResponse> {\n return this.request<ReindexResponse>(\"POST\", `/api/views/${name}/reindex`, options);\n }\n\n async deleteView(name: string): Promise<{ message: string }> {\n return this.request<{ message: string }>(\"DELETE\", `/api/views/${name}`);\n }\n\n async deployView(data: DeployViewRequest): Promise<DeployViewResponse> {\n return this.request<DeployViewResponse>(\"POST\", \"/api/views\", data);\n }\n\n async queryTable(name: string, table: string, params: ViewQueryParams = {}): Promise<unknown[]> {\n return this.request<unknown[]>(\"GET\", `/api/views/${name}/${table}${buildViewQueryString(params)}`);\n }\n\n async queryTableCount(name: string, table: string, params: ViewQueryParams = {}): Promise<{ count: number }> {\n return this.request<{ count: number }>(\"GET\", `/api/views/${name}/${table}/count${buildViewQueryString(params)}`);\n }\n}\n\nfunction buildViewQueryString(params: ViewQueryParams): string {\n const qs = new URLSearchParams();\n if (params.sort) qs.set(\"_sort\", params.sort);\n if (params.order) qs.set(\"_order\", params.order);\n if (params.limit !== undefined) qs.set(\"_limit\", String(params.limit));\n if (params.offset !== undefined) qs.set(\"_offset\", String(params.offset));\n if (params.fields) qs.set(\"_fields\", params.fields);\n if (params.filters) {\n for (const [key, value] of Object.entries(params.filters)) {\n qs.set(key, value);\n }\n }\n const str = qs.toString();\n return str ? `?${str}` : \"\";\n}\n"
5
+ "/**\n * Error thrown by {@link SecondLayer} when an API request fails.\n * Includes the HTTP status code for programmatic error handling.\n *\n * @example\n * ```ts\n * try {\n * await client.streams.get(\"abc123\");\n * } catch (err) {\n * if (err instanceof ApiError && err.status === 404) {\n * console.log(\"Stream not found\");\n * }\n * }\n * ```\n */\nexport class ApiError extends Error {\n constructor(\n /** HTTP status code (0 for network errors). */\n public status: number,\n message: string\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n",
6
+ "import { ApiError } from \"./errors.ts\";\n\nexport interface SecondLayerOptions {\n /** Base URL of the Secondlayer API (trailing slashes are stripped). */\n baseUrl: string;\n /** Bearer token for authenticated requests. */\n apiKey?: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.secondlayer.tools\";\n\nexport abstract class BaseClient {\n protected baseUrl: string;\n protected apiKey?: string;\n\n constructor(options: Partial<SecondLayerOptions> = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n\n static authHeaders(apiKey?: string): Record<string, string> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (apiKey) {\n headers[\"Authorization\"] = `Bearer ${apiKey}`;\n }\n return headers;\n }\n\n protected async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers = BaseClient.authHeaders(this.apiKey);\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch {\n throw new ApiError(0, `Cannot reach API at ${this.baseUrl}. Check your connection or try again.`);\n }\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new ApiError(401, \"API key invalid or expired.\");\n }\n\n if (response.status === 429) {\n const retryAfter = response.headers.get(\"Retry-After\");\n const msg = retryAfter\n ? `Rate limited. Wait ${retryAfter} seconds.`\n : \"Rate limited. Try again later.\";\n throw new ApiError(429, msg);\n }\n\n if (response.status >= 500) {\n throw new ApiError(response.status, `Server error. Try again or check status at ${this.baseUrl}/health`);\n }\n\n const errorBody = await response.text();\n let message = `HTTP ${response.status}`;\n try {\n const json = JSON.parse(errorBody);\n message = json.error || json.message || message;\n } catch {\n if (errorBody) message = errorBody;\n }\n throw new ApiError(response.status, message);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return response.json() as Promise<T>;\n }\n}\n",
7
+ "import type {\n CreateStream,\n UpdateStream,\n StreamResponse,\n CreateStreamResponse,\n ListStreamsResponse,\n BulkPauseResponse,\n BulkResumeResponse,\n} from \"@secondlayer/shared/schemas\";\nimport { ApiError } from \"../errors.ts\";\nimport { BaseClient } from \"../base.ts\";\n\nexport class Streams extends BaseClient {\n private async requestWithStreamId<T>(\n method: string,\n pathTemplate: (id: string) => string,\n id: string,\n body?: unknown\n ): Promise<T> {\n const fullId = await this.resolveStreamId(id);\n return this.request<T>(method, pathTemplate(fullId), body);\n }\n\n async resolveStreamId(partialId: string): Promise<string> {\n if (partialId.length === 36 && partialId.includes(\"-\")) {\n return partialId;\n }\n\n const { streams } = await this.list();\n const typedStreams = streams as { id: string }[];\n const matches = typedStreams.filter((s) => s.id.startsWith(partialId));\n\n if (matches.length === 0) {\n throw new ApiError(404, `No stream found matching \"${partialId}\"`);\n }\n if (matches.length > 1) {\n throw new ApiError(400, `Multiple streams match \"${partialId}\": ${matches.map((s) => s.id.slice(0, 8)).join(\", \")}`);\n }\n\n return matches[0]!.id;\n }\n\n async create(data: CreateStream): Promise<CreateStreamResponse> {\n return this.request<CreateStreamResponse>(\"POST\", \"/api/streams\", data);\n }\n\n async update(id: string, data: UpdateStream): Promise<StreamResponse> {\n return this.requestWithStreamId(\"PATCH\", (id) => `/api/streams/${id}`, id, data);\n }\n\n async updateByName(name: string, data: CreateStream): Promise<StreamResponse> {\n const { streams } = await this.list();\n const typedStreams = streams as { id: string; name: string }[];\n const existing = typedStreams.find((s) => s.name === name);\n if (!existing) {\n throw new ApiError(404, `Stream with name \"${name}\" not found`);\n }\n return this.update(existing.id, data);\n }\n\n async list(params?: { status?: string }): Promise<ListStreamsResponse> {\n const searchParams = new URLSearchParams();\n if (params?.status) searchParams.set(\"status\", params.status);\n const query = searchParams.toString();\n const path = query ? `/api/streams?${query}` : \"/api/streams\";\n return this.request<ListStreamsResponse>(\"GET\", path);\n }\n\n async get(id: string): Promise<StreamResponse> {\n return this.requestWithStreamId(\"GET\", (id) => `/api/streams/${id}`, id);\n }\n\n async delete(id: string): Promise<void> {\n return this.requestWithStreamId(\"DELETE\", (id) => `/api/streams/${id}`, id);\n }\n\n async enable(id: string): Promise<StreamResponse> {\n return this.requestWithStreamId(\"POST\", (id) => `/api/streams/${id}/enable`, id);\n }\n\n async disable(id: string): Promise<StreamResponse> {\n return this.requestWithStreamId(\"POST\", (id) => `/api/streams/${id}/disable`, id);\n }\n\n async rotateSecret(id: string): Promise<{ secret: string }> {\n return this.requestWithStreamId(\"POST\", (id) => `/api/streams/${id}/rotate-secret`, id);\n }\n\n async pauseAll(): Promise<BulkPauseResponse> {\n return this.request<BulkPauseResponse>(\"POST\", \"/api/streams/pause\");\n }\n\n async resumeAll(): Promise<BulkResumeResponse> {\n return this.request<BulkResumeResponse>(\"POST\", \"/api/streams/resume\");\n }\n}\n",
8
+ "import type {\n ViewSummary,\n ViewDetail,\n ViewQueryParams,\n ReindexResponse,\n} from \"@secondlayer/shared/schemas\";\nimport type { DeployViewRequest, DeployViewResponse } from \"@secondlayer/shared/schemas/views\";\nimport { BaseClient } from \"../base.ts\";\n\nfunction buildViewQueryString(params: ViewQueryParams): string {\n const qs = new URLSearchParams();\n if (params.sort) qs.set(\"_sort\", params.sort);\n if (params.order) qs.set(\"_order\", params.order);\n if (params.limit !== undefined) qs.set(\"_limit\", String(params.limit));\n if (params.offset !== undefined) qs.set(\"_offset\", String(params.offset));\n if (params.fields) qs.set(\"_fields\", params.fields);\n if (params.filters) {\n for (const [key, value] of Object.entries(params.filters)) {\n qs.set(key, value);\n }\n }\n const str = qs.toString();\n return str ? `?${str}` : \"\";\n}\n\nexport class Views extends BaseClient {\n async list(): Promise<{ data: ViewSummary[] }> {\n return this.request<{ data: ViewSummary[] }>(\"GET\", \"/api/views\");\n }\n\n async get(name: string): Promise<ViewDetail> {\n return this.request<ViewDetail>(\"GET\", `/api/views/${name}`);\n }\n\n async reindex(name: string, options?: { fromBlock?: number; toBlock?: number }): Promise<ReindexResponse> {\n return this.request<ReindexResponse>(\"POST\", `/api/views/${name}/reindex`, options);\n }\n\n async delete(name: string): Promise<{ message: string }> {\n return this.request<{ message: string }>(\"DELETE\", `/api/views/${name}`);\n }\n\n async deploy(data: DeployViewRequest): Promise<DeployViewResponse> {\n return this.request<DeployViewResponse>(\"POST\", \"/api/views\", data);\n }\n\n async queryTable(name: string, table: string, params: ViewQueryParams = {}): Promise<unknown[]> {\n return this.request<unknown[]>(\"GET\", `/api/views/${name}/${table}${buildViewQueryString(params)}`);\n }\n\n async queryTableCount(name: string, table: string, params: ViewQueryParams = {}): Promise<{ count: number }> {\n return this.request<{ count: number }>(\"GET\", `/api/views/${name}/${table}/count${buildViewQueryString(params)}`);\n }\n}\n",
9
+ "import type { QueueStats } from \"@secondlayer/shared/types\";\nimport { BaseClient } from \"./base.ts\";\nimport type { SecondLayerOptions } from \"./base.ts\";\nimport { Streams } from \"./streams/client.ts\";\nimport { Views } from \"./views/client.ts\";\n\nexport class SecondLayer extends BaseClient {\n readonly streams: Streams;\n readonly views: Views;\n\n constructor(options: Partial<SecondLayerOptions> = {}) {\n super(options);\n this.streams = new Streams(options);\n this.views = new Views(options);\n }\n\n async getQueueStats(): Promise<QueueStats> {\n const status = await this.request<{ queue: QueueStats }>(\"GET\", \"/status\");\n return status.queue;\n }\n}\n"
7
10
  ],
8
- "mappings": "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",
9
- "debugId": "25305F1E09AEB0F664756E2164756E21",
11
+ "mappings": ";AAeO,MAAM,iBAAiB,MAAM;AAAA,EAGzB;AAAA,EAFT,WAAW,CAEF,QACP,SACA;AAAA,IACA,MAAM,OAAO;AAAA,IAHN;AAAA,IAIP,KAAK,OAAO;AAAA;AAEhB;;;ACfA,IAAM,mBAAmB;AAAA;AAElB,MAAe,WAAW;AAAA,EACrB;AAAA,EACA;AAAA,EAEV,WAAW,CAAC,UAAuC,CAAC,GAAG;AAAA,IACrD,KAAK,WAAW,QAAQ,WAAW,kBAAkB,QAAQ,QAAQ,EAAE;AAAA,IACvE,KAAK,SAAS,QAAQ;AAAA;AAAA,SAGjB,WAAW,CAAC,QAAyC;AAAA,IAC1D,MAAM,UAAkC,EAAE,gBAAgB,mBAAmB;AAAA,IAC7E,IAAI,QAAQ;AAAA,MACV,QAAQ,mBAAmB,UAAU;AAAA,IACvC;AAAA,IACA,OAAO;AAAA;AAAA,OAGO,QAAU,CAAC,QAAgB,MAAc,MAA4B;AAAA,IACnF,MAAM,MAAM,GAAG,KAAK,UAAU;AAAA,IAC9B,MAAM,UAAU,WAAW,YAAY,KAAK,MAAM;AAAA,IAElD,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,WAAW,MAAM,MAAM,KAAK;AAAA,QAC1B;AAAA,QACA;AAAA,QACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,MACtC,CAAC;AAAA,MACD,MAAM;AAAA,MACN,MAAM,IAAI,SAAS,GAAG,uBAAuB,KAAK,8CAA8C;AAAA;AAAA,IAGlG,IAAI,CAAC,SAAS,IAAI;AAAA,MAChB,IAAI,SAAS,WAAW,KAAK;AAAA,QAC3B,MAAM,IAAI,SAAS,KAAK,6BAA6B;AAAA,MACvD;AAAA,MAEA,IAAI,SAAS,WAAW,KAAK;AAAA,QAC3B,MAAM,aAAa,SAAS,QAAQ,IAAI,aAAa;AAAA,QACrD,MAAM,MAAM,aACR,sBAAsB,wBACtB;AAAA,QACJ,MAAM,IAAI,SAAS,KAAK,GAAG;AAAA,MAC7B;AAAA,MAEA,IAAI,SAAS,UAAU,KAAK;AAAA,QAC1B,MAAM,IAAI,SAAS,SAAS,QAAQ,8CAA8C,KAAK,gBAAgB;AAAA,MACzG;AAAA,MAEA,MAAM,YAAY,MAAM,SAAS,KAAK;AAAA,MACtC,IAAI,UAAU,QAAQ,SAAS;AAAA,MAC/B,IAAI;AAAA,QACF,MAAM,OAAO,KAAK,MAAM,SAAS;AAAA,QACjC,UAAU,KAAK,SAAS,KAAK,WAAW;AAAA,QACxC,MAAM;AAAA,QACN,IAAI;AAAA,UAAW,UAAU;AAAA;AAAA,MAE3B,MAAM,IAAI,SAAS,SAAS,QAAQ,OAAO;AAAA,IAC7C;AAAA,IAEA,IAAI,SAAS,WAAW,KAAK;AAAA,MAC3B;AAAA,IACF;AAAA,IAEA,OAAO,SAAS,KAAK;AAAA;AAEzB;;;ACjEO,MAAM,gBAAgB,WAAW;AAAA,OACxB,oBAAsB,CAClC,QACA,cACA,IACA,MACY;AAAA,IACZ,MAAM,SAAS,MAAM,KAAK,gBAAgB,EAAE;AAAA,IAC5C,OAAO,KAAK,QAAW,QAAQ,aAAa,MAAM,GAAG,IAAI;AAAA;AAAA,OAGrD,gBAAe,CAAC,WAAoC;AAAA,IACxD,IAAI,UAAU,WAAW,MAAM,UAAU,SAAS,GAAG,GAAG;AAAA,MACtD,OAAO;AAAA,IACT;AAAA,IAEA,QAAQ,YAAY,MAAM,KAAK,KAAK;AAAA,IACpC,MAAM,eAAe;AAAA,IACrB,MAAM,UAAU,aAAa,OAAO,CAAC,MAAM,EAAE,GAAG,WAAW,SAAS,CAAC;AAAA,IAErE,IAAI,QAAQ,WAAW,GAAG;AAAA,MACxB,MAAM,IAAI,SAAS,KAAK,6BAA6B,YAAY;AAAA,IACnE;AAAA,IACA,IAAI,QAAQ,SAAS,GAAG;AAAA,MACtB,MAAM,IAAI,SAAS,KAAK,2BAA2B,eAAe,QAAQ,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,IAAI,GAAG;AAAA,IACrH;AAAA,IAEA,OAAO,QAAQ,GAAI;AAAA;AAAA,OAGf,OAAM,CAAC,MAAmD;AAAA,IAC9D,OAAO,KAAK,QAA8B,QAAQ,gBAAgB,IAAI;AAAA;AAAA,OAGlE,OAAM,CAAC,IAAY,MAA6C;AAAA,IACpE,OAAO,KAAK,oBAAoB,SAAS,CAAC,QAAO,gBAAgB,OAAM,IAAI,IAAI;AAAA;AAAA,OAG3E,aAAY,CAAC,MAAc,MAA6C;AAAA,IAC5E,QAAQ,YAAY,MAAM,KAAK,KAAK;AAAA,IACpC,MAAM,eAAe;AAAA,IACrB,MAAM,WAAW,aAAa,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,IACzD,IAAI,CAAC,UAAU;AAAA,MACb,MAAM,IAAI,SAAS,KAAK,qBAAqB,iBAAiB;AAAA,IAChE;AAAA,IACA,OAAO,KAAK,OAAO,SAAS,IAAI,IAAI;AAAA;AAAA,OAGhC,KAAI,CAAC,QAA4D;AAAA,IACrE,MAAM,eAAe,IAAI;AAAA,IACzB,IAAI,QAAQ;AAAA,MAAQ,aAAa,IAAI,UAAU,OAAO,MAAM;AAAA,IAC5D,MAAM,QAAQ,aAAa,SAAS;AAAA,IACpC,MAAM,OAAO,QAAQ,gBAAgB,UAAU;AAAA,IAC/C,OAAO,KAAK,QAA6B,OAAO,IAAI;AAAA;AAAA,OAGhD,IAAG,CAAC,IAAqC;AAAA,IAC7C,OAAO,KAAK,oBAAoB,OAAO,CAAC,QAAO,gBAAgB,OAAM,EAAE;AAAA;AAAA,OAGnE,OAAM,CAAC,IAA2B;AAAA,IACtC,OAAO,KAAK,oBAAoB,UAAU,CAAC,QAAO,gBAAgB,OAAM,EAAE;AAAA;AAAA,OAGtE,OAAM,CAAC,IAAqC;AAAA,IAChD,OAAO,KAAK,oBAAoB,QAAQ,CAAC,QAAO,gBAAgB,cAAa,EAAE;AAAA;AAAA,OAG3E,QAAO,CAAC,IAAqC;AAAA,IACjD,OAAO,KAAK,oBAAoB,QAAQ,CAAC,QAAO,gBAAgB,eAAc,EAAE;AAAA;AAAA,OAG5E,aAAY,CAAC,IAAyC;AAAA,IAC1D,OAAO,KAAK,oBAAoB,QAAQ,CAAC,QAAO,gBAAgB,qBAAoB,EAAE;AAAA;AAAA,OAGlF,SAAQ,GAA+B;AAAA,IAC3C,OAAO,KAAK,QAA2B,QAAQ,oBAAoB;AAAA;AAAA,OAG/D,UAAS,GAAgC;AAAA,IAC7C,OAAO,KAAK,QAA4B,QAAQ,qBAAqB;AAAA;AAEzE;;ACtFA,SAAS,oBAAoB,CAAC,QAAiC;AAAA,EAC7D,MAAM,KAAK,IAAI;AAAA,EACf,IAAI,OAAO;AAAA,IAAM,GAAG,IAAI,SAAS,OAAO,IAAI;AAAA,EAC5C,IAAI,OAAO;AAAA,IAAO,GAAG,IAAI,UAAU,OAAO,KAAK;AAAA,EAC/C,IAAI,OAAO,UAAU;AAAA,IAAW,GAAG,IAAI,UAAU,OAAO,OAAO,KAAK,CAAC;AAAA,EACrE,IAAI,OAAO,WAAW;AAAA,IAAW,GAAG,IAAI,WAAW,OAAO,OAAO,MAAM,CAAC;AAAA,EACxE,IAAI,OAAO;AAAA,IAAQ,GAAG,IAAI,WAAW,OAAO,MAAM;AAAA,EAClD,IAAI,OAAO,SAAS;AAAA,IAClB,YAAY,KAAK,UAAU,OAAO,QAAQ,OAAO,OAAO,GAAG;AAAA,MACzD,GAAG,IAAI,KAAK,KAAK;AAAA,IACnB;AAAA,EACF;AAAA,EACA,MAAM,MAAM,GAAG,SAAS;AAAA,EACxB,OAAO,MAAM,IAAI,QAAQ;AAAA;AAAA;AAGpB,MAAM,cAAc,WAAW;AAAA,OAC9B,KAAI,GAAqC;AAAA,IAC7C,OAAO,KAAK,QAAiC,OAAO,YAAY;AAAA;AAAA,OAG5D,IAAG,CAAC,MAAmC;AAAA,IAC3C,OAAO,KAAK,QAAoB,OAAO,cAAc,MAAM;AAAA;AAAA,OAGvD,QAAO,CAAC,MAAc,SAA8E;AAAA,IACxG,OAAO,KAAK,QAAyB,QAAQ,cAAc,gBAAgB,OAAO;AAAA;AAAA,OAG9E,OAAM,CAAC,MAA4C;AAAA,IACvD,OAAO,KAAK,QAA6B,UAAU,cAAc,MAAM;AAAA;AAAA,OAGnE,OAAM,CAAC,MAAsD;AAAA,IACjE,OAAO,KAAK,QAA4B,QAAQ,cAAc,IAAI;AAAA;AAAA,OAG9D,WAAU,CAAC,MAAc,OAAe,SAA0B,CAAC,GAAuB;AAAA,IAC9F,OAAO,KAAK,QAAmB,OAAO,cAAc,QAAQ,QAAQ,qBAAqB,MAAM,GAAG;AAAA;AAAA,OAG9F,gBAAe,CAAC,MAAc,OAAe,SAA0B,CAAC,GAA+B;AAAA,IAC3G,OAAO,KAAK,QAA2B,OAAO,cAAc,QAAQ,cAAc,qBAAqB,MAAM,GAAG;AAAA;AAEpH;;AC/CO,MAAM,oBAAoB,WAAW;AAAA,EACjC;AAAA,EACA;AAAA,EAET,WAAW,CAAC,UAAuC,CAAC,GAAG;AAAA,IACrD,MAAM,OAAO;AAAA,IACb,KAAK,UAAU,IAAI,QAAQ,OAAO;AAAA,IAClC,KAAK,QAAQ,IAAI,MAAM,OAAO;AAAA;AAAA,OAG1B,cAAa,GAAwB;AAAA,IACzC,MAAM,SAAS,MAAM,KAAK,QAA+B,OAAO,SAAS;AAAA,IACzE,OAAO,OAAO;AAAA;AAElB;",
12
+ "debugId": "3185A873B53583DC64756E2164756E21",
10
13
  "names": []
11
14
  }
@@ -0,0 +1,34 @@
1
+ import { CreateStream, UpdateStream, StreamResponse, CreateStreamResponse, ListStreamsResponse, BulkPauseResponse, BulkResumeResponse } from "@secondlayer/shared/schemas";
2
+ interface SecondLayerOptions {
3
+ /** Base URL of the Secondlayer API (trailing slashes are stripped). */
4
+ baseUrl: string;
5
+ /** Bearer token for authenticated requests. */
6
+ apiKey?: string;
7
+ }
8
+ declare abstract class BaseClient {
9
+ protected baseUrl: string;
10
+ protected apiKey?: string;
11
+ constructor(options?: Partial<SecondLayerOptions>);
12
+ static authHeaders(apiKey?: string): Record<string, string>;
13
+ protected request<T>(method: string, path: string, body?: unknown): Promise<T>;
14
+ }
15
+ declare class Streams extends BaseClient {
16
+ private requestWithStreamId;
17
+ resolveStreamId(partialId: string): Promise<string>;
18
+ create(data: CreateStream): Promise<CreateStreamResponse>;
19
+ update(id: string, data: UpdateStream): Promise<StreamResponse>;
20
+ updateByName(name: string, data: CreateStream): Promise<StreamResponse>;
21
+ list(params?: {
22
+ status?: string
23
+ }): Promise<ListStreamsResponse>;
24
+ get(id: string): Promise<StreamResponse>;
25
+ delete(id: string): Promise<void>;
26
+ enable(id: string): Promise<StreamResponse>;
27
+ disable(id: string): Promise<StreamResponse>;
28
+ rotateSecret(id: string): Promise<{
29
+ secret: string
30
+ }>;
31
+ pauseAll(): Promise<BulkPauseResponse>;
32
+ resumeAll(): Promise<BulkResumeResponse>;
33
+ }
34
+ export { Streams, SecondLayerOptions };
@@ -0,0 +1,142 @@
1
+ // src/errors.ts
2
+ class ApiError extends Error {
3
+ status;
4
+ constructor(status, message) {
5
+ super(message);
6
+ this.status = status;
7
+ this.name = "ApiError";
8
+ }
9
+ }
10
+
11
+ // src/base.ts
12
+ var DEFAULT_BASE_URL = "https://api.secondlayer.tools";
13
+
14
+ class BaseClient {
15
+ baseUrl;
16
+ apiKey;
17
+ constructor(options = {}) {
18
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
19
+ this.apiKey = options.apiKey;
20
+ }
21
+ static authHeaders(apiKey) {
22
+ const headers = { "Content-Type": "application/json" };
23
+ if (apiKey) {
24
+ headers["Authorization"] = `Bearer ${apiKey}`;
25
+ }
26
+ return headers;
27
+ }
28
+ async request(method, path, body) {
29
+ const url = `${this.baseUrl}${path}`;
30
+ const headers = BaseClient.authHeaders(this.apiKey);
31
+ let response;
32
+ try {
33
+ response = await fetch(url, {
34
+ method,
35
+ headers,
36
+ body: body ? JSON.stringify(body) : undefined
37
+ });
38
+ } catch {
39
+ throw new ApiError(0, `Cannot reach API at ${this.baseUrl}. Check your connection or try again.`);
40
+ }
41
+ if (!response.ok) {
42
+ if (response.status === 401) {
43
+ throw new ApiError(401, "API key invalid or expired.");
44
+ }
45
+ if (response.status === 429) {
46
+ const retryAfter = response.headers.get("Retry-After");
47
+ const msg = retryAfter ? `Rate limited. Wait ${retryAfter} seconds.` : "Rate limited. Try again later.";
48
+ throw new ApiError(429, msg);
49
+ }
50
+ if (response.status >= 500) {
51
+ throw new ApiError(response.status, `Server error. Try again or check status at ${this.baseUrl}/health`);
52
+ }
53
+ const errorBody = await response.text();
54
+ let message = `HTTP ${response.status}`;
55
+ try {
56
+ const json = JSON.parse(errorBody);
57
+ message = json.error || json.message || message;
58
+ } catch {
59
+ if (errorBody)
60
+ message = errorBody;
61
+ }
62
+ throw new ApiError(response.status, message);
63
+ }
64
+ if (response.status === 204) {
65
+ return;
66
+ }
67
+ return response.json();
68
+ }
69
+ }
70
+
71
+ // src/streams/client.ts
72
+ class Streams extends BaseClient {
73
+ async requestWithStreamId(method, pathTemplate, id, body) {
74
+ const fullId = await this.resolveStreamId(id);
75
+ return this.request(method, pathTemplate(fullId), body);
76
+ }
77
+ async resolveStreamId(partialId) {
78
+ if (partialId.length === 36 && partialId.includes("-")) {
79
+ return partialId;
80
+ }
81
+ const { streams } = await this.list();
82
+ const typedStreams = streams;
83
+ const matches = typedStreams.filter((s) => s.id.startsWith(partialId));
84
+ if (matches.length === 0) {
85
+ throw new ApiError(404, `No stream found matching "${partialId}"`);
86
+ }
87
+ if (matches.length > 1) {
88
+ throw new ApiError(400, `Multiple streams match "${partialId}": ${matches.map((s) => s.id.slice(0, 8)).join(", ")}`);
89
+ }
90
+ return matches[0].id;
91
+ }
92
+ async create(data) {
93
+ return this.request("POST", "/api/streams", data);
94
+ }
95
+ async update(id, data) {
96
+ return this.requestWithStreamId("PATCH", (id2) => `/api/streams/${id2}`, id, data);
97
+ }
98
+ async updateByName(name, data) {
99
+ const { streams } = await this.list();
100
+ const typedStreams = streams;
101
+ const existing = typedStreams.find((s) => s.name === name);
102
+ if (!existing) {
103
+ throw new ApiError(404, `Stream with name "${name}" not found`);
104
+ }
105
+ return this.update(existing.id, data);
106
+ }
107
+ async list(params) {
108
+ const searchParams = new URLSearchParams;
109
+ if (params?.status)
110
+ searchParams.set("status", params.status);
111
+ const query = searchParams.toString();
112
+ const path = query ? `/api/streams?${query}` : "/api/streams";
113
+ return this.request("GET", path);
114
+ }
115
+ async get(id) {
116
+ return this.requestWithStreamId("GET", (id2) => `/api/streams/${id2}`, id);
117
+ }
118
+ async delete(id) {
119
+ return this.requestWithStreamId("DELETE", (id2) => `/api/streams/${id2}`, id);
120
+ }
121
+ async enable(id) {
122
+ return this.requestWithStreamId("POST", (id2) => `/api/streams/${id2}/enable`, id);
123
+ }
124
+ async disable(id) {
125
+ return this.requestWithStreamId("POST", (id2) => `/api/streams/${id2}/disable`, id);
126
+ }
127
+ async rotateSecret(id) {
128
+ return this.requestWithStreamId("POST", (id2) => `/api/streams/${id2}/rotate-secret`, id);
129
+ }
130
+ async pauseAll() {
131
+ return this.request("POST", "/api/streams/pause");
132
+ }
133
+ async resumeAll() {
134
+ return this.request("POST", "/api/streams/resume");
135
+ }
136
+ }
137
+ export {
138
+ Streams
139
+ };
140
+
141
+ //# debugId=EFD3CCF7032CC87A64756E2164756E21
142
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/errors.ts", "../src/base.ts", "../src/streams/client.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Error thrown by {@link SecondLayer} when an API request fails.\n * Includes the HTTP status code for programmatic error handling.\n *\n * @example\n * ```ts\n * try {\n * await client.streams.get(\"abc123\");\n * } catch (err) {\n * if (err instanceof ApiError && err.status === 404) {\n * console.log(\"Stream not found\");\n * }\n * }\n * ```\n */\nexport class ApiError extends Error {\n constructor(\n /** HTTP status code (0 for network errors). */\n public status: number,\n message: string\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n",
6
+ "import { ApiError } from \"./errors.ts\";\n\nexport interface SecondLayerOptions {\n /** Base URL of the Secondlayer API (trailing slashes are stripped). */\n baseUrl: string;\n /** Bearer token for authenticated requests. */\n apiKey?: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.secondlayer.tools\";\n\nexport abstract class BaseClient {\n protected baseUrl: string;\n protected apiKey?: string;\n\n constructor(options: Partial<SecondLayerOptions> = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n\n static authHeaders(apiKey?: string): Record<string, string> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (apiKey) {\n headers[\"Authorization\"] = `Bearer ${apiKey}`;\n }\n return headers;\n }\n\n protected async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers = BaseClient.authHeaders(this.apiKey);\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch {\n throw new ApiError(0, `Cannot reach API at ${this.baseUrl}. Check your connection or try again.`);\n }\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new ApiError(401, \"API key invalid or expired.\");\n }\n\n if (response.status === 429) {\n const retryAfter = response.headers.get(\"Retry-After\");\n const msg = retryAfter\n ? `Rate limited. Wait ${retryAfter} seconds.`\n : \"Rate limited. Try again later.\";\n throw new ApiError(429, msg);\n }\n\n if (response.status >= 500) {\n throw new ApiError(response.status, `Server error. Try again or check status at ${this.baseUrl}/health`);\n }\n\n const errorBody = await response.text();\n let message = `HTTP ${response.status}`;\n try {\n const json = JSON.parse(errorBody);\n message = json.error || json.message || message;\n } catch {\n if (errorBody) message = errorBody;\n }\n throw new ApiError(response.status, message);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return response.json() as Promise<T>;\n }\n}\n",
7
+ "import type {\n CreateStream,\n UpdateStream,\n StreamResponse,\n CreateStreamResponse,\n ListStreamsResponse,\n BulkPauseResponse,\n BulkResumeResponse,\n} from \"@secondlayer/shared/schemas\";\nimport { ApiError } from \"../errors.ts\";\nimport { BaseClient } from \"../base.ts\";\n\nexport class Streams extends BaseClient {\n private async requestWithStreamId<T>(\n method: string,\n pathTemplate: (id: string) => string,\n id: string,\n body?: unknown\n ): Promise<T> {\n const fullId = await this.resolveStreamId(id);\n return this.request<T>(method, pathTemplate(fullId), body);\n }\n\n async resolveStreamId(partialId: string): Promise<string> {\n if (partialId.length === 36 && partialId.includes(\"-\")) {\n return partialId;\n }\n\n const { streams } = await this.list();\n const typedStreams = streams as { id: string }[];\n const matches = typedStreams.filter((s) => s.id.startsWith(partialId));\n\n if (matches.length === 0) {\n throw new ApiError(404, `No stream found matching \"${partialId}\"`);\n }\n if (matches.length > 1) {\n throw new ApiError(400, `Multiple streams match \"${partialId}\": ${matches.map((s) => s.id.slice(0, 8)).join(\", \")}`);\n }\n\n return matches[0]!.id;\n }\n\n async create(data: CreateStream): Promise<CreateStreamResponse> {\n return this.request<CreateStreamResponse>(\"POST\", \"/api/streams\", data);\n }\n\n async update(id: string, data: UpdateStream): Promise<StreamResponse> {\n return this.requestWithStreamId(\"PATCH\", (id) => `/api/streams/${id}`, id, data);\n }\n\n async updateByName(name: string, data: CreateStream): Promise<StreamResponse> {\n const { streams } = await this.list();\n const typedStreams = streams as { id: string; name: string }[];\n const existing = typedStreams.find((s) => s.name === name);\n if (!existing) {\n throw new ApiError(404, `Stream with name \"${name}\" not found`);\n }\n return this.update(existing.id, data);\n }\n\n async list(params?: { status?: string }): Promise<ListStreamsResponse> {\n const searchParams = new URLSearchParams();\n if (params?.status) searchParams.set(\"status\", params.status);\n const query = searchParams.toString();\n const path = query ? `/api/streams?${query}` : \"/api/streams\";\n return this.request<ListStreamsResponse>(\"GET\", path);\n }\n\n async get(id: string): Promise<StreamResponse> {\n return this.requestWithStreamId(\"GET\", (id) => `/api/streams/${id}`, id);\n }\n\n async delete(id: string): Promise<void> {\n return this.requestWithStreamId(\"DELETE\", (id) => `/api/streams/${id}`, id);\n }\n\n async enable(id: string): Promise<StreamResponse> {\n return this.requestWithStreamId(\"POST\", (id) => `/api/streams/${id}/enable`, id);\n }\n\n async disable(id: string): Promise<StreamResponse> {\n return this.requestWithStreamId(\"POST\", (id) => `/api/streams/${id}/disable`, id);\n }\n\n async rotateSecret(id: string): Promise<{ secret: string }> {\n return this.requestWithStreamId(\"POST\", (id) => `/api/streams/${id}/rotate-secret`, id);\n }\n\n async pauseAll(): Promise<BulkPauseResponse> {\n return this.request<BulkPauseResponse>(\"POST\", \"/api/streams/pause\");\n }\n\n async resumeAll(): Promise<BulkResumeResponse> {\n return this.request<BulkResumeResponse>(\"POST\", \"/api/streams/resume\");\n }\n}\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "EFD3CCF7032CC87A64756E2164756E21",
11
+ "names": []
12
+ }
@@ -0,0 +1,34 @@
1
+ import { ViewSummary, ViewDetail, ViewQueryParams, ReindexResponse } from "@secondlayer/shared/schemas";
2
+ import { DeployViewRequest, DeployViewResponse } from "@secondlayer/shared/schemas/views";
3
+ interface SecondLayerOptions {
4
+ /** Base URL of the Secondlayer API (trailing slashes are stripped). */
5
+ baseUrl: string;
6
+ /** Bearer token for authenticated requests. */
7
+ apiKey?: string;
8
+ }
9
+ declare abstract class BaseClient {
10
+ protected baseUrl: string;
11
+ protected apiKey?: string;
12
+ constructor(options?: Partial<SecondLayerOptions>);
13
+ static authHeaders(apiKey?: string): Record<string, string>;
14
+ protected request<T>(method: string, path: string, body?: unknown): Promise<T>;
15
+ }
16
+ declare class Views extends BaseClient {
17
+ list(): Promise<{
18
+ data: ViewSummary[]
19
+ }>;
20
+ get(name: string): Promise<ViewDetail>;
21
+ reindex(name: string, options?: {
22
+ fromBlock?: number
23
+ toBlock?: number
24
+ }): Promise<ReindexResponse>;
25
+ delete(name: string): Promise<{
26
+ message: string
27
+ }>;
28
+ deploy(data: DeployViewRequest): Promise<DeployViewResponse>;
29
+ queryTable(name: string, table: string, params?: ViewQueryParams): Promise<unknown[]>;
30
+ queryTableCount(name: string, table: string, params?: ViewQueryParams): Promise<{
31
+ count: number
32
+ }>;
33
+ }
34
+ export { Views, SecondLayerOptions };
@@ -8,12 +8,14 @@ class ApiError extends Error {
8
8
  }
9
9
  }
10
10
 
11
- // src/client.ts
12
- class StreamsClient {
11
+ // src/base.ts
12
+ var DEFAULT_BASE_URL = "https://api.secondlayer.tools";
13
+
14
+ class BaseClient {
13
15
  baseUrl;
14
16
  apiKey;
15
- constructor(options) {
16
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
17
+ constructor(options = {}) {
18
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
17
19
  this.apiKey = options.apiKey;
18
20
  }
19
21
  static authHeaders(apiKey) {
@@ -25,7 +27,7 @@ class StreamsClient {
25
27
  }
26
28
  async request(method, path, body) {
27
29
  const url = `${this.baseUrl}${path}`;
28
- const headers = StreamsClient.authHeaders(this.apiKey);
30
+ const headers = BaseClient.authHeaders(this.apiKey);
29
31
  let response;
30
32
  try {
31
33
  response = await fetch(url, {
@@ -64,95 +66,9 @@ class StreamsClient {
64
66
  }
65
67
  return response.json();
66
68
  }
67
- async resolveStreamId(partialId) {
68
- if (partialId.length === 36 && partialId.includes("-")) {
69
- return partialId;
70
- }
71
- const { streams } = await this.listStreams();
72
- const matches = streams.filter((s) => s.id.startsWith(partialId));
73
- if (matches.length === 0) {
74
- throw new ApiError(404, `No stream found matching "${partialId}"`);
75
- }
76
- if (matches.length > 1) {
77
- throw new ApiError(400, `Multiple streams match "${partialId}": ${matches.map((s) => s.id.slice(0, 8)).join(", ")}`);
78
- }
79
- return matches[0].id;
80
- }
81
- async createStream(data) {
82
- return this.request("POST", "/api/streams", data);
83
- }
84
- async updateStream(id, data) {
85
- const fullId = await this.resolveStreamId(id);
86
- return this.request("PATCH", `/api/streams/${fullId}`, data);
87
- }
88
- async updateStreamByName(name, data) {
89
- const { streams } = await this.listStreams();
90
- const existing = streams.find((s) => s.name === name);
91
- if (!existing) {
92
- throw new ApiError(404, `Stream with name "${name}" not found`);
93
- }
94
- return this.updateStream(existing.id, data);
95
- }
96
- async listStreams(params) {
97
- const searchParams = new URLSearchParams;
98
- if (params?.status)
99
- searchParams.set("status", params.status);
100
- const query = searchParams.toString();
101
- const path = query ? `/api/streams?${query}` : "/api/streams";
102
- return this.request("GET", path);
103
- }
104
- async getStream(id) {
105
- const fullId = await this.resolveStreamId(id);
106
- return this.request("GET", `/api/streams/${fullId}`);
107
- }
108
- async deleteStream(id) {
109
- const fullId = await this.resolveStreamId(id);
110
- return this.request("DELETE", `/api/streams/${fullId}`);
111
- }
112
- async enableStream(id) {
113
- const fullId = await this.resolveStreamId(id);
114
- return this.request("POST", `/api/streams/${fullId}/enable`);
115
- }
116
- async disableStream(id) {
117
- const fullId = await this.resolveStreamId(id);
118
- return this.request("POST", `/api/streams/${fullId}/disable`);
119
- }
120
- async rotateSecret(id) {
121
- const fullId = await this.resolveStreamId(id);
122
- return this.request("POST", `/api/streams/${fullId}/rotate-secret`);
123
- }
124
- async pauseAll() {
125
- return this.request("POST", "/api/streams/pause");
126
- }
127
- async resumeAll() {
128
- return this.request("POST", "/api/streams/resume");
129
- }
130
- async getQueueStats() {
131
- const status = await this.request("GET", "/status");
132
- return status.queue;
133
- }
134
- async listViews() {
135
- return this.request("GET", "/api/views");
136
- }
137
- async getView(name) {
138
- return this.request("GET", `/api/views/${name}`);
139
- }
140
- async reindexView(name, options) {
141
- return this.request("POST", `/api/views/${name}/reindex`, options);
142
- }
143
- async deleteView(name) {
144
- return this.request("DELETE", `/api/views/${name}`);
145
- }
146
- async deployView(data) {
147
- return this.request("POST", "/api/views", data);
148
- }
149
- async queryTable(name, table, params = {}) {
150
- return this.request("GET", `/api/views/${name}/${table}${buildViewQueryString(params)}`);
151
- }
152
- async queryTableCount(name, table, params = {}) {
153
- return this.request("GET", `/api/views/${name}/${table}/count${buildViewQueryString(params)}`);
154
- }
155
69
  }
70
+
71
+ // src/views/client.ts
156
72
  function buildViewQueryString(params) {
157
73
  const qs = new URLSearchParams;
158
74
  if (params.sort)
@@ -173,9 +89,33 @@ function buildViewQueryString(params) {
173
89
  const str = qs.toString();
174
90
  return str ? `?${str}` : "";
175
91
  }
92
+
93
+ class Views extends BaseClient {
94
+ async list() {
95
+ return this.request("GET", "/api/views");
96
+ }
97
+ async get(name) {
98
+ return this.request("GET", `/api/views/${name}`);
99
+ }
100
+ async reindex(name, options) {
101
+ return this.request("POST", `/api/views/${name}/reindex`, options);
102
+ }
103
+ async delete(name) {
104
+ return this.request("DELETE", `/api/views/${name}`);
105
+ }
106
+ async deploy(data) {
107
+ return this.request("POST", "/api/views", data);
108
+ }
109
+ async queryTable(name, table, params = {}) {
110
+ return this.request("GET", `/api/views/${name}/${table}${buildViewQueryString(params)}`);
111
+ }
112
+ async queryTableCount(name, table, params = {}) {
113
+ return this.request("GET", `/api/views/${name}/${table}/count${buildViewQueryString(params)}`);
114
+ }
115
+ }
176
116
  export {
177
- StreamsClient
117
+ Views
178
118
  };
179
119
 
180
- //# debugId=2645915545BCF30D64756E2164756E21
181
- //# sourceMappingURL=client.js.map
120
+ //# debugId=5FCD78685AE9CEC764756E2164756E21
121
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/errors.ts", "../src/base.ts", "../src/views/client.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Error thrown by {@link SecondLayer} when an API request fails.\n * Includes the HTTP status code for programmatic error handling.\n *\n * @example\n * ```ts\n * try {\n * await client.streams.get(\"abc123\");\n * } catch (err) {\n * if (err instanceof ApiError && err.status === 404) {\n * console.log(\"Stream not found\");\n * }\n * }\n * ```\n */\nexport class ApiError extends Error {\n constructor(\n /** HTTP status code (0 for network errors). */\n public status: number,\n message: string\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n",
6
+ "import { ApiError } from \"./errors.ts\";\n\nexport interface SecondLayerOptions {\n /** Base URL of the Secondlayer API (trailing slashes are stripped). */\n baseUrl: string;\n /** Bearer token for authenticated requests. */\n apiKey?: string;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.secondlayer.tools\";\n\nexport abstract class BaseClient {\n protected baseUrl: string;\n protected apiKey?: string;\n\n constructor(options: Partial<SecondLayerOptions> = {}) {\n this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n\n static authHeaders(apiKey?: string): Record<string, string> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (apiKey) {\n headers[\"Authorization\"] = `Bearer ${apiKey}`;\n }\n return headers;\n }\n\n protected async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers = BaseClient.authHeaders(this.apiKey);\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch {\n throw new ApiError(0, `Cannot reach API at ${this.baseUrl}. Check your connection or try again.`);\n }\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new ApiError(401, \"API key invalid or expired.\");\n }\n\n if (response.status === 429) {\n const retryAfter = response.headers.get(\"Retry-After\");\n const msg = retryAfter\n ? `Rate limited. Wait ${retryAfter} seconds.`\n : \"Rate limited. Try again later.\";\n throw new ApiError(429, msg);\n }\n\n if (response.status >= 500) {\n throw new ApiError(response.status, `Server error. Try again or check status at ${this.baseUrl}/health`);\n }\n\n const errorBody = await response.text();\n let message = `HTTP ${response.status}`;\n try {\n const json = JSON.parse(errorBody);\n message = json.error || json.message || message;\n } catch {\n if (errorBody) message = errorBody;\n }\n throw new ApiError(response.status, message);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return response.json() as Promise<T>;\n }\n}\n",
7
+ "import type {\n ViewSummary,\n ViewDetail,\n ViewQueryParams,\n ReindexResponse,\n} from \"@secondlayer/shared/schemas\";\nimport type { DeployViewRequest, DeployViewResponse } from \"@secondlayer/shared/schemas/views\";\nimport { BaseClient } from \"../base.ts\";\n\nfunction buildViewQueryString(params: ViewQueryParams): string {\n const qs = new URLSearchParams();\n if (params.sort) qs.set(\"_sort\", params.sort);\n if (params.order) qs.set(\"_order\", params.order);\n if (params.limit !== undefined) qs.set(\"_limit\", String(params.limit));\n if (params.offset !== undefined) qs.set(\"_offset\", String(params.offset));\n if (params.fields) qs.set(\"_fields\", params.fields);\n if (params.filters) {\n for (const [key, value] of Object.entries(params.filters)) {\n qs.set(key, value);\n }\n }\n const str = qs.toString();\n return str ? `?${str}` : \"\";\n}\n\nexport class Views extends BaseClient {\n async list(): Promise<{ data: ViewSummary[] }> {\n return this.request<{ data: ViewSummary[] }>(\"GET\", \"/api/views\");\n }\n\n async get(name: string): Promise<ViewDetail> {\n return this.request<ViewDetail>(\"GET\", `/api/views/${name}`);\n }\n\n async reindex(name: string, options?: { fromBlock?: number; toBlock?: number }): Promise<ReindexResponse> {\n return this.request<ReindexResponse>(\"POST\", `/api/views/${name}/reindex`, options);\n }\n\n async delete(name: string): Promise<{ message: string }> {\n return this.request<{ message: string }>(\"DELETE\", `/api/views/${name}`);\n }\n\n async deploy(data: DeployViewRequest): Promise<DeployViewResponse> {\n return this.request<DeployViewResponse>(\"POST\", \"/api/views\", data);\n }\n\n async queryTable(name: string, table: string, params: ViewQueryParams = {}): Promise<unknown[]> {\n return this.request<unknown[]>(\"GET\", `/api/views/${name}/${table}${buildViewQueryString(params)}`);\n }\n\n async queryTableCount(name: string, table: string, params: ViewQueryParams = {}): Promise<{ count: number }> {\n return this.request<{ count: number }>(\"GET\", `/api/views/${name}/${table}/count${buildViewQueryString(params)}`);\n }\n}\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "5FCD78685AE9CEC764756E2164756E21",
11
+ "names": []
12
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -9,13 +9,13 @@
9
9
  "types": "./dist/index.d.ts",
10
10
  "import": "./dist/index.js"
11
11
  },
12
- "./client": {
13
- "types": "./dist/client.d.ts",
14
- "import": "./dist/client.js"
12
+ "./streams": {
13
+ "types": "./dist/streams/index.d.ts",
14
+ "import": "./dist/streams/index.js"
15
15
  },
16
- "./errors": {
17
- "types": "./dist/errors.d.ts",
18
- "import": "./dist/errors.js"
16
+ "./views": {
17
+ "types": "./dist/views/index.d.ts",
18
+ "import": "./dist/views/index.js"
19
19
  }
20
20
  },
21
21
  "files": [
package/dist/client.d.ts DELETED
@@ -1,48 +0,0 @@
1
- import { CreateStream, UpdateStream, StreamResponse, CreateStreamResponse, ListStreamsResponse, BulkPauseResponse, BulkResumeResponse, ViewSummary, ViewDetail, ViewQueryParams, ReindexResponse } from "@secondlayer/shared/schemas";
2
- import { DeployViewRequest, DeployViewResponse } from "@secondlayer/shared/schemas/views";
3
- import { QueueStats } from "@secondlayer/shared/types";
4
- interface StreamsClientOptions {
5
- baseUrl: string;
6
- apiKey?: string;
7
- }
8
- declare class StreamsClient {
9
- private baseUrl;
10
- private apiKey?;
11
- constructor(options: StreamsClientOptions);
12
- static authHeaders(apiKey?: string): Record<string, string>;
13
- private request;
14
- resolveStreamId(partialId: string): Promise<string>;
15
- createStream(data: CreateStream): Promise<CreateStreamResponse>;
16
- updateStream(id: string, data: UpdateStream): Promise<StreamResponse>;
17
- updateStreamByName(name: string, data: CreateStream): Promise<StreamResponse>;
18
- listStreams(params?: {
19
- status?: string
20
- }): Promise<ListStreamsResponse>;
21
- getStream(id: string): Promise<StreamResponse>;
22
- deleteStream(id: string): Promise<void>;
23
- enableStream(id: string): Promise<StreamResponse>;
24
- disableStream(id: string): Promise<StreamResponse>;
25
- rotateSecret(id: string): Promise<{
26
- secret: string
27
- }>;
28
- pauseAll(): Promise<BulkPauseResponse>;
29
- resumeAll(): Promise<BulkResumeResponse>;
30
- getQueueStats(): Promise<QueueStats>;
31
- listViews(): Promise<{
32
- data: ViewSummary[]
33
- }>;
34
- getView(name: string): Promise<ViewDetail>;
35
- reindexView(name: string, options?: {
36
- fromBlock?: number
37
- toBlock?: number
38
- }): Promise<ReindexResponse>;
39
- deleteView(name: string): Promise<{
40
- message: string
41
- }>;
42
- deployView(data: DeployViewRequest): Promise<DeployViewResponse>;
43
- queryTable(name: string, table: string, params?: ViewQueryParams): Promise<unknown[]>;
44
- queryTableCount(name: string, table: string, params?: ViewQueryParams): Promise<{
45
- count: number
46
- }>;
47
- }
48
- export { StreamsClientOptions, StreamsClient };
@@ -1,11 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/errors.ts", "../src/client.ts"],
4
- "sourcesContent": [
5
- "export class ApiError extends Error {\n constructor(\n public status: number,\n message: string\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n",
6
- "import type {\n CreateStream,\n UpdateStream,\n StreamResponse,\n CreateStreamResponse,\n ListStreamsResponse,\n BulkPauseResponse,\n BulkResumeResponse,\n ViewSummary,\n ViewDetail,\n ViewQueryParams,\n ReindexResponse,\n} from \"@secondlayer/shared/schemas\";\nimport type { DeployViewRequest, DeployViewResponse } from \"@secondlayer/shared/schemas/views\";\nimport type { QueueStats } from \"@secondlayer/shared/types\";\nimport { ApiError } from \"./errors.ts\";\n\nexport interface StreamsClientOptions {\n baseUrl: string;\n apiKey?: string;\n}\n\nexport class StreamsClient {\n private baseUrl: string;\n private apiKey?: string;\n\n constructor(options: StreamsClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n }\n\n // ── Helpers ───────────────────────────────────────────────────────────\n\n static authHeaders(apiKey?: string): Record<string, string> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (apiKey) {\n headers[\"Authorization\"] = `Bearer ${apiKey}`;\n }\n return headers;\n }\n\n private async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers = StreamsClient.authHeaders(this.apiKey);\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch {\n throw new ApiError(0, `Cannot reach API at ${this.baseUrl}. Check your connection or try again.`);\n }\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new ApiError(401, \"API key invalid or expired.\");\n }\n\n if (response.status === 429) {\n const retryAfter = response.headers.get(\"Retry-After\");\n const msg = retryAfter\n ? `Rate limited. Wait ${retryAfter} seconds.`\n : \"Rate limited. Try again later.\";\n throw new ApiError(429, msg);\n }\n\n if (response.status >= 500) {\n throw new ApiError(response.status, `Server error. Try again or check status at ${this.baseUrl}/health`);\n }\n\n const errorBody = await response.text();\n let message = `HTTP ${response.status}`;\n try {\n const json = JSON.parse(errorBody);\n message = json.error || json.message || message;\n } catch {\n if (errorBody) message = errorBody;\n }\n throw new ApiError(response.status, message);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return response.json() as Promise<T>;\n }\n\n // ── Stream ID Resolution ──────────────────────────────────────────────\n\n async resolveStreamId(partialId: string): Promise<string> {\n if (partialId.length === 36 && partialId.includes(\"-\")) {\n return partialId;\n }\n\n const { streams } = await this.listStreams();\n const matches = streams.filter((s) => s.id.startsWith(partialId));\n\n if (matches.length === 0) {\n throw new ApiError(404, `No stream found matching \"${partialId}\"`);\n }\n if (matches.length > 1) {\n throw new ApiError(400, `Multiple streams match \"${partialId}\": ${matches.map((s) => s.id.slice(0, 8)).join(\", \")}`);\n }\n\n return matches[0]!.id;\n }\n\n // ── Streams ───────────────────────────────────────────────────────────\n\n async createStream(data: CreateStream): Promise<CreateStreamResponse> {\n return this.request<CreateStreamResponse>(\"POST\", \"/api/streams\", data);\n }\n\n async updateStream(id: string, data: UpdateStream): Promise<StreamResponse> {\n const fullId = await this.resolveStreamId(id);\n return this.request<StreamResponse>(\"PATCH\", `/api/streams/${fullId}`, data);\n }\n\n async updateStreamByName(name: string, data: CreateStream): Promise<StreamResponse> {\n const { streams } = await this.listStreams();\n const existing = streams.find((s) => s.name === name);\n if (!existing) {\n throw new ApiError(404, `Stream with name \"${name}\" not found`);\n }\n return this.updateStream(existing.id, data);\n }\n\n async listStreams(params?: { status?: string }): Promise<ListStreamsResponse> {\n const searchParams = new URLSearchParams();\n if (params?.status) searchParams.set(\"status\", params.status);\n const query = searchParams.toString();\n const path = query ? `/api/streams?${query}` : \"/api/streams\";\n return this.request<ListStreamsResponse>(\"GET\", path);\n }\n\n async getStream(id: string): Promise<StreamResponse> {\n const fullId = await this.resolveStreamId(id);\n return this.request<StreamResponse>(\"GET\", `/api/streams/${fullId}`);\n }\n\n async deleteStream(id: string): Promise<void> {\n const fullId = await this.resolveStreamId(id);\n return this.request<void>(\"DELETE\", `/api/streams/${fullId}`);\n }\n\n async enableStream(id: string): Promise<StreamResponse> {\n const fullId = await this.resolveStreamId(id);\n return this.request<StreamResponse>(\"POST\", `/api/streams/${fullId}/enable`);\n }\n\n async disableStream(id: string): Promise<StreamResponse> {\n const fullId = await this.resolveStreamId(id);\n return this.request<StreamResponse>(\"POST\", `/api/streams/${fullId}/disable`);\n }\n\n async rotateSecret(id: string): Promise<{ secret: string }> {\n const fullId = await this.resolveStreamId(id);\n return this.request<{ secret: string }>(\"POST\", `/api/streams/${fullId}/rotate-secret`);\n }\n\n async pauseAll(): Promise<BulkPauseResponse> {\n return this.request<BulkPauseResponse>(\"POST\", \"/api/streams/pause\");\n }\n\n async resumeAll(): Promise<BulkResumeResponse> {\n return this.request<BulkResumeResponse>(\"POST\", \"/api/streams/resume\");\n }\n\n // ── Queue ─────────────────────────────────────────────────────────────\n\n async getQueueStats(): Promise<QueueStats> {\n const status = await this.request<{ queue: QueueStats }>(\"GET\", \"/status\");\n return status.queue;\n }\n\n // ── Views ─────────────────────────────────────────────────────────────\n\n async listViews(): Promise<{ data: ViewSummary[] }> {\n return this.request<{ data: ViewSummary[] }>(\"GET\", \"/api/views\");\n }\n\n async getView(name: string): Promise<ViewDetail> {\n return this.request<ViewDetail>(\"GET\", `/api/views/${name}`);\n }\n\n async reindexView(name: string, options?: { fromBlock?: number; toBlock?: number }): Promise<ReindexResponse> {\n return this.request<ReindexResponse>(\"POST\", `/api/views/${name}/reindex`, options);\n }\n\n async deleteView(name: string): Promise<{ message: string }> {\n return this.request<{ message: string }>(\"DELETE\", `/api/views/${name}`);\n }\n\n async deployView(data: DeployViewRequest): Promise<DeployViewResponse> {\n return this.request<DeployViewResponse>(\"POST\", \"/api/views\", data);\n }\n\n async queryTable(name: string, table: string, params: ViewQueryParams = {}): Promise<unknown[]> {\n return this.request<unknown[]>(\"GET\", `/api/views/${name}/${table}${buildViewQueryString(params)}`);\n }\n\n async queryTableCount(name: string, table: string, params: ViewQueryParams = {}): Promise<{ count: number }> {\n return this.request<{ count: number }>(\"GET\", `/api/views/${name}/${table}/count${buildViewQueryString(params)}`);\n }\n}\n\nfunction buildViewQueryString(params: ViewQueryParams): string {\n const qs = new URLSearchParams();\n if (params.sort) qs.set(\"_sort\", params.sort);\n if (params.order) qs.set(\"_order\", params.order);\n if (params.limit !== undefined) qs.set(\"_limit\", String(params.limit));\n if (params.offset !== undefined) qs.set(\"_offset\", String(params.offset));\n if (params.fields) qs.set(\"_fields\", params.fields);\n if (params.filters) {\n for (const [key, value] of Object.entries(params.filters)) {\n qs.set(key, value);\n }\n }\n const str = qs.toString();\n return str ? `?${str}` : \"\";\n}\n"
7
- ],
8
- "mappings": "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",
9
- "debugId": "2645915545BCF30D64756E2164756E21",
10
- "names": []
11
- }
package/dist/errors.d.ts DELETED
@@ -1,5 +0,0 @@
1
- declare class ApiError extends Error {
2
- status: number;
3
- constructor(status: number, message: string);
4
- }
5
- export { ApiError };
package/dist/errors.js DELETED
@@ -1,15 +0,0 @@
1
- // src/errors.ts
2
- class ApiError extends Error {
3
- status;
4
- constructor(status, message) {
5
- super(message);
6
- this.status = status;
7
- this.name = "ApiError";
8
- }
9
- }
10
- export {
11
- ApiError
12
- };
13
-
14
- //# debugId=7DCD1AB2054ADEE564756E2164756E21
15
- //# sourceMappingURL=errors.js.map
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/errors.ts"],
4
- "sourcesContent": [
5
- "export class ApiError extends Error {\n constructor(\n public status: number,\n message: string\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n"
6
- ],
7
- "mappings": ";AAAO,MAAM,iBAAiB,MAAM;AAAA,EAEzB;AAAA,EADT,WAAW,CACF,QACP,SACA;AAAA,IACA,MAAM,OAAO;AAAA,IAHN;AAAA,IAIP,KAAK,OAAO;AAAA;AAEhB;",
8
- "debugId": "7DCD1AB2054ADEE564756E2164756E21",
9
- "names": []
10
- }