@mevdragon/vidfarm-devcli 0.1.0 → 0.2.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/.env.example +11 -4
- package/PLATFORM_SPEC.md +142 -2
- package/README.md +165 -16
- package/SKILL.developer.md +577 -0
- package/dist/infra/cdk/bin/vidfarm-prod.js +59 -0
- package/dist/infra/cdk/lib/vidfarm-prod-stack.js +212 -0
- package/dist/src/account-pages.js +578 -0
- package/dist/src/app.js +887 -66
- package/dist/src/cli.js +284 -5
- package/dist/src/config.js +24 -4
- package/dist/src/db.js +427 -18
- package/dist/src/dev-app.js +59 -12
- package/dist/src/homepage.js +441 -0
- package/dist/src/index.js +12 -7
- package/dist/src/lib/crypto.js +14 -0
- package/dist/src/lib/template-dna.js +542 -0
- package/dist/src/lib/template-style-options.js +49 -0
- package/dist/src/registry.js +54 -7
- package/dist/src/runtime.js +3 -1
- package/dist/src/services/auth.js +69 -5
- package/dist/src/services/jobs.js +23 -4
- package/dist/src/services/providers.js +74 -12
- package/dist/src/services/storage.js +52 -18
- package/dist/src/services/template-certification.js +160 -0
- package/dist/src/services/template-loader.js +37 -0
- package/dist/src/services/template-sources.js +135 -0
- package/dist/src/worker.js +19 -7
- package/dist/templates/template_0000/src/lib/images.js +242 -0
- package/dist/templates/template_0000/src/remotion/Root.js +33 -0
- package/dist/templates/template_0000/src/sdk.js +3 -0
- package/dist/templates/template_0000/src/style-options.js +51 -0
- package/dist/templates/template_0000/src/template-dna.js +9 -0
- package/dist/templates/template_0000/src/template.js +1217 -0
- package/package.json +9 -1
- package/templates/template_0000/README.md +121 -0
- package/templates/template_0000/SKILL.md +193 -0
- package/templates/template_0000/assets/Abel-Regular.ttf +0 -0
- package/templates/template_0000/assets/DMSerifDisplay-Regular.ttf +0 -0
- package/templates/template_0000/assets/Montserrat[wght].ttf +0 -0
- package/templates/template_0000/assets/SourceCodePro[wght].ttf +0 -0
- package/templates/template_0000/assets/TikTokSans-SemiBold.ttf +0 -0
- package/templates/template_0000/assets/Yesteryear-Regular.ttf +0 -0
- package/templates/template_0000/composition.json +11 -0
- package/templates/template_0000/package-lock.json +5137 -0
- package/templates/template_0000/package.json +30 -0
- package/templates/template_0000/research/preview/.gitkeep +1 -0
- package/templates/template_0000/research/source_notes.md +7 -0
- package/templates/template_0000/scripts/create-site.mjs +27 -0
- package/templates/template_0000/scripts/render-cloud.mjs +72 -0
- package/templates/template_0000/src/lib/images.ts +284 -0
- package/templates/template_0000/src/remotion/Root.js +33 -0
- package/templates/template_0000/src/remotion/Root.tsx +75 -0
- package/templates/template_0000/src/remotion/index.tsx +4 -0
- package/templates/template_0000/src/sdk.ts +122 -0
- package/templates/template_0000/src/style-options.js +51 -0
- package/templates/template_0000/src/style-options.ts +60 -0
- package/templates/template_0000/src/template-dna.ts +15 -0
- package/templates/template_0000/src/template.ts +1747 -0
- package/templates/template_0000/template.config.json +26 -0
- package/templates/template_0000/tsconfig.json +19 -0
- package/dist/templates/template_0000/demo-template.js +0 -196
- package/dist/templates/template_0000/remotion/Root.js +0 -66
- /package/dist/templates/template_0000/{remotion → src/remotion}/index.js +0 -0
package/dist/src/db.js
CHANGED
|
@@ -11,6 +11,12 @@ create table if not exists customers (
|
|
|
11
11
|
email text not null unique,
|
|
12
12
|
name text,
|
|
13
13
|
default_webhook_url text,
|
|
14
|
+
is_developer integer not null default 0,
|
|
15
|
+
is_paid_plan integer not null default 0,
|
|
16
|
+
about text,
|
|
17
|
+
groupchat_url text,
|
|
18
|
+
flockposter_api_key text,
|
|
19
|
+
password_hash text,
|
|
14
20
|
created_at text not null,
|
|
15
21
|
updated_at text not null
|
|
16
22
|
);
|
|
@@ -19,6 +25,7 @@ create table if not exists api_keys (
|
|
|
19
25
|
id text primary key,
|
|
20
26
|
customer_id text not null references customers(id) on delete cascade,
|
|
21
27
|
key_hash text not null unique,
|
|
28
|
+
raw_value text,
|
|
22
29
|
label text,
|
|
23
30
|
status text not null,
|
|
24
31
|
last_used_at text,
|
|
@@ -160,7 +167,87 @@ create table if not exists webhook_deliveries (
|
|
|
160
167
|
created_at text not null,
|
|
161
168
|
updated_at text not null
|
|
162
169
|
);
|
|
170
|
+
|
|
171
|
+
create table if not exists user_attachments (
|
|
172
|
+
id text primary key,
|
|
173
|
+
customer_id text not null references customers(id) on delete cascade,
|
|
174
|
+
file_name text not null,
|
|
175
|
+
content_type text not null,
|
|
176
|
+
size_bytes integer not null,
|
|
177
|
+
storage_key text not null,
|
|
178
|
+
public_url text,
|
|
179
|
+
created_at text not null
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
create index if not exists idx_user_attachments_customer_created on user_attachments(customer_id, created_at desc);
|
|
183
|
+
|
|
184
|
+
create table if not exists template_sources (
|
|
185
|
+
id text primary key,
|
|
186
|
+
template_id text not null unique,
|
|
187
|
+
slug_id text,
|
|
188
|
+
repo_url text not null,
|
|
189
|
+
branch text not null,
|
|
190
|
+
template_module_path text not null,
|
|
191
|
+
skill_path text not null,
|
|
192
|
+
install_command text not null,
|
|
193
|
+
build_command text not null,
|
|
194
|
+
status text not null,
|
|
195
|
+
created_at text not null,
|
|
196
|
+
updated_at text not null
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
create table if not exists template_releases (
|
|
200
|
+
id text primary key,
|
|
201
|
+
source_id text not null references template_sources(id) on delete cascade,
|
|
202
|
+
template_id text not null,
|
|
203
|
+
branch text not null,
|
|
204
|
+
commit_sha text not null,
|
|
205
|
+
checkout_path text not null,
|
|
206
|
+
skill_path text not null,
|
|
207
|
+
module_path text not null,
|
|
208
|
+
status text not null,
|
|
209
|
+
certification_report_json text,
|
|
210
|
+
activated_at text,
|
|
211
|
+
created_at text not null,
|
|
212
|
+
updated_at text not null,
|
|
213
|
+
unique(source_id, commit_sha)
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
create index if not exists idx_template_releases_template_status on template_releases(template_id, status, created_at);
|
|
217
|
+
`);
|
|
218
|
+
const customerColumns = db.prepare(`pragma table_info(customers)`).all();
|
|
219
|
+
if (!customerColumns.some((column) => column.name === "is_developer")) {
|
|
220
|
+
db.exec(`alter table customers add column is_developer integer not null default 0;`);
|
|
221
|
+
}
|
|
222
|
+
if (!customerColumns.some((column) => column.name === "is_paid_plan")) {
|
|
223
|
+
db.exec(`alter table customers add column is_paid_plan integer not null default 0;`);
|
|
224
|
+
}
|
|
225
|
+
if (!customerColumns.some((column) => column.name === "password_hash")) {
|
|
226
|
+
db.exec(`alter table customers add column password_hash text;`);
|
|
227
|
+
}
|
|
228
|
+
if (!customerColumns.some((column) => column.name === "about")) {
|
|
229
|
+
db.exec(`alter table customers add column about text;`);
|
|
230
|
+
}
|
|
231
|
+
if (!customerColumns.some((column) => column.name === "groupchat_url")) {
|
|
232
|
+
db.exec(`alter table customers add column groupchat_url text;`);
|
|
233
|
+
}
|
|
234
|
+
if (!customerColumns.some((column) => column.name === "flockposter_api_key")) {
|
|
235
|
+
db.exec(`alter table customers add column flockposter_api_key text;`);
|
|
236
|
+
}
|
|
237
|
+
const apiKeyColumns = db.prepare(`pragma table_info(api_keys)`).all();
|
|
238
|
+
if (!apiKeyColumns.some((column) => column.name === "raw_value")) {
|
|
239
|
+
db.exec(`alter table api_keys add column raw_value text;`);
|
|
240
|
+
}
|
|
241
|
+
const templateSourceColumns = db.prepare(`pragma table_info(template_sources)`).all();
|
|
242
|
+
if (!templateSourceColumns.some((column) => column.name === "slug_id")) {
|
|
243
|
+
db.exec(`alter table template_sources add column slug_id text;`);
|
|
244
|
+
}
|
|
245
|
+
db.exec(`
|
|
246
|
+
update template_sources
|
|
247
|
+
set slug_id = replace(template_id, '-', '_')
|
|
248
|
+
where slug_id is null or trim(slug_id) = '';
|
|
163
249
|
`);
|
|
250
|
+
db.exec(`create unique index if not exists idx_template_sources_slug_id on template_sources(slug_id);`);
|
|
164
251
|
function mapJob(row) {
|
|
165
252
|
return {
|
|
166
253
|
id: String(row.id),
|
|
@@ -186,23 +273,85 @@ function mapJob(row) {
|
|
|
186
273
|
completedAt: row.completed_at ? String(row.completed_at) : null
|
|
187
274
|
};
|
|
188
275
|
}
|
|
276
|
+
function mapTemplateSource(row) {
|
|
277
|
+
return {
|
|
278
|
+
id: String(row.id),
|
|
279
|
+
templateId: String(row.template_id),
|
|
280
|
+
slugId: String(row.slug_id),
|
|
281
|
+
repoUrl: String(row.repo_url),
|
|
282
|
+
branch: String(row.branch),
|
|
283
|
+
templateModulePath: String(row.template_module_path),
|
|
284
|
+
skillPath: String(row.skill_path),
|
|
285
|
+
installCommand: String(row.install_command),
|
|
286
|
+
buildCommand: String(row.build_command),
|
|
287
|
+
status: row.status,
|
|
288
|
+
createdAt: String(row.created_at),
|
|
289
|
+
updatedAt: String(row.updated_at)
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function mapTemplateRelease(row) {
|
|
293
|
+
return {
|
|
294
|
+
id: String(row.id),
|
|
295
|
+
sourceId: String(row.source_id),
|
|
296
|
+
templateId: String(row.template_id),
|
|
297
|
+
branch: String(row.branch),
|
|
298
|
+
commitSha: String(row.commit_sha),
|
|
299
|
+
checkoutPath: String(row.checkout_path),
|
|
300
|
+
skillPath: String(row.skill_path),
|
|
301
|
+
modulePath: String(row.module_path),
|
|
302
|
+
status: row.status,
|
|
303
|
+
certificationReport: parseJson(row.certification_report_json, null),
|
|
304
|
+
activatedAt: row.activated_at ? String(row.activated_at) : null,
|
|
305
|
+
createdAt: String(row.created_at),
|
|
306
|
+
updatedAt: String(row.updated_at)
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function mapUserAttachment(row) {
|
|
310
|
+
return {
|
|
311
|
+
id: String(row.id),
|
|
312
|
+
customerId: String(row.customer_id),
|
|
313
|
+
fileName: String(row.file_name),
|
|
314
|
+
contentType: String(row.content_type),
|
|
315
|
+
sizeBytes: Number(row.size_bytes),
|
|
316
|
+
storageKey: String(row.storage_key),
|
|
317
|
+
publicUrl: row.public_url ? String(row.public_url) : null,
|
|
318
|
+
createdAt: String(row.created_at)
|
|
319
|
+
};
|
|
320
|
+
}
|
|
189
321
|
export const database = {
|
|
190
322
|
raw: db,
|
|
191
323
|
upsertCustomer(input) {
|
|
192
324
|
const timestamp = nowIso();
|
|
325
|
+
const current = db.prepare(`select * from customers where id = ?`).get(input.id);
|
|
193
326
|
db.prepare(`
|
|
194
|
-
insert into customers (
|
|
195
|
-
|
|
327
|
+
insert into customers (
|
|
328
|
+
id, email, name, default_webhook_url, is_developer, is_paid_plan, about, groupchat_url, flockposter_api_key, password_hash, created_at, updated_at
|
|
329
|
+
)
|
|
330
|
+
values (
|
|
331
|
+
@id, @email, @name, @default_webhook_url, @is_developer, @is_paid_plan, @about, @groupchat_url, @flockposter_api_key, @password_hash, @created_at, @updated_at
|
|
332
|
+
)
|
|
196
333
|
on conflict(id) do update set
|
|
197
334
|
email = excluded.email,
|
|
198
335
|
name = excluded.name,
|
|
199
336
|
default_webhook_url = excluded.default_webhook_url,
|
|
337
|
+
is_developer = excluded.is_developer,
|
|
338
|
+
is_paid_plan = excluded.is_paid_plan,
|
|
339
|
+
about = excluded.about,
|
|
340
|
+
groupchat_url = excluded.groupchat_url,
|
|
341
|
+
flockposter_api_key = excluded.flockposter_api_key,
|
|
342
|
+
password_hash = excluded.password_hash,
|
|
200
343
|
updated_at = excluded.updated_at
|
|
201
344
|
`).run({
|
|
202
345
|
id: input.id,
|
|
203
346
|
email: input.email,
|
|
204
347
|
name: input.name ?? null,
|
|
205
348
|
default_webhook_url: input.defaultWebhookUrl ?? null,
|
|
349
|
+
is_developer: input.isDeveloper === undefined ? Number(current?.is_developer ?? 0) : (input.isDeveloper ? 1 : 0),
|
|
350
|
+
is_paid_plan: input.isPaidPlan === undefined ? Number(current?.is_paid_plan ?? 0) : (input.isPaidPlan ? 1 : 0),
|
|
351
|
+
about: input.about === undefined ? (current?.about ?? null) : input.about,
|
|
352
|
+
groupchat_url: input.groupchatUrl === undefined ? (current?.groupchat_url ?? null) : input.groupchatUrl,
|
|
353
|
+
flockposter_api_key: input.flockposterApiKey === undefined ? (current?.flockposter_api_key ?? null) : input.flockposterApiKey,
|
|
354
|
+
password_hash: input.passwordHash === undefined ? (current?.password_hash ?? null) : input.passwordHash,
|
|
206
355
|
created_at: timestamp,
|
|
207
356
|
updated_at: timestamp
|
|
208
357
|
});
|
|
@@ -217,13 +366,48 @@ export const database = {
|
|
|
217
366
|
id: String(row.id),
|
|
218
367
|
email: String(row.email),
|
|
219
368
|
name: row.name ? String(row.name) : null,
|
|
220
|
-
defaultWebhookUrl: row.default_webhook_url ? String(row.default_webhook_url) : null
|
|
369
|
+
defaultWebhookUrl: row.default_webhook_url ? String(row.default_webhook_url) : null,
|
|
370
|
+
isDeveloper: Boolean(row.is_developer),
|
|
371
|
+
isPaidPlan: Boolean(row.is_paid_plan),
|
|
372
|
+
about: row.about ? String(row.about) : null,
|
|
373
|
+
groupchatUrl: row.groupchat_url ? String(row.groupchat_url) : null,
|
|
374
|
+
flockposterApiKey: row.flockposter_api_key ? String(row.flockposter_api_key) : null
|
|
221
375
|
};
|
|
222
376
|
},
|
|
223
377
|
getCustomerByEmail(email) {
|
|
224
378
|
const row = db.prepare(`select * from customers where lower(email) = lower(?)`).get(email);
|
|
225
379
|
return row ? this.getCustomerById(String(row.id)) : null;
|
|
226
380
|
},
|
|
381
|
+
getCustomerAuthByEmail(email) {
|
|
382
|
+
return db.prepare(`
|
|
383
|
+
select id, email, name, default_webhook_url, is_developer, is_paid_plan, password_hash
|
|
384
|
+
, about, groupchat_url, flockposter_api_key
|
|
385
|
+
from customers
|
|
386
|
+
where lower(email) = lower(?)
|
|
387
|
+
limit 1
|
|
388
|
+
`).get(email);
|
|
389
|
+
},
|
|
390
|
+
updateCustomerPassword(customerId, passwordHash) {
|
|
391
|
+
db.prepare(`
|
|
392
|
+
update customers
|
|
393
|
+
set password_hash = ?, updated_at = ?
|
|
394
|
+
where id = ?
|
|
395
|
+
`).run(passwordHash, nowIso(), customerId);
|
|
396
|
+
},
|
|
397
|
+
updateCustomerPaidPlan(customerId, isPaidPlan) {
|
|
398
|
+
db.prepare(`
|
|
399
|
+
update customers
|
|
400
|
+
set is_paid_plan = ?, updated_at = ?
|
|
401
|
+
where id = ?
|
|
402
|
+
`).run(isPaidPlan ? 1 : 0, nowIso(), customerId);
|
|
403
|
+
},
|
|
404
|
+
updateCustomerProfile(input) {
|
|
405
|
+
db.prepare(`
|
|
406
|
+
update customers
|
|
407
|
+
set about = ?, groupchat_url = ?, flockposter_api_key = ?, updated_at = ?
|
|
408
|
+
where id = ?
|
|
409
|
+
`).run(input.about, input.groupchatUrl, input.flockposterApiKey, nowIso(), input.customerId);
|
|
410
|
+
},
|
|
227
411
|
listProviderKeys(customerId) {
|
|
228
412
|
return db.prepare(`
|
|
229
413
|
select id, provider, label, status, weight, last_used_at, cooldown_until, disabled_reason, created_at, updated_at
|
|
@@ -232,6 +416,17 @@ export const database = {
|
|
|
232
416
|
order by provider asc, created_at desc
|
|
233
417
|
`).all(customerId);
|
|
234
418
|
},
|
|
419
|
+
listProviderKeysWithSecrets(customerId) {
|
|
420
|
+
return db.prepare(`
|
|
421
|
+
select id, provider, label, encrypted_secret as secret, status, weight, last_used_at, cooldown_until, disabled_reason, created_at, updated_at
|
|
422
|
+
from customer_provider_keys
|
|
423
|
+
where customer_id = ?
|
|
424
|
+
order by provider asc, created_at desc
|
|
425
|
+
`).all(customerId);
|
|
426
|
+
},
|
|
427
|
+
deleteProviderKey(customerId, keyId) {
|
|
428
|
+
db.prepare(`delete from customer_provider_keys where id = ? and customer_id = ?`).run(keyId, customerId);
|
|
429
|
+
},
|
|
235
430
|
insertOtpChallenge(record) {
|
|
236
431
|
db.prepare(`
|
|
237
432
|
insert into otp_challenges (id, email, code_hash, expires_at, created_at)
|
|
@@ -258,20 +453,30 @@ export const database = {
|
|
|
258
453
|
insertApiKey(record) {
|
|
259
454
|
const timestamp = nowIso();
|
|
260
455
|
db.prepare(`
|
|
261
|
-
insert into api_keys (id, customer_id, key_hash, label, status, created_at, updated_at)
|
|
262
|
-
values (@id, @customer_id, @key_hash, @label, 'active', @created_at, @updated_at)
|
|
456
|
+
insert into api_keys (id, customer_id, key_hash, raw_value, label, status, created_at, updated_at)
|
|
457
|
+
values (@id, @customer_id, @key_hash, @raw_value, @label, 'active', @created_at, @updated_at)
|
|
263
458
|
`).run({
|
|
264
459
|
id: record.id,
|
|
265
460
|
customer_id: record.customerId,
|
|
266
461
|
key_hash: record.keyHash,
|
|
462
|
+
raw_value: record.rawValue ?? null,
|
|
267
463
|
label: record.label,
|
|
268
464
|
created_at: timestamp,
|
|
269
465
|
updated_at: timestamp
|
|
270
466
|
});
|
|
271
467
|
},
|
|
468
|
+
getLatestApiKeyForCustomer(customerId) {
|
|
469
|
+
return db.prepare(`
|
|
470
|
+
select id, raw_value, label, last_used_at, created_at, updated_at
|
|
471
|
+
from api_keys
|
|
472
|
+
where customer_id = ? and status = 'active'
|
|
473
|
+
order by case when raw_value is null or trim(raw_value) = '' then 1 else 0 end asc, created_at desc
|
|
474
|
+
limit 1
|
|
475
|
+
`).get(customerId);
|
|
476
|
+
},
|
|
272
477
|
findApiKeyByHash(keyHash) {
|
|
273
478
|
return db.prepare(`
|
|
274
|
-
select a.*, c.email, c.name, c.default_webhook_url
|
|
479
|
+
select a.*, c.email, c.name, c.default_webhook_url, c.is_developer, c.is_paid_plan, c.about, c.groupchat_url, c.flockposter_api_key
|
|
275
480
|
from api_keys a
|
|
276
481
|
join customers c on c.id = a.customer_id
|
|
277
482
|
where a.key_hash = ? and a.status = 'active'
|
|
@@ -346,6 +551,21 @@ export const database = {
|
|
|
346
551
|
const row = db.prepare(`select * from jobs where id = ?`).get(id);
|
|
347
552
|
return row ? mapJob(row) : null;
|
|
348
553
|
},
|
|
554
|
+
countJobsByStatuses(input) {
|
|
555
|
+
const statuses = input.statuses.length ? input.statuses : ["queued"];
|
|
556
|
+
const filters = [`status in (${statuses.map(() => "?").join(", ")})`];
|
|
557
|
+
const values = [...statuses];
|
|
558
|
+
if (input.customerId) {
|
|
559
|
+
filters.push("customer_id = ?");
|
|
560
|
+
values.push(input.customerId);
|
|
561
|
+
}
|
|
562
|
+
const row = db.prepare(`
|
|
563
|
+
select count(*) as count
|
|
564
|
+
from jobs
|
|
565
|
+
where ${filters.join(" and ")}
|
|
566
|
+
`).get(...values);
|
|
567
|
+
return Number(row.count);
|
|
568
|
+
},
|
|
349
569
|
listRunnableJobs(limit) {
|
|
350
570
|
const rows = db.prepare(`
|
|
351
571
|
select * from jobs
|
|
@@ -386,10 +606,32 @@ export const database = {
|
|
|
386
606
|
updated_at: nowIso()
|
|
387
607
|
});
|
|
388
608
|
},
|
|
389
|
-
listJobsForCustomer(
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
609
|
+
listJobsForCustomer(input) {
|
|
610
|
+
const filters = ["customer_id = ?"];
|
|
611
|
+
const values = [input.customerId];
|
|
612
|
+
if (input.templateId) {
|
|
613
|
+
filters.push("template_id = ?");
|
|
614
|
+
values.push(input.templateId);
|
|
615
|
+
}
|
|
616
|
+
if (input.tracer) {
|
|
617
|
+
filters.push("tracer = ?");
|
|
618
|
+
values.push(input.tracer);
|
|
619
|
+
}
|
|
620
|
+
if (input.startTime) {
|
|
621
|
+
filters.push("created_at >= ?");
|
|
622
|
+
values.push(input.startTime);
|
|
623
|
+
}
|
|
624
|
+
if (input.endTime) {
|
|
625
|
+
filters.push("created_at <= ?");
|
|
626
|
+
values.push(input.endTime);
|
|
627
|
+
}
|
|
628
|
+
values.push(Math.max(1, Math.min(input.limit ?? 100, 500)));
|
|
629
|
+
const rows = db.prepare(`
|
|
630
|
+
select * from jobs
|
|
631
|
+
where ${filters.join(" and ")}
|
|
632
|
+
order by created_at desc
|
|
633
|
+
limit ?
|
|
634
|
+
`).all(...values);
|
|
393
635
|
return rows.map(mapJob);
|
|
394
636
|
},
|
|
395
637
|
addJobEvent(event) {
|
|
@@ -407,14 +649,24 @@ export const database = {
|
|
|
407
649
|
created_at: nowIso()
|
|
408
650
|
});
|
|
409
651
|
},
|
|
410
|
-
getJobEvents(
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
652
|
+
getJobEvents(input) {
|
|
653
|
+
const filters = ["job_id = ?"];
|
|
654
|
+
const values = [input.jobId];
|
|
655
|
+
if (input.startTime) {
|
|
656
|
+
filters.push("created_at >= ?");
|
|
657
|
+
values.push(input.startTime);
|
|
658
|
+
}
|
|
659
|
+
if (input.endTime) {
|
|
660
|
+
filters.push("created_at <= ?");
|
|
661
|
+
values.push(input.endTime);
|
|
662
|
+
}
|
|
663
|
+
values.push(Math.max(1, Math.min(input.limit ?? 100, 500)));
|
|
664
|
+
const rows = db.prepare(`
|
|
665
|
+
select * from job_events
|
|
666
|
+
where ${filters.join(" and ")}
|
|
667
|
+
order by created_at asc
|
|
668
|
+
limit ?
|
|
669
|
+
`).all(...values);
|
|
418
670
|
return rows.map((row) => ({
|
|
419
671
|
id: String(row.id),
|
|
420
672
|
jobId: String(row.job_id),
|
|
@@ -584,5 +836,162 @@ export const database = {
|
|
|
584
836
|
created_at: timestamp,
|
|
585
837
|
updated_at: timestamp
|
|
586
838
|
});
|
|
839
|
+
},
|
|
840
|
+
createUserAttachment(record) {
|
|
841
|
+
db.prepare(`
|
|
842
|
+
insert into user_attachments (
|
|
843
|
+
id, customer_id, file_name, content_type, size_bytes, storage_key, public_url, created_at
|
|
844
|
+
) values (
|
|
845
|
+
@id, @customer_id, @file_name, @content_type, @size_bytes, @storage_key, @public_url, @created_at
|
|
846
|
+
)
|
|
847
|
+
`).run({
|
|
848
|
+
id: record.id,
|
|
849
|
+
customer_id: record.customerId,
|
|
850
|
+
file_name: record.fileName,
|
|
851
|
+
content_type: record.contentType,
|
|
852
|
+
size_bytes: record.sizeBytes,
|
|
853
|
+
storage_key: record.storageKey,
|
|
854
|
+
public_url: record.publicUrl ?? null,
|
|
855
|
+
created_at: nowIso()
|
|
856
|
+
});
|
|
857
|
+
},
|
|
858
|
+
listUserAttachments(customerId) {
|
|
859
|
+
const rows = db.prepare(`
|
|
860
|
+
select *
|
|
861
|
+
from user_attachments
|
|
862
|
+
where customer_id = ?
|
|
863
|
+
order by created_at desc
|
|
864
|
+
`).all(customerId);
|
|
865
|
+
return rows.map(mapUserAttachment);
|
|
866
|
+
},
|
|
867
|
+
getUserAttachment(customerId, attachmentId) {
|
|
868
|
+
const row = db.prepare(`
|
|
869
|
+
select *
|
|
870
|
+
from user_attachments
|
|
871
|
+
where customer_id = ? and id = ?
|
|
872
|
+
limit 1
|
|
873
|
+
`).get(customerId, attachmentId);
|
|
874
|
+
return row ? mapUserAttachment(row) : null;
|
|
875
|
+
},
|
|
876
|
+
deleteUserAttachment(customerId, attachmentId) {
|
|
877
|
+
db.prepare(`delete from user_attachments where customer_id = ? and id = ?`).run(customerId, attachmentId);
|
|
878
|
+
},
|
|
879
|
+
createTemplateSource(record) {
|
|
880
|
+
const timestamp = nowIso();
|
|
881
|
+
db.prepare(`
|
|
882
|
+
insert into template_sources (
|
|
883
|
+
id, template_id, slug_id, repo_url, branch, template_module_path, skill_path, install_command, build_command, status, created_at, updated_at
|
|
884
|
+
) values (
|
|
885
|
+
@id, @template_id, @slug_id, @repo_url, @branch, @template_module_path, @skill_path, @install_command, @build_command, @status, @created_at, @updated_at
|
|
886
|
+
)
|
|
887
|
+
`).run({
|
|
888
|
+
id: record.id,
|
|
889
|
+
template_id: record.templateId,
|
|
890
|
+
slug_id: record.slugId,
|
|
891
|
+
repo_url: record.repoUrl,
|
|
892
|
+
branch: record.branch,
|
|
893
|
+
template_module_path: record.templateModulePath,
|
|
894
|
+
skill_path: record.skillPath,
|
|
895
|
+
install_command: record.installCommand,
|
|
896
|
+
build_command: record.buildCommand,
|
|
897
|
+
status: record.status,
|
|
898
|
+
created_at: timestamp,
|
|
899
|
+
updated_at: timestamp
|
|
900
|
+
});
|
|
901
|
+
return this.getTemplateSourceByTemplateId(record.templateId);
|
|
902
|
+
},
|
|
903
|
+
getTemplateSource(id) {
|
|
904
|
+
const row = db.prepare(`select * from template_sources where id = ?`).get(id);
|
|
905
|
+
return row ? mapTemplateSource(row) : null;
|
|
906
|
+
},
|
|
907
|
+
getTemplateSourceByTemplateId(templateId) {
|
|
908
|
+
const row = db.prepare(`select * from template_sources where template_id = ?`).get(templateId);
|
|
909
|
+
return row ? mapTemplateSource(row) : null;
|
|
910
|
+
},
|
|
911
|
+
getTemplateSourceBySlugId(slugId) {
|
|
912
|
+
const row = db.prepare(`select * from template_sources where slug_id = ?`).get(slugId);
|
|
913
|
+
return row ? mapTemplateSource(row) : null;
|
|
914
|
+
},
|
|
915
|
+
listTemplateSources() {
|
|
916
|
+
return db.prepare(`select * from template_sources order by template_id asc`).all().map(mapTemplateSource);
|
|
917
|
+
},
|
|
918
|
+
createTemplateRelease(record) {
|
|
919
|
+
const timestamp = nowIso();
|
|
920
|
+
db.prepare(`
|
|
921
|
+
insert into template_releases (
|
|
922
|
+
id, source_id, template_id, branch, commit_sha, checkout_path, skill_path, module_path, status,
|
|
923
|
+
certification_report_json, activated_at, created_at, updated_at
|
|
924
|
+
) values (
|
|
925
|
+
@id, @source_id, @template_id, @branch, @commit_sha, @checkout_path, @skill_path, @module_path, @status,
|
|
926
|
+
@certification_report_json, @activated_at, @created_at, @updated_at
|
|
927
|
+
)
|
|
928
|
+
on conflict(source_id, commit_sha) do update set
|
|
929
|
+
checkout_path = excluded.checkout_path,
|
|
930
|
+
skill_path = excluded.skill_path,
|
|
931
|
+
module_path = excluded.module_path,
|
|
932
|
+
status = excluded.status,
|
|
933
|
+
certification_report_json = excluded.certification_report_json,
|
|
934
|
+
activated_at = excluded.activated_at,
|
|
935
|
+
updated_at = excluded.updated_at
|
|
936
|
+
`).run({
|
|
937
|
+
id: record.id,
|
|
938
|
+
source_id: record.sourceId,
|
|
939
|
+
template_id: record.templateId,
|
|
940
|
+
branch: record.branch,
|
|
941
|
+
commit_sha: record.commitSha,
|
|
942
|
+
checkout_path: record.checkoutPath,
|
|
943
|
+
skill_path: record.skillPath,
|
|
944
|
+
module_path: record.modulePath,
|
|
945
|
+
status: record.status,
|
|
946
|
+
certification_report_json: stringifyJson(record.certificationReport ?? null),
|
|
947
|
+
activated_at: record.activatedAt ?? null,
|
|
948
|
+
created_at: timestamp,
|
|
949
|
+
updated_at: timestamp
|
|
950
|
+
});
|
|
951
|
+
return this.getTemplateReleaseBySourceAndCommit(record.sourceId, record.commitSha);
|
|
952
|
+
},
|
|
953
|
+
getTemplateRelease(id) {
|
|
954
|
+
const row = db.prepare(`select * from template_releases where id = ?`).get(id);
|
|
955
|
+
return row ? mapTemplateRelease(row) : null;
|
|
956
|
+
},
|
|
957
|
+
getTemplateReleaseBySourceAndCommit(sourceId, commitSha) {
|
|
958
|
+
const row = db.prepare(`select * from template_releases where source_id = ? and commit_sha = ?`).get(sourceId, commitSha);
|
|
959
|
+
return row ? mapTemplateRelease(row) : null;
|
|
960
|
+
},
|
|
961
|
+
listTemplateReleases(templateId) {
|
|
962
|
+
const rows = templateId
|
|
963
|
+
? db.prepare(`select * from template_releases where template_id = ? order by created_at desc`).all(templateId)
|
|
964
|
+
: db.prepare(`select * from template_releases order by created_at desc`).all();
|
|
965
|
+
return rows.map(mapTemplateRelease);
|
|
966
|
+
},
|
|
967
|
+
getActiveTemplateReleases() {
|
|
968
|
+
return db.prepare(`select * from template_releases where status = 'active' order by template_id asc`).all().map(mapTemplateRelease);
|
|
969
|
+
},
|
|
970
|
+
updateTemplateReleaseStatus(input) {
|
|
971
|
+
const current = this.getTemplateRelease(input.id);
|
|
972
|
+
db.prepare(`
|
|
973
|
+
update template_releases
|
|
974
|
+
set status = @status,
|
|
975
|
+
certification_report_json = @certification_report_json,
|
|
976
|
+
activated_at = @activated_at,
|
|
977
|
+
updated_at = @updated_at
|
|
978
|
+
where id = @id
|
|
979
|
+
`).run({
|
|
980
|
+
id: input.id,
|
|
981
|
+
status: input.status,
|
|
982
|
+
certification_report_json: input.certificationReport === undefined
|
|
983
|
+
? stringifyJson(current?.certificationReport ?? null)
|
|
984
|
+
: stringifyJson(input.certificationReport),
|
|
985
|
+
activated_at: input.activatedAt === undefined ? current?.activatedAt ?? null : input.activatedAt,
|
|
986
|
+
updated_at: nowIso()
|
|
987
|
+
});
|
|
988
|
+
},
|
|
989
|
+
clearActiveTemplateReleases(templateId) {
|
|
990
|
+
db.prepare(`
|
|
991
|
+
update template_releases
|
|
992
|
+
set status = case when status = 'active' then 'certified' else status end,
|
|
993
|
+
updated_at = ?
|
|
994
|
+
where template_id = ?
|
|
995
|
+
`).run(nowIso(), templateId);
|
|
587
996
|
}
|
|
588
997
|
};
|