@secondlayer/shared 0.8.1 → 0.10.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.
@@ -108,6 +108,8 @@ interface SubgraphsTable {
108
108
  schema_name: string | null;
109
109
  start_block: Generated<number>;
110
110
  last_processed_block: Generated<number>;
111
+ reindex_from_block: number | null;
112
+ reindex_to_block: number | null;
111
113
  last_error: string | null;
112
114
  last_error_at: Date | null;
113
115
  total_processed: Generated<number>;
@@ -160,6 +162,7 @@ interface MagicLinksTable {
160
162
  id: Generated<string>;
161
163
  email: string;
162
164
  token: string;
165
+ code: string | null;
163
166
  expires_at: Date;
164
167
  used_at: Date | null;
165
168
  failed_attempts: Generated<number>;
@@ -94,6 +94,8 @@ interface SubgraphsTable {
94
94
  schema_name: string | null;
95
95
  start_block: Generated<number>;
96
96
  last_processed_block: Generated<number>;
97
+ reindex_from_block: number | null;
98
+ reindex_to_block: number | null;
97
99
  last_error: string | null;
98
100
  last_error_at: Date | null;
99
101
  total_processed: Generated<number>;
@@ -146,6 +148,7 @@ interface MagicLinksTable {
146
148
  id: Generated<string>;
147
149
  email: string;
148
150
  token: string;
151
+ code: string | null;
149
152
  expires_at: Date;
150
153
  used_at: Date | null;
151
154
  failed_attempts: Generated<number>;
@@ -256,10 +259,16 @@ type Account = Selectable<AccountsTable>;
256
259
  declare function upsertAccount(db: Kysely<Database>, email: string): Promise<Account>;
257
260
  declare function getAccountById(db: Kysely<Database>, id: string): Promise<Account | null>;
258
261
  declare function isEmailAllowed(db: Kysely<Database>, email: string): Promise<boolean>;
259
- declare function createMagicLink(db: Kysely<Database>, email: string, token: string, expiresInMs?: number): Promise<void>;
262
+ declare function createMagicLink(db: Kysely<Database>, email: string, token: string, code: string, expiresInMs?: number): Promise<void>;
260
263
  /**
261
264
  * Verify a magic link token. Returns the email if valid, null otherwise.
262
- * Marks the token as used atomically. Rejects after 5 failed attempts.
265
+ * Marks the token as used atomically. Rejects after 3 failed attempts.
263
266
  */
264
267
  declare function verifyMagicLink(db: Kysely<Database>, token: string): Promise<string | null>;
265
- export { verifyMagicLink, upsertAccount, isEmailAllowed, getAccountById, createMagicLink };
268
+ /**
269
+ * Verify by 6-digit code + email. Same atomic pattern as verifyMagicLink.
270
+ * Rejects after 3 failed attempts. Increments failed_attempts on all
271
+ * active codes for this email on failure (prevents parallel brute-force).
272
+ */
273
+ declare function verifyMagicLinkByCode(db: Kysely<Database>, email: string, code: string): Promise<string | null>;
274
+ export { verifyMagicLinkByCode, verifyMagicLink, upsertAccount, isEmailAllowed, getAccountById, createMagicLink };
@@ -31,21 +31,30 @@ async function isEmailAllowed(db, email) {
31
31
  `.execute(db);
32
32
  return result.rows.length > 0;
33
33
  }
34
- async function createMagicLink(db, email, token, expiresInMs = 15 * 60 * 1000) {
34
+ async function createMagicLink(db, email, token, code, expiresInMs = 15 * 60 * 1000) {
35
35
  await db.insertInto("magic_links").values({
36
36
  email,
37
37
  token,
38
+ code,
38
39
  expires_at: new Date(Date.now() + expiresInMs)
39
40
  }).execute();
40
41
  }
41
42
  async function verifyMagicLink(db, token) {
42
- const result = await db.updateTable("magic_links").set({ used_at: new Date }).where("token", "=", token).where("used_at", "is", null).where("expires_at", ">", new Date).where("failed_attempts", "<", 5).returning("email").executeTakeFirst();
43
+ const result = await db.updateTable("magic_links").set({ used_at: new Date }).where("token", "=", token).where("used_at", "is", null).where("expires_at", ">", new Date).where("failed_attempts", "<", 3).returning("email").executeTakeFirst();
43
44
  if (result?.email)
44
45
  return result.email;
45
46
  await db.updateTable("magic_links").set({ failed_attempts: sql`failed_attempts + 1` }).where("token", "=", token).where("used_at", "is", null).where("expires_at", ">", new Date).execute();
46
47
  return null;
47
48
  }
49
+ async function verifyMagicLinkByCode(db, email, code) {
50
+ const result = await db.updateTable("magic_links").set({ used_at: new Date }).where("email", "=", email).where("code", "=", code).where("used_at", "is", null).where("expires_at", ">", new Date).where("failed_attempts", "<", 3).returning("email").executeTakeFirst();
51
+ if (result?.email)
52
+ return result.email;
53
+ await db.updateTable("magic_links").set({ failed_attempts: sql`failed_attempts + 1` }).where("email", "=", email).where("used_at", "is", null).where("expires_at", ">", new Date).execute();
54
+ return null;
55
+ }
48
56
  export {
57
+ verifyMagicLinkByCode,
49
58
  verifyMagicLink,
50
59
  upsertAccount,
51
60
  isEmailAllowed,
@@ -53,5 +62,5 @@ export {
53
62
  createMagicLink
54
63
  };
55
64
 
56
- //# debugId=20A55F621EB14D5064756E2164756E21
65
+ //# debugId=8F0ACA05832385B164756E2164756E21
57
66
  //# sourceMappingURL=accounts.js.map
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/db/queries/accounts.ts"],
4
4
  "sourcesContent": [
5
- "import { type Kysely, sql } from \"kysely\";\nimport type { Account, Database } from \"../types.ts\";\n\nexport async function upsertAccount(\n\tdb: Kysely<Database>,\n\temail: string,\n): Promise<Account> {\n\treturn await db\n\t\t.insertInto(\"accounts\")\n\t\t.values({ email })\n\t\t.onConflict(\n\t\t\t(oc) => oc.column(\"email\").doUpdateSet({ email }), // no-op update to return existing\n\t\t)\n\t\t.returningAll()\n\t\t.executeTakeFirstOrThrow();\n}\n\nexport async function getAccountById(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<Account | null> {\n\treturn (\n\t\t(await db\n\t\t\t.selectFrom(\"accounts\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst()) ?? null\n\t);\n}\n\nexport async function isEmailAllowed(\n\tdb: Kysely<Database>,\n\temail: string,\n): Promise<boolean> {\n\tconst result = await sql<{ found: number }>`\n SELECT 1 AS found FROM accounts WHERE email = ${email}\n UNION ALL\n SELECT 1 AS found FROM waitlist WHERE email = ${email} AND status = 'approved'\n LIMIT 1\n `.execute(db);\n\n\treturn result.rows.length > 0;\n}\n\nexport async function createMagicLink(\n\tdb: Kysely<Database>,\n\temail: string,\n\ttoken: string,\n\texpiresInMs: number = 15 * 60 * 1000,\n): Promise<void> {\n\tawait db\n\t\t.insertInto(\"magic_links\")\n\t\t.values({\n\t\t\temail,\n\t\t\ttoken,\n\t\t\texpires_at: new Date(Date.now() + expiresInMs),\n\t\t})\n\t\t.execute();\n}\n\n/**\n * Verify a magic link token. Returns the email if valid, null otherwise.\n * Marks the token as used atomically. Rejects after 5 failed attempts.\n */\nexport async function verifyMagicLink(\n\tdb: Kysely<Database>,\n\ttoken: string,\n): Promise<string | null> {\n\tconst result = await db\n\t\t.updateTable(\"magic_links\")\n\t\t.set({ used_at: new Date() })\n\t\t.where(\"token\", \"=\", token)\n\t\t.where(\"used_at\", \"is\", null)\n\t\t.where(\"expires_at\", \">\", new Date())\n\t\t.where(\"failed_attempts\", \"<\", 5)\n\t\t.returning(\"email\")\n\t\t.executeTakeFirst();\n\n\tif (result?.email) return result.email;\n\n\t// Increment failed attempts if token exists but didn't verify\n\tawait db\n\t\t.updateTable(\"magic_links\")\n\t\t.set({ failed_attempts: sql`failed_attempts + 1` })\n\t\t.where(\"token\", \"=\", token)\n\t\t.where(\"used_at\", \"is\", null)\n\t\t.where(\"expires_at\", \">\", new Date())\n\t\t.execute();\n\n\treturn null;\n}\n"
5
+ "import { type Kysely, sql } from \"kysely\";\nimport type { Account, Database } from \"../types.ts\";\n\nexport async function upsertAccount(\n\tdb: Kysely<Database>,\n\temail: string,\n): Promise<Account> {\n\treturn await db\n\t\t.insertInto(\"accounts\")\n\t\t.values({ email })\n\t\t.onConflict(\n\t\t\t(oc) => oc.column(\"email\").doUpdateSet({ email }), // no-op update to return existing\n\t\t)\n\t\t.returningAll()\n\t\t.executeTakeFirstOrThrow();\n}\n\nexport async function getAccountById(\n\tdb: Kysely<Database>,\n\tid: string,\n): Promise<Account | null> {\n\treturn (\n\t\t(await db\n\t\t\t.selectFrom(\"accounts\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst()) ?? null\n\t);\n}\n\nexport async function isEmailAllowed(\n\tdb: Kysely<Database>,\n\temail: string,\n): Promise<boolean> {\n\tconst result = await sql<{ found: number }>`\n SELECT 1 AS found FROM accounts WHERE email = ${email}\n UNION ALL\n SELECT 1 AS found FROM waitlist WHERE email = ${email} AND status = 'approved'\n LIMIT 1\n `.execute(db);\n\n\treturn result.rows.length > 0;\n}\n\nexport async function createMagicLink(\n\tdb: Kysely<Database>,\n\temail: string,\n\ttoken: string,\n\tcode: string,\n\texpiresInMs: number = 15 * 60 * 1000,\n): Promise<void> {\n\tawait db\n\t\t.insertInto(\"magic_links\")\n\t\t.values({\n\t\t\temail,\n\t\t\ttoken,\n\t\t\tcode,\n\t\t\texpires_at: new Date(Date.now() + expiresInMs),\n\t\t})\n\t\t.execute();\n}\n\n/**\n * Verify a magic link token. Returns the email if valid, null otherwise.\n * Marks the token as used atomically. Rejects after 3 failed attempts.\n */\nexport async function verifyMagicLink(\n\tdb: Kysely<Database>,\n\ttoken: string,\n): Promise<string | null> {\n\tconst result = await db\n\t\t.updateTable(\"magic_links\")\n\t\t.set({ used_at: new Date() })\n\t\t.where(\"token\", \"=\", token)\n\t\t.where(\"used_at\", \"is\", null)\n\t\t.where(\"expires_at\", \">\", new Date())\n\t\t.where(\"failed_attempts\", \"<\", 3)\n\t\t.returning(\"email\")\n\t\t.executeTakeFirst();\n\n\tif (result?.email) return result.email;\n\n\t// Increment failed attempts if token exists but didn't verify\n\tawait db\n\t\t.updateTable(\"magic_links\")\n\t\t.set({ failed_attempts: sql`failed_attempts + 1` })\n\t\t.where(\"token\", \"=\", token)\n\t\t.where(\"used_at\", \"is\", null)\n\t\t.where(\"expires_at\", \">\", new Date())\n\t\t.execute();\n\n\treturn null;\n}\n\n/**\n * Verify by 6-digit code + email. Same atomic pattern as verifyMagicLink.\n * Rejects after 3 failed attempts. Increments failed_attempts on all\n * active codes for this email on failure (prevents parallel brute-force).\n */\nexport async function verifyMagicLinkByCode(\n\tdb: Kysely<Database>,\n\temail: string,\n\tcode: string,\n): Promise<string | null> {\n\tconst result = await db\n\t\t.updateTable(\"magic_links\")\n\t\t.set({ used_at: new Date() })\n\t\t.where(\"email\", \"=\", email)\n\t\t.where(\"code\", \"=\", code)\n\t\t.where(\"used_at\", \"is\", null)\n\t\t.where(\"expires_at\", \">\", new Date())\n\t\t.where(\"failed_attempts\", \"<\", 3)\n\t\t.returning(\"email\")\n\t\t.executeTakeFirst();\n\n\tif (result?.email) return result.email;\n\n\t// Increment failed attempts on all active codes for this email\n\tawait db\n\t\t.updateTable(\"magic_links\")\n\t\t.set({ failed_attempts: sql`failed_attempts + 1` })\n\t\t.where(\"email\", \"=\", email)\n\t\t.where(\"used_at\", \"is\", null)\n\t\t.where(\"expires_at\", \">\", new Date())\n\t\t.execute();\n\n\treturn null;\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAGA,eAAsB,aAAa,CAClC,IACA,OACmB;AAAA,EACnB,OAAO,MAAM,GACX,WAAW,UAAU,EACrB,OAAO,EAAE,MAAM,CAAC,EAChB,WACA,CAAC,OAAO,GAAG,OAAO,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,CACjD,EACC,aAAa,EACb,wBAAwB;AAAA;AAG3B,eAAsB,cAAc,CACnC,IACA,IAC0B;AAAA,EAC1B,OACE,MAAM,GACL,WAAW,UAAU,EACrB,UAAU,EACV,MAAM,MAAM,KAAK,EAAE,EACnB,iBAAiB,KAAM;AAAA;AAI3B,eAAsB,cAAc,CACnC,IACA,OACmB;AAAA,EACnB,MAAM,SAAS,MAAM;AAAA,oDAC8B;AAAA;AAAA,oDAEA;AAAA;AAAA,IAEhD,QAAQ,EAAE;AAAA,EAEb,OAAO,OAAO,KAAK,SAAS;AAAA;AAG7B,eAAsB,eAAe,CACpC,IACA,OACA,OACA,cAAsB,KAAK,KAAK,MAChB;AAAA,EAChB,MAAM,GACJ,WAAW,aAAa,EACxB,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW;AAAA,EAC9C,CAAC,EACA,QAAQ;AAAA;AAOX,eAAsB,eAAe,CACpC,IACA,OACyB;AAAA,EACzB,MAAM,SAAS,MAAM,GACnB,YAAY,aAAa,EACzB,IAAI,EAAE,SAAS,IAAI,KAAO,CAAC,EAC3B,MAAM,SAAS,KAAK,KAAK,EACzB,MAAM,WAAW,MAAM,IAAI,EAC3B,MAAM,cAAc,KAAK,IAAI,IAAM,EACnC,MAAM,mBAAmB,KAAK,CAAC,EAC/B,UAAU,OAAO,EACjB,iBAAiB;AAAA,EAEnB,IAAI,QAAQ;AAAA,IAAO,OAAO,OAAO;AAAA,EAGjC,MAAM,GACJ,YAAY,aAAa,EACzB,IAAI,EAAE,iBAAiB,yBAAyB,CAAC,EACjD,MAAM,SAAS,KAAK,KAAK,EACzB,MAAM,WAAW,MAAM,IAAI,EAC3B,MAAM,cAAc,KAAK,IAAI,IAAM,EACnC,QAAQ;AAAA,EAEV,OAAO;AAAA;",
8
- "debugId": "20A55F621EB14D5064756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAGA,eAAsB,aAAa,CAClC,IACA,OACmB;AAAA,EACnB,OAAO,MAAM,GACX,WAAW,UAAU,EACrB,OAAO,EAAE,MAAM,CAAC,EAChB,WACA,CAAC,OAAO,GAAG,OAAO,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,CACjD,EACC,aAAa,EACb,wBAAwB;AAAA;AAG3B,eAAsB,cAAc,CACnC,IACA,IAC0B;AAAA,EAC1B,OACE,MAAM,GACL,WAAW,UAAU,EACrB,UAAU,EACV,MAAM,MAAM,KAAK,EAAE,EACnB,iBAAiB,KAAM;AAAA;AAI3B,eAAsB,cAAc,CACnC,IACA,OACmB;AAAA,EACnB,MAAM,SAAS,MAAM;AAAA,oDAC8B;AAAA;AAAA,oDAEA;AAAA;AAAA,IAEhD,QAAQ,EAAE;AAAA,EAEb,OAAO,OAAO,KAAK,SAAS;AAAA;AAG7B,eAAsB,eAAe,CACpC,IACA,OACA,OACA,MACA,cAAsB,KAAK,KAAK,MAChB;AAAA,EAChB,MAAM,GACJ,WAAW,aAAa,EACxB,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW;AAAA,EAC9C,CAAC,EACA,QAAQ;AAAA;AAOX,eAAsB,eAAe,CACpC,IACA,OACyB;AAAA,EACzB,MAAM,SAAS,MAAM,GACnB,YAAY,aAAa,EACzB,IAAI,EAAE,SAAS,IAAI,KAAO,CAAC,EAC3B,MAAM,SAAS,KAAK,KAAK,EACzB,MAAM,WAAW,MAAM,IAAI,EAC3B,MAAM,cAAc,KAAK,IAAI,IAAM,EACnC,MAAM,mBAAmB,KAAK,CAAC,EAC/B,UAAU,OAAO,EACjB,iBAAiB;AAAA,EAEnB,IAAI,QAAQ;AAAA,IAAO,OAAO,OAAO;AAAA,EAGjC,MAAM,GACJ,YAAY,aAAa,EACzB,IAAI,EAAE,iBAAiB,yBAAyB,CAAC,EACjD,MAAM,SAAS,KAAK,KAAK,EACzB,MAAM,WAAW,MAAM,IAAI,EAC3B,MAAM,cAAc,KAAK,IAAI,IAAM,EACnC,QAAQ;AAAA,EAEV,OAAO;AAAA;AAQR,eAAsB,qBAAqB,CAC1C,IACA,OACA,MACyB;AAAA,EACzB,MAAM,SAAS,MAAM,GACnB,YAAY,aAAa,EACzB,IAAI,EAAE,SAAS,IAAI,KAAO,CAAC,EAC3B,MAAM,SAAS,KAAK,KAAK,EACzB,MAAM,QAAQ,KAAK,IAAI,EACvB,MAAM,WAAW,MAAM,IAAI,EAC3B,MAAM,cAAc,KAAK,IAAI,IAAM,EACnC,MAAM,mBAAmB,KAAK,CAAC,EAC/B,UAAU,OAAO,EACjB,iBAAiB;AAAA,EAEnB,IAAI,QAAQ;AAAA,IAAO,OAAO,OAAO;AAAA,EAGjC,MAAM,GACJ,YAAY,aAAa,EACzB,IAAI,EAAE,iBAAiB,yBAAyB,CAAC,EACjD,MAAM,SAAS,KAAK,KAAK,EACzB,MAAM,WAAW,MAAM,IAAI,EAC3B,MAAM,cAAc,KAAK,IAAI,IAAM,EACnC,QAAQ;AAAA,EAEV,OAAO;AAAA;",
8
+ "debugId": "8F0ACA05832385B164756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -94,6 +94,8 @@ interface SubgraphsTable {
94
94
  schema_name: string | null;
95
95
  start_block: Generated<number>;
96
96
  last_processed_block: Generated<number>;
97
+ reindex_from_block: number | null;
98
+ reindex_to_block: number | null;
97
99
  last_error: string | null;
98
100
  last_error_at: Date | null;
99
101
  total_processed: Generated<number>;
@@ -146,6 +148,7 @@ interface MagicLinksTable {
146
148
  id: Generated<string>;
147
149
  email: string;
148
150
  token: string;
151
+ code: string | null;
149
152
  expires_at: Date;
150
153
  used_at: Date | null;
151
154
  failed_attempts: Generated<number>;
@@ -94,6 +94,8 @@ interface SubgraphsTable {
94
94
  schema_name: string | null;
95
95
  start_block: Generated<number>;
96
96
  last_processed_block: Generated<number>;
97
+ reindex_from_block: number | null;
98
+ reindex_to_block: number | null;
97
99
  last_error: string | null;
98
100
  last_error_at: Date | null;
99
101
  total_processed: Generated<number>;
@@ -146,6 +148,7 @@ interface MagicLinksTable {
146
148
  id: Generated<string>;
147
149
  email: string;
148
150
  token: string;
151
+ code: string | null;
149
152
  expires_at: Date;
150
153
  used_at: Date | null;
151
154
  failed_attempts: Generated<number>;
@@ -94,6 +94,8 @@ interface SubgraphsTable {
94
94
  schema_name: string | null;
95
95
  start_block: Generated<number>;
96
96
  last_processed_block: Generated<number>;
97
+ reindex_from_block: number | null;
98
+ reindex_to_block: number | null;
97
99
  last_error: string | null;
98
100
  last_error_at: Date | null;
99
101
  total_processed: Generated<number>;
@@ -146,6 +148,7 @@ interface MagicLinksTable {
146
148
  id: Generated<string>;
147
149
  email: string;
148
150
  token: string;
151
+ code: string | null;
149
152
  expires_at: Date;
150
153
  used_at: Date | null;
151
154
  failed_attempts: Generated<number>;
@@ -94,6 +94,8 @@ interface SubgraphsTable {
94
94
  schema_name: string | null;
95
95
  start_block: Generated<number>;
96
96
  last_processed_block: Generated<number>;
97
+ reindex_from_block: number | null;
98
+ reindex_to_block: number | null;
97
99
  last_error: string | null;
98
100
  last_error_at: Date | null;
99
101
  total_processed: Generated<number>;
@@ -146,6 +148,7 @@ interface MagicLinksTable {
146
148
  id: Generated<string>;
147
149
  email: string;
148
150
  token: string;
151
+ code: string | null;
149
152
  expires_at: Date;
150
153
  used_at: Date | null;
151
154
  failed_attempts: Generated<number>;
@@ -102,6 +102,8 @@ interface SubgraphsTable {
102
102
  schema_name: string | null;
103
103
  start_block: Generated<number>;
104
104
  last_processed_block: Generated<number>;
105
+ reindex_from_block: number | null;
106
+ reindex_to_block: number | null;
105
107
  last_error: string | null;
106
108
  last_error_at: Date | null;
107
109
  total_processed: Generated<number>;
@@ -154,6 +156,7 @@ interface MagicLinksTable {
154
156
  id: Generated<string>;
155
157
  email: string;
156
158
  token: string;
159
+ code: string | null;
157
160
  expires_at: Date;
158
161
  used_at: Date | null;
159
162
  failed_attempts: Generated<number>;
@@ -93,6 +93,8 @@ interface SubgraphsTable {
93
93
  schema_name: string | null;
94
94
  start_block: Generated<number>;
95
95
  last_processed_block: Generated<number>;
96
+ reindex_from_block: number | null;
97
+ reindex_to_block: number | null;
96
98
  last_error: string | null;
97
99
  last_error_at: Date | null;
98
100
  total_processed: Generated<number>;
@@ -145,6 +147,7 @@ interface MagicLinksTable {
145
147
  id: Generated<string>;
146
148
  email: string;
147
149
  token: string;
150
+ code: string | null;
148
151
  expires_at: Date;
149
152
  used_at: Date | null;
150
153
  failed_attempts: Generated<number>;
@@ -93,6 +93,8 @@ interface SubgraphsTable {
93
93
  schema_name: string | null;
94
94
  start_block: Generated<number>;
95
95
  last_processed_block: Generated<number>;
96
+ reindex_from_block: number | null;
97
+ reindex_to_block: number | null;
96
98
  last_error: string | null;
97
99
  last_error_at: Date | null;
98
100
  total_processed: Generated<number>;
@@ -145,6 +147,7 @@ interface MagicLinksTable {
145
147
  id: Generated<string>;
146
148
  email: string;
147
149
  token: string;
150
+ code: string | null;
148
151
  expires_at: Date;
149
152
  used_at: Date | null;
150
153
  failed_attempts: Generated<number>;
@@ -94,6 +94,8 @@ interface SubgraphsTable {
94
94
  schema_name: string | null;
95
95
  start_block: Generated<number>;
96
96
  last_processed_block: Generated<number>;
97
+ reindex_from_block: number | null;
98
+ reindex_to_block: number | null;
97
99
  last_error: string | null;
98
100
  last_error_at: Date | null;
99
101
  total_processed: Generated<number>;
@@ -146,6 +148,7 @@ interface MagicLinksTable {
146
148
  id: Generated<string>;
147
149
  email: string;
148
150
  token: string;
151
+ code: string | null;
149
152
  expires_at: Date;
150
153
  used_at: Date | null;
151
154
  failed_attempts: Generated<number>;
@@ -0,0 +1,11 @@
1
+ import { type Kysely, sql } from "kysely";
2
+
3
+ export async function up(db: Kysely<unknown>): Promise<void> {
4
+ await sql`ALTER TABLE magic_links ADD COLUMN IF NOT EXISTS code text`.execute(
5
+ db,
6
+ );
7
+ }
8
+
9
+ export async function down(db: Kysely<unknown>): Promise<void> {
10
+ await sql`ALTER TABLE magic_links DROP COLUMN IF EXISTS code`.execute(db);
11
+ }
@@ -0,0 +1,19 @@
1
+ import { type Kysely, sql } from "kysely";
2
+
3
+ export async function up(db: Kysely<unknown>): Promise<void> {
4
+ await sql`ALTER TABLE subgraphs ADD COLUMN IF NOT EXISTS reindex_from_block bigint`.execute(
5
+ db,
6
+ );
7
+ await sql`ALTER TABLE subgraphs ADD COLUMN IF NOT EXISTS reindex_to_block bigint`.execute(
8
+ db,
9
+ );
10
+ }
11
+
12
+ export async function down(db: Kysely<unknown>): Promise<void> {
13
+ await sql`ALTER TABLE subgraphs DROP COLUMN IF EXISTS reindex_from_block`.execute(
14
+ db,
15
+ );
16
+ await sql`ALTER TABLE subgraphs DROP COLUMN IF EXISTS reindex_to_block`.execute(
17
+ db,
18
+ );
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/shared",
3
- "version": "0.8.1",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "main": "./dist/src/index.js",
6
6
  "types": "./dist/src/index.d.ts",