@secondlayer/shared 0.7.1 → 0.8.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 (68) hide show
  1. package/dist/src/crypto/hmac.js +2 -2
  2. package/dist/src/crypto/hmac.js.map +3 -3
  3. package/dist/src/db/index.d.ts +15 -1
  4. package/dist/src/db/index.js +5 -3
  5. package/dist/src/db/index.js.map +4 -4
  6. package/dist/src/db/jsonb.js.map +2 -2
  7. package/dist/src/db/queries/accounts.d.ts +12 -0
  8. package/dist/src/db/queries/accounts.js.map +2 -2
  9. package/dist/src/db/queries/integrity.d.ts +12 -0
  10. package/dist/src/db/queries/integrity.js.map +2 -2
  11. package/dist/src/db/queries/metrics.d.ts +12 -0
  12. package/dist/src/db/queries/metrics.js.map +2 -2
  13. package/dist/src/db/queries/subgraph-gaps.d.ts +305 -0
  14. package/dist/src/db/queries/subgraph-gaps.js +103 -0
  15. package/dist/src/db/queries/subgraph-gaps.js.map +10 -0
  16. package/dist/src/db/queries/subgraphs.d.ts +12 -0
  17. package/dist/src/db/queries/subgraphs.js.map +3 -3
  18. package/dist/src/db/queries/usage.d.ts +12 -0
  19. package/dist/src/db/queries/usage.js +13 -3
  20. package/dist/src/db/queries/usage.js.map +4 -4
  21. package/dist/src/db/schema.d.ts +15 -1
  22. package/dist/src/env.js.map +2 -2
  23. package/dist/src/errors.js.map +2 -2
  24. package/dist/src/index.d.ts +59 -1
  25. package/dist/src/index.js +12 -8
  26. package/dist/src/index.js.map +12 -12
  27. package/dist/src/lib/plans.js.map +2 -2
  28. package/dist/src/logger.js.map +3 -3
  29. package/dist/src/node/archive-client.js +22 -6
  30. package/dist/src/node/archive-client.js.map +5 -5
  31. package/dist/src/node/client.js.map +2 -2
  32. package/dist/src/node/hiro-client.js +47 -11
  33. package/dist/src/node/hiro-client.js.map +5 -5
  34. package/dist/src/node/hiro-pg-client.js +131 -26
  35. package/dist/src/node/hiro-pg-client.js.map +3 -3
  36. package/dist/src/node/local-client.d.ts +12 -0
  37. package/dist/src/node/local-client.js.map +2 -2
  38. package/dist/src/queue/index.js +7 -5
  39. package/dist/src/queue/index.js.map +5 -5
  40. package/dist/src/queue/listener.js.map +2 -2
  41. package/dist/src/queue/recovery.js +5 -3
  42. package/dist/src/queue/recovery.js.map +5 -5
  43. package/dist/src/schemas/filters.js +2 -2
  44. package/dist/src/schemas/filters.js.map +3 -3
  45. package/dist/src/schemas/index.d.ts +45 -1
  46. package/dist/src/schemas/index.js +5 -3
  47. package/dist/src/schemas/index.js.map +5 -5
  48. package/dist/src/schemas/subgraphs.d.ts +45 -1
  49. package/dist/src/schemas/subgraphs.js.map +2 -2
  50. package/migrations/0001_initial.ts +295 -159
  51. package/migrations/0002_api_keys.ts +44 -28
  52. package/migrations/0003_tenant_isolation.ts +116 -107
  53. package/migrations/0004_accounts_and_usage.ts +81 -75
  54. package/migrations/0005_sessions.ts +33 -33
  55. package/migrations/0006_tx_index.ts +6 -2
  56. package/migrations/0007_contracts.ts +38 -24
  57. package/migrations/0008_drop_contracts.ts +33 -19
  58. package/migrations/0009_waitlist.ts +12 -12
  59. package/migrations/0010_waitlist_status.ts +5 -5
  60. package/migrations/0011_account_insights.ts +52 -52
  61. package/migrations/0012_view_health_snapshots.ts +21 -21
  62. package/migrations/0013_view_processing_stats.ts +32 -32
  63. package/migrations/0014_view_table_snapshots.ts +24 -24
  64. package/migrations/0015_rename_views_to_subgraphs.ts +137 -75
  65. package/migrations/0016_rename_webhook_to_endpoint.ts +12 -4
  66. package/migrations/0017_security_hardening.ts +23 -11
  67. package/migrations/0018_subgraph_gaps.ts +39 -0
  68. package/package.json +147 -143
