@secondlayer/shared 1.1.0 → 2.1.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 (67) hide show
  1. package/dist/src/db/index.d.ts +89 -6
  2. package/dist/src/db/index.js +53 -29
  3. package/dist/src/db/index.js.map +4 -4
  4. package/dist/src/db/jsonb.js.map +2 -2
  5. package/dist/src/db/queries/accounts.d.ts +58 -2
  6. package/dist/src/db/queries/integrity.d.ts +58 -2
  7. package/dist/src/db/queries/projects.d.ts +58 -2
  8. package/dist/src/db/queries/projects.js.map +2 -2
  9. package/dist/src/db/queries/{marketplace.d.ts → provisioning-audit.d.ts} +79 -56
  10. package/dist/src/db/queries/provisioning-audit.js +40 -0
  11. package/dist/src/db/queries/provisioning-audit.js.map +10 -0
  12. package/dist/src/db/queries/subgraph-gaps.d.ts +58 -2
  13. package/dist/src/db/queries/subgraphs.d.ts +62 -5
  14. package/dist/src/db/queries/subgraphs.js +3 -9
  15. package/dist/src/db/queries/subgraphs.js.map +4 -4
  16. package/dist/src/db/queries/tenants.d.ts +527 -0
  17. package/dist/src/db/queries/tenants.js +220 -0
  18. package/dist/src/db/queries/tenants.js.map +11 -0
  19. package/dist/src/db/queries/usage.d.ts +58 -2
  20. package/dist/src/db/queries/usage.js +3 -3
  21. package/dist/src/db/queries/usage.js.map +3 -3
  22. package/dist/src/db/queries/workflows.d.ts +58 -2
  23. package/dist/src/db/queries/workflows.js +31 -3
  24. package/dist/src/db/queries/workflows.js.map +4 -4
  25. package/dist/src/db/schema.d.ts +67 -3
  26. package/dist/src/env.d.ts +10 -0
  27. package/dist/src/env.js +3 -1
  28. package/dist/src/env.js.map +3 -3
  29. package/dist/src/errors.d.ts +17 -3
  30. package/dist/src/errors.js +34 -3
  31. package/dist/src/errors.js.map +3 -3
  32. package/dist/src/index.d.ts +142 -84
  33. package/dist/src/index.js +146 -99
  34. package/dist/src/index.js.map +8 -8
  35. package/dist/src/logger.js +3 -1
  36. package/dist/src/logger.js.map +3 -3
  37. package/dist/src/mode.d.ts +29 -0
  38. package/dist/src/mode.js +43 -0
  39. package/dist/src/mode.js.map +10 -0
  40. package/dist/src/node/archive-client.js +3 -1
  41. package/dist/src/node/archive-client.js.map +3 -3
  42. package/dist/src/node/hiro-client.js +3 -1
  43. package/dist/src/node/hiro-client.js.map +3 -3
  44. package/dist/src/node/local-client.d.ts +58 -2
  45. package/dist/src/queue/listener.d.ts +11 -2
  46. package/dist/src/queue/listener.js +11 -12
  47. package/dist/src/queue/listener.js.map +3 -3
  48. package/dist/src/schemas/accounts.d.ts +14 -0
  49. package/dist/src/schemas/{marketplace.js → accounts.js} +4 -14
  50. package/dist/src/schemas/accounts.js.map +10 -0
  51. package/dist/src/schemas/index.d.ts +28 -77
  52. package/dist/src/schemas/index.js +59 -69
  53. package/dist/src/schemas/index.js.map +4 -4
  54. package/dist/src/types.d.ts +10 -0
  55. package/migrations/0037_nullable_api_key.ts +35 -0
  56. package/migrations/0038_drop_workflow_tables.ts +46 -0
  57. package/migrations/0039_tenants.ts +66 -0
  58. package/migrations/0040_tenant_key_generations.ts +29 -0
  59. package/migrations/0041_subgraphs_drop_api_key_id.ts +49 -0
  60. package/migrations/0042_tenant_project_id.ts +25 -0
  61. package/migrations/0043_tenant_usage_monthly.ts +36 -0
  62. package/migrations/0044_provisioning_audit_log.ts +40 -0
  63. package/package.json +15 -7
  64. package/dist/src/db/queries/marketplace.js +0 -142
  65. package/dist/src/db/queries/marketplace.js.map +0 -10
  66. package/dist/src/schemas/marketplace.d.ts +0 -63
  67. package/dist/src/schemas/marketplace.js.map +0 -10
