@secondlayer/shared 0.10.2 → 0.12.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.
- package/dist/src/db/index.d.ts +180 -2
- package/dist/src/db/queries/accounts.d.ts +157 -2
- package/dist/src/db/queries/accounts.js +17 -1
- package/dist/src/db/queries/accounts.js.map +3 -3
- package/dist/src/db/queries/integrity.d.ts +150 -1
- package/dist/src/db/queries/marketplace.d.ts +464 -0
- package/dist/src/db/queries/marketplace.js +142 -0
- package/dist/src/db/queries/marketplace.js.map +10 -0
- package/dist/src/db/queries/metrics.d.ts +150 -1
- package/dist/src/db/queries/projects.d.ts +424 -0
- package/dist/src/db/queries/projects.js +47 -0
- package/dist/src/db/queries/projects.js.map +10 -0
- package/dist/src/db/queries/subgraph-gaps.d.ts +150 -1
- package/dist/src/db/queries/subgraphs.d.ts +158 -6
- package/dist/src/db/queries/subgraphs.js +18 -13
- package/dist/src/db/queries/subgraphs.js.map +3 -3
- package/dist/src/db/queries/usage.d.ts +150 -1
- package/dist/src/db/queries/workflows.d.ts +440 -0
- package/dist/src/db/queries/workflows.js +115 -0
- package/dist/src/db/queries/workflows.js.map +11 -0
- package/dist/src/db/schema.d.ts +180 -2
- package/dist/src/index.d.ts +258 -10
- package/dist/src/index.js +91 -72
- package/dist/src/index.js.map +5 -4
- package/dist/src/node/local-client.d.ts +150 -1
- package/dist/src/schemas/index.d.ts +79 -9
- package/dist/src/schemas/index.js +93 -74
- package/dist/src/schemas/index.js.map +5 -4
- package/dist/src/schemas/marketplace.d.ts +63 -0
- package/dist/src/schemas/marketplace.js +39 -0
- package/dist/src/schemas/marketplace.js.map +10 -0
- package/dist/src/schemas/subgraphs.d.ts +8 -0
- package/dist/src/schemas/subgraphs.js.map +2 -2
- package/dist/src/schemas/workflows.d.ts +66 -0
- package/dist/src/schemas/workflows.js +39 -0
- package/dist/src/schemas/workflows.js.map +10 -0
- package/dist/src/types.d.ts +1 -0
- package/migrations/0022_marketplace.ts +88 -0
- package/migrations/0023_projects.ts +149 -0
- package/migrations/0024_chat_sessions.ts +51 -0
- package/migrations/0025_chat_session_summary.ts +15 -0
- package/migrations/0026_workflows.ts +204 -0
- package/migrations/0027_workflow_cursors.ts +16 -0
- package/migrations/0028_subgraph_account_scoping.ts +116 -0
- package/migrations/0029_subgraph_handler_code.ts +23 -0
- package/package.json +22 -2
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
interface DeployWorkflowRequest {
|
|
3
|
+
name: string;
|
|
4
|
+
trigger: Record<string, unknown>;
|
|
5
|
+
handlerCode: string;
|
|
6
|
+
retries?: {
|
|
7
|
+
maxAttempts?: number
|
|
8
|
+
backoffMs?: number
|
|
9
|
+
backoffMultiplier?: number
|
|
10
|
+
};
|
|
11
|
+
timeout?: number;
|
|
12
|
+
}
|
|
13
|
+
declare const DeployWorkflowRequestSchema: z.ZodType<DeployWorkflowRequest>;
|
|
14
|
+
interface DeployWorkflowResponse {
|
|
15
|
+
action: "created" | "updated";
|
|
16
|
+
workflowId: string;
|
|
17
|
+
message: string;
|
|
18
|
+
}
|
|
19
|
+
interface WorkflowSummaryResponse {
|
|
20
|
+
name: string;
|
|
21
|
+
version: string;
|
|
22
|
+
status: string;
|
|
23
|
+
triggerType: string;
|
|
24
|
+
totalRuns: number;
|
|
25
|
+
lastRunAt: string | null;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
updatedAt: string;
|
|
28
|
+
}
|
|
29
|
+
interface WorkflowDetailResponse extends WorkflowSummaryResponse {
|
|
30
|
+
triggerConfig: Record<string, unknown>;
|
|
31
|
+
retriesConfig: Record<string, unknown> | null;
|
|
32
|
+
timeoutMs: number | null;
|
|
33
|
+
}
|
|
34
|
+
interface WorkflowRunResponse {
|
|
35
|
+
id: string;
|
|
36
|
+
workflowName: string;
|
|
37
|
+
status: string;
|
|
38
|
+
triggerType: string;
|
|
39
|
+
triggerData: Record<string, unknown> | null;
|
|
40
|
+
error: string | null;
|
|
41
|
+
startedAt: string | null;
|
|
42
|
+
completedAt: string | null;
|
|
43
|
+
durationMs: number | null;
|
|
44
|
+
totalAiTokens: number;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
steps: WorkflowStepResponse[];
|
|
47
|
+
}
|
|
48
|
+
interface WorkflowStepResponse {
|
|
49
|
+
id: string;
|
|
50
|
+
stepIndex: number;
|
|
51
|
+
stepId: string;
|
|
52
|
+
stepType: string;
|
|
53
|
+
status: string;
|
|
54
|
+
output: unknown | null;
|
|
55
|
+
error: string | null;
|
|
56
|
+
retryCount: number;
|
|
57
|
+
aiTokensUsed: number;
|
|
58
|
+
startedAt: string | null;
|
|
59
|
+
completedAt: string | null;
|
|
60
|
+
durationMs: number | null;
|
|
61
|
+
}
|
|
62
|
+
interface TriggerWorkflowRequest {
|
|
63
|
+
input?: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
declare const TriggerWorkflowRequestSchema: z.ZodType<TriggerWorkflowRequest>;
|
|
66
|
+
export { WorkflowSummaryResponse, WorkflowStepResponse, WorkflowRunResponse, WorkflowDetailResponse, TriggerWorkflowRequestSchema, TriggerWorkflowRequest, DeployWorkflowResponse, DeployWorkflowRequestSchema, DeployWorkflowRequest };
|
|
@@ -0,0 +1,39 @@
|
|
|
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/schemas/workflows.ts
|
|
18
|
+
import { z } from "zod/v4";
|
|
19
|
+
var DeployWorkflowRequestSchema = z.object({
|
|
20
|
+
name: z.string().regex(/^[a-z][a-z0-9-]*$/, "lowercase alphanumeric + hyphens, must start with letter").max(63),
|
|
21
|
+
trigger: z.record(z.string(), z.unknown()),
|
|
22
|
+
handlerCode: z.string().max(1048576, "handler code exceeds 1MB limit"),
|
|
23
|
+
retries: z.object({
|
|
24
|
+
maxAttempts: z.number().int().positive().optional(),
|
|
25
|
+
backoffMs: z.number().int().nonnegative().optional(),
|
|
26
|
+
backoffMultiplier: z.number().positive().optional()
|
|
27
|
+
}).optional(),
|
|
28
|
+
timeout: z.number().int().positive().optional()
|
|
29
|
+
});
|
|
30
|
+
var TriggerWorkflowRequestSchema = z.object({
|
|
31
|
+
input: z.record(z.string(), z.unknown()).optional()
|
|
32
|
+
});
|
|
33
|
+
export {
|
|
34
|
+
TriggerWorkflowRequestSchema,
|
|
35
|
+
DeployWorkflowRequestSchema
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
//# debugId=C5C0F7222546009064756E2164756E21
|
|
39
|
+
//# sourceMappingURL=workflows.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/schemas/workflows.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { z } from \"zod/v4\";\n\n// ── Deploy Workflow Request ──────────────────────────────────────────\n\nexport interface DeployWorkflowRequest {\n\tname: string;\n\ttrigger: Record<string, unknown>;\n\thandlerCode: string;\n\tretries?: { maxAttempts?: number; backoffMs?: number; backoffMultiplier?: number };\n\ttimeout?: number;\n}\n\nexport const DeployWorkflowRequestSchema: z.ZodType<DeployWorkflowRequest> =\n\tz.object({\n\t\tname: z\n\t\t\t.string()\n\t\t\t.regex(/^[a-z][a-z0-9-]*$/, \"lowercase alphanumeric + hyphens, must start with letter\")\n\t\t\t.max(63),\n\t\ttrigger: z.record(z.string(), z.unknown()),\n\t\thandlerCode: z.string().max(1_048_576, \"handler code exceeds 1MB limit\"),\n\t\tretries: z\n\t\t\t.object({\n\t\t\t\tmaxAttempts: z.number().int().positive().optional(),\n\t\t\t\tbackoffMs: z.number().int().nonnegative().optional(),\n\t\t\t\tbackoffMultiplier: z.number().positive().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\ttimeout: z.number().int().positive().optional(),\n\t});\n\nexport interface DeployWorkflowResponse {\n\taction: \"created\" | \"updated\";\n\tworkflowId: string;\n\tmessage: string;\n}\n\n// ── API Response Types ───────────────────────────────────────────────\n\nexport interface WorkflowSummaryResponse {\n\tname: string;\n\tversion: string;\n\tstatus: string;\n\ttriggerType: string;\n\ttotalRuns: number;\n\tlastRunAt: string | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface WorkflowDetailResponse extends WorkflowSummaryResponse {\n\ttriggerConfig: Record<string, unknown>;\n\tretriesConfig: Record<string, unknown> | null;\n\ttimeoutMs: number | null;\n}\n\nexport interface WorkflowRunResponse {\n\tid: string;\n\tworkflowName: string;\n\tstatus: string;\n\ttriggerType: string;\n\ttriggerData: Record<string, unknown> | null;\n\terror: string | null;\n\tstartedAt: string | null;\n\tcompletedAt: string | null;\n\tdurationMs: number | null;\n\ttotalAiTokens: number;\n\tcreatedAt: string;\n\tsteps: WorkflowStepResponse[];\n}\n\nexport interface WorkflowStepResponse {\n\tid: string;\n\tstepIndex: number;\n\tstepId: string;\n\tstepType: string;\n\tstatus: string;\n\toutput: unknown | null;\n\terror: string | null;\n\tretryCount: number;\n\taiTokensUsed: number;\n\tstartedAt: string | null;\n\tcompletedAt: string | null;\n\tdurationMs: number | null;\n}\n\nexport interface TriggerWorkflowRequest {\n\tinput?: Record<string, unknown>;\n}\n\nexport const TriggerWorkflowRequestSchema: z.ZodType<TriggerWorkflowRequest> =\n\tz.object({\n\t\tinput: z.record(z.string(), z.unknown()).optional(),\n\t});\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAYO,IAAM,8BACZ,EAAE,OAAO;AAAA,EACR,MAAM,EACJ,OAAO,EACP,MAAM,qBAAqB,0DAA0D,EACrF,IAAI,EAAE;AAAA,EACR,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC;AAAA,EACzC,aAAa,EAAE,OAAO,EAAE,IAAI,SAAW,gCAAgC;AAAA,EACvE,SAAS,EACP,OAAO;AAAA,IACP,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,IAClD,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,IACnD,mBAAmB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACnD,CAAC,EACA,SAAS;AAAA,EACX,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAC/C,CAAC;AA6DK,IAAM,+BACZ,EAAE,OAAO;AAAA,EACR,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACnD,CAAC;",
|
|
8
|
+
"debugId": "C5C0F7222546009064756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { sql, type Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Add marketplace columns to subgraphs and accounts.
|
|
5
|
+
* Create per-subgraph usage tracking table.
|
|
6
|
+
*/
|
|
7
|
+
export async function up(db: Kysely<any>): Promise<void> {
|
|
8
|
+
// Subgraph marketplace columns
|
|
9
|
+
await db.schema
|
|
10
|
+
.alterTable("subgraphs")
|
|
11
|
+
.addColumn("is_public", "boolean", (c) => c.notNull().defaultTo(false))
|
|
12
|
+
.execute();
|
|
13
|
+
await db.schema
|
|
14
|
+
.alterTable("subgraphs")
|
|
15
|
+
.addColumn("tags", sql`text[]`, (c) => c.notNull().defaultTo(sql`'{}'`))
|
|
16
|
+
.execute();
|
|
17
|
+
await db.schema
|
|
18
|
+
.alterTable("subgraphs")
|
|
19
|
+
.addColumn("description", "text")
|
|
20
|
+
.execute();
|
|
21
|
+
await db.schema
|
|
22
|
+
.alterTable("subgraphs")
|
|
23
|
+
.addColumn("forked_from_id", "uuid", (c) =>
|
|
24
|
+
c.references("subgraphs.id").onDelete("set null"),
|
|
25
|
+
)
|
|
26
|
+
.execute();
|
|
27
|
+
|
|
28
|
+
// Account profile columns
|
|
29
|
+
await db.schema
|
|
30
|
+
.alterTable("accounts")
|
|
31
|
+
.addColumn("display_name", "text")
|
|
32
|
+
.execute();
|
|
33
|
+
await db.schema.alterTable("accounts").addColumn("bio", "text").execute();
|
|
34
|
+
await db.schema
|
|
35
|
+
.alterTable("accounts")
|
|
36
|
+
.addColumn("avatar_url", "text")
|
|
37
|
+
.execute();
|
|
38
|
+
await db.schema
|
|
39
|
+
.alterTable("accounts")
|
|
40
|
+
.addColumn("slug", "text", (c) => c.unique())
|
|
41
|
+
.execute();
|
|
42
|
+
|
|
43
|
+
// Per-subgraph usage tracking
|
|
44
|
+
await db.schema
|
|
45
|
+
.createTable("subgraph_usage_daily")
|
|
46
|
+
.addColumn("subgraph_id", "uuid", (c) =>
|
|
47
|
+
c.notNull().references("subgraphs.id").onDelete("cascade"),
|
|
48
|
+
)
|
|
49
|
+
.addColumn("date", "date", (c) => c.notNull())
|
|
50
|
+
.addColumn("query_count", "integer", (c) => c.notNull().defaultTo(0))
|
|
51
|
+
.addPrimaryKeyConstraint("subgraph_usage_daily_pk", [
|
|
52
|
+
"subgraph_id",
|
|
53
|
+
"date",
|
|
54
|
+
])
|
|
55
|
+
.execute();
|
|
56
|
+
|
|
57
|
+
// Indexes
|
|
58
|
+
await sql`CREATE INDEX subgraphs_is_public_idx ON subgraphs (is_public) WHERE is_public = true`.execute(
|
|
59
|
+
db,
|
|
60
|
+
);
|
|
61
|
+
await sql`CREATE INDEX subgraphs_tags_idx ON subgraphs USING gin (tags)`.execute(
|
|
62
|
+
db,
|
|
63
|
+
);
|
|
64
|
+
await sql`CREATE INDEX accounts_slug_idx ON accounts (slug) WHERE slug IS NOT NULL`.execute(
|
|
65
|
+
db,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function down(db: Kysely<any>): Promise<void> {
|
|
70
|
+
await db.schema.dropTable("subgraph_usage_daily").execute();
|
|
71
|
+
|
|
72
|
+
await sql`DROP INDEX IF EXISTS accounts_slug_idx`.execute(db);
|
|
73
|
+
await sql`DROP INDEX IF EXISTS subgraphs_tags_idx`.execute(db);
|
|
74
|
+
await sql`DROP INDEX IF EXISTS subgraphs_is_public_idx`.execute(db);
|
|
75
|
+
|
|
76
|
+
await db.schema.alterTable("accounts").dropColumn("slug").execute();
|
|
77
|
+
await db.schema.alterTable("accounts").dropColumn("avatar_url").execute();
|
|
78
|
+
await db.schema.alterTable("accounts").dropColumn("bio").execute();
|
|
79
|
+
await db.schema.alterTable("accounts").dropColumn("display_name").execute();
|
|
80
|
+
|
|
81
|
+
await db.schema
|
|
82
|
+
.alterTable("subgraphs")
|
|
83
|
+
.dropColumn("forked_from_id")
|
|
84
|
+
.execute();
|
|
85
|
+
await db.schema.alterTable("subgraphs").dropColumn("description").execute();
|
|
86
|
+
await db.schema.alterTable("subgraphs").dropColumn("tags").execute();
|
|
87
|
+
await db.schema.alterTable("subgraphs").dropColumn("is_public").execute();
|
|
88
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { sql, type Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Add projects, team_members, and team_invitations tables.
|
|
5
|
+
* Add project_id to streams and subgraphs.
|
|
6
|
+
* Backfill: create a default project per account and assign existing resources.
|
|
7
|
+
*/
|
|
8
|
+
export async function up(db: Kysely<any>): Promise<void> {
|
|
9
|
+
// Projects table
|
|
10
|
+
await db.schema
|
|
11
|
+
.createTable("projects")
|
|
12
|
+
.addColumn("id", "uuid", (c) =>
|
|
13
|
+
c.primaryKey().defaultTo(sql`gen_random_uuid()`),
|
|
14
|
+
)
|
|
15
|
+
.addColumn("name", "text", (c) => c.notNull())
|
|
16
|
+
.addColumn("slug", "text", (c) => c.notNull())
|
|
17
|
+
.addColumn("account_id", "uuid", (c) =>
|
|
18
|
+
c.notNull().references("accounts.id").onDelete("cascade"),
|
|
19
|
+
)
|
|
20
|
+
.addColumn("settings", "jsonb", (c) => c.notNull().defaultTo(sql`'{}'`))
|
|
21
|
+
.addColumn("network", "varchar(20)", (c) =>
|
|
22
|
+
c.notNull().defaultTo("mainnet"),
|
|
23
|
+
)
|
|
24
|
+
.addColumn("node_rpc", "text")
|
|
25
|
+
.addColumn("created_at", "timestamptz", (c) =>
|
|
26
|
+
c.notNull().defaultTo(sql`now()`),
|
|
27
|
+
)
|
|
28
|
+
.addColumn("updated_at", "timestamptz", (c) =>
|
|
29
|
+
c.notNull().defaultTo(sql`now()`),
|
|
30
|
+
)
|
|
31
|
+
.execute();
|
|
32
|
+
|
|
33
|
+
// Unique slug per account
|
|
34
|
+
await sql`CREATE UNIQUE INDEX projects_account_slug_idx ON projects (account_id, slug)`.execute(
|
|
35
|
+
db,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Team members table
|
|
39
|
+
await db.schema
|
|
40
|
+
.createTable("team_members")
|
|
41
|
+
.addColumn("id", "uuid", (c) =>
|
|
42
|
+
c.primaryKey().defaultTo(sql`gen_random_uuid()`),
|
|
43
|
+
)
|
|
44
|
+
.addColumn("project_id", "uuid", (c) =>
|
|
45
|
+
c.notNull().references("projects.id").onDelete("cascade"),
|
|
46
|
+
)
|
|
47
|
+
.addColumn("account_id", "uuid", (c) =>
|
|
48
|
+
c.notNull().references("accounts.id").onDelete("cascade"),
|
|
49
|
+
)
|
|
50
|
+
.addColumn("role", "varchar(20)", (c) => c.notNull().defaultTo("member"))
|
|
51
|
+
.addColumn("invited_by", "uuid", (c) =>
|
|
52
|
+
c.references("accounts.id").onDelete("set null"),
|
|
53
|
+
)
|
|
54
|
+
.addColumn("created_at", "timestamptz", (c) =>
|
|
55
|
+
c.notNull().defaultTo(sql`now()`),
|
|
56
|
+
)
|
|
57
|
+
.execute();
|
|
58
|
+
|
|
59
|
+
await sql`CREATE UNIQUE INDEX team_members_project_account_idx ON team_members (project_id, account_id)`.execute(
|
|
60
|
+
db,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
// Team invitations table
|
|
64
|
+
await db.schema
|
|
65
|
+
.createTable("team_invitations")
|
|
66
|
+
.addColumn("id", "uuid", (c) =>
|
|
67
|
+
c.primaryKey().defaultTo(sql`gen_random_uuid()`),
|
|
68
|
+
)
|
|
69
|
+
.addColumn("project_id", "uuid", (c) =>
|
|
70
|
+
c.notNull().references("projects.id").onDelete("cascade"),
|
|
71
|
+
)
|
|
72
|
+
.addColumn("email", "text", (c) => c.notNull())
|
|
73
|
+
.addColumn("role", "varchar(20)", (c) => c.notNull().defaultTo("member"))
|
|
74
|
+
.addColumn("token", "varchar(64)", (c) => c.notNull())
|
|
75
|
+
.addColumn("invited_by", "uuid", (c) =>
|
|
76
|
+
c.references("accounts.id").onDelete("set null"),
|
|
77
|
+
)
|
|
78
|
+
.addColumn("expires_at", "timestamptz", (c) => c.notNull())
|
|
79
|
+
.addColumn("accepted_at", "timestamptz")
|
|
80
|
+
.addColumn("created_at", "timestamptz", (c) =>
|
|
81
|
+
c.notNull().defaultTo(sql`now()`),
|
|
82
|
+
)
|
|
83
|
+
.execute();
|
|
84
|
+
|
|
85
|
+
// Add project_id to streams and subgraphs
|
|
86
|
+
await db.schema
|
|
87
|
+
.alterTable("streams")
|
|
88
|
+
.addColumn("project_id", "uuid", (c) =>
|
|
89
|
+
c.references("projects.id").onDelete("set null"),
|
|
90
|
+
)
|
|
91
|
+
.execute();
|
|
92
|
+
|
|
93
|
+
await db.schema
|
|
94
|
+
.alterTable("subgraphs")
|
|
95
|
+
.addColumn("project_id", "uuid", (c) =>
|
|
96
|
+
c.references("projects.id").onDelete("set null"),
|
|
97
|
+
)
|
|
98
|
+
.execute();
|
|
99
|
+
|
|
100
|
+
// Backfill: create default project per account, assign resources
|
|
101
|
+
await sql`
|
|
102
|
+
INSERT INTO projects (id, name, slug, account_id)
|
|
103
|
+
SELECT gen_random_uuid(), 'my-project', 'my-project', id
|
|
104
|
+
FROM accounts
|
|
105
|
+
`.execute(db);
|
|
106
|
+
|
|
107
|
+
await sql`
|
|
108
|
+
UPDATE streams SET project_id = p.id
|
|
109
|
+
FROM api_keys ak
|
|
110
|
+
JOIN projects p ON p.account_id = ak.account_id
|
|
111
|
+
WHERE streams.api_key_id = ak.id AND streams.project_id IS NULL
|
|
112
|
+
`.execute(db);
|
|
113
|
+
|
|
114
|
+
await sql`
|
|
115
|
+
UPDATE subgraphs SET project_id = p.id
|
|
116
|
+
FROM api_keys ak
|
|
117
|
+
JOIN projects p ON p.account_id = ak.account_id
|
|
118
|
+
WHERE subgraphs.api_key_id = ak.id AND subgraphs.project_id IS NULL
|
|
119
|
+
`.execute(db);
|
|
120
|
+
|
|
121
|
+
// Add owner team_member for each project
|
|
122
|
+
await sql`
|
|
123
|
+
INSERT INTO team_members (id, project_id, account_id, role)
|
|
124
|
+
SELECT gen_random_uuid(), id, account_id, 'owner'
|
|
125
|
+
FROM projects
|
|
126
|
+
`.execute(db);
|
|
127
|
+
|
|
128
|
+
// Indexes
|
|
129
|
+
await sql`CREATE INDEX streams_project_id_idx ON streams (project_id) WHERE project_id IS NOT NULL`.execute(
|
|
130
|
+
db,
|
|
131
|
+
);
|
|
132
|
+
await sql`CREATE INDEX subgraphs_project_id_idx ON subgraphs (project_id) WHERE project_id IS NOT NULL`.execute(
|
|
133
|
+
db,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export async function down(db: Kysely<any>): Promise<void> {
|
|
138
|
+
await sql`DROP INDEX IF EXISTS subgraphs_project_id_idx`.execute(db);
|
|
139
|
+
await sql`DROP INDEX IF EXISTS streams_project_id_idx`.execute(db);
|
|
140
|
+
|
|
141
|
+
await db.schema.alterTable("subgraphs").dropColumn("project_id").execute();
|
|
142
|
+
await db.schema.alterTable("streams").dropColumn("project_id").execute();
|
|
143
|
+
|
|
144
|
+
await db.schema.dropTable("team_invitations").execute();
|
|
145
|
+
await db.schema.dropTable("team_members").execute();
|
|
146
|
+
|
|
147
|
+
await sql`DROP INDEX IF EXISTS projects_account_slug_idx`.execute(db);
|
|
148
|
+
await db.schema.dropTable("projects").execute();
|
|
149
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { sql, type Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
+
await db.schema
|
|
5
|
+
.createTable("chat_sessions")
|
|
6
|
+
.addColumn("id", "uuid", (c) =>
|
|
7
|
+
c.primaryKey().defaultTo(sql`gen_random_uuid()`),
|
|
8
|
+
)
|
|
9
|
+
.addColumn("account_id", "uuid", (c) =>
|
|
10
|
+
c.notNull().references("accounts.id").onDelete("cascade"),
|
|
11
|
+
)
|
|
12
|
+
.addColumn("title", "text")
|
|
13
|
+
.addColumn("created_at", "timestamptz", (c) =>
|
|
14
|
+
c.notNull().defaultTo(sql`now()`),
|
|
15
|
+
)
|
|
16
|
+
.addColumn("updated_at", "timestamptz", (c) =>
|
|
17
|
+
c.notNull().defaultTo(sql`now()`),
|
|
18
|
+
)
|
|
19
|
+
.execute();
|
|
20
|
+
|
|
21
|
+
await sql`CREATE INDEX chat_sessions_account_idx ON chat_sessions (account_id, created_at DESC)`.execute(
|
|
22
|
+
db,
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
await db.schema
|
|
26
|
+
.createTable("chat_messages")
|
|
27
|
+
.addColumn("id", "uuid", (c) =>
|
|
28
|
+
c.primaryKey().defaultTo(sql`gen_random_uuid()`),
|
|
29
|
+
)
|
|
30
|
+
.addColumn("chat_session_id", "uuid", (c) =>
|
|
31
|
+
c.notNull().references("chat_sessions.id").onDelete("cascade"),
|
|
32
|
+
)
|
|
33
|
+
.addColumn("role", "varchar(20)", (c) => c.notNull())
|
|
34
|
+
.addColumn("parts", "jsonb", (c) => c.notNull())
|
|
35
|
+
.addColumn("metadata", "jsonb")
|
|
36
|
+
.addColumn("created_at", "timestamptz", (c) =>
|
|
37
|
+
c.notNull().defaultTo(sql`now()`),
|
|
38
|
+
)
|
|
39
|
+
.execute();
|
|
40
|
+
|
|
41
|
+
await sql`CREATE INDEX chat_messages_session_idx ON chat_messages (chat_session_id, created_at)`.execute(
|
|
42
|
+
db,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function down(db: Kysely<any>): Promise<void> {
|
|
47
|
+
await sql`DROP INDEX IF EXISTS chat_messages_session_idx`.execute(db);
|
|
48
|
+
await db.schema.dropTable("chat_messages").execute();
|
|
49
|
+
await sql`DROP INDEX IF EXISTS chat_sessions_account_idx`.execute(db);
|
|
50
|
+
await db.schema.dropTable("chat_sessions").execute();
|
|
51
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
+
await db.schema
|
|
5
|
+
.alterTable("chat_sessions")
|
|
6
|
+
.addColumn("summary", "jsonb")
|
|
7
|
+
.execute();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function down(db: Kysely<any>): Promise<void> {
|
|
11
|
+
await db.schema
|
|
12
|
+
.alterTable("chat_sessions")
|
|
13
|
+
.dropColumn("summary")
|
|
14
|
+
.execute();
|
|
15
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { sql, type Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
+
// ── workflow_definitions ──────────────────────────────────────────
|
|
5
|
+
await db.schema
|
|
6
|
+
.createTable("workflow_definitions")
|
|
7
|
+
.addColumn("id", "uuid", (c) =>
|
|
8
|
+
c.primaryKey().defaultTo(sql`gen_random_uuid()`),
|
|
9
|
+
)
|
|
10
|
+
.addColumn("name", "text", (c) => c.notNull())
|
|
11
|
+
.addColumn("version", "text", (c) => c.notNull().defaultTo("1.0.0"))
|
|
12
|
+
.addColumn("status", "text", (c) => c.notNull().defaultTo("active"))
|
|
13
|
+
.addColumn("trigger_type", "text", (c) => c.notNull())
|
|
14
|
+
.addColumn("trigger_config", "jsonb", (c) => c.notNull())
|
|
15
|
+
.addColumn("handler_path", "text", (c) => c.notNull())
|
|
16
|
+
.addColumn("retries_config", "jsonb")
|
|
17
|
+
.addColumn("timeout_ms", "integer")
|
|
18
|
+
.addColumn("api_key_id", "uuid", (c) =>
|
|
19
|
+
c.notNull().references("api_keys.id"),
|
|
20
|
+
)
|
|
21
|
+
.addColumn("project_id", "uuid", (c) =>
|
|
22
|
+
c.references("projects.id").onDelete("set null"),
|
|
23
|
+
)
|
|
24
|
+
.addColumn("created_at", "timestamptz", (c) =>
|
|
25
|
+
c.notNull().defaultTo(sql`now()`),
|
|
26
|
+
)
|
|
27
|
+
.addColumn("updated_at", "timestamptz", (c) =>
|
|
28
|
+
c.notNull().defaultTo(sql`now()`),
|
|
29
|
+
)
|
|
30
|
+
.execute();
|
|
31
|
+
|
|
32
|
+
await sql`CREATE UNIQUE INDEX workflow_definitions_name_key_idx ON workflow_definitions (name, api_key_id)`.execute(
|
|
33
|
+
db,
|
|
34
|
+
);
|
|
35
|
+
await sql`CREATE INDEX workflow_definitions_status_idx ON workflow_definitions (status)`.execute(
|
|
36
|
+
db,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// ── workflow_runs ─────────────────────────────────────────────────
|
|
40
|
+
await db.schema
|
|
41
|
+
.createTable("workflow_runs")
|
|
42
|
+
.addColumn("id", "uuid", (c) =>
|
|
43
|
+
c.primaryKey().defaultTo(sql`gen_random_uuid()`),
|
|
44
|
+
)
|
|
45
|
+
.addColumn("definition_id", "uuid", (c) =>
|
|
46
|
+
c.notNull().references("workflow_definitions.id").onDelete("cascade"),
|
|
47
|
+
)
|
|
48
|
+
.addColumn("status", "text", (c) => c.notNull().defaultTo("pending"))
|
|
49
|
+
.addColumn("trigger_type", "text", (c) => c.notNull())
|
|
50
|
+
.addColumn("trigger_data", "jsonb")
|
|
51
|
+
.addColumn("dedup_key", "text")
|
|
52
|
+
.addColumn("error", "text")
|
|
53
|
+
.addColumn("started_at", "timestamptz")
|
|
54
|
+
.addColumn("completed_at", "timestamptz")
|
|
55
|
+
.addColumn("duration_ms", "integer")
|
|
56
|
+
.addColumn("total_ai_tokens", "integer", (c) => c.notNull().defaultTo(0))
|
|
57
|
+
.addColumn("created_at", "timestamptz", (c) =>
|
|
58
|
+
c.notNull().defaultTo(sql`now()`),
|
|
59
|
+
)
|
|
60
|
+
.execute();
|
|
61
|
+
|
|
62
|
+
await sql`CREATE INDEX workflow_runs_definition_idx ON workflow_runs (definition_id, created_at DESC)`.execute(
|
|
63
|
+
db,
|
|
64
|
+
);
|
|
65
|
+
await sql`CREATE INDEX workflow_runs_status_idx ON workflow_runs (status)`.execute(
|
|
66
|
+
db,
|
|
67
|
+
);
|
|
68
|
+
await sql`CREATE UNIQUE INDEX workflow_runs_dedup_idx ON workflow_runs (definition_id, dedup_key) WHERE dedup_key IS NOT NULL`.execute(
|
|
69
|
+
db,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// ── workflow_steps ────────────────────────────────────────────────
|
|
73
|
+
await db.schema
|
|
74
|
+
.createTable("workflow_steps")
|
|
75
|
+
.addColumn("id", "uuid", (c) =>
|
|
76
|
+
c.primaryKey().defaultTo(sql`gen_random_uuid()`),
|
|
77
|
+
)
|
|
78
|
+
.addColumn("run_id", "uuid", (c) =>
|
|
79
|
+
c.notNull().references("workflow_runs.id").onDelete("cascade"),
|
|
80
|
+
)
|
|
81
|
+
.addColumn("step_index", "integer", (c) => c.notNull())
|
|
82
|
+
.addColumn("step_id", "text", (c) => c.notNull())
|
|
83
|
+
.addColumn("step_type", "text", (c) => c.notNull())
|
|
84
|
+
.addColumn("status", "text", (c) => c.notNull().defaultTo("pending"))
|
|
85
|
+
.addColumn("input", "jsonb")
|
|
86
|
+
.addColumn("output", "jsonb")
|
|
87
|
+
.addColumn("error", "text")
|
|
88
|
+
.addColumn("retry_count", "integer", (c) => c.notNull().defaultTo(0))
|
|
89
|
+
.addColumn("ai_tokens_used", "integer", (c) => c.notNull().defaultTo(0))
|
|
90
|
+
.addColumn("started_at", "timestamptz")
|
|
91
|
+
.addColumn("completed_at", "timestamptz")
|
|
92
|
+
.addColumn("duration_ms", "integer")
|
|
93
|
+
.addColumn("created_at", "timestamptz", (c) =>
|
|
94
|
+
c.notNull().defaultTo(sql`now()`),
|
|
95
|
+
)
|
|
96
|
+
.execute();
|
|
97
|
+
|
|
98
|
+
await sql`CREATE INDEX workflow_steps_run_idx ON workflow_steps (run_id, step_index)`.execute(
|
|
99
|
+
db,
|
|
100
|
+
);
|
|
101
|
+
await sql`CREATE UNIQUE INDEX workflow_steps_dedup_idx ON workflow_steps (run_id, step_id)`.execute(
|
|
102
|
+
db,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// ── workflow_queue ────────────────────────────────────────────────
|
|
106
|
+
await db.schema
|
|
107
|
+
.createTable("workflow_queue")
|
|
108
|
+
.addColumn("id", "uuid", (c) =>
|
|
109
|
+
c.primaryKey().defaultTo(sql`gen_random_uuid()`),
|
|
110
|
+
)
|
|
111
|
+
.addColumn("run_id", "uuid", (c) =>
|
|
112
|
+
c.notNull().references("workflow_runs.id").onDelete("cascade"),
|
|
113
|
+
)
|
|
114
|
+
.addColumn("status", "text", (c) => c.notNull().defaultTo("pending"))
|
|
115
|
+
.addColumn("attempts", "integer", (c) => c.notNull().defaultTo(0))
|
|
116
|
+
.addColumn("max_attempts", "integer", (c) => c.notNull().defaultTo(3))
|
|
117
|
+
.addColumn("scheduled_for", "timestamptz", (c) =>
|
|
118
|
+
c.notNull().defaultTo(sql`now()`),
|
|
119
|
+
)
|
|
120
|
+
.addColumn("locked_at", "timestamptz")
|
|
121
|
+
.addColumn("locked_by", "text")
|
|
122
|
+
.addColumn("error", "text")
|
|
123
|
+
.addColumn("created_at", "timestamptz", (c) =>
|
|
124
|
+
c.notNull().defaultTo(sql`now()`),
|
|
125
|
+
)
|
|
126
|
+
.addColumn("completed_at", "timestamptz")
|
|
127
|
+
.execute();
|
|
128
|
+
|
|
129
|
+
await sql`CREATE INDEX workflow_queue_poll_idx ON workflow_queue (scheduled_for, status, locked_at)`.execute(
|
|
130
|
+
db,
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// ── workflow_schedules ────────────────────────────────────────────
|
|
134
|
+
await db.schema
|
|
135
|
+
.createTable("workflow_schedules")
|
|
136
|
+
.addColumn("id", "uuid", (c) =>
|
|
137
|
+
c.primaryKey().defaultTo(sql`gen_random_uuid()`),
|
|
138
|
+
)
|
|
139
|
+
.addColumn("definition_id", "uuid", (c) =>
|
|
140
|
+
c
|
|
141
|
+
.notNull()
|
|
142
|
+
.references("workflow_definitions.id")
|
|
143
|
+
.onDelete("cascade"),
|
|
144
|
+
)
|
|
145
|
+
.addColumn("cron_expr", "text", (c) => c.notNull())
|
|
146
|
+
.addColumn("timezone", "text", (c) => c.notNull().defaultTo("UTC"))
|
|
147
|
+
.addColumn("next_run_at", "timestamptz", (c) => c.notNull())
|
|
148
|
+
.addColumn("last_run_at", "timestamptz")
|
|
149
|
+
.addColumn("enabled", "boolean", (c) => c.notNull().defaultTo(true))
|
|
150
|
+
.addColumn("created_at", "timestamptz", (c) =>
|
|
151
|
+
c.notNull().defaultTo(sql`now()`),
|
|
152
|
+
)
|
|
153
|
+
.execute();
|
|
154
|
+
|
|
155
|
+
await sql`CREATE UNIQUE INDEX workflow_schedules_definition_idx ON workflow_schedules (definition_id)`.execute(
|
|
156
|
+
db,
|
|
157
|
+
);
|
|
158
|
+
await sql`CREATE INDEX workflow_schedules_poll_idx ON workflow_schedules (enabled, next_run_at)`.execute(
|
|
159
|
+
db,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// ── PG NOTIFY trigger on workflow_queue ───────────────────────────
|
|
163
|
+
await sql`
|
|
164
|
+
CREATE OR REPLACE FUNCTION notify_workflow_job() RETURNS trigger AS $$
|
|
165
|
+
BEGIN
|
|
166
|
+
PERFORM pg_notify('workflows:new_job', NEW.run_id::text);
|
|
167
|
+
RETURN NEW;
|
|
168
|
+
END;
|
|
169
|
+
$$ LANGUAGE plpgsql
|
|
170
|
+
`.execute(db);
|
|
171
|
+
|
|
172
|
+
await sql`
|
|
173
|
+
CREATE TRIGGER workflow_queue_notify
|
|
174
|
+
AFTER INSERT ON workflow_queue
|
|
175
|
+
FOR EACH ROW EXECUTE FUNCTION notify_workflow_job()
|
|
176
|
+
`.execute(db);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export async function down(db: Kysely<any>): Promise<void> {
|
|
180
|
+
await sql`DROP TRIGGER IF EXISTS workflow_queue_notify ON workflow_queue`.execute(
|
|
181
|
+
db,
|
|
182
|
+
);
|
|
183
|
+
await sql`DROP FUNCTION IF EXISTS notify_workflow_job`.execute(db);
|
|
184
|
+
|
|
185
|
+
await sql`DROP INDEX IF EXISTS workflow_schedules_poll_idx`.execute(db);
|
|
186
|
+
await sql`DROP INDEX IF EXISTS workflow_schedules_definition_idx`.execute(db);
|
|
187
|
+
await db.schema.dropTable("workflow_schedules").execute();
|
|
188
|
+
|
|
189
|
+
await sql`DROP INDEX IF EXISTS workflow_queue_poll_idx`.execute(db);
|
|
190
|
+
await db.schema.dropTable("workflow_queue").execute();
|
|
191
|
+
|
|
192
|
+
await sql`DROP INDEX IF EXISTS workflow_steps_dedup_idx`.execute(db);
|
|
193
|
+
await sql`DROP INDEX IF EXISTS workflow_steps_run_idx`.execute(db);
|
|
194
|
+
await db.schema.dropTable("workflow_steps").execute();
|
|
195
|
+
|
|
196
|
+
await sql`DROP INDEX IF EXISTS workflow_runs_dedup_idx`.execute(db);
|
|
197
|
+
await sql`DROP INDEX IF EXISTS workflow_runs_status_idx`.execute(db);
|
|
198
|
+
await sql`DROP INDEX IF EXISTS workflow_runs_definition_idx`.execute(db);
|
|
199
|
+
await db.schema.dropTable("workflow_runs").execute();
|
|
200
|
+
|
|
201
|
+
await sql`DROP INDEX IF EXISTS workflow_definitions_status_idx`.execute(db);
|
|
202
|
+
await sql`DROP INDEX IF EXISTS workflow_definitions_name_key_idx`.execute(db);
|
|
203
|
+
await db.schema.dropTable("workflow_definitions").execute();
|
|
204
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { sql, type Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
+
await db.schema
|
|
5
|
+
.createTable("workflow_cursors")
|
|
6
|
+
.addColumn("name", "text", (c) => c.primaryKey())
|
|
7
|
+
.addColumn("block_height", "integer", (c) => c.notNull().defaultTo(0))
|
|
8
|
+
.addColumn("updated_at", "timestamptz", (c) =>
|
|
9
|
+
c.notNull().defaultTo(sql`now()`),
|
|
10
|
+
)
|
|
11
|
+
.execute();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function down(db: Kysely<any>): Promise<void> {
|
|
15
|
+
await db.schema.dropTable("workflow_cursors").execute();
|
|
16
|
+
}
|