@@ -1,114 +1,123 @@
1
1
  import { type Kysely, sql } from "kysely";
2
2
 
3
3
  export async function up(db: Kysely<any>): Promise<void> {
4
- // 1. Drop PG schemas for views with null api_key_id (orphaned pre-product data)
5
- const orphanedViews = await db
6
- .selectFrom("views")
7
- .select("name")
8
- .where("api_key_id", "is", null)
9
- .execute();
10
-
11
- for (const view of orphanedViews) {
12
- const schemaName = `view_${view.name.replace(/-/g, "_")}`;
13
- await sql.raw(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`).execute(db);
14
- }
15
-
16
- // 2. Delete orphaned rows (null api_key_id)
17
- await db.deleteFrom("views").where("api_key_id", "is", null).execute();
18
-
19
- // Delete stream_metrics for orphaned streams first (FK)
20
- const orphanedStreamIds = await db
21
- .selectFrom("streams")
22
- .select("id")
23
- .where("api_key_id", "is", null)
24
- .execute();
25
-
26
- if (orphanedStreamIds.length > 0) {
27
- await db
28
- .deleteFrom("stream_metrics")
29
- .where(
30
- "stream_id",
31
- "in",
32
- orphanedStreamIds.map((s) => s.id),
33
- )
34
- .execute();
35
-
36
- // Delete jobs + deliveries for orphaned streams
37
- await db
38
- .deleteFrom("deliveries")
39
- .where(
40
- "stream_id",
41
- "in",
42
- orphanedStreamIds.map((s) => s.id),
43
- )
44
- .execute();
45
-
46
- await db
47
- .deleteFrom("jobs")
48
- .where(
49
- "stream_id",
50
- "in",
51
- orphanedStreamIds.map((s) => s.id),
52
- )
53
- .execute();
54
- }
55
-
56
- await db.deleteFrom("streams").where("api_key_id", "is", null).execute();
57
-
58
- // 3. Add schema_name column to views
59
- await db.schema
60
- .alterTable("views")
61
- .addColumn("schema_name", "text")
62
- .execute();
63
-
64
- // Backfill schema_name for existing views
65
- const existingViews = await db
66
- .selectFrom("views")
67
- .select(["id", "name"])
68
- .execute();
69
-
70
- for (const view of existingViews) {
71
- const schemaName = `view_${view.name.replace(/-/g, "_")}`;
72
- await db
73
- .updateTable("views")
74
- .set({ schema_name: schemaName })
75
- .where("id", "=", view.id)
76
- .execute();
77
- }
78
-
79
- // 4. Drop unique constraint on views(name), replace with views(name, api_key_id)
80
- // The original unique constraint is from the initial migration on "name"
81
- await sql.raw(`ALTER TABLE views DROP CONSTRAINT IF EXISTS views_name_key`).execute(db);
82
- await sql.raw(`ALTER TABLE views DROP CONSTRAINT IF EXISTS views_name_unique`).execute(db);
83
-
84
- await db.schema
85
- .createIndex("views_name_api_key_id_unique")
86
- .on("views")
87
- .columns(["name", "api_key_id"])
88
- .unique()
89
- .execute();
90
-
91
- // 5. Add indexes for tenant scoping
92
- await db.schema
93
- .createIndex("streams_api_key_id_idx")
94
- .on("streams")
95
- .column("api_key_id")
96
- .execute();
97
-
98
- await db.schema
99
- .createIndex("views_api_key_id_idx")
100
- .on("views")
101
- .column("api_key_id")
102
- .execute();
4
+ // 1. Drop PG schemas for views with null api_key_id (orphaned pre-product data)
5
+ const orphanedViews = await db
6
+ .selectFrom("views")
7
+ .select("name")
8
+ .where("api_key_id", "is", null)
9
+ .execute();
10
+
11
+ for (const view of orphanedViews) {
12
+ const schemaName = `view_${view.name.replace(/-/g, "_")}`;
13
+ await sql.raw(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`).execute(db);
14
+ }
15
+
16
+ // 2. Delete orphaned rows (null api_key_id)
17
+ await db.deleteFrom("views").where("api_key_id", "is", null).execute();
18
+
19
+ // Delete stream_metrics for orphaned streams first (FK)
20
+ const orphanedStreamIds = await db
21
+ .selectFrom("streams")
22
+ .select("id")
23
+ .where("api_key_id", "is", null)
24
+ .execute();
25
+
26
+ if (orphanedStreamIds.length > 0) {
27
+ await db
28
+ .deleteFrom("stream_metrics")
29
+ .where(
30
+ "stream_id",
31
+ "in",
32
+ orphanedStreamIds.map((s) => s.id),
33
+ )
34
+ .execute();
35
+
36
+ // Delete jobs + deliveries for orphaned streams
37
+ await db
38
+ .deleteFrom("deliveries")
39
+ .where(
40
+ "stream_id",
41
+ "in",
42
+ orphanedStreamIds.map((s) => s.id),
43
+ )
44
+ .execute();
45
+
46
+ await db
47
+ .deleteFrom("jobs")
48
+ .where(
49
+ "stream_id",
50
+ "in",
51
+ orphanedStreamIds.map((s) => s.id),
52
+ )
53
+ .execute();
54
+ }
55
+
56
+ await db.deleteFrom("streams").where("api_key_id", "is", null).execute();
57
+
58
+ // 3. Add schema_name column to views
59
+ await db.schema
60
+ .alterTable("views")
61
+ .addColumn("schema_name", "text")
62
+ .execute();
63
+
64
+ // Backfill schema_name for existing views
65
+ const existingViews = await db
66
+ .selectFrom("views")
67
+ .select(["id", "name"])
68
+ .execute();
69
+
70
+ for (const view of existingViews) {
71
+ const schemaName = `view_${view.name.replace(/-/g, "_")}`;
72
+ await db
73
+ .updateTable("views")
74
+ .set({ schema_name: schemaName })
75
+ .where("id", "=", view.id)
76
+ .execute();
77
+ }
78
+
79
+ // 4. Drop unique constraint on views(name), replace with views(name, api_key_id)
80
+ // The original unique constraint is from the initial migration on "name"
81
+ await sql
82
+ .raw(`ALTER TABLE views DROP CONSTRAINT IF EXISTS views_name_key`)
83
+ .execute(db);
84
+ await sql
85
+ .raw(`ALTER TABLE views DROP CONSTRAINT IF EXISTS views_name_unique`)
86
+ .execute(db);
87
+
88
+ await db.schema
89
+ .createIndex("views_name_api_key_id_unique")
90
+ .on("views")
91
+ .columns(["name", "api_key_id"])
92
+ .unique()
93
+ .execute();
94
+
95
+ // 5. Add indexes for tenant scoping
96
+ await db.schema
97
+ .createIndex("streams_api_key_id_idx")
98
+ .on("streams")
99
+ .column("api_key_id")
100
+ .execute();
101
+
102
+ await db.schema
103
+ .createIndex("views_api_key_id_idx")
104
+ .on("views")
105
+ .column("api_key_id")
106
+ .execute();
103
107
  }