@@ -0,0 +1,36 @@
1
+ import { type Kysely, sql } from "kysely";
2
+
3
+ /**
4
+ * Monthly usage snapshots for tenants. Billing lands later; this table
5
+ * captures the raw measurements so we can backfill charges once pricing
6
+ * ships.
7
+ *
8
+ * One row per (tenant_id, period_month). The period_month is the first
9
+ * day of the calendar month in UTC (e.g. 2026-04-01). `storage_peak_mb`
10
+ * is the max observation within the period; `measurements` counts how
11
+ * many samples fed into peak/avg so we can judge confidence.
12
+ */
13
+ export async function up(db: Kysely<unknown>): Promise<void> {
14
+ await sql`
15
+ CREATE TABLE tenant_usage_monthly (
16
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
17
+ tenant_id uuid NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
18
+ period_month date NOT NULL,
19
+ storage_peak_mb integer NOT NULL DEFAULT 0,
20
+ storage_avg_mb integer NOT NULL DEFAULT 0,
21
+ storage_last_mb integer NOT NULL DEFAULT 0,
22
+ measurements integer NOT NULL DEFAULT 0,
23
+ first_at timestamptz NOT NULL DEFAULT now(),
24
+ last_at timestamptz NOT NULL DEFAULT now(),
25
+ UNIQUE (tenant_id, period_month)
26
+ )
27
+ `.execute(db);
28
+ await sql`
29
+ CREATE INDEX tenant_usage_monthly_period_idx
30
+ ON tenant_usage_monthly (period_month DESC)
31
+ `.execute(db);
32
+ }
33
+
34
+ export async function down(db: Kysely<unknown>): Promise<void> {
35
+ await sql`DROP TABLE IF EXISTS tenant_usage_monthly`.execute(db);
36
+ }
@@ -0,0 +1,40 @@
1
+ import { type Kysely, sql } from "kysely";
2
+
3
+ /**
4
+ * Audit trail of provisioning-facing lifecycle events. Captures what
5
+ * happened, who triggered it, and the outcome — source of truth for
6
+ * post-incident review and billing disputes.
7
+ *
8
+ * `tenant_id` is nullable so provision-start rows (where the tenant row
9
+ * does not yet exist) can be recorded alongside lifecycle events on an
10
+ * existing tenant.
11
+ */
12
+ export async function up(db: Kysely<unknown>): Promise<void> {
13
+ await sql`
14
+ CREATE TABLE provisioning_audit_log (
15
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
16
+ tenant_id uuid REFERENCES tenants(id) ON DELETE SET NULL,
17
+ tenant_slug text,
18
+ account_id uuid REFERENCES accounts(id) ON DELETE SET NULL,
19
+ actor text NOT NULL,
20
+ event text NOT NULL,
21
+ status text NOT NULL,
22
+ detail jsonb,
23
+ error text,
24
+ created_at timestamptz NOT NULL DEFAULT now()
25
+ )
26
+ `.execute(db);
27
+ await sql`CREATE INDEX provisioning_audit_tenant_idx ON provisioning_audit_log (tenant_id, created_at DESC)`.execute(
28
+ db,
29
+ );
30
+ await sql`CREATE INDEX provisioning_audit_account_idx ON provisioning_audit_log (account_id, created_at DESC)`.execute(
31
+ db,
32
+ );
33
+ await sql`CREATE INDEX provisioning_audit_event_idx ON provisioning_audit_log (event, created_at DESC)`.execute(
34
+ db,
35
+ );
36
+ }
37
+
38
+ export async function down(db: Kysely<unknown>): Promise<void> {
39
+ await sql`DROP TABLE IF EXISTS provisioning_audit_log`.execute(db);
40
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/shared",
3
- "version": "1.1.0",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "main": "./dist/src/index.js",
6
6
  "types": "./dist/src/index.d.ts",
@@ -61,9 +61,9 @@
61
61
  "types": "./dist/src/schemas/subgraphs.d.ts",
62
62
  "import": "./dist/src/schemas/subgraphs.js"
63
63
  },
