@manablox/db 0.3.0 → 0.4.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/{index-Cyf_N5K3.d.ts → index-BLAkQMJT.d.ts} +223 -4
- package/dist/{index-rZ24t-Ln.d.ts → index-DrNMGM9N.d.ts} +858 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/{repositories-DYjzuuF6.js → repositories-pz4NeWaF.js} +407 -12
- package/dist/{schema-Bb4p16Yz.js → schema-Dm3RcBst.js} +111 -2
- package/dist/schema.d.ts +2 -2
- package/dist/schema.js +2 -2
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/migrations/0009_audit-log.sql +40 -0
- package/migrations/0010_notifications-approvals.sql +45 -0
- package/migrations/meta/0009_snapshot.json +3192 -0
- package/migrations/meta/0010_snapshot.json +3574 -0
- package/migrations/meta/_journal.json +14 -0
- package/package.json +2 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { T as webhooks, U as contents, W as publishedContents, _ as UserRow, a as ContentApprovalRow, b as index_d_exports, d as MenuItemRow, f as MenuRow, g as SpaceRow, h as RoleRow, i as AuditEntryRow, l as ContentVersionRow, m as PushSubscriptionRow, p as NotificationRow, r as AssetVariantRow, s as ContentRow, t as AssetRow, u as MembershipRow, v as WorkflowRow, w as webhookDeliveries, y as WorkflowRunRow } from "./index-DrNMGM9N.js";
|
|
2
2
|
import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
3
3
|
import postgres from "postgres";
|
|
4
4
|
import { SQL, SQL as SQL$1 } from "drizzle-orm";
|
|
5
5
|
import { PgColumn, PgColumn as PgColumn$1, PgTable } from "drizzle-orm/pg-core";
|
|
6
|
-
import { ContentStatus, ContentTypeDefinition, ContentTypeInput, ContentTypeRegistry, DatabaseConfig, FilterOperator, Loose, WorkflowCursor, WorkflowRunContext, WorkflowRunStatus, WorkflowSelection, WorkflowStep, WorkflowStepLog, WorkflowTrigger } from "@manablox/core";
|
|
6
|
+
import { ApprovalStatus, AuditAction, AuditActor, AuditActorKind, AuditChange, AuditSortField, AuditTargetKind, ContentStatus, ContentTypeDefinition, ContentTypeInput, ContentTypeRegistry, DatabaseConfig, FilterOperator, Loose, NotificationKind, NotificationPreferences, WorkflowCursor, WorkflowRunContext, WorkflowRunStatus, WorkflowSelection, WorkflowStep, WorkflowStepLog, WorkflowTrigger } from "@manablox/core";
|
|
7
7
|
//#region src/client.d.ts
|
|
8
8
|
type Database = PostgresJsDatabase<typeof index_d_exports>;
|
|
9
9
|
/** What `db.transaction((tx) => …)` hands its callback. */
|
|
@@ -138,6 +138,8 @@ declare class AssetRepository {
|
|
|
138
138
|
create(data: AssetWriteData): Promise<AssetRow>;
|
|
139
139
|
update(id: string, data: Loose<Pick<AssetWriteData, 'name' | 'alt' | 'title' | 'meta'>>): Promise<AssetRow>;
|
|
140
140
|
delete(id: string): Promise<AssetRow | null>;
|
|
141
|
+
/** Timestamps an import carries over; `create()` can only stamp the moment of import. */
|
|
142
|
+
restoreTimestamps(id: string, createdAt: Date, updatedAt: Date): Promise<void>;
|
|
141
143
|
variants(assetIds: string[]): Promise<AssetVariantRow[]>;
|
|
142
144
|
findVariant(assetId: string, preset: string, format: string): Promise<AssetVariantRow | null>;
|
|
143
145
|
/** Drops every variant row; the caller removes the files. */
|
|
@@ -206,6 +208,92 @@ declare class AssetUsageRepository {
|
|
|
206
208
|
}>>;
|
|
207
209
|
}
|
|
208
210
|
//#endregion
|
|
211
|
+
//#region src/repositories/audit.d.ts
|
|
212
|
+
interface AuditAppendInput {
|
|
213
|
+
/** The space the action concerns; omit for an instance-wide action. */
|
|
214
|
+
spaceId?: string | null | undefined;
|
|
215
|
+
/** Who did it; the current actor (see `runAsActor`) when omitted. */
|
|
216
|
+
actor?: AuditActor | undefined;
|
|
217
|
+
action: AuditAction;
|
|
218
|
+
targetKind: AuditTargetKind;
|
|
219
|
+
targetId?: string | null | undefined;
|
|
220
|
+
targetLabel?: string | null | undefined;
|
|
221
|
+
changes?: AuditChange[] | undefined;
|
|
222
|
+
meta?: Record<string, unknown> | null | undefined;
|
|
223
|
+
at?: Date | undefined;
|
|
224
|
+
}
|
|
225
|
+
interface AuditFilter {
|
|
226
|
+
/** A space's entries; `null` for instance-wide entries only; absent for every entry. */
|
|
227
|
+
spaceId?: string | null | undefined;
|
|
228
|
+
actorKind?: AuditActorKind | undefined;
|
|
229
|
+
actorId?: string | undefined;
|
|
230
|
+
actions?: AuditAction[] | undefined;
|
|
231
|
+
targetKind?: AuditTargetKind | undefined;
|
|
232
|
+
targetId?: string | undefined;
|
|
233
|
+
from?: Date | undefined;
|
|
234
|
+
to?: Date | undefined;
|
|
235
|
+
/** Matched against the actor's label, the target's label and the action. */
|
|
236
|
+
search?: string | undefined;
|
|
237
|
+
}
|
|
238
|
+
interface AuditSort {
|
|
239
|
+
by: AuditSortField;
|
|
240
|
+
direction: 'asc' | 'desc';
|
|
241
|
+
}
|
|
242
|
+
/** The outcome of walking the chain: where it broke, if it did. */
|
|
243
|
+
interface AuditVerification {
|
|
244
|
+
ok: boolean;
|
|
245
|
+
checked: number;
|
|
246
|
+
/** The first entry whose hash does not match, or whose `prevHash` is not its predecessor's. */
|
|
247
|
+
brokenAt: {
|
|
248
|
+
seq: number;
|
|
249
|
+
id: string;
|
|
250
|
+
reason: 'hash' | 'link';
|
|
251
|
+
} | null;
|
|
252
|
+
}
|
|
253
|
+
interface AuditRepositoryOptions {
|
|
254
|
+
/** Told when `record` could not write; the action itself is not undone. */
|
|
255
|
+
onError?: ((error: unknown, input: AuditAppendInput) => void) | undefined;
|
|
256
|
+
/**
|
|
257
|
+
* Told after every entry has been committed: the realtime feed listens here, because
|
|
258
|
+
* an audit entry is written for every change and only after it has happened. A
|
|
259
|
+
* listener that throws is reported to `onError`; the entry stays written.
|
|
260
|
+
*/
|
|
261
|
+
onAppended?: ((row: AuditEntryRow) => void) | undefined;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Appends to and reads the audit log. There is no update and no delete: the table
|
|
265
|
+
* refuses both, so this class offers neither.
|
|
266
|
+
*/
|
|
267
|
+
declare class AuditRepository {
|
|
268
|
+
private readonly db;
|
|
269
|
+
private readonly options;
|
|
270
|
+
constructor(db: Database, options?: AuditRepositoryOptions);
|
|
271
|
+
/**
|
|
272
|
+
* Writes one entry, chained to the last. Writers are serialised on a transaction-level
|
|
273
|
+
* advisory lock, so two entries can never both claim the same predecessor; the lock
|
|
274
|
+
* is held for one read and one insert.
|
|
275
|
+
*/
|
|
276
|
+
append(input: AuditAppendInput): Promise<AuditEntryRow>;
|
|
277
|
+
private write;
|
|
278
|
+
/**
|
|
279
|
+
* `append` that never throws. The write it describes has already happened; failing
|
|
280
|
+
* the request now would report an error for something that succeeded, so the failure
|
|
281
|
+
* is reported to `onError` (the host logs it) and the caller carries on.
|
|
282
|
+
*/
|
|
283
|
+
record(input: AuditAppendInput): Promise<AuditEntryRow | null>;
|
|
284
|
+
findById(id: string): Promise<AuditEntryRow | null>;
|
|
285
|
+
list(filter: AuditFilter, sort?: AuditSort, pagination?: Pagination): Promise<Paginated<AuditEntryRow>>;
|
|
286
|
+
/** The entries about one thing, oldest first: a document's history. */
|
|
287
|
+
forTarget(targetKind: AuditTargetKind, targetId: string, limit?: number): Promise<AuditEntryRow[]>;
|
|
288
|
+
/**
|
|
289
|
+
* Recomputes every hash from the first entry on and checks each link to its
|
|
290
|
+
* predecessor. The chain is one across the instance, so this walks all of it, in
|
|
291
|
+
* batches; on a large log it takes a while and that is the point.
|
|
292
|
+
*/
|
|
293
|
+
verify(batchSize?: number): Promise<AuditVerification>;
|
|
294
|
+
count(filter?: AuditFilter): Promise<number>;
|
|
295
|
+
}
|
|
296
|
+
//#endregion
|
|
209
297
|
//#region src/repositories/content.d.ts
|
|
210
298
|
interface ContentWriteData {
|
|
211
299
|
id?: string | undefined;
|
|
@@ -328,6 +416,25 @@ declare class ContentRepository {
|
|
|
328
416
|
}>>;
|
|
329
417
|
/** The row exactly as it was at that version — `snapshot()` stores the whole row. */
|
|
330
418
|
versionSnapshot(contentId: string, version: number): Promise<ContentRow | null>;
|
|
419
|
+
/** Every stored version of these documents, oldest first, for a space export. */
|
|
420
|
+
history(contentIds: string[]): Promise<ContentVersionRow[]>;
|
|
421
|
+
/**
|
|
422
|
+
* Puts an imported document back the way its source had it: the version counter and
|
|
423
|
+
* timestamps `create()` had to invent, and the version history in place of the single
|
|
424
|
+
* snapshot `create()` wrote. The row's own columns are left alone otherwise.
|
|
425
|
+
*/
|
|
426
|
+
restoreHistory(id: string, data: {
|
|
427
|
+
version: number;
|
|
428
|
+
createdAt: Date;
|
|
429
|
+
updatedAt: Date;
|
|
430
|
+
versions: Array<{
|
|
431
|
+
version: number;
|
|
432
|
+
label: string | null;
|
|
433
|
+
snapshot: Record<string, unknown>;
|
|
434
|
+
createdAt: Date;
|
|
435
|
+
createdBy: string | null;
|
|
436
|
+
}>;
|
|
437
|
+
}): Promise<void>;
|
|
331
438
|
private snapshot;
|
|
332
439
|
private findRow;
|
|
333
440
|
private lockRow;
|
|
@@ -340,6 +447,55 @@ declare function buildTree(rows: Array<ContentRow & {
|
|
|
340
447
|
depth: number;
|
|
341
448
|
}>, rootId: string | null): TreeNode[];
|
|
342
449
|
//#endregion
|
|
450
|
+
//#region src/repositories/content-approval.d.ts
|
|
451
|
+
interface ApprovalRequestData {
|
|
452
|
+
spaceId: string;
|
|
453
|
+
contentId: string;
|
|
454
|
+
typeId: string;
|
|
455
|
+
requestedBy: string | null;
|
|
456
|
+
requestedByLabel: string;
|
|
457
|
+
requestNote?: string | null | undefined;
|
|
458
|
+
contentVersion?: number | null | undefined;
|
|
459
|
+
}
|
|
460
|
+
interface ApprovalDecisionData {
|
|
461
|
+
status: Exclude<ApprovalStatus, 'pending'>;
|
|
462
|
+
decidedBy: string | null;
|
|
463
|
+
decidedByLabel: string | null;
|
|
464
|
+
decisionNote?: string | null | undefined;
|
|
465
|
+
}
|
|
466
|
+
/** A pending request with the document it concerns, for the reviewers' queue. */
|
|
467
|
+
interface PendingApproval extends ContentApprovalRow {
|
|
468
|
+
content: {
|
|
469
|
+
id: string;
|
|
470
|
+
title: string;
|
|
471
|
+
locale: string;
|
|
472
|
+
typeId: string;
|
|
473
|
+
updatedAt: Date;
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* The approval history of documents. Rows are appended when someone asks and closed
|
|
478
|
+
* when someone decides; the "one pending per document" rule is the service's, this
|
|
479
|
+
* only offers the reads it needs to keep it.
|
|
480
|
+
*/
|
|
481
|
+
declare class ContentApprovalRepository {
|
|
482
|
+
private readonly db;
|
|
483
|
+
constructor(db: Database);
|
|
484
|
+
findById(id: string): Promise<ContentApprovalRow | null>;
|
|
485
|
+
/** The open request on a document, if there is one. */
|
|
486
|
+
pendingFor(contentId: string): Promise<ContentApprovalRow | null>;
|
|
487
|
+
/** The most recent request on a document, whatever became of it. */
|
|
488
|
+
latestFor(contentId: string): Promise<ContentApprovalRow | null>;
|
|
489
|
+
historyFor(contentId: string, limit?: number): Promise<ContentApprovalRow[]>;
|
|
490
|
+
/**
|
|
491
|
+
* Every open request in a space, oldest first, with the document beside it. Narrowed
|
|
492
|
+
* to `typeIds` when the reader may only publish some types; `null` means every type.
|
|
493
|
+
*/
|
|
494
|
+
pendingInSpace(spaceId: string, typeIds?: string[] | null): Promise<PendingApproval[]>;
|
|
495
|
+
request(data: ApprovalRequestData): Promise<ContentApprovalRow>;
|
|
496
|
+
decide(id: string, data: ApprovalDecisionData): Promise<ContentApprovalRow>;
|
|
497
|
+
}
|
|
498
|
+
//#endregion
|
|
343
499
|
//#region src/repositories/content-type.d.ts
|
|
344
500
|
/**
|
|
345
501
|
* Persistence for *runtime-defined* content types only. Code-defined types come from
|
|
@@ -420,8 +576,49 @@ declare class MenuRepository {
|
|
|
420
576
|
resolve(menu: MenuRow, locale: string, published?: boolean): Promise<ResolvedMenuItem[]>;
|
|
421
577
|
}
|
|
422
578
|
//#endregion
|
|
579
|
+
//#region src/repositories/notification.d.ts
|
|
580
|
+
interface NotificationInsert {
|
|
581
|
+
userId: string;
|
|
582
|
+
spaceId?: string | null | undefined;
|
|
583
|
+
kind: NotificationKind;
|
|
584
|
+
title: string;
|
|
585
|
+
body?: string | undefined;
|
|
586
|
+
url?: string | null | undefined;
|
|
587
|
+
targetKind?: string | null | undefined;
|
|
588
|
+
targetId?: string | null | undefined;
|
|
589
|
+
actorId?: string | null | undefined;
|
|
590
|
+
actorLabel?: string | null | undefined;
|
|
591
|
+
meta?: Record<string, unknown> | null | undefined;
|
|
592
|
+
}
|
|
593
|
+
interface NotificationFilter {
|
|
594
|
+
unreadOnly?: boolean | undefined;
|
|
595
|
+
kinds?: NotificationKind[] | undefined;
|
|
596
|
+
spaceId?: string | null | undefined;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* One person's inbox. Every method is scoped to a `userId`, so a row id from another
|
|
600
|
+
* account is inert: there is no way to read or change what is not yours.
|
|
601
|
+
*/
|
|
602
|
+
declare class NotificationRepository {
|
|
603
|
+
private readonly db;
|
|
604
|
+
constructor(db: Database);
|
|
605
|
+
/** Inserts one row per recipient in one statement; an empty list writes nothing. */
|
|
606
|
+
insertMany(rows: NotificationInsert[]): Promise<NotificationRow[]>;
|
|
607
|
+
list(userId: string, filter?: NotificationFilter, pagination?: Pagination): Promise<Paginated<NotificationRow>>;
|
|
608
|
+
findById(userId: string, id: string): Promise<NotificationRow | null>;
|
|
609
|
+
countUnread(userId: string): Promise<number>;
|
|
610
|
+
/** Marks the named rows read; rows already read keep their original time. Returns how many changed. */
|
|
611
|
+
markRead(userId: string, ids: string[]): Promise<number>;
|
|
612
|
+
markUnread(userId: string, ids: string[]): Promise<number>;
|
|
613
|
+
markAllRead(userId: string): Promise<number>;
|
|
614
|
+
delete(userId: string, ids: string[]): Promise<number>;
|
|
615
|
+
deleteRead(userId: string): Promise<number>;
|
|
616
|
+
}
|
|
617
|
+
//#endregion
|
|
423
618
|
//#region src/repositories/role.d.ts
|
|
424
619
|
interface RoleWriteData {
|
|
620
|
+
/** Kept when given, so an import can restore a role under the id its memberships name. */
|
|
621
|
+
id?: string | undefined;
|
|
425
622
|
name: string;
|
|
426
623
|
machineName: string;
|
|
427
624
|
description?: string | null;
|
|
@@ -489,6 +686,8 @@ declare class UserRepository {
|
|
|
489
686
|
constructor(db: Database);
|
|
490
687
|
findById(id: string): Promise<UserRow | null>;
|
|
491
688
|
findManyByIds(ids: string[]): Promise<UserRow[]>;
|
|
689
|
+
/** Every account holding an instance role, for a fan-out to the superadmins. */
|
|
690
|
+
findByRole(role: string): Promise<UserRow[]>;
|
|
492
691
|
findByEmail(email: string): Promise<UserRow | null>;
|
|
493
692
|
list(pagination: Pagination, search?: string): Promise<Paginated<UserRow>>;
|
|
494
693
|
/**
|
|
@@ -515,6 +714,9 @@ declare class UserRepository {
|
|
|
515
714
|
/** Signs the user out everywhere. */
|
|
516
715
|
revokeSessions(userId: string): Promise<void>;
|
|
517
716
|
countByRole(role: string): Promise<number>;
|
|
717
|
+
setNotificationPreferences(id: string, preferences: NotificationPreferences): Promise<UserRow>;
|
|
718
|
+
/** The stored hash of the password credential, or `null` for an account without one. */
|
|
719
|
+
passwordHash(userId: string): Promise<string | null>;
|
|
518
720
|
setRole(id: string, role: string): Promise<UserRow>;
|
|
519
721
|
/**
|
|
520
722
|
* Authoritative role plus space memberships in one query.
|
|
@@ -548,6 +750,15 @@ declare class UserRepository {
|
|
|
548
750
|
//#region src/repositories/webhook.d.ts
|
|
549
751
|
type WebhookRow = typeof webhooks.$inferSelect;
|
|
550
752
|
type WebhookDeliveryRow = typeof webhookDeliveries.$inferSelect;
|
|
753
|
+
interface WebhookWriteData {
|
|
754
|
+
id?: string | undefined;
|
|
755
|
+
spaceId: string;
|
|
756
|
+
name: string;
|
|
757
|
+
url: string;
|
|
758
|
+
secret?: string | null | undefined;
|
|
759
|
+
events: string[];
|
|
760
|
+
enabled?: boolean | undefined;
|
|
761
|
+
}
|
|
551
762
|
interface WebhookDeliveryData {
|
|
552
763
|
webhookId: string;
|
|
553
764
|
event: string;
|
|
@@ -560,6 +771,8 @@ declare class WebhookRepository {
|
|
|
560
771
|
private readonly db;
|
|
561
772
|
constructor(db: Database);
|
|
562
773
|
findById(id: string): Promise<WebhookRow | null>;
|
|
774
|
+
listBySpace(spaceId: string): Promise<WebhookRow[]>;
|
|
775
|
+
create(data: WebhookWriteData): Promise<WebhookRow>;
|
|
563
776
|
/** The switched-on webhooks of a space, for fanning an event out. */
|
|
564
777
|
findEnabled(spaceId: string): Promise<WebhookRow[]>;
|
|
565
778
|
recordDelivery(data: WebhookDeliveryData): Promise<WebhookDeliveryRow>;
|
|
@@ -652,7 +865,13 @@ interface Repositories {
|
|
|
652
865
|
roles: RoleRepository;
|
|
653
866
|
workflows: WorkflowRepository;
|
|
654
867
|
webhooks: WebhookRepository;
|
|
868
|
+
audit: AuditRepository;
|
|
869
|
+
notifications: NotificationRepository;
|
|
870
|
+
approvals: ContentApprovalRepository;
|
|
871
|
+
}
|
|
872
|
+
interface RepositoriesOptions {
|
|
873
|
+
audit?: AuditRepositoryOptions | undefined;
|
|
655
874
|
}
|
|
656
|
-
declare function createRepositories(db: Database, registry: ContentTypeRegistry): Repositories;
|
|
875
|
+
declare function createRepositories(db: Database, registry: ContentTypeRegistry, options?: RepositoriesOptions): Repositories;
|
|
657
876
|
//#endregion
|
|
658
|
-
export {
|
|
877
|
+
export { Pagination as $, ContentApprovalRepository as A, AuditRepositoryOptions as B, MenuItemNode as C, ContentTypeRepository as D, ResolvedMenuItem as E, TreeNode as F, AssetRepository as G, AuditVerification as H, buildTree as I, paginate as J, AssetWriteData as K, AuditAppendInput as L, ContentRepository as M, ContentWriteData as N, ApprovalDecisionData as O, SQL$1 as P, FieldFilter as Q, AuditFilter as R, MenuItemInput as S, MenuWriteData as T, AssetUsageRepository as U, AuditSort as V, AssetFilter as W, ContentSort as X, ContentFilter as Y, ContentTable as Z, SpaceRepository as _, WorkflowRepository as a, DatabaseOptions as at, NotificationInsert as b, WebhookDeliveryData as c, Transaction as ct, WebhookRow as d, PgColumn$1 as et, WebhookWriteData as f, UserUpdateData as g, UserRepository as h, RUNS_KEPT_PER_WORKFLOW as i, DatabaseHandle as it, PendingApproval as j, ApprovalRequestData as k, WebhookDeliveryRow as l, createDatabase as lt, UserCreateData as m, RepositoriesOptions as n, buildOrderBy as nt, WorkflowRunCreateData as o, Executor as ot, SpaceRole as p, Paginated as q, createRepositories as r, Database as rt, WorkflowWriteData as s, Sql as st, Repositories as t, buildContentWhere as tt, WebhookRepository as u, SpaceWriteData as v, MenuRepository as w, NotificationRepository as x, NotificationFilter as y, AuditRepository as z };
|