104
108
 
105
109
  export async function down(db: Kysely<any>): Promise<void> {
106
- await db.schema.dropIndex("views_api_key_id_idx").ifExists().execute();
107
- await db.schema.dropIndex("streams_api_key_id_idx").ifExists().execute();
108
- await db.schema.dropIndex("views_name_api_key_id_unique").ifExists().execute();
109
-
110
- // Restore original unique constraint on name
111
- await sql.raw(`ALTER TABLE views ADD CONSTRAINT views_name_key UNIQUE (name)`).execute(db);
112
-
113
- await db.schema.alterTable("views").dropColumn("schema_name").execute();
110
+ await db.schema.dropIndex("views_api_key_id_idx").ifExists().execute();
111
+ await db.schema.dropIndex("streams_api_key_id_idx").ifExists().execute();
112
+ await db.schema
113
+ .dropIndex("views_name_api_key_id_unique")
114
+ .ifExists()
115
+ .execute();
116
+
117
+ // Restore original unique constraint on name
118
+ await sql
119
+ .raw(`ALTER TABLE views ADD CONSTRAINT views_name_key UNIQUE (name)`)
120
+ .execute(db);
121
+
122
+ await db.schema.alterTable("views").dropColumn("schema_name").execute();
114
123
  }
@@ -1,90 +1,96 @@
1
1
  import { type Kysely, sql } from "kysely";