64
- "./schemas/marketplace": {
65
- "types": "./dist/src/schemas/marketplace.d.ts",
66
- "import": "./dist/src/schemas/marketplace.js"
64
+ "./schemas/accounts": {
65
+ "types": "./dist/src/schemas/accounts.d.ts",
66
+ "import": "./dist/src/schemas/accounts.js"
67
67
  },
68
68
  "./schemas/workflows": {
69
69
  "types": "./dist/src/schemas/workflows.d.ts",
@@ -73,14 +73,18 @@
73
73
  "types": "./dist/src/db/queries/workflows.d.ts",
74
74
  "import": "./dist/src/db/queries/workflows.js"
75
75
  },
76
- "./db/queries/marketplace": {
77
- "types": "./dist/src/db/queries/marketplace.d.ts",
78
- "import": "./dist/src/db/queries/marketplace.js"
76
+ "./db/queries/tenants": {
77
+ "types": "./dist/src/db/queries/tenants.d.ts",
78
+ "import": "./dist/src/db/queries/tenants.js"
79
79
  },
80
80
  "./db/queries/projects": {
81
81
  "types": "./dist/src/db/queries/projects.d.ts",
82
82
  "import": "./dist/src/db/queries/projects.js"
83
83
  },
84
+ "./db/queries/provisioning-audit": {
85
+ "types": "./dist/src/db/queries/provisioning-audit.d.ts",
86
+ "import": "./dist/src/db/queries/provisioning-audit.js"
87
+ },
84
88
  "./types": {
85
89
  "types": "./dist/src/types.d.ts",
86
90
  "import": "./dist/src/types.js"
@@ -89,6 +93,10 @@
89
93
  "types": "./dist/src/env.d.ts",
90
94
  "import": "./dist/src/env.js"
91
95
  },
96
+ "./mode": {
97
+ "types": "./dist/src/mode.d.ts",
98
+ "import": "./dist/src/mode.js"
99
+ },
92
100
  "./logger": {
93
101
  "types": "./dist/src/logger.d.ts",
94
102
  "import": "./dist/src/logger.js"
@@ -1,142 +0,0 @@
1
- import { createRequire } from "node:module";
2
- var __defProp = Object.defineProperty;
3
- var __returnValue = (v) => v;
4
- function __exportSetter(name, newValue) {
5
- this[name] = __returnValue.bind(null, newValue);
6
- }
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, {
10
- get: all[name],
11
- enumerable: true,
12
- configurable: true,
13
- set: __exportSetter.bind(all, name)
14
- });
15
- };
16
-
17
- // src/db/queries/marketplace.ts
18
- import { sql } from "kysely";
19
- async function listPublicSubgraphs(db, opts = {}) {
20
- const limit = Math.min(Math.max(1, opts.limit ?? 50), 100);
21
- const offset = Math.max(0, opts.offset ?? 0);
22
- let query = db.selectFrom("subgraphs").innerJoin("api_keys", "api_keys.id", "subgraphs.api_key_id").innerJoin("accounts", "accounts.id", "api_keys.account_id").select([
23
- "subgraphs.id",
24
- "subgraphs.name",
25
- "subgraphs.description",
26
- "subgraphs.tags",
27
- "subgraphs.status",
28
- "subgraphs.version",
29
- "subgraphs.definition",
30
- "subgraphs.last_processed_block",
31
- "subgraphs.start_block",
32
- "subgraphs.total_processed",
33
- "subgraphs.created_at",
34
- "subgraphs.forked_from_id",
35
- "accounts.display_name",
36
- "accounts.slug",
37
- sql`(SELECT COALESCE(SUM(query_count), 0) FROM subgraph_usage_daily WHERE subgraph_id = subgraphs.id AND date >= CURRENT_DATE - 7)::int`.as("queries_7d"),
38
- sql`(SELECT COUNT(*) FROM subgraphs s2 WHERE s2.forked_from_id = subgraphs.id)::int`.as("fork_count")
39
- ]).where("subgraphs.is_public", "=", true);
40
- if (opts.tags && opts.tags.length > 0) {
41
- query = query.where(sql`subgraphs.tags @> ${sql.val(opts.tags)}::text[]`);
42
- }
43
- if (opts.search) {
44
- const term = `%${opts.search}%`;
45
- query = query.where((eb) => eb.or([
46
- eb("subgraphs.name", "ilike", term),
47
- eb("subgraphs.description", "ilike", term)
48
- ]));
49
- }
50
- if (opts.sort === "popular") {
51
- query = query.orderBy(sql`queries_7d`, "desc");
52
- } else if (opts.sort === "name") {
53
- query = query.orderBy("subgraphs.name", "asc");
54
- } else {
55
- query = query.orderBy("subgraphs.created_at", "desc");
56
- }
57
- let countQuery = db.selectFrom("subgraphs").select(sql`count(*)::int`.as("count")).where("is_public", "=", true);
58
- if (opts.tags && opts.tags.length > 0) {
59
- countQuery = countQuery.where(sql`tags @> ${sql.val(opts.tags)}::text[]`);
60
- }
61
- if (opts.search) {
62
- const term = `%${opts.search}%`;
63
- countQuery = countQuery.where((eb) => eb.or([
64
- eb("name", "ilike", term),
65
- eb("description", "ilike", term)
66
- ]));
67
- }
68
- const [rows, countRow] = await Promise.all([
69
- query.limit(limit).offset(offset).execute(),
70
- countQuery.executeTakeFirst()
71
- ]);
72
- return {
73
- data: rows,
74
- meta: { total: countRow?.count ?? 0, limit, offset }
75
- };
76
- }
77
- async function getPublicSubgraph(db, name) {
78
- return db.selectFrom("subgraphs").innerJoin("api_keys", "api_keys.id", "subgraphs.api_key_id").innerJoin("accounts", "accounts.id", "api_keys.account_id").selectAll("subgraphs").select(["accounts.display_name", "accounts.slug"]).where("subgraphs.name", "=", name).where("subgraphs.is_public", "=", true).executeTakeFirst();
79
- }
80
- async function getCreatorProfile(db, slug) {
81
- const account = await db.selectFrom("accounts").select(["id", "display_name", "bio", "avatar_url", "slug"]).where("slug", "=", slug).executeTakeFirst();
82
- if (!account)
83
- return null;
84
- const subgraphs = await db.selectFrom("subgraphs").innerJoin("api_keys", "api_keys.id", "subgraphs.api_key_id").select([
85
- "subgraphs.id",
86
- "subgraphs.name",
87
- "subgraphs.description",
88
- "subgraphs.tags",
89
- "subgraphs.status",
90
- "subgraphs.version",
91
- "subgraphs.definition",
92
- "subgraphs.last_processed_block",
93
- "subgraphs.start_block",
94
- "subgraphs.total_processed",
95
- "subgraphs.created_at",
96
- sql`(SELECT COALESCE(SUM(query_count), 0) FROM subgraph_usage_daily WHERE subgraph_id = subgraphs.id AND date >= CURRENT_DATE - 7)::int`.as("queries_7d")
97
- ]).where("api_keys.account_id", "=", account.id).where("subgraphs.is_public", "=", true).orderBy("subgraphs.created_at", "desc").execute();
98
- return { account, subgraphs };
99
- }
100
- async function publishSubgraph(db, subgraphId, opts) {
101
- const set = {
102
- is_public: true,
103
- updated_at: new Date
104
- };
105
- if (opts?.tags)
106
- set.tags = sql`${sql.val(opts.tags)}::text[]`;
107
- if (opts?.description !== undefined)
108
- set.description = opts.description;
109
- return db.updateTable("subgraphs").set(set).where("id", "=", subgraphId).returningAll().executeTakeFirstOrThrow();
110
- }
111
- async function unpublishSubgraph(db, subgraphId) {
112
- return db.updateTable("subgraphs").set({ is_public: false, updated_at: new Date }).where("id", "=", subgraphId).returningAll().executeTakeFirstOrThrow();
113
- }
114
- async function incrementSubgraphQueryCount(db, subgraphId) {
115
- const today = new Date().toISOString().slice(0, 10);
116
- await sql`
117
- INSERT INTO subgraph_usage_daily (subgraph_id, date, query_count)
118
- VALUES (${subgraphId}, ${today}, 1)
119
- ON CONFLICT (subgraph_id, date)
120
- DO UPDATE SET query_count = subgraph_usage_daily.query_count + 1
121
- `.execute(db);
122
- }
123
- async function getSubgraphUsageHistory(db, subgraphId, days) {
124
- return db.selectFrom("subgraph_usage_daily").select(["date", "query_count"]).where("subgraph_id", "=", subgraphId).where("date", ">=", sql`CURRENT_DATE - ${days}::int`).orderBy("date", "asc").execute();
125
- }
126
- async function getSubgraphQueryTotal(db, subgraphId, days) {
127
- const row = await db.selectFrom("subgraph_usage_daily").select(sql`COALESCE(SUM(query_count), 0)::int`.as("total")).where("subgraph_id", "=", subgraphId).where("date", ">=", sql`CURRENT_DATE - ${days}::int`).executeTakeFirst();
128
- return row?.total ?? 0;
129
- }
130
- export {
131
- unpublishSubgraph,
132
- publishSubgraph,
133
- listPublicSubgraphs,
134
- incrementSubgraphQueryCount,
135
- getSubgraphUsageHistory,
136
- getSubgraphQueryTotal,
137
- getPublicSubgraph,
138
- getCreatorProfile
139
- };
140
-
141
- //# debugId=3D863C761F66BE2664756E2164756E21
142
- //# sourceMappingURL=marketplace.js.map
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/db/queries/marketplace.ts"],
4
- "sourcesContent": [
5
- "import { type Kysely, sql } from \"kysely\";\nimport type { Database, Subgraph } from \"../types.ts\";\n\n/**\n * List public subgraphs with creator info and usage stats.\n */\nexport async function listPublicSubgraphs(\n\tdb: Kysely<Database>,\n\topts: {\n\t\tlimit?: number;\n\t\toffset?: number;\n\t\ttags?: string[];\n\t\tsearch?: string;\n\t\tsort?: \"recent\" | \"popular\" | \"name\";\n\t} = {},\n): Promise<{ data: any[]; meta: { total: number; limit: number; offset: number } }> {\n\tconst limit = Math.min(Math.max(1, opts.limit ?? 50), 100);\n\tconst offset = Math.max(0, opts.offset ?? 0);\n\n\tlet query = db\n\t\t.selectFrom(\"subgraphs\")\n\t\t.innerJoin(\"api_keys\", \"api_keys.id\", \"subgraphs.api_key_id\")\n\t\t.innerJoin(\"accounts\", \"accounts.id\", \"api_keys.account_id\")\n\t\t.select([\n\t\t\t\"subgraphs.id\",\n\t\t\t\"subgraphs.name\",\n\t\t\t\"subgraphs.description\",\n\t\t\t\"subgraphs.tags\",\n\t\t\t\"subgraphs.status\",\n\t\t\t\"subgraphs.version\",\n\t\t\t\"subgraphs.definition\",\n\t\t\t\"subgraphs.last_processed_block\",\n\t\t\t\"subgraphs.start_block\",\n\t\t\t\"subgraphs.total_processed\",\n\t\t\t\"subgraphs.created_at\",\n\t\t\t\"subgraphs.forked_from_id\",\n\t\t\t\"accounts.display_name\",\n\t\t\t\"accounts.slug\",\n\t\t\tsql<number>`(SELECT COALESCE(SUM(query_count), 0) FROM subgraph_usage_daily WHERE subgraph_id = subgraphs.id AND date >= CURRENT_DATE - 7)::int`.as(\"queries_7d\"),\n\t\t\tsql<number>`(SELECT COUNT(*) FROM subgraphs s2 WHERE s2.forked_from_id = subgraphs.id)::int`.as(\"fork_count\"),\n\t\t])\n\t\t.where(\"subgraphs.is_public\", \"=\", true);\n\n\t// Filter by tags (AND — all must match)\n\tif (opts.tags && opts.tags.length > 0) {\n\t\tquery = query.where(\n\t\t\tsql<boolean>`subgraphs.tags @> ${sql.val(opts.tags)}::text[]`,\n\t\t);\n\t}\n\n\t// Search by name or description\n\tif (opts.search) {\n\t\tconst term = `%${opts.search}%`;\n\t\tquery = query.where((eb) =>\n\t\t\teb.or([\n\t\t\t\teb(\"subgraphs.name\", \"ilike\", term),\n\t\t\t\teb(\"subgraphs.description\", \"ilike\", term),\n\t\t\t]),\n\t\t);\n\t}\n\n\t// Sort\n\tif (opts.sort === \"popular\") {\n\t\tquery = query.orderBy(sql`queries_7d`, \"desc\");\n\t} else if (opts.sort === \"name\") {\n\t\tquery = query.orderBy(\"subgraphs.name\", \"asc\");\n\t} else {\n\t\t// Default: recent\n\t\tquery = query.orderBy(\"subgraphs.created_at\", \"desc\");\n\t}\n\n\t// Count\n\tlet countQuery = db\n\t\t.selectFrom(\"subgraphs\")\n\t\t.select(sql<number>`count(*)::int`.as(\"count\"))\n\t\t.where(\"is_public\", \"=\", true);\n\n\tif (opts.tags && opts.tags.length > 0) {\n\t\tcountQuery = countQuery.where(\n\t\t\tsql<boolean>`tags @> ${sql.val(opts.tags)}::text[]`,\n\t\t);\n\t}\n\tif (opts.search) {\n\t\tconst term = `%${opts.search}%`;\n\t\tcountQuery = countQuery.where((eb) =>\n\t\t\teb.or([\n\t\t\t\teb(\"name\", \"ilike\", term),\n\t\t\t\teb(\"description\", \"ilike\", term),\n\t\t\t]),\n\t\t);\n\t}\n\n\tconst [rows, countRow] = await Promise.all([\n\t\tquery.limit(limit).offset(offset).execute(),\n\t\tcountQuery.executeTakeFirst(),\n\t]);\n\n\treturn {\n\t\tdata: rows,\n\t\tmeta: { total: countRow?.count ?? 0, limit, offset },\n\t};\n}\n\n/**\n * Get a single public subgraph by name with creator info.\n */\nexport async function getPublicSubgraph(db: Kysely<Database>, name: string): Promise<any | undefined> {\n\treturn db\n\t\t.selectFrom(\"subgraphs\")\n\t\t.innerJoin(\"api_keys\", \"api_keys.id\", \"subgraphs.api_key_id\")\n\t\t.innerJoin(\"accounts\", \"accounts.id\", \"api_keys.account_id\")\n\t\t.selectAll(\"subgraphs\")\n\t\t.select([\"accounts.display_name\", \"accounts.slug\"])\n\t\t.where(\"subgraphs.name\", \"=\", name)\n\t\t.where(\"subgraphs.is_public\", \"=\", true)\n\t\t.executeTakeFirst();\n}\n\n/**\n * Get a creator profile by slug with their public subgraphs.\n */\nexport async function getCreatorProfile(db: Kysely<Database>, slug: string): Promise<{ account: any; subgraphs: any[] } | null> {\n\tconst account = await db\n\t\t.selectFrom(\"accounts\")\n\t\t.select([\"id\", \"display_name\", \"bio\", \"avatar_url\", \"slug\"])\n\t\t.where(\"slug\", \"=\", slug)\n\t\t.executeTakeFirst();\n\n\tif (!account) return null;\n\n\tconst subgraphs = await db\n\t\t.selectFrom(\"subgraphs\")\n\t\t.innerJoin(\"api_keys\", \"api_keys.id\", \"subgraphs.api_key_id\")\n\t\t.select([\n\t\t\t\"subgraphs.id\",\n\t\t\t\"subgraphs.name\",\n\t\t\t\"subgraphs.description\",\n\t\t\t\"subgraphs.tags\",\n\t\t\t\"subgraphs.status\",\n\t\t\t\"subgraphs.version\",\n\t\t\t\"subgraphs.definition\",\n\t\t\t\"subgraphs.last_processed_block\",\n\t\t\t\"subgraphs.start_block\",\n\t\t\t\"subgraphs.total_processed\",\n\t\t\t\"subgraphs.created_at\",\n\t\t\tsql<number>`(SELECT COALESCE(SUM(query_count), 0) FROM subgraph_usage_daily WHERE subgraph_id = subgraphs.id AND date >= CURRENT_DATE - 7)::int`.as(\"queries_7d\"),\n\t\t])\n\t\t.where(\"api_keys.account_id\", \"=\", account.id)\n\t\t.where(\"subgraphs.is_public\", \"=\", true)\n\t\t.orderBy(\"subgraphs.created_at\", \"desc\")\n\t\t.execute();\n\n\treturn { account, subgraphs };\n}\n\n/**\n * Publish a subgraph (set is_public = true).\n */\nexport async function publishSubgraph(\n\tdb: Kysely<Database>,\n\tsubgraphId: string,\n\topts?: { tags?: string[]; description?: string },\n): Promise<Subgraph> {\n\tconst set: Record<string, unknown> = {\n\t\tis_public: true,\n\t\tupdated_at: new Date(),\n\t};\n\tif (opts?.tags) set.tags = sql`${sql.val(opts.tags)}::text[]`;\n\tif (opts?.description !== undefined) set.description = opts.description;\n\n\treturn db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set(set)\n\t\t.where(\"id\", \"=\", subgraphId)\n\t\t.returningAll()\n\t\t.executeTakeFirstOrThrow();\n}\n\n/**\n * Unpublish a subgraph (set is_public = false).\n */\nexport async function unpublishSubgraph(\n\tdb: Kysely<Database>,\n\tsubgraphId: string,\n): Promise<Subgraph> {\n\treturn db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({ is_public: false, updated_at: new Date() })\n\t\t.where(\"id\", \"=\", subgraphId)\n\t\t.returningAll()\n\t\t.executeTakeFirstOrThrow();\n}\n\n/**\n * Increment per-subgraph query count for today. Fire-and-forget safe.\n */\nexport async function incrementSubgraphQueryCount(\n\tdb: Kysely<Database>,\n\tsubgraphId: string,\n): Promise<void> {\n\tconst today = new Date().toISOString().slice(0, 10);\n\tawait sql`\n\t\tINSERT INTO subgraph_usage_daily (subgraph_id, date, query_count)\n\t\tVALUES (${subgraphId}, ${today}, 1)\n\t\tON CONFLICT (subgraph_id, date)\n\t\tDO UPDATE SET query_count = subgraph_usage_daily.query_count + 1\n\t`.execute(db);\n}\n\n/**\n * Get daily usage history for a subgraph.\n */\nexport async function getSubgraphUsageHistory(\n\tdb: Kysely<Database>,\n\tsubgraphId: string,\n\tdays: number,\n): Promise<Array<{ date: string; query_count: number }>> {\n\treturn db\n\t\t.selectFrom(\"subgraph_usage_daily\")\n\t\t.select([\"date\", \"query_count\"])\n\t\t.where(\"subgraph_id\", \"=\", subgraphId)\n\t\t.where(\"date\", \">=\", sql<string>`CURRENT_DATE - ${days}::int`)\n\t\t.orderBy(\"date\", \"asc\")\n\t\t.execute();\n}\n\n/**\n * Get total query count for a subgraph over last N days.\n */\nexport async function getSubgraphQueryTotal(\n\tdb: Kysely<Database>,\n\tsubgraphId: string,\n\tdays: number,\n): Promise<number> {\n\tconst row = await db\n\t\t.selectFrom(\"subgraph_usage_daily\")\n\t\t.select(sql<number>`COALESCE(SUM(query_count), 0)::int`.as(\"total\"))\n\t\t.where(\"subgraph_id\", \"=\", subgraphId)\n\t\t.where(\"date\", \">=\", sql<string>`CURRENT_DATE - ${days}::int`)\n\t\t.executeTakeFirst();\n\treturn row?.total ?? 0;\n}\n"
6
- ],
7
- "mappings": "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",
8
- "debugId": "3D863C761F66BE2664756E2164756E21",
9
- "names": []
10
- }
@@ -1,63 +0,0 @@
1
- import { z } from "zod/v4";
2
- interface PublishSubgraphRequest {
3
- tags?: string[];
4
- description?: string;
5
- }
6
- interface UpdateProfileRequest {
7
- display_name?: string;
8
- bio?: string;
9
- slug?: string;
10
- }
11
- interface ForkSubgraphRequest {
12
- sourceSubgraphName: string;
13
- newName?: string;
14
- }
15
- declare const PublishSubgraphRequestSchema: z.ZodType<PublishSubgraphRequest>;
16
- declare const UpdateProfileRequestSchema: z.ZodType<UpdateProfileRequest>;
17
- declare const ForkSubgraphRequestSchema: z.ZodType<ForkSubgraphRequest>;
18
- interface MarketplaceCreator {
19
- displayName: string | null;
20
- slug: string | null;
21
- }
22
- interface MarketplaceSubgraphSummary {
23
- name: string;
24
- description: string | null;
25
- tags: string[];
26
- creator: MarketplaceCreator;
27
- status: string;
28
- version: string;
29
- tables: string[];
30
- totalQueries7d: number;
31
- progress: number;
32
- createdAt: string;
33
- }
34
- interface MarketplaceSubgraphDetail extends MarketplaceSubgraphSummary {
35
- tableSchemas: Record<string, {
36
- columns: Record<string, {
37
- type: string
38
- nullable?: boolean
39
- }>
40
- rowCount: number
41
- endpoint: string
42
- }>;
43
- sources: Record<string, unknown>;
44
- startBlock: number;
45
- lastProcessedBlock: number;
46
- forkedFrom: string | null;
47
- usage: {
48
- totalQueries7d: number
49
- totalQueries30d: number
50
- daily: Array<{
51
- date: string
52
- count: number
53
- }>
54
- };
55
- }
56
- interface CreatorProfile {
57
- displayName: string | null;
58
- bio: string | null;
59
- avatarUrl: string | null;
60
- slug: string | null;
61
- subgraphs: MarketplaceSubgraphSummary[];
62
- }
63
- export { UpdateProfileRequestSchema, UpdateProfileRequest, PublishSubgraphRequestSchema, PublishSubgraphRequest, MarketplaceSubgraphSummary, MarketplaceSubgraphDetail, MarketplaceCreator, ForkSubgraphRequestSchema, ForkSubgraphRequest, CreatorProfile };
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/schemas/marketplace.ts"],
4
- "sourcesContent": [
5
- "import { z } from \"zod/v4\";\n\n// ── Request Types ────────────────────────────────────────────────────\n\nexport interface PublishSubgraphRequest {\n\ttags?: string[];\n\tdescription?: string;\n}\n\nexport interface UpdateProfileRequest {\n\tdisplay_name?: string;\n\tbio?: string;\n\tslug?: string;\n}\n\nexport interface ForkSubgraphRequest {\n\tsourceSubgraphName: string;\n\tnewName?: string;\n}\n\n// ── Request Schemas ───────────────────────────────────────────────────\n\nexport const PublishSubgraphRequestSchema: z.ZodType<PublishSubgraphRequest> =\n\tz.object({\n\t\ttags: z.array(z.string().max(30)).max(5).optional(),\n\t\tdescription: z.string().max(500).optional(),\n\t});\n\nexport const UpdateProfileRequestSchema: z.ZodType<UpdateProfileRequest> =\n\tz.object({\n\t\tdisplay_name: z.string().max(50).optional(),\n\t\tbio: z.string().max(300).optional(),\n\t\tslug: z\n\t\t\t.string()\n\t\t\t.regex(/^[a-z0-9-]+$/, \"lowercase alphanumeric + hyphens only\")\n\t\t\t.min(3)\n\t\t\t.max(30)\n\t\t\t.optional(),\n\t});\n\nexport const ForkSubgraphRequestSchema: z.ZodType<ForkSubgraphRequest> =\n\tz.object({\n\t\tsourceSubgraphName: z.string(),\n\t\tnewName: z\n\t\t\t.string()\n\t\t\t.regex(/^[a-z0-9-]+$/, \"lowercase alphanumeric + hyphens only\")\n\t\t\t.max(63)\n\t\t\t.optional(),\n\t});\n\n// ── Response Types ────────────────────────────────────────────────────\n\nexport interface MarketplaceCreator {\n\tdisplayName: string | null;\n\tslug: string | null;\n}\n\nexport interface MarketplaceSubgraphSummary {\n\tname: string;\n\tdescription: string | null;\n\ttags: string[];\n\tcreator: MarketplaceCreator;\n\tstatus: string;\n\tversion: string;\n\ttables: string[];\n\ttotalQueries7d: number;\n\tprogress: number;\n\tcreatedAt: string;\n}\n\nexport interface MarketplaceSubgraphDetail extends MarketplaceSubgraphSummary {\n\ttableSchemas: Record<\n\t\tstring,\n\t\t{\n\t\t\tcolumns: Record<string, { type: string; nullable?: boolean }>;\n\t\t\trowCount: number;\n\t\t\tendpoint: string;\n\t\t}\n\t>;\n\tsources: Record<string, unknown>;\n\tstartBlock: number;\n\tlastProcessedBlock: number;\n\tforkedFrom: string | null;\n\tusage: {\n\t\ttotalQueries7d: number;\n\t\ttotalQueries30d: number;\n\t\tdaily: Array<{ date: string; count: number }>;\n\t};\n}\n\nexport interface CreatorProfile {\n\tdisplayName: string | null;\n\tbio: string | null;\n\tavatarUrl: string | null;\n\tslug: string | null;\n\tsubgraphs: MarketplaceSubgraphSummary[];\n}\n"
6
- ],
7
- "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAsBO,IAAM,+BACZ,EAAE,OAAO;AAAA,EACR,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAClD,aAAa,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS;AAC3C,CAAC;AAEK,IAAM,6BACZ,EAAE,OAAO;AAAA,EACR,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EAC1C,KAAK,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EAClC,MAAM,EACJ,OAAO,EACP,MAAM,gBAAgB,uCAAuC,EAC7D,IAAI,CAAC,EACL,IAAI,EAAE,EACN,SAAS;AACZ,CAAC;AAEK,IAAM,4BACZ,EAAE,OAAO;AAAA,EACR,oBAAoB,EAAE,OAAO;AAAA,EAC7B,SAAS,EACP,OAAO,EACP,MAAM,gBAAgB,uCAAuC,EAC7D,IAAI,EAAE,EACN,SAAS;AACZ,CAAC;",
8
- "debugId": "14EEEDD6D32C5A5A64756E2164756E21",
9
- "names": []
10
- }