@powerhousedao/vetra-builder-package 0.0.15 → 0.0.17
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/document-models/index.d.ts +0 -1
- package/dist/document-models/index.js +0 -1
- package/dist/editors/index.d.ts +0 -1
- package/dist/editors/index.js +0 -1
- package/dist/index.d.ts +1 -1
- package/dist/processors/factory.js +6 -4
- package/dist/processors/index.d.ts +2 -4
- package/dist/processors/index.js +2 -4
- package/dist/processors/vetra-builder-read-model/builder-account-handlers.d.ts +27 -0
- package/dist/processors/vetra-builder-read-model/builder-account-handlers.js +249 -0
- package/dist/processors/vetra-builder-read-model/database-helpers.d.ts +39 -0
- package/dist/processors/vetra-builder-read-model/database-helpers.js +144 -0
- package/dist/processors/vetra-builder-read-model/factory.d.ts +3 -0
- package/dist/processors/vetra-builder-read-model/factory.js +25 -0
- package/dist/processors/vetra-builder-read-model/index.d.ts +29 -0
- package/dist/processors/vetra-builder-read-model/index.js +370 -0
- package/dist/processors/vetra-builder-read-model/migrations.d.ts +3 -0
- package/dist/processors/vetra-builder-read-model/migrations.js +152 -0
- package/dist/processors/vetra-builder-read-model/package-handlers.d.ts +20 -0
- package/dist/processors/vetra-builder-read-model/package-handlers.js +116 -0
- package/dist/processors/vetra-builder-read-model/schema.d.ts +66 -0
- package/dist/processors/vetra-builder-read-model/schema.js +1 -0
- package/dist/processors/vetra-builder-read-model/types.d.ts +32 -0
- package/dist/processors/vetra-builder-read-model/types.js +1 -0
- package/dist/style.css +3 -180
- package/dist/subgraphs/index.d.ts +1 -2
- package/dist/subgraphs/index.js +1 -3
- package/dist/subgraphs/vetra-builder-read-model/index.d.ts +10 -0
- package/dist/subgraphs/vetra-builder-read-model/index.js +11 -0
- package/dist/subgraphs/vetra-builder-read-model/resolvers.d.ts +2 -0
- package/dist/subgraphs/vetra-builder-read-model/resolvers.js +174 -0
- package/dist/subgraphs/vetra-builder-read-model/schema.d.ts +2 -0
- package/dist/subgraphs/vetra-builder-read-model/schema.js +79 -0
- package/package.json +1 -1
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { RelationalDbProcessor } from "document-drive/processors/relational";
|
|
2
|
+
import { up } from "./migrations.js";
|
|
3
|
+
import { toPascalCase } from "document-drive/utils/misc";
|
|
4
|
+
export class VetraBuilderReadModelProcessor extends RelationalDbProcessor {
|
|
5
|
+
static getNamespace(driveId) {
|
|
6
|
+
// Default namespace: `${this.name}_${driveId.replaceAll("-", "_")}`
|
|
7
|
+
return super.getNamespace(driveId);
|
|
8
|
+
}
|
|
9
|
+
async initAndUpgrade() {
|
|
10
|
+
await up(this.relationalDb);
|
|
11
|
+
}
|
|
12
|
+
async onStrands(strands) {
|
|
13
|
+
if (strands.length === 0) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
for (const strand of strands) {
|
|
17
|
+
if (strand.operations.length === 0) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
for (const operation of strand.operations) {
|
|
21
|
+
if (strand.documentType.includes("powerhouse/document-drive")) {
|
|
22
|
+
await this.handleDocumentDriveOperation(strand.documentId, strand.driveId, operation.action, operation.state);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
await this.handlePackageOperation(strand.documentId, operation.action, operation.state);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async handleDocumentDriveOperation(documentId, driveId = "", action, state) {
|
|
31
|
+
switch (action.type) {
|
|
32
|
+
case "DELETE_NODE":
|
|
33
|
+
await this.relationalDb
|
|
34
|
+
.insertInto("deleted_files")
|
|
35
|
+
.values({
|
|
36
|
+
id: documentId + "-" + action.input.id,
|
|
37
|
+
document_id: action.input.id,
|
|
38
|
+
drive_id: driveId,
|
|
39
|
+
deleted_at: new Date(),
|
|
40
|
+
})
|
|
41
|
+
.onConflict((oc) => oc.column("id").doNothing())
|
|
42
|
+
.execute();
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async handlePackageOperation(documentId, action, state) {
|
|
47
|
+
switch (action.type) {
|
|
48
|
+
// Profile operations
|
|
49
|
+
case "SET_LOGO":
|
|
50
|
+
await this.handleSetLogo(documentId, action, state);
|
|
51
|
+
break;
|
|
52
|
+
case "SET_PROFILE_NAME":
|
|
53
|
+
await this.handleSetProfileName(documentId, action, state);
|
|
54
|
+
break;
|
|
55
|
+
case "SET_SLUG":
|
|
56
|
+
await this.handleSetSlug(documentId, action, state);
|
|
57
|
+
break;
|
|
58
|
+
case "SET_PROFILE_DESCRIPTION":
|
|
59
|
+
await this.handleSetProfileDescription(documentId, action, state);
|
|
60
|
+
break;
|
|
61
|
+
case "UPDATE_SOCIALS":
|
|
62
|
+
await this.handleUpdateSocials(documentId, action, state);
|
|
63
|
+
break;
|
|
64
|
+
// Members operations
|
|
65
|
+
case "ADD_MEMBER":
|
|
66
|
+
await this.handleAddMember(documentId, action, state);
|
|
67
|
+
break;
|
|
68
|
+
case "REMOVE_MEMBER":
|
|
69
|
+
await this.handleRemoveMember(documentId, action, state);
|
|
70
|
+
break;
|
|
71
|
+
// Spaces operations
|
|
72
|
+
case "ADD_SPACE":
|
|
73
|
+
await this.handleAddSpace(documentId, action, state);
|
|
74
|
+
break;
|
|
75
|
+
case "DELETE_SPACE":
|
|
76
|
+
await this.handleDeleteSpace(documentId, action, state);
|
|
77
|
+
break;
|
|
78
|
+
case "SET_SPACE_TITLE":
|
|
79
|
+
await this.handleSetSpaceTitle(documentId, action, state);
|
|
80
|
+
break;
|
|
81
|
+
case "SET_SPACE_DESCRIPTION":
|
|
82
|
+
await this.handleSetSpaceDescription(documentId, action, state);
|
|
83
|
+
break;
|
|
84
|
+
case "REORDER_SPACES":
|
|
85
|
+
await this.handleReorderSpaces(documentId, action, state);
|
|
86
|
+
break;
|
|
87
|
+
// Packages operations
|
|
88
|
+
case "ADD_PACKAGE":
|
|
89
|
+
await this.handleAddPackage(documentId, action, state);
|
|
90
|
+
break;
|
|
91
|
+
case "SET_PACKAGE_DRIVE_ID":
|
|
92
|
+
await this.handleSetPackageDriveId(documentId, action, state);
|
|
93
|
+
break;
|
|
94
|
+
case "UPDATE_PACKAGE":
|
|
95
|
+
await this.handleUpdatePackage(documentId, action, state);
|
|
96
|
+
break;
|
|
97
|
+
case "REORDER_PACKAGES":
|
|
98
|
+
await this.handleReorderPackages(documentId, action, state);
|
|
99
|
+
break;
|
|
100
|
+
case "DELETE_PACKAGE":
|
|
101
|
+
await this.handleDeletePackage(documentId, action, state);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Profile operations
|
|
106
|
+
async handleSetLogo(documentId, action, state) {
|
|
107
|
+
await this.ensureBuilderAccount(documentId);
|
|
108
|
+
await this.relationalDb
|
|
109
|
+
.updateTable("builder_accounts")
|
|
110
|
+
.set({
|
|
111
|
+
profile_logo: action.input.logoUrl,
|
|
112
|
+
updated_at: new Date(),
|
|
113
|
+
})
|
|
114
|
+
.where("id", "=", documentId)
|
|
115
|
+
.execute();
|
|
116
|
+
}
|
|
117
|
+
async handleSetProfileName(documentId, action, state) {
|
|
118
|
+
await this.ensureBuilderAccount(documentId);
|
|
119
|
+
await this.relationalDb
|
|
120
|
+
.updateTable("builder_accounts")
|
|
121
|
+
.set({
|
|
122
|
+
profile_name: action.input.name,
|
|
123
|
+
updated_at: new Date(),
|
|
124
|
+
})
|
|
125
|
+
.where("id", "=", documentId)
|
|
126
|
+
.execute();
|
|
127
|
+
}
|
|
128
|
+
async handleSetSlug(documentId, action, state) {
|
|
129
|
+
await this.ensureBuilderAccount(documentId);
|
|
130
|
+
await this.relationalDb
|
|
131
|
+
.updateTable("builder_accounts")
|
|
132
|
+
.set({
|
|
133
|
+
profile_slug: action.input.slug,
|
|
134
|
+
updated_at: new Date(),
|
|
135
|
+
})
|
|
136
|
+
.where("id", "=", documentId)
|
|
137
|
+
.execute();
|
|
138
|
+
}
|
|
139
|
+
async handleSetProfileDescription(documentId, action, state) {
|
|
140
|
+
await this.ensureBuilderAccount(documentId);
|
|
141
|
+
await this.relationalDb
|
|
142
|
+
.updateTable("builder_accounts")
|
|
143
|
+
.set({
|
|
144
|
+
profile_description: action.input.description,
|
|
145
|
+
updated_at: new Date(),
|
|
146
|
+
})
|
|
147
|
+
.where("id", "=", documentId)
|
|
148
|
+
.execute();
|
|
149
|
+
}
|
|
150
|
+
async handleUpdateSocials(documentId, action, state) {
|
|
151
|
+
await this.ensureBuilderAccount(documentId);
|
|
152
|
+
await this.relationalDb
|
|
153
|
+
.updateTable("builder_accounts")
|
|
154
|
+
.set({
|
|
155
|
+
profile_socials_x: action.input.x,
|
|
156
|
+
profile_socials_github: action.input.github,
|
|
157
|
+
profile_socials_website: action.input.website,
|
|
158
|
+
updated_at: new Date(),
|
|
159
|
+
})
|
|
160
|
+
.where("id", "=", documentId)
|
|
161
|
+
.execute();
|
|
162
|
+
}
|
|
163
|
+
// Members operations
|
|
164
|
+
async handleAddMember(documentId, action, state) {
|
|
165
|
+
await this.ensureBuilderAccount(documentId);
|
|
166
|
+
if (!action.input.ethAddress)
|
|
167
|
+
return;
|
|
168
|
+
// Check if member already exists
|
|
169
|
+
const existingMember = await this.relationalDb
|
|
170
|
+
.selectFrom("builder_account_members")
|
|
171
|
+
.select("id")
|
|
172
|
+
.where("builder_account_id", "=", documentId)
|
|
173
|
+
.where("eth_address", "=", action.input.ethAddress)
|
|
174
|
+
.executeTakeFirst();
|
|
175
|
+
if (!existingMember) {
|
|
176
|
+
await this.relationalDb
|
|
177
|
+
.insertInto("builder_account_members")
|
|
178
|
+
.values({
|
|
179
|
+
id: action.input.ethAddress,
|
|
180
|
+
builder_account_id: documentId,
|
|
181
|
+
eth_address: action.input.ethAddress,
|
|
182
|
+
created_at: new Date(),
|
|
183
|
+
})
|
|
184
|
+
.execute();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async handleRemoveMember(documentId, action, state) {
|
|
188
|
+
if (!action.input.ethAddress)
|
|
189
|
+
return;
|
|
190
|
+
await this.relationalDb
|
|
191
|
+
.deleteFrom("builder_account_members")
|
|
192
|
+
.where("builder_account_id", "=", documentId)
|
|
193
|
+
.where("eth_address", "=", action.input.ethAddress)
|
|
194
|
+
.execute();
|
|
195
|
+
}
|
|
196
|
+
// Spaces operations
|
|
197
|
+
async handleAddSpace(documentId, action, state) {
|
|
198
|
+
await this.ensureBuilderAccount(documentId);
|
|
199
|
+
const spaceId = toPascalCase(action.input.title);
|
|
200
|
+
await this.relationalDb
|
|
201
|
+
.insertInto("builder_spaces")
|
|
202
|
+
.values({
|
|
203
|
+
id: spaceId,
|
|
204
|
+
builder_account_id: documentId,
|
|
205
|
+
title: action.input.title,
|
|
206
|
+
description: action.input.description || null,
|
|
207
|
+
sort_order: 0,
|
|
208
|
+
created_at: new Date(),
|
|
209
|
+
updated_at: new Date(),
|
|
210
|
+
})
|
|
211
|
+
.onConflict((oc) => oc.column("id").doNothing())
|
|
212
|
+
.execute();
|
|
213
|
+
}
|
|
214
|
+
async handleDeleteSpace(documentId, action, state) {
|
|
215
|
+
await this.relationalDb
|
|
216
|
+
.deleteFrom("builder_spaces")
|
|
217
|
+
.where("id", "=", action.input.id)
|
|
218
|
+
.where("builder_account_id", "=", documentId)
|
|
219
|
+
.execute();
|
|
220
|
+
}
|
|
221
|
+
async handleSetSpaceTitle(documentId, action, state) {
|
|
222
|
+
await this.relationalDb
|
|
223
|
+
.updateTable("builder_spaces")
|
|
224
|
+
.set({
|
|
225
|
+
title: action.input.newTitle,
|
|
226
|
+
updated_at: new Date(),
|
|
227
|
+
})
|
|
228
|
+
.where("id", "=", action.input.id)
|
|
229
|
+
.where("builder_account_id", "=", documentId)
|
|
230
|
+
.execute();
|
|
231
|
+
}
|
|
232
|
+
async handleSetSpaceDescription(documentId, action, state) {
|
|
233
|
+
await this.relationalDb
|
|
234
|
+
.updateTable("builder_spaces")
|
|
235
|
+
.set({
|
|
236
|
+
description: action.input.description,
|
|
237
|
+
updated_at: new Date(),
|
|
238
|
+
})
|
|
239
|
+
.where("id", "=", action.input.id)
|
|
240
|
+
.where("builder_account_id", "=", documentId)
|
|
241
|
+
.execute();
|
|
242
|
+
}
|
|
243
|
+
async handleReorderSpaces(documentId, action, state) {
|
|
244
|
+
const { ids, insertAfter } = action.input;
|
|
245
|
+
for (let i = 0; i < ids.length; i++) {
|
|
246
|
+
const spaceId = ids[i];
|
|
247
|
+
const sortOrder = insertAfter !== null ? Number(insertAfter) + i + 1 : i;
|
|
248
|
+
await this.relationalDb
|
|
249
|
+
.updateTable("builder_spaces")
|
|
250
|
+
.set({
|
|
251
|
+
sort_order: sortOrder,
|
|
252
|
+
updated_at: new Date(),
|
|
253
|
+
})
|
|
254
|
+
.where("id", "=", spaceId)
|
|
255
|
+
.where("builder_account_id", "=", documentId)
|
|
256
|
+
.execute();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Packages operations
|
|
260
|
+
async handleAddPackage(documentId, action, state) {
|
|
261
|
+
const packageId = action.input.spaceId + "-" + toPascalCase(action.input.name);
|
|
262
|
+
await this.relationalDb
|
|
263
|
+
.insertInto("builder_packages")
|
|
264
|
+
.values({
|
|
265
|
+
id: `${packageId}`,
|
|
266
|
+
space_id: action.input.spaceId,
|
|
267
|
+
name: action.input.name,
|
|
268
|
+
description: action.input.description || null,
|
|
269
|
+
category: action.input.category || null,
|
|
270
|
+
author_name: action.input.author?.name || "",
|
|
271
|
+
author_website: action.input.author?.website || null,
|
|
272
|
+
github_url: action.input.github || null,
|
|
273
|
+
npm_url: action.input.npm || null,
|
|
274
|
+
vetra_drive_url: action.input.vetraDriveUrl || null,
|
|
275
|
+
drive_id: null,
|
|
276
|
+
sort_order: 0,
|
|
277
|
+
created_at: new Date(),
|
|
278
|
+
updated_at: new Date(),
|
|
279
|
+
})
|
|
280
|
+
.onConflict((oc) => oc.column("id").doNothing())
|
|
281
|
+
.execute();
|
|
282
|
+
// Add keywords if provided
|
|
283
|
+
if (action.input.keywords && action.input.keywords.length > 0) {
|
|
284
|
+
for (const keyword of action.input.keywords) {
|
|
285
|
+
await this.relationalDb
|
|
286
|
+
.insertInto("builder_package_keywords")
|
|
287
|
+
.values({
|
|
288
|
+
id: `${packageId}-${keyword}`,
|
|
289
|
+
package_id: packageId,
|
|
290
|
+
label: keyword,
|
|
291
|
+
created_at: new Date(),
|
|
292
|
+
})
|
|
293
|
+
.execute();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
async handleSetPackageDriveId(documentId, action, state) {
|
|
298
|
+
await this.relationalDb
|
|
299
|
+
.updateTable("builder_packages")
|
|
300
|
+
.set({
|
|
301
|
+
drive_id: action.input.driveId,
|
|
302
|
+
updated_at: new Date(),
|
|
303
|
+
})
|
|
304
|
+
.where("id", "=", action.input.packageId)
|
|
305
|
+
.execute();
|
|
306
|
+
}
|
|
307
|
+
async handleUpdatePackage(documentId, action, state) {
|
|
308
|
+
const updates = { updated_at: new Date() };
|
|
309
|
+
if (action.input.title !== undefined) {
|
|
310
|
+
updates.name = action.input.title;
|
|
311
|
+
}
|
|
312
|
+
if (action.input.description !== undefined) {
|
|
313
|
+
updates.description = action.input.description;
|
|
314
|
+
}
|
|
315
|
+
await this.relationalDb
|
|
316
|
+
.updateTable("builder_packages")
|
|
317
|
+
.set(updates)
|
|
318
|
+
.where("id", "=", action.input.id)
|
|
319
|
+
.execute();
|
|
320
|
+
}
|
|
321
|
+
async handleReorderPackages(documentId, action, state) {
|
|
322
|
+
const { ids, insertAfter, spaceId } = action.input;
|
|
323
|
+
for (let i = 0; i < ids.length; i++) {
|
|
324
|
+
const packageId = ids[i];
|
|
325
|
+
const sortOrder = insertAfter !== null ? Number(insertAfter) + i + 1 : i;
|
|
326
|
+
await this.relationalDb
|
|
327
|
+
.updateTable("builder_packages")
|
|
328
|
+
.set({
|
|
329
|
+
sort_order: sortOrder,
|
|
330
|
+
updated_at: new Date(),
|
|
331
|
+
})
|
|
332
|
+
.where("id", "=", packageId)
|
|
333
|
+
.where("space_id", "=", spaceId)
|
|
334
|
+
.execute();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async handleDeletePackage(documentId, action, state) {
|
|
338
|
+
await this.relationalDb
|
|
339
|
+
.deleteFrom("builder_packages")
|
|
340
|
+
.where("id", "=", action.input.id)
|
|
341
|
+
.execute();
|
|
342
|
+
}
|
|
343
|
+
// Helper method to ensure builder account exists
|
|
344
|
+
async ensureBuilderAccount(documentId) {
|
|
345
|
+
const existing = await this.relationalDb
|
|
346
|
+
.selectFrom("builder_accounts")
|
|
347
|
+
.select("id")
|
|
348
|
+
.where("id", "=", documentId)
|
|
349
|
+
.executeTakeFirst();
|
|
350
|
+
if (!existing) {
|
|
351
|
+
await this.relationalDb
|
|
352
|
+
.insertInto("builder_accounts")
|
|
353
|
+
.values({
|
|
354
|
+
id: documentId,
|
|
355
|
+
profile_name: "",
|
|
356
|
+
profile_slug: "",
|
|
357
|
+
profile_logo: null,
|
|
358
|
+
profile_description: null,
|
|
359
|
+
profile_socials_x: null,
|
|
360
|
+
profile_socials_github: null,
|
|
361
|
+
profile_socials_website: null,
|
|
362
|
+
created_at: new Date(),
|
|
363
|
+
updated_at: new Date(),
|
|
364
|
+
})
|
|
365
|
+
.onConflict((oc) => oc.column("id").doNothing())
|
|
366
|
+
.execute();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
async onDisconnect() { }
|
|
370
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
export async function up(db) {
|
|
2
|
+
if (process.env.NODE_ENV !== "production") {
|
|
3
|
+
await down(db);
|
|
4
|
+
}
|
|
5
|
+
// Create builder_accounts table
|
|
6
|
+
await db.schema
|
|
7
|
+
.createTable("builder_accounts")
|
|
8
|
+
.addColumn("id", "varchar(255)", (col) => col.primaryKey())
|
|
9
|
+
.addColumn("profile_name", "varchar(255)", (col) => col.notNull())
|
|
10
|
+
.addColumn("profile_slug", "varchar(255)", (col) => col.notNull())
|
|
11
|
+
.addColumn("profile_logo", "text")
|
|
12
|
+
.addColumn("profile_description", "text")
|
|
13
|
+
.addColumn("profile_socials_x", "text")
|
|
14
|
+
.addColumn("profile_socials_github", "text")
|
|
15
|
+
.addColumn("profile_socials_website", "text")
|
|
16
|
+
.addColumn("created_at", "timestamp", (col) => col.defaultTo("now()").notNull())
|
|
17
|
+
.addColumn("updated_at", "timestamp", (col) => col.defaultTo("now()").notNull())
|
|
18
|
+
.ifNotExists()
|
|
19
|
+
.execute();
|
|
20
|
+
// Create builder_account_members table
|
|
21
|
+
await db.schema
|
|
22
|
+
.createTable("builder_account_members")
|
|
23
|
+
.addColumn("id", "varchar(255)", (col) => col.primaryKey())
|
|
24
|
+
.addColumn("builder_account_id", "varchar(255)", (col) => col.notNull())
|
|
25
|
+
.addColumn("eth_address", "varchar(42)", (col) => col.notNull()) // Ethereum addresses are 42 chars
|
|
26
|
+
.addColumn("created_at", "timestamp", (col) => col.defaultTo("now()").notNull())
|
|
27
|
+
.addForeignKeyConstraint("builder_account_members_account_fk", ["builder_account_id"], "builder_accounts", ["id"], (cb) => cb.onDelete("cascade"))
|
|
28
|
+
.ifNotExists()
|
|
29
|
+
.execute();
|
|
30
|
+
// Create builder_spaces table
|
|
31
|
+
await db.schema
|
|
32
|
+
.createTable("builder_spaces")
|
|
33
|
+
.addColumn("id", "varchar(255)", (col) => col.primaryKey())
|
|
34
|
+
.addColumn("builder_account_id", "varchar(255)", (col) => col.notNull())
|
|
35
|
+
.addColumn("title", "varchar(255)", (col) => col.notNull())
|
|
36
|
+
.addColumn("description", "text")
|
|
37
|
+
.addColumn("sort_order", "integer", (col) => col.defaultTo(0).notNull())
|
|
38
|
+
.addColumn("created_at", "timestamp", (col) => col.defaultTo("now()").notNull())
|
|
39
|
+
.addColumn("updated_at", "timestamp", (col) => col.defaultTo("now()").notNull())
|
|
40
|
+
.addForeignKeyConstraint("builder_spaces_account_fk", ["builder_account_id"], "builder_accounts", ["id"], (cb) => cb.onDelete("cascade"))
|
|
41
|
+
.ifNotExists()
|
|
42
|
+
.execute();
|
|
43
|
+
// Create builder_packages table
|
|
44
|
+
await db.schema
|
|
45
|
+
.createTable("builder_packages")
|
|
46
|
+
.addColumn("id", "varchar(255)", (col) => col.primaryKey())
|
|
47
|
+
.addColumn("space_id", "varchar(255)", (col) => col.notNull())
|
|
48
|
+
.addColumn("name", "varchar(255)", (col) => col.notNull())
|
|
49
|
+
.addColumn("description", "text")
|
|
50
|
+
.addColumn("category", "varchar(255)")
|
|
51
|
+
.addColumn("author_name", "varchar(255)", (col) => col.notNull())
|
|
52
|
+
.addColumn("author_website", "text")
|
|
53
|
+
.addColumn("github_url", "text")
|
|
54
|
+
.addColumn("npm_url", "text")
|
|
55
|
+
.addColumn("vetra_drive_url", "text")
|
|
56
|
+
.addColumn("drive_id", "varchar(255)") // For SetPackageDriveId operation
|
|
57
|
+
.addColumn("sort_order", "integer", (col) => col.defaultTo(0).notNull())
|
|
58
|
+
.addColumn("created_at", "timestamp", (col) => col.defaultTo("now()").notNull())
|
|
59
|
+
.addColumn("updated_at", "timestamp", (col) => col.defaultTo("now()").notNull())
|
|
60
|
+
.addForeignKeyConstraint("builder_packages_space_fk", ["space_id"], "builder_spaces", ["id"], (cb) => cb.onDelete("cascade"))
|
|
61
|
+
.ifNotExists()
|
|
62
|
+
.execute();
|
|
63
|
+
// Create builder_package_keywords table
|
|
64
|
+
await db.schema
|
|
65
|
+
.createTable("builder_package_keywords")
|
|
66
|
+
.addColumn("id", "varchar(255)", (col) => col.primaryKey())
|
|
67
|
+
.addColumn("package_id", "varchar(255)", (col) => col.notNull())
|
|
68
|
+
.addColumn("label", "varchar(255)", (col) => col.notNull())
|
|
69
|
+
.addColumn("created_at", "timestamp", (col) => col.defaultTo("now()").notNull())
|
|
70
|
+
.addForeignKeyConstraint("builder_package_keywords_package_fk", ["package_id"], "builder_packages", ["id"], (cb) => cb.onDelete("cascade"))
|
|
71
|
+
.ifNotExists()
|
|
72
|
+
.execute();
|
|
73
|
+
// Create deleted_files table
|
|
74
|
+
await db.schema
|
|
75
|
+
.createTable("deleted_files")
|
|
76
|
+
.addColumn("id", "varchar(255)", (col) => col.primaryKey())
|
|
77
|
+
.addColumn("document_id", "varchar(255)", (col) => col.notNull())
|
|
78
|
+
.addColumn("drive_id", "varchar(255)", (col) => col.notNull())
|
|
79
|
+
.addColumn("deleted_at", "timestamp", (col) => col.defaultTo("now()").notNull())
|
|
80
|
+
.ifNotExists()
|
|
81
|
+
.execute();
|
|
82
|
+
// Create indexes for better performance
|
|
83
|
+
await db.schema
|
|
84
|
+
.createIndex("idx_builder_accounts_slug")
|
|
85
|
+
.on("builder_accounts")
|
|
86
|
+
.column("profile_slug")
|
|
87
|
+
.ifNotExists()
|
|
88
|
+
.execute();
|
|
89
|
+
await db.schema
|
|
90
|
+
.createIndex("idx_builder_account_members_account")
|
|
91
|
+
.on("builder_account_members")
|
|
92
|
+
.column("builder_account_id")
|
|
93
|
+
.ifNotExists()
|
|
94
|
+
.execute();
|
|
95
|
+
await db.schema
|
|
96
|
+
.createIndex("idx_builder_account_members_eth_address")
|
|
97
|
+
.on("builder_account_members")
|
|
98
|
+
.column("eth_address")
|
|
99
|
+
.ifNotExists()
|
|
100
|
+
.execute();
|
|
101
|
+
await db.schema
|
|
102
|
+
.createIndex("idx_builder_spaces_account")
|
|
103
|
+
.on("builder_spaces")
|
|
104
|
+
.column("builder_account_id")
|
|
105
|
+
.ifNotExists()
|
|
106
|
+
.execute();
|
|
107
|
+
await db.schema
|
|
108
|
+
.createIndex("idx_builder_spaces_sort_order")
|
|
109
|
+
.on("builder_spaces")
|
|
110
|
+
.column("sort_order")
|
|
111
|
+
.ifNotExists()
|
|
112
|
+
.execute();
|
|
113
|
+
await db.schema
|
|
114
|
+
.createIndex("idx_builder_packages_space")
|
|
115
|
+
.on("builder_packages")
|
|
116
|
+
.column("space_id")
|
|
117
|
+
.ifNotExists()
|
|
118
|
+
.execute();
|
|
119
|
+
await db.schema
|
|
120
|
+
.createIndex("idx_builder_packages_sort_order")
|
|
121
|
+
.on("builder_packages")
|
|
122
|
+
.column("sort_order")
|
|
123
|
+
.ifNotExists()
|
|
124
|
+
.execute();
|
|
125
|
+
await db.schema
|
|
126
|
+
.createIndex("idx_builder_package_keywords_package")
|
|
127
|
+
.on("builder_package_keywords")
|
|
128
|
+
.column("package_id")
|
|
129
|
+
.ifNotExists()
|
|
130
|
+
.execute();
|
|
131
|
+
await db.schema
|
|
132
|
+
.createIndex("idx_deleted_files_document_id")
|
|
133
|
+
.on("deleted_files")
|
|
134
|
+
.column("document_id")
|
|
135
|
+
.ifNotExists()
|
|
136
|
+
.execute();
|
|
137
|
+
await db.schema
|
|
138
|
+
.createIndex("idx_deleted_files_drive_id")
|
|
139
|
+
.on("deleted_files")
|
|
140
|
+
.column("drive_id")
|
|
141
|
+
.ifNotExists()
|
|
142
|
+
.execute();
|
|
143
|
+
}
|
|
144
|
+
export async function down(db) {
|
|
145
|
+
// Drop tables in reverse order due to foreign key constraints
|
|
146
|
+
await db.schema.dropTable("deleted_files").ifExists().execute();
|
|
147
|
+
await db.schema.dropTable("builder_package_keywords").ifExists().execute();
|
|
148
|
+
await db.schema.dropTable("builder_packages").ifExists().execute();
|
|
149
|
+
await db.schema.dropTable("builder_spaces").ifExists().execute();
|
|
150
|
+
await db.schema.dropTable("builder_account_members").ifExists().execute();
|
|
151
|
+
await db.schema.dropTable("builder_accounts").ifExists().execute();
|
|
152
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Action } from "document-model";
|
|
2
|
+
import type { BuilderAccountState } from "document-models/builder-account/index.js";
|
|
3
|
+
import type { DB } from "./schema.js";
|
|
4
|
+
import type { IRelationalDb } from "document-drive";
|
|
5
|
+
export declare class PackageHandlers {
|
|
6
|
+
private db;
|
|
7
|
+
private dbHelpers;
|
|
8
|
+
constructor(db: IRelationalDb<DB>);
|
|
9
|
+
handlePackageOperation(documentId: string, action: Action, state: BuilderAccountState, driveId?: string): Promise<void>;
|
|
10
|
+
private handleSetPackageName;
|
|
11
|
+
private handleSetPackageDescription;
|
|
12
|
+
private handleSetPackageCategory;
|
|
13
|
+
private handleSetPackageAuthor;
|
|
14
|
+
private handleSetPackageAuthorName;
|
|
15
|
+
private handleSetPackageAuthorWebsite;
|
|
16
|
+
private handleAddPackageKeyword;
|
|
17
|
+
private handleRemovePackageKeyword;
|
|
18
|
+
private handleSetPackageGithubUrl;
|
|
19
|
+
private handleSetPackageNpmUrl;
|
|
20
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { DatabaseHelpers } from "./database-helpers.js";
|
|
2
|
+
export class PackageHandlers {
|
|
3
|
+
db;
|
|
4
|
+
dbHelpers;
|
|
5
|
+
constructor(db) {
|
|
6
|
+
this.db = db;
|
|
7
|
+
this.dbHelpers = new DatabaseHelpers(db);
|
|
8
|
+
}
|
|
9
|
+
async handlePackageOperation(documentId, action, state, driveId) {
|
|
10
|
+
const packageDriveId = driveId || "";
|
|
11
|
+
switch (action.type) {
|
|
12
|
+
case "SET_PACKAGE_NAME":
|
|
13
|
+
await this.handleSetPackageName(documentId, packageDriveId, action, state);
|
|
14
|
+
break;
|
|
15
|
+
case "SET_PACKAGE_DESCRIPTION":
|
|
16
|
+
await this.handleSetPackageDescription(documentId, packageDriveId, action, state);
|
|
17
|
+
break;
|
|
18
|
+
case "SET_PACKAGE_CATEGORY":
|
|
19
|
+
await this.handleSetPackageCategory(documentId, packageDriveId, action, state);
|
|
20
|
+
break;
|
|
21
|
+
case "SET_PACKAGE_AUTHOR":
|
|
22
|
+
await this.handleSetPackageAuthor(documentId, packageDriveId, action, state);
|
|
23
|
+
break;
|
|
24
|
+
case "SET_PACKAGE_AUTHOR_NAME":
|
|
25
|
+
await this.handleSetPackageAuthorName(documentId, packageDriveId, action, state);
|
|
26
|
+
break;
|
|
27
|
+
case "SET_PACKAGE_AUTHOR_WEBSITE":
|
|
28
|
+
await this.handleSetPackageAuthorWebsite(documentId, packageDriveId, action, state);
|
|
29
|
+
break;
|
|
30
|
+
case "ADD_PACKAGE_KEYWORD":
|
|
31
|
+
await this.handleAddPackageKeyword(documentId, packageDriveId, action, state);
|
|
32
|
+
break;
|
|
33
|
+
case "REMOVE_PACKAGE_KEYWORD":
|
|
34
|
+
await this.handleRemovePackageKeyword(documentId, packageDriveId, action, state);
|
|
35
|
+
break;
|
|
36
|
+
case "SET_PACKAGE_GITHUB_URL":
|
|
37
|
+
await this.handleSetPackageGithubUrl(documentId, packageDriveId, action, state);
|
|
38
|
+
break;
|
|
39
|
+
case "SET_PACKAGE_NPM_URL":
|
|
40
|
+
await this.handleSetPackageNpmUrl(documentId, packageDriveId, action, state);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async handleSetPackageName(documentId, driveId, action, state) {
|
|
45
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
46
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
47
|
+
name: action.input.name,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async handleSetPackageDescription(documentId, driveId, action, state) {
|
|
51
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
52
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
53
|
+
description: action.input.description,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async handleSetPackageCategory(documentId, driveId, action, state) {
|
|
57
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
58
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
59
|
+
category: action.input.category,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async handleSetPackageAuthor(documentId, driveId, action, state) {
|
|
63
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
64
|
+
const input = action.input;
|
|
65
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
66
|
+
author_name: input.name,
|
|
67
|
+
author_website: input.website,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async handleSetPackageAuthorName(documentId, driveId, action, state) {
|
|
71
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
72
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
73
|
+
author_name: action.input.name,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async handleSetPackageAuthorWebsite(documentId, driveId, action, state) {
|
|
77
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
78
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
79
|
+
author_website: action.input.website,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async handleAddPackageKeyword(documentId, driveId, action, state) {
|
|
83
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
84
|
+
const input = action.input;
|
|
85
|
+
await this.db
|
|
86
|
+
.insertInto("builder_package_keywords")
|
|
87
|
+
.values({
|
|
88
|
+
id: input.id,
|
|
89
|
+
package_id: documentId,
|
|
90
|
+
label: input.label,
|
|
91
|
+
created_at: new Date(),
|
|
92
|
+
})
|
|
93
|
+
.onConflict((oc) => oc.column("id").doNothing())
|
|
94
|
+
.execute();
|
|
95
|
+
}
|
|
96
|
+
async handleRemovePackageKeyword(documentId, driveId, action, state) {
|
|
97
|
+
const input = action.input;
|
|
98
|
+
await this.db
|
|
99
|
+
.deleteFrom("builder_package_keywords")
|
|
100
|
+
.where("id", "=", input.id)
|
|
101
|
+
.where("package_id", "=", documentId)
|
|
102
|
+
.execute();
|
|
103
|
+
}
|
|
104
|
+
async handleSetPackageGithubUrl(documentId, driveId, action, state) {
|
|
105
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
106
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
107
|
+
github_url: action.input.url,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
async handleSetPackageNpmUrl(documentId, driveId, action, state) {
|
|
111
|
+
await this.dbHelpers.ensurePackageExists(documentId, driveId);
|
|
112
|
+
await this.dbHelpers.updatePackage(documentId, {
|
|
113
|
+
npm_url: action.input.url,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|