2
2
 
3
3
  export async function up(db: Kysely<any>): Promise<void> {
4
- // 1. Create accounts table
5
- await db.schema
6
- .createTable("accounts")
7
- .addColumn("id", "uuid", (col) =>
8
- col.primaryKey().defaultTo(sql`gen_random_uuid()`),
9
- )
10
- .addColumn("email", "text", (col) => col.unique().notNull())
11
- .addColumn("plan", "text", (col) => col.defaultTo("free").notNull())
12
- .addColumn("created_at", "timestamptz", (col) =>
13
- col.defaultTo(sql`NOW()`).notNull(),
14
- )
15
- .execute();
4
+ // 1. Create accounts table
5
+ await db.schema
6
+ .createTable("accounts")
7
+ .addColumn("id", "uuid", (col) =>
8
+ col.primaryKey().defaultTo(sql`gen_random_uuid()`),
9
+ )
10
+ .addColumn("email", "text", (col) => col.unique().notNull())
11
+ .addColumn("plan", "text", (col) => col.defaultTo("free").notNull())
12
+ .addColumn("created_at", "timestamptz", (col) =>
13
+ col.defaultTo(sql`NOW()`).notNull(),
14
+ )
15
+ .execute();
16
16
 
17
- // 2. Create magic_links table
18
- await db.schema
19
- .createTable("magic_links")
20
- .addColumn("id", "uuid", (col) =>
21
- col.primaryKey().defaultTo(sql`gen_random_uuid()`),
22
- )
23
- .addColumn("email", "text", (col) => col.notNull())
24
- .addColumn("token", "text", (col) => col.unique().notNull())
25
- .addColumn("expires_at", "timestamptz", (col) => col.notNull())
26
- .addColumn("used_at", "timestamptz")
27
- .addColumn("created_at", "timestamptz", (col) =>
28
- col.defaultTo(sql`NOW()`).notNull(),
29
- )
30
- .execute();
17
+ // 2. Create magic_links table
18
+ await db.schema
19
+ .createTable("magic_links")
20
+ .addColumn("id", "uuid", (col) =>
21
+ col.primaryKey().defaultTo(sql`gen_random_uuid()`),
22
+ )
23
+ .addColumn("email", "text", (col) => col.notNull())
24
+ .addColumn("token", "text", (col) => col.unique().notNull())
25
+ .addColumn("expires_at", "timestamptz", (col) => col.notNull())
26
+ .addColumn("used_at", "timestamptz")
27
+ .addColumn("created_at", "timestamptz", (col) =>
28
+ col.defaultTo(sql`NOW()`).notNull(),
29
+ )
30
+ .execute();
31
31
 
32
- // 3. Create usage_daily table
33
- await db.schema
34
- .createTable("usage_daily")
35
- .addColumn("account_id", "uuid", (col) =>
36
- col.references("accounts.id").onDelete("cascade").notNull(),
37
- )
38
- .addColumn("date", "date", (col) => col.notNull())
39
- .addColumn("api_requests", "integer", (col) => col.defaultTo(0).notNull())
40
- .addColumn("deliveries", "integer", (col) => col.defaultTo(0).notNull())
41
- .execute();
32
+ // 3. Create usage_daily table
33
+ await db.schema
34
+ .createTable("usage_daily")
35
+ .addColumn("account_id", "uuid", (col) =>
36
+ col.references("accounts.id").onDelete("cascade").notNull(),
37
+ )
38
+ .addColumn("date", "date", (col) => col.notNull())
39
+ .addColumn("api_requests", "integer", (col) => col.defaultTo(0).notNull())
40
+ .addColumn("deliveries", "integer", (col) => col.defaultTo(0).notNull())
41
+ .execute();
42
42
 
43
- await sql`ALTER TABLE usage_daily ADD PRIMARY KEY (account_id, date)`.execute(db);
43
+ await sql`ALTER TABLE usage_daily ADD PRIMARY KEY (account_id, date)`.execute(
44
+ db,
45
+ );
44
46
 
45
- // 4. Create usage_snapshots table
46
- await db.schema
47
- .createTable("usage_snapshots")
48
- .addColumn("id", "uuid", (col) =>
49
- col.primaryKey().defaultTo(sql`gen_random_uuid()`),
50
- )
51
- .addColumn("account_id", "uuid", (col) =>
52
- col.references("accounts.id").onDelete("cascade").notNull(),
53
- )
54
- .addColumn("measured_at", "timestamptz", (col) =>
55
- col.defaultTo(sql`NOW()`).notNull(),
56
- )
57
- .addColumn("storage_bytes", "bigint", (col) => col.defaultTo(0).notNull())
58
- .execute();
47
+ // 4. Create usage_snapshots table
48
+ await db.schema
49
+ .createTable("usage_snapshots")
50
+ .addColumn("id", "uuid", (col) =>
51
+ col.primaryKey().defaultTo(sql`gen_random_uuid()`),
52
+ )
53
+ .addColumn("account_id", "uuid", (col) =>
54
+ col.references("accounts.id").onDelete("cascade").notNull(),
55
+ )
56
+ .addColumn("measured_at", "timestamptz", (col) =>
57
+ col.defaultTo(sql`NOW()`).notNull(),
58
+ )
59
+ .addColumn("storage_bytes", "bigint", (col) => col.defaultTo(0).notNull())
60
+ .execute();
59
61
 
60
- // 5. Add account_id FK to api_keys
61
- await db.schema
62
- .alterTable("api_keys")
63
- .addColumn("account_id", "uuid", (col) =>
64
- col.references("accounts.id").onDelete("cascade"),
65
- )
66
- .execute();
62
+ // 5. Add account_id FK to api_keys
63
+ await db.schema
64
+ .alterTable("api_keys")
65
+ .addColumn("account_id", "uuid", (col) =>
66
+ col.references("accounts.id").onDelete("cascade"),
67
+ )
68
+ .execute();
67
69
 
68
- // 6. Delete orphan api_keys (no account_id)
69
- await db.deleteFrom("api_keys").where("account_id", "is", null).execute();
70
+ // 6. Delete orphan api_keys (no account_id)
71
+ await db.deleteFrom("api_keys").where("account_id", "is", null).execute();
70
72
 
71
- // 7. Set NOT NULL on account_id
72
- await sql`ALTER TABLE api_keys ALTER COLUMN account_id SET NOT NULL`.execute(db);
73
+ // 7. Set NOT NULL on account_id
74
+ await sql`ALTER TABLE api_keys ALTER COLUMN account_id SET NOT NULL`.execute(
75
+ db,
76
+ );
73
77
 
74
- // 8. Index for account_id lookups
75
- await db.schema
76
- .createIndex("api_keys_account_id_idx")
77
- .on("api_keys")
78
- .column("account_id")
79
- .execute();
78
+ // 8. Index for account_id lookups
79
+ await db.schema
80
+ .createIndex("api_keys_account_id_idx")
81
+ .on("api_keys")
82
+ .column("account_id")
83
+ .execute();
80
84
  }
