@secondlayer/shared 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +19 -0
  2. package/dist/src/crypto/hmac.d.ts +26 -0
  3. package/dist/src/crypto/hmac.js +75 -0
  4. package/dist/src/crypto/hmac.js.map +10 -0
  5. package/dist/src/db/index.d.ts +227 -0
  6. package/dist/src/db/index.js +75 -0
  7. package/dist/src/db/index.js.map +11 -0
  8. package/dist/src/db/jsonb.d.ts +13 -0
  9. package/dist/src/db/jsonb.js +35 -0
  10. package/dist/src/db/jsonb.js.map +10 -0
  11. package/dist/src/db/queries/accounts.d.ts +179 -0
  12. package/dist/src/db/queries/accounts.js +39 -0
  13. package/dist/src/db/queries/accounts.js.map +10 -0
  14. package/dist/src/db/queries/integrity.d.ts +178 -0
  15. package/dist/src/db/queries/integrity.js +68 -0
  16. package/dist/src/db/queries/integrity.js.map +10 -0
  17. package/dist/src/db/queries/metrics.d.ts +179 -0
  18. package/dist/src/db/queries/metrics.js +51 -0
  19. package/dist/src/db/queries/metrics.js.map +10 -0
  20. package/dist/src/db/queries/usage.d.ts +205 -0
  21. package/dist/src/db/queries/usage.js +117 -0
  22. package/dist/src/db/queries/usage.js.map +11 -0
  23. package/dist/src/db/queries/views.d.ts +191 -0
  24. package/dist/src/db/queries/views.js +111 -0
  25. package/dist/src/db/queries/views.js.map +11 -0
  26. package/dist/src/db/schema.d.ts +207 -0
  27. package/dist/src/db/schema.js +3 -0
  28. package/dist/src/db/schema.js.map +9 -0
  29. package/dist/src/env.d.ts +7 -0
  30. package/dist/src/env.js +60 -0
  31. package/dist/src/env.js.map +10 -0
  32. package/dist/src/errors.d.ts +51 -0
  33. package/dist/src/errors.js +103 -0
  34. package/dist/src/errors.js.map +10 -0
  35. package/dist/src/index.d.ts +464 -0
  36. package/dist/src/index.js +642 -0
  37. package/dist/src/index.js.map +19 -0
  38. package/dist/src/lib/plans.d.ts +10 -0
  39. package/dist/src/lib/plans.js +34 -0
  40. package/dist/src/lib/plans.js.map +10 -0
  41. package/dist/src/logger.d.ts +2 -0
  42. package/dist/src/logger.js +130 -0
  43. package/dist/src/logger.js.map +11 -0
  44. package/dist/src/node/client.d.ts +35 -0
  45. package/dist/src/node/client.js +56 -0
  46. package/dist/src/node/client.js.map +10 -0
  47. package/dist/src/node/hiro-client.d.ts +186 -0
  48. package/dist/src/node/hiro-client.js +410 -0
  49. package/dist/src/node/hiro-client.js.map +12 -0
  50. package/dist/src/queue/index.d.ts +50 -0
  51. package/dist/src/queue/index.js +176 -0
  52. package/dist/src/queue/index.js.map +12 -0
  53. package/dist/src/queue/listener.d.ts +20 -0
  54. package/dist/src/queue/listener.js +63 -0
  55. package/dist/src/queue/listener.js.map +10 -0
  56. package/dist/src/queue/recovery.d.ts +14 -0
  57. package/dist/src/queue/recovery.js +100 -0
  58. package/dist/src/queue/recovery.js.map +12 -0
  59. package/dist/src/schemas/filters.d.ts +30 -0
  60. package/dist/src/schemas/filters.js +133 -0
  61. package/dist/src/schemas/filters.js.map +10 -0
  62. package/dist/src/schemas/index.d.ts +109 -0
  63. package/dist/src/schemas/index.js +228 -0
  64. package/dist/src/schemas/index.js.map +12 -0
  65. package/dist/src/schemas/views.d.ts +51 -0
  66. package/dist/src/schemas/views.js +29 -0
  67. package/dist/src/schemas/views.js.map +10 -0
  68. package/dist/src/types.d.ts +102 -0
  69. package/dist/src/types.js +3 -0
  70. package/dist/src/types.js.map +9 -0
  71. package/migrations/0001_initial.ts +182 -0
  72. package/migrations/0002_api_keys.ts +38 -0
  73. package/migrations/0003_tenant_isolation.ts +114 -0
  74. package/migrations/0004_accounts_and_usage.ts +90 -0
  75. package/migrations/0005_sessions.ts +42 -0
  76. package/package.json +128 -0