81
85
 
82
86
  export async function down(db: Kysely<any>): Promise<void> {
83
- await db.schema.dropIndex("api_keys_account_id_idx").ifExists().execute();
84
- await sql`ALTER TABLE api_keys ALTER COLUMN account_id DROP NOT NULL`.execute(db);
85
- await db.schema.alterTable("api_keys").dropColumn("account_id").execute();
86
- await db.schema.dropTable("usage_snapshots").ifExists().execute();
87
- await db.schema.dropTable("usage_daily").ifExists().execute();
88
- await db.schema.dropTable("magic_links").ifExists().execute();
89
- await db.schema.dropTable("accounts").ifExists().execute();
87
+ await db.schema.dropIndex("api_keys_account_id_idx").ifExists().execute();
88
+ await sql`ALTER TABLE api_keys ALTER COLUMN account_id DROP NOT NULL`.execute(
89
+ db,
90
+ );
91
+ await db.schema.alterTable("api_keys").dropColumn("account_id").execute();
92
+ await db.schema.dropTable("usage_snapshots").ifExists().execute();
93
+ await db.schema.dropTable("usage_daily").ifExists().execute();
94
+ await db.schema.dropTable("magic_links").ifExists().execute();
95
+ await db.schema.dropTable("accounts").ifExists().execute();
90
96
  }
@@ -1,42 +1,42 @@
1
1
  import { type Kysely, sql } from "kysely";
2
2
 
3
3
  export async function up(db: Kysely<any>): Promise<void> {
4
- await db.schema
5
- .createTable("sessions")
6
- .addColumn("id", "uuid", (col) =>
7
- col.primaryKey().defaultTo(sql`gen_random_uuid()`),
8
- )
9
- .addColumn("token_hash", "text", (col) => col.unique().notNull())
10
- .addColumn("token_prefix", "text", (col) => col.notNull())
11
- .addColumn("account_id", "uuid", (col) =>
12
- col.references("accounts.id").onDelete("cascade").notNull(),
13
- )
14
- .addColumn("ip_address", "text", (col) => col.notNull())
15
- .addColumn("expires_at", "timestamptz", (col) =>
16
- col.defaultTo(sql`NOW() + INTERVAL '90 days'`).notNull(),
17
- )
18
- .addColumn("revoked_at", "timestamptz")
19
- .addColumn("last_used_at", "timestamptz")
20
- .addColumn("created_at", "timestamptz", (col) =>
21
- col.defaultTo(sql`NOW()`).notNull(),
22
- )
23
- .execute();
4
+ await db.schema
5
+ .createTable("sessions")
6
+ .addColumn("id", "uuid", (col) =>
7
+ col.primaryKey().defaultTo(sql`gen_random_uuid()`),
8
+ )
9
+ .addColumn("token_hash", "text", (col) => col.unique().notNull())
10
+ .addColumn("token_prefix", "text", (col) => col.notNull())
11
+ .addColumn("account_id", "uuid", (col) =>
12
+ col.references("accounts.id").onDelete("cascade").notNull(),
13
+ )
14
+ .addColumn("ip_address", "text", (col) => col.notNull())
15
+ .addColumn("expires_at", "timestamptz", (col) =>
16
+ col.defaultTo(sql`NOW() + INTERVAL '90 days'`).notNull(),
17
+ )
18
+ .addColumn("revoked_at", "timestamptz")
19
+ .addColumn("last_used_at", "timestamptz")
20
+ .addColumn("created_at", "timestamptz", (col) =>
21
+ col.defaultTo(sql`NOW()`).notNull(),
22
+ )
23
+ .execute();
24
24
 
25
- await db.schema
26
- .createIndex("sessions_token_hash_idx")
27
- .on("sessions")
28
- .column("token_hash")
29
- .execute();
25
+ await db.schema
26
+ .createIndex("sessions_token_hash_idx")
27
+ .on("sessions")
28
+ .column("token_hash")
29
+ .execute();
30
30
 
31
- await db.schema
32
- .createIndex("sessions_account_id_idx")
33
- .on("sessions")
34
- .column("account_id")
35
- .execute();
31
+ await db.schema
32
+ .createIndex("sessions_account_id_idx")
33
+ .on("sessions")
34
+ .column("account_id")
35
+ .execute();
36
36
  }
37
37
 
38
38
  export async function down(db: Kysely<any>): Promise<void> {
39
- await db.schema.dropIndex("sessions_account_id_idx").ifExists().execute();
40
- await db.schema.dropIndex("sessions_token_hash_idx").ifExists().execute();
41
- await db.schema.dropTable("sessions").ifExists().execute();
39
+ await db.schema.dropIndex("sessions_account_id_idx").ifExists().execute();
40
+ await db.schema.dropIndex("sessions_token_hash_idx").ifExists().execute();
41
+ await db.schema.dropTable("sessions").ifExists().execute();
42
42
  }
@@ -1,9 +1,13 @@
1
1
  import { type Kysely, sql } from "kysely";
2
2
 
3
3
  export async function up(db: Kysely<any>): Promise<void> {
4
- await sql`ALTER TABLE transactions ADD COLUMN IF NOT EXISTS tx_index INTEGER NOT NULL DEFAULT 0`.execute(db);
4
+ await sql`ALTER TABLE transactions ADD COLUMN IF NOT EXISTS tx_index INTEGER NOT NULL DEFAULT 0`.execute(
5
+ db,
6
+ );
5
7
  }