@@ -0,0 +1,642 @@
1
+ import { createRequire } from "node:module";
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ // src/db/jsonb.ts
13
+ import { sql } from "kysely";
14
+ function jsonb(value) {
15
+ const escaped = JSON.stringify(value).replace(/'/g, "''");
16
+ return sql`${sql.raw(`'${escaped}'::jsonb`)}`;
17
+ }
18
+ function parseJsonb(value) {
19
+ if (typeof value === "string") {
20
+ try {
21
+ return JSON.parse(value);
22
+ } catch {
23
+ return value;
24
+ }
25
+ }
26
+ return value ?? {};
27
+ }
28
+
29
+ // src/db/index.ts
30
+ import { Kysely } from "kysely";
31
+ import { PostgresJSDialect } from "kysely-postgres-js";
32
+ import postgres from "postgres";
33
+ import { sql as sql2 } from "kysely";
34
+ var db = null;
35
+ var rawClient = null;
36
+ function getDb(connectionString) {
37
+ if (!db) {
38
+ const url = connectionString || process.env.DATABASE_URL || "postgres://postgres:postgres@localhost:5432/streams_dev";
39
+ const isLocal = url.includes("localhost") || url.includes("127.0.0.1") || url.includes("@postgres:");
40
+ rawClient = postgres(url, {
41
+ ssl: isLocal ? undefined : { rejectUnauthorized: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0" }
42
+ });
43
+ db = new Kysely({
44
+ dialect: new PostgresJSDialect({ postgres: rawClient })
45
+ });
46
+ }
47
+ return db;
48
+ }
49
+ function getRawClient() {
50
+ if (!rawClient)
51
+ getDb();
52
+ return rawClient;
53
+ }
54
+ async function closeDb() {
55
+ if (db) {
56
+ await db.destroy();
57
+ db = null;
58
+ }
59
+ if (rawClient) {
60
+ await rawClient.end();
61
+ rawClient = null;
62
+ }
63
+ }
64
+ // src/errors.ts
65
+ class StreamsError extends Error {
66
+ code;
67
+ cause;
68
+ constructor(code, message, cause) {
69
+ super(message);
70
+ this.code = code;
71
+ this.cause = cause;
72
+ this.name = this.constructor.name;
73
+ Error.captureStackTrace?.(this, this.constructor);
74
+ }
75
+ toJSON() {
76
+ return {
77
+ name: this.name,
78
+ code: this.code,
79
+ message: this.message,
80
+ stack: this.stack,
81
+ cause: this.cause
82
+ };
83
+ }
84
+ }
85
+
86
+ class StreamNotFoundError extends StreamsError {
87
+ constructor(streamId) {
88
+ super("STREAM_NOT_FOUND", `Stream not found: ${streamId}`);
89
+ }
90
+ }
91
+
92
+ class ValidationError extends StreamsError {
93
+ constructor(message, cause) {
94
+ super("VALIDATION_ERROR", message, cause);
95
+ }
96
+ }
97
+
98
+ class DatabaseError extends StreamsError {
99
+ constructor(message, cause) {
100
+ super("DATABASE_ERROR", message, cause);
101
+ }
102
+ }
103
+
104
+ class WebhookDeliveryError extends StreamsError {
105
+ statusCode;
106
+ constructor(message, statusCode, cause) {
107
+ super("WEBHOOK_DELIVERY_ERROR", message, cause);
108
+ this.statusCode = statusCode;
109
+ }
110
+ toJSON() {
111
+ return {
112
+ ...super.toJSON(),
113
+ statusCode: this.statusCode
114
+ };
115
+ }
116
+ }
117
+
118
+ class FilterEvaluationError extends StreamsError {
119
+ constructor(message, cause) {
120
+ super("FILTER_EVALUATION_ERROR", message, cause);
121
+ }
122
+ }
123
+
124
+ class AuthenticationError extends StreamsError {
125
+ constructor(message) {
126
+ super("AUTHENTICATION_ERROR", message);
127
+ }
128
+ }
129
+
130
+ class AuthorizationError extends StreamsError {
131
+ constructor(message) {
132
+ super("AUTHORIZATION_ERROR", message);
133
+ }
134
+ }
135
+
136
+ class RateLimitError extends StreamsError {
137
+ constructor(message) {
138
+ super("RATE_LIMIT_ERROR", message);
139
+ }
140
+ }
141
+
142
+ // src/env.ts
143
+ import { z } from "zod";
144
+ var networksSchema = z.string().transform((val) => {
145
+ const networks = val.split(",").map((n) => n.trim()).filter(Boolean);
146
+ const valid = ["mainnet", "testnet"];
147
+ for (const n of networks) {
148
+ if (!valid.includes(n)) {
149
+ throw new Error(`Invalid network: ${n}. Must be one of: ${valid.join(", ")}`);
150
+ }
151
+ }
152
+ return networks;
153
+ });
154
+ var envSchema = z.object({
155
+ DATABASE_URL: z.preprocess((val) => typeof val === "string" && val.length === 0 ? undefined : val, z.string().url().optional()),
156
+ NETWORK: z.enum(["mainnet", "testnet"]).optional(),
157
+ NETWORKS: networksSchema.optional(),
158
+ LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
159
+ NODE_ENV: z.enum(["development", "production", "test"]).default("development")
160
+ });
161
+ var cachedEnv = null;
162
+ function getEnv() {
163
+ if (cachedEnv) {
164
+ return cachedEnv;
165
+ }
166
+ const result = envSchema.safeParse(process.env);
167
+ if (!result.success) {
168
+ console.error("❌ Invalid environment configuration:");
169
+ console.error(result.error.format());
170
+ throw new Error("Invalid environment configuration");
171
+ }
172
+ let enabledNetworks;
173
+ if (result.data.NETWORKS && result.data.NETWORKS.length > 0) {
174
+ enabledNetworks = result.data.NETWORKS;
175
+ } else if (result.data.NETWORK) {
176
+ enabledNetworks = [result.data.NETWORK];
177
+ } else {
178
+ enabledNetworks = ["mainnet"];
179
+ }
180
+ cachedEnv = { ...result.data, enabledNetworks };
181
+ return cachedEnv;
182
+ }
183
+ // src/logger.ts
184
+ var LOG_LEVELS = {
185
+ debug: 0,
186
+ info: 1,
187
+ warn: 2,
188
+ error: 3
189
+ };
190
+
191
+ class Logger {
192
+ _level;
193
+ _isProduction;
194
+ _initialized = false;
195
+ init() {
196
+ if (this._initialized)
197
+ return;
198
+ this._initialized = true;
199
+ try {
200
+ const env = getEnv();
201
+ this._level = env.LOG_LEVEL;
202
+ this._isProduction = env.NODE_ENV === "production";
203
+ } catch {
204
+ this._level = "info";
205
+ this._isProduction = false;
206
+ }
207
+ }
208
+ get level() {
209
+ this.init();
210
+ return this._level;
211
+ }
212
+ get isProduction() {
213
+ this.init();
214
+ return this._isProduction;
215
+ }
216
+ shouldLog(level) {
217
+ return LOG_LEVELS[level] >= LOG_LEVELS[this.level];
218
+ }
219
+ formatMessage(level, message, meta) {
220
+ const timestamp = new Date().toISOString();
221
+ if (this.isProduction) {
222
+ return JSON.stringify({
223
+ timestamp,
224
+ level,
225
+ message,
226
+ ...meta
227
+ });
228
+ }
229
+ const metaStr = meta ? ` ${JSON.stringify(meta)}` : "";
230
+ return `[${timestamp}] ${level.toUpperCase()}: ${message}${metaStr}`;
231
+ }
232
+ debug(message, meta) {
233
+ if (this.shouldLog("debug")) {
234
+ console.debug(this.formatMessage("debug", message, meta));
235
+ }
236
+ }
237
+ info(message, meta) {
238
+ if (this.shouldLog("info")) {
239
+ console.info(this.formatMessage("info", message, meta));
240
+ }
241
+ }
242
+ warn(message, meta) {
243
+ if (this.shouldLog("warn")) {
244
+ console.warn(this.formatMessage("warn", message, meta));
245
+ }
246
+ }
247
+ error(message, meta) {
248
+ if (this.shouldLog("error")) {
249
+ console.error(this.formatMessage("error", message, meta));
250
+ }
251
+ }
252
+ }
253
+ var logger = new Logger;
254
+
255
+ // src/queue/index.ts
256
+ var exports_queue = {};
257
+ __export(exports_queue, {
258
+ stats: () => stats,
259
+ getWorkerId: () => getWorkerId,
260
+ fail: () => fail,
261
+ enqueue: () => enqueue,
262
+ complete: () => complete,
263
+ claim: () => claim,
264
+ WORKER_ID: () => WORKER_ID
265
+ });
266
+ import { sql as sql3 } from "kysely";
267
+ import { randomUUID } from "crypto";
268
+ var WORKER_ID = `worker-${randomUUID().slice(0, 8)}`;
269
+ async function enqueue(streamId, blockHeight, backfill = false) {
270
+ const db2 = getDb();
271
+ const row = await db2.insertInto("jobs").values({
272
+ stream_id: streamId,
273
+ block_height: blockHeight,
274
+ backfill,
275
+ status: "pending",
276
+ attempts: 0
277
+ }).returning(["id"]).executeTakeFirstOrThrow();
278
+ return row.id;
279
+ }
280
+ async function claim() {
281
+ const db2 = getDb();
282
+ const { rows } = await sql3`
283
+ UPDATE jobs
284
+ SET
285
+ status = 'processing',
286
+ locked_at = NOW(),
287
+ locked_by = ${WORKER_ID},
288
+ attempts = attempts + 1
289
+ WHERE id = (
290
+ SELECT id FROM jobs
291
+ WHERE status = 'pending'
292
+ ORDER BY
293
+ backfill ASC,
294
+ block_height ASC,
295
+ created_at ASC
296
+ FOR UPDATE SKIP LOCKED
297
+ LIMIT 1
298
+ )
299
+ RETURNING *
300
+ `.execute(db2);
301
+ return rows[0] ?? null;
302
+ }
303
+ async function complete(jobId) {
304
+ const db2 = getDb();
305
+ await db2.updateTable("jobs").set({
306
+ status: "completed",
307
+ completed_at: new Date,
308
+ locked_at: null,
309
+ locked_by: null
310
+ }).where("id", "=", jobId).execute();
311
+ }
312
+ async function fail(jobId, error, maxAttempts = 3) {
313
+ const db2 = getDb();
314
+ const job = await db2.selectFrom("jobs").select("attempts").where("id", "=", jobId).executeTakeFirst();
315
+ if (!job)
316
+ return;
317
+ if (job.attempts < maxAttempts) {
318
+ await db2.updateTable("jobs").set({
319
+ status: "pending",
320
+ error,
321
+ locked_at: null,
322
+ locked_by: null
323
+ }).where("id", "=", jobId).execute();
324
+ } else {
325
+ await db2.updateTable("jobs").set({
326
+ status: "failed",
327
+ error,
328
+ completed_at: new Date,
329
+ locked_at: null,
330
+ locked_by: null
331
+ }).where("id", "=", jobId).execute();
332
+ }
333
+ }
334
+ async function stats() {
335
+ const { rows } = await sql3`
336
+ SELECT status, COUNT(*) as count
337
+ FROM jobs
338
+ GROUP BY status
339
+ `.execute(getDb());
340
+ const counts = {};
341
+ for (const row of rows) {
342
+ counts[row.status] = parseInt(row.count, 10);
343
+ }
344
+ return {
345
+ pending: counts["pending"] || 0,
346
+ processing: counts["processing"] || 0,
347
+ completed: counts["completed"] || 0,
348
+ failed: counts["failed"] || 0,
349
+ total: Object.values(counts).reduce((a, b) => a + b, 0)
350
+ };
351
+ }
352
+ function getWorkerId() {
353
+ return WORKER_ID;
354
+ }
355
+ // src/schemas/filters.ts
356
+ import { z as z2 } from "zod";
357
+ import { validateStacksAddress } from "@stacks/transactions";
358
+ var stacksPrincipal = z2.string().refine((val) => {
359
+ const parts = val.split(".");
360
+ if (parts.length > 2)
361
+ return false;
362
+ return validateStacksAddress(parts[0]);
363
+ }, "Invalid Stacks principal address");
364
+ var baseFilter = {
365
+ sender: stacksPrincipal.optional(),
366
+ recipient: stacksPrincipal.optional()
367
+ };
368
+ var StxTransferFilterSchema = z2.object({
369
+ type: z2.literal("stx_transfer"),
370
+ ...baseFilter,
371
+ minAmount: z2.coerce.number().int().positive().optional(),
372
+ maxAmount: z2.coerce.number().int().positive().optional()
373
+ });
374
+ var StxMintFilterSchema = z2.object({
375
+ type: z2.literal("stx_mint"),
376
+ recipient: stacksPrincipal.optional(),
377
+ minAmount: z2.coerce.number().int().positive().optional()
378
+ });
379
+ var StxBurnFilterSchema = z2.object({
380
+ type: z2.literal("stx_burn"),
381
+ sender: stacksPrincipal.optional(),
382
+ minAmount: z2.coerce.number().int().positive().optional()
383
+ });
384
+ var StxLockFilterSchema = z2.object({
385
+ type: z2.literal("stx_lock"),
386
+ lockedAddress: stacksPrincipal.optional(),
387
+ minAmount: z2.coerce.number().int().positive().optional()
388
+ });
389
+ var FtTransferFilterSchema = z2.object({
390
+ type: z2.literal("ft_transfer"),
391
+ ...baseFilter,
392
+ assetIdentifier: z2.string().optional(),
393
+ minAmount: z2.coerce.number().int().positive().optional()
394
+ });
395
+ var FtMintFilterSchema = z2.object({
396
+ type: z2.literal("ft_mint"),
397
+ recipient: stacksPrincipal.optional(),
398
+ assetIdentifier: z2.string().optional(),
399
+ minAmount: z2.coerce.number().int().positive().optional()
400
+ });
401
+ var FtBurnFilterSchema = z2.object({
402
+ type: z2.literal("ft_burn"),
403
+ sender: stacksPrincipal.optional(),
404
+ assetIdentifier: z2.string().optional(),
405
+ minAmount: z2.coerce.number().int().positive().optional()
406
+ });
407
+ var NftTransferFilterSchema = z2.object({
408
+ type: z2.literal("nft_transfer"),
409
+ ...baseFilter,
410
+ assetIdentifier: z2.string().optional(),
411
+ tokenId: z2.string().optional()
412
+ });
413
+ var NftMintFilterSchema = z2.object({
414
+ type: z2.literal("nft_mint"),
415
+ recipient: stacksPrincipal.optional(),
416
+ assetIdentifier: z2.string().optional(),
417
+ tokenId: z2.string().optional()
418
+ });
419
+ var NftBurnFilterSchema = z2.object({
420
+ type: z2.literal("nft_burn"),
421
+ sender: stacksPrincipal.optional(),
422
+ assetIdentifier: z2.string().optional(),
423
+ tokenId: z2.string().optional()
424
+ });
425
+ var ContractCallFilterSchema = z2.object({
426
+ type: z2.literal("contract_call"),
427
+ contractId: stacksPrincipal.optional(),
428
+ functionName: z2.string().optional(),
429
+ caller: stacksPrincipal.optional()
430
+ });
431
+ var ContractDeployFilterSchema = z2.object({
432
+ type: z2.literal("contract_deploy"),
433
+ deployer: stacksPrincipal.optional(),
434
+ contractName: z2.string().optional()
435
+ });
436
+ var PrintEventFilterSchema = z2.object({
437
+ type: z2.literal("print_event"),
438
+ contractId: stacksPrincipal.optional(),
439
+ topic: z2.string().optional(),
440
+ contains: z2.string().optional()
441
+ });
442
+ var StreamFilterSchema = z2.discriminatedUnion("type", [
443
+ StxTransferFilterSchema,
444
+ StxMintFilterSchema,
445
+ StxBurnFilterSchema,
446
+ StxLockFilterSchema,
447
+ FtTransferFilterSchema,
448
+ FtMintFilterSchema,
449
+ FtBurnFilterSchema,
450
+ NftTransferFilterSchema,
451
+ NftMintFilterSchema,
452
+ NftBurnFilterSchema,
453
+ ContractCallFilterSchema,
454
+ ContractDeployFilterSchema,
455
+ PrintEventFilterSchema
456
+ ]);
457
+
458
+ // src/schemas/views.ts
459
+ import { z as z3 } from "zod";
460
+ var DeployViewRequestSchema = z3.object({
461
+ name: z3.string().regex(/^[a-z0-9-]+$/, "lowercase alphanumeric + hyphens only").max(63),
462
+ version: z3.string().optional(),
463
+ description: z3.string().optional(),
464
+ sources: z3.array(z3.string()).min(1),
465
+ schema: z3.record(z3.unknown()),
466
+ handlerCode: z3.string().max(1048576, "handler code exceeds 1MB limit"),
467
+ reindex: z3.boolean().optional()
468
+ });
469
+ // src/schemas/stream.ts
470
+ import { z as z4 } from "zod";
471
+ var StreamOptionsSchema = z4.object({
472
+ decodeClarityValues: z4.boolean().default(true),
473
+ includeRawTx: z4.boolean().default(false),
474
+ includeBlockMetadata: z4.boolean().default(true),
475
+ rateLimit: z4.number().int().positive().max(100).default(10),
476
+ timeoutMs: z4.number().int().positive().max(30000).default(1e4),
477
+ maxRetries: z4.number().int().min(0).max(10).default(3)
478
+ });
479
+ var CreateStreamSchema = z4.object({
480
+ name: z4.string().min(1).max(255),
481
+ webhookUrl: z4.string().url(),
482
+ filters: z4.array(StreamFilterSchema).min(1),
483
+ options: StreamOptionsSchema.optional().default({}),
484
+ startBlock: z4.number().int().positive().optional(),
485
+ endBlock: z4.number().int().positive().optional()
486
+ });
487
+ var UpdateStreamSchema = z4.object({
488
+ name: z4.string().min(1).max(255).optional(),
489
+ webhookUrl: z4.string().url().optional(),
490
+ filters: z4.array(StreamFilterSchema).min(1).optional(),
491
+ options: StreamOptionsSchema.partial().optional()
492
+ }).refine((data) => Object.keys(data).length > 0, { message: "At least one field must be provided for update" });
493
+ var WebhookPayloadSchema = z4.object({
494
+ streamId: z4.string().uuid(),
495
+ streamName: z4.string(),
496
+ block: z4.object({
497
+ height: z4.number(),
498
+ hash: z4.string(),
499
+ parentHash: z4.string(),
500
+ burnBlockHeight: z4.number(),
501
+ timestamp: z4.number()
502
+ }),
503
+ matches: z4.object({
504
+ transactions: z4.array(z4.object({
505
+ txId: z4.string(),
506
+ type: z4.string(),
507
+ sender: z4.string(),
508
+ status: z4.string(),
509
+ contractId: z4.string().nullable(),
510
+ functionName: z4.string().nullable(),
511
+ rawTx: z4.string().optional()
512
+ })),
513
+ events: z4.array(z4.object({
514
+ txId: z4.string(),
515
+ eventIndex: z4.number(),
516
+ type: z4.string(),
517
+ data: z4.any()
518
+ }))
519
+ }),
520
+ isBackfill: z4.boolean(),
521
+ deliveredAt: z4.string().datetime()
522
+ });
523
+ var StreamMetricsSchema = z4.object({
524
+ totalDeliveries: z4.number(),
525
+ failedDeliveries: z4.number(),
526
+ lastTriggeredAt: z4.string().datetime().nullable(),
527
+ lastTriggeredBlock: z4.number().nullable(),
528
+ errorMessage: z4.string().nullable()
529
+ });
530
+ var StreamResponseSchema = z4.object({
531
+ id: z4.string().uuid(),
532
+ name: z4.string(),
533
+ status: z4.enum(["inactive", "active", "paused", "failed"]),
534
+ webhookUrl: z4.string().url(),
535
+ filters: z4.array(StreamFilterSchema),
536
+ options: StreamOptionsSchema,
537
+ totalDeliveries: z4.number().int().default(0),
538
+ failedDeliveries: z4.number().int().default(0),
539
+ lastTriggeredAt: z4.string().datetime().nullable().optional(),
540
+ lastTriggeredBlock: z4.number().int().nullable().optional(),
541
+ errorMessage: z4.string().nullable().optional(),
542
+ createdAt: z4.string().datetime(),
543
+ updatedAt: z4.string().datetime()
544
+ });
545
+ // src/crypto/hmac.ts
546
+ var exports_hmac = {};
547
+ __export(exports_hmac, {
548
+ verifySignatureHeader: () => verifySignatureHeader,
549
+ verifySignature: () => verifySignature,
550
+ signPayload: () => signPayload,
551
+ generateSecret: () => generateSecret,
552
+ createSignatureHeader: () => createSignatureHeader
553
+ });
554
+ import { createHmac, randomBytes } from "crypto";
555
+ function generateSecret() {
556
+ return randomBytes(32).toString("hex");
557
+ }
558
+ function signPayload(payload, secret) {
559
+ const hmac = createHmac("sha256", secret);
560
+ hmac.update(payload);
561
+ return hmac.digest("hex");
562
+ }
563
+ function verifySignature(payload, signature, secret) {
564
+ const expectedSignature = signPayload(payload, secret);
565
+ if (signature.length !== expectedSignature.length) {
566
+ return false;
567
+ }
568
+ let result = 0;
569
+ for (let i = 0;i < signature.length; i++) {
570
+ result |= signature.charCodeAt(i) ^ expectedSignature.charCodeAt(i);
571
+ }
572
+ return result === 0;
573
+ }
574
+ function createSignatureHeader(payload, secret, timestamp) {
575
+ const ts = timestamp ?? Math.floor(Date.now() / 1000);
576
+ const signedPayload = `${ts}.${payload}`;
577
+ const signature = signPayload(signedPayload, secret);
578
+ return `t=${ts},v1=${signature}`;
579
+ }
580
+ function verifySignatureHeader(payload, header, secret, toleranceSeconds = 300) {
581
+ const parts = header.split(",");
582
+ const timestamp = parts.find((p) => p.startsWith("t="))?.slice(2);
583
+ const signature = parts.find((p) => p.startsWith("v1="))?.slice(3);
584
+ if (!timestamp || !signature) {
585
+ return false;
586
+ }
587
+ const ts = parseInt(timestamp, 10);
588
+ if (isNaN(ts)) {
589
+ return false;
590
+ }
591
+ const now = Math.floor(Date.now() / 1000);
592
+ if (Math.abs(now - ts) > toleranceSeconds) {
593
+ return false;
594
+ }
595
+ const signedPayload = `${ts}.${payload}`;
596
+ return verifySignature(signedPayload, signature, secret);
597
+ }
598
+ export {
599
+ sql2 as sql,
600
+ exports_queue as queue,
601
+ parseJsonb,
602
+ logger,
603
+ jsonb,
604
+ getRawClient,
605
+ getEnv,
606
+ getDb,
607
+ exports_hmac as crypto,
608
+ closeDb,
609
+ WebhookPayloadSchema,
610
+ WebhookDeliveryError,
611
+ ValidationError,
612
+ UpdateStreamSchema,
613
+ StxTransferFilterSchema,
614
+ StxMintFilterSchema,
615
+ StxLockFilterSchema,
616
+ StxBurnFilterSchema,
617
+ StreamsError,
618
+ StreamResponseSchema,
619
+ StreamOptionsSchema,
620
+ StreamNotFoundError,
621
+ StreamMetricsSchema,
622
+ StreamFilterSchema,
623
+ RateLimitError,
624
+ PrintEventFilterSchema,
625
+ NftTransferFilterSchema,
626
+ NftMintFilterSchema,
627
+ NftBurnFilterSchema,
628
+ FtTransferFilterSchema,
629
+ FtMintFilterSchema,
630
+ FtBurnFilterSchema,
631
+ FilterEvaluationError,
632
+ DeployViewRequestSchema,
633
+ DatabaseError,
634
+ CreateStreamSchema,
635
+ ContractDeployFilterSchema,
636
+ ContractCallFilterSchema,
637
+ AuthorizationError,
638
+ AuthenticationError
639
+ };
640
+
641
+ //# debugId=52ED396A08F9D61564756E2164756E21
642
+ //# sourceMappingURL=index.js.map