6
8
 
7
9
  export async function down(db: Kysely<any>): Promise<void> {
8
- await sql`ALTER TABLE transactions DROP COLUMN IF EXISTS tx_index`.execute(db);
10
+ await sql`ALTER TABLE transactions DROP COLUMN IF EXISTS tx_index`.execute(
11
+ db,
12
+ );
9
13
  }
@@ -1,30 +1,44 @@
1
1
  import { type Kysely, sql } from "kysely";
2
2
 
3
3
  export async function up(db: Kysely<any>): Promise<void> {
4
- // Enable pg_trgm for fast ILIKE search
5
- await sql`CREATE EXTENSION IF NOT EXISTS pg_trgm`.execute(db);
4
+ // Enable pg_trgm for fast ILIKE search
5
+ await sql`CREATE EXTENSION IF NOT EXISTS pg_trgm`.execute(db);
6
6
 
7
- await db.schema
8
- .createTable("contracts")
9
- .addColumn("contract_id", "text", (c) => c.primaryKey())
10
- .addColumn("name", "text", (c) => c.notNull())
11
- .addColumn("deployer", "text", (c) => c.notNull())
12
- .addColumn("deploy_block", "integer", (c) => c.notNull())
13
- .addColumn("deploy_tx_id", "text", (c) => c.notNull())
14
- .addColumn("call_count", "integer", (c) => c.notNull().defaultTo(0))
15
- .addColumn("last_called_at", "timestamptz")
16
- .addColumn("abi", "jsonb")
17
- .addColumn("abi_fetched_at", "timestamptz")
18
- .addColumn("created_at", "timestamptz", (c) => c.notNull().defaultTo(sql`NOW()`))
19
- .addColumn("updated_at", "timestamptz", (c) => c.notNull().defaultTo(sql`NOW()`))
20
- .execute();
7
+ await db.schema
8
+ .createTable("contracts")
9
+ .addColumn("contract_id", "text", (c) => c.primaryKey())
10
+ .addColumn("name", "text", (c) => c.notNull())
11
+ .addColumn("deployer", "text", (c) => c.notNull())
12
+ .addColumn("deploy_block", "integer", (c) => c.notNull())
13
+ .addColumn("deploy_tx_id", "text", (c) => c.notNull())
14
+ .addColumn("call_count", "integer", (c) => c.notNull().defaultTo(0))
15
+ .addColumn("last_called_at", "timestamptz")
16
+ .addColumn("abi", "jsonb")
17
+ .addColumn("abi_fetched_at", "timestamptz")
18
+ .addColumn("created_at", "timestamptz", (c) =>
19
+ c.notNull().defaultTo(sql`NOW()`),
20
+ )
21
+ .addColumn("updated_at", "timestamptz", (c) =>
22
+ c.notNull().defaultTo(sql`NOW()`),
23
+ )
24
+ .execute();
21
25
 
22
- await db.schema.createIndex("contracts_name_idx").on("contracts").column("name").execute();
23
- await db.schema.createIndex("contracts_deployer_idx").on("contracts").column("deployer").execute();
24
- await sql`CREATE INDEX contracts_name_trgm_idx ON contracts USING gin(name gin_trgm_ops)`.execute(db);
26
+ await db.schema
27
+ .createIndex("contracts_name_idx")
28
+ .on("contracts")
29
+ .column("name")
30
+ .execute();
31
+ await db.schema
32
+ .createIndex("contracts_deployer_idx")
33
+ .on("contracts")
34
+ .column("deployer")
35
+ .execute();
36
+ await sql`CREATE INDEX contracts_name_trgm_idx ON contracts USING gin(name gin_trgm_ops)`.execute(
37
+ db,
38
+ );
25
39
 
26
- // Backfill step 1: insert deployed contracts from transactions
27
- await sql`
40
+ // Backfill step 1: insert deployed contracts from transactions
41
+ await sql`
28
42
  INSERT INTO contracts (contract_id, name, deployer, deploy_block, deploy_tx_id, created_at)
29
43
  SELECT DISTINCT ON (contract_id)
30
44
  contract_id,
@@ -39,8 +53,8 @@ export async function up(db: Kysely<any>): Promise<void> {
39
53
  ON CONFLICT (contract_id) DO NOTHING
40
54
  `.execute(db);
41
55
 
42
- // Backfill step 2: update call counts from contract_call transactions
43
- await sql`
56
+ // Backfill step 2: update call counts from contract_call transactions
57
+ await sql`
44
58
  UPDATE contracts c
45
59
  SET call_count = sub.cnt, last_called_at = sub.last_call
46
60
  FROM (
@@ -54,5 +68,5 @@ export async function up(db: Kysely<any>): Promise<void> {
54
68
  }
55
69
 
56
70
  export async function down(db: Kysely<any>): Promise<void> {
57
- await db.schema.dropTable("contracts").ifExists().cascade().execute();
71
+ await db.schema.dropTable("contracts").ifExists().cascade().execute();
58
72
  }
@@ -1,28 +1,42 @@
1
1
  import { type Kysely, sql } from "kysely";
2
2
 
3
3
  export async function up(db: Kysely<any>): Promise<void> {
4
- await db.schema.dropTable("contracts").ifExists().cascade().execute();
4
+ await db.schema.dropTable("contracts").ifExists().cascade().execute();
5
5
  }
6
6
 
7
7
  export async function down(db: Kysely<any>): Promise<void> {
8
- await sql`CREATE EXTENSION IF NOT EXISTS pg_trgm`.execute(db);
8
+ await sql`CREATE EXTENSION IF NOT EXISTS pg_trgm`.execute(db);
9
9
 
10
- await db.schema
11
- .createTable("contracts")
12
- .addColumn("contract_id", "text", (c) => c.primaryKey())
13
- .addColumn("name", "text", (c) => c.notNull())
14
- .addColumn("deployer", "text", (c) => c.notNull())
15
- .addColumn("deploy_block", "integer", (c) => c.notNull())
16
- .addColumn("deploy_tx_id", "text", (c) => c.notNull())
17
- .addColumn("call_count", "integer", (c) => c.notNull().defaultTo(0))
18
- .addColumn("last_called_at", "timestamptz")
19
- .addColumn("abi", "jsonb")
20
- .addColumn("abi_fetched_at", "timestamptz")
21
- .addColumn("created_at", "timestamptz", (c) => c.notNull().defaultTo(sql`NOW()`))
22
- .addColumn("updated_at", "timestamptz", (c) => c.notNull().defaultTo(sql`NOW()`))
23
- .execute();
10
+ await db.schema
11
+ .createTable("contracts")
12
+ .addColumn("contract_id", "text", (c) => c.primaryKey())
13
+ .addColumn("name", "text", (c) => c.notNull())
14
+ .addColumn("deployer", "text", (c) => c.notNull())
15
+ .addColumn("deploy_block", "integer", (c) => c.notNull())
16
+ .addColumn("deploy_tx_id", "text", (c) => c.notNull())
17
+ .addColumn("call_count", "integer", (c) => c.notNull().defaultTo(0))
18
+ .addColumn("last_called_at", "timestamptz")
19
+ .addColumn("abi", "jsonb")
20
+ .addColumn("abi_fetched_at", "timestamptz")
21
+ .addColumn("created_at", "timestamptz", (c) =>
22
+ c.notNull().defaultTo(sql`NOW()`),
23
+ )
24
+ .addColumn("updated_at", "timestamptz", (c) =>
25
+ c.notNull().defaultTo(sql`NOW()`),
26
+ )
27
+ .execute();
24
28
 
25
- await db.schema.createIndex("contracts_name_idx").on("contracts").column("name").execute();
26
- await db.schema.createIndex("contracts_deployer_idx").on("contracts").column("deployer").execute();
27
- await sql`CREATE INDEX contracts_name_trgm_idx ON contracts USING gin(name gin_trgm_ops)`.execute(db);
29
+ await db.schema
30
+ .createIndex("contracts_name_idx")
31
+ .on("contracts")
32
+ .column("name")
33
+ .execute();
34
+ await db.schema
35
+ .createIndex("contracts_deployer_idx")
36
+ .on("contracts")
37
+ .column("deployer")
38
+ .execute();
39
+ await sql`CREATE INDEX contracts_name_trgm_idx ON contracts USING gin(name gin_trgm_ops)`.execute(
40
+ db,
41
+ );
28
42
  }