@kernhq/module-quire 0.2.1 → 0.3.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/contract/events.d.ts +11 -0
- package/dist/contract/events.d.ts.map +1 -1
- package/dist/contract/events.js +2 -0
- package/dist/contract/events.js.map +1 -1
- package/dist/contract/models.d.ts +29 -0
- package/dist/contract/models.d.ts.map +1 -1
- package/dist/contract/models.js +19 -0
- package/dist/contract/models.js.map +1 -1
- package/dist/contract/permissions.d.ts +7 -0
- package/dist/contract/permissions.d.ts.map +1 -1
- package/dist/contract/permissions.js +8 -0
- package/dist/contract/permissions.js.map +1 -1
- package/dist/contract/router.d.ts +285 -0
- package/dist/contract/router.d.ts.map +1 -1
- package/dist/contract/router.js +37 -1
- package/dist/contract/router.js.map +1 -1
- package/dist/server/_impl.d.ts +319 -0
- package/dist/server/_impl.d.ts.map +1 -1
- package/dist/server/_impl.js +90 -16
- package/dist/server/_impl.js.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +61 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/schema.d.ts +206 -1
- package/dist/server/schema.d.ts.map +1 -1
- package/dist/server/schema.js +38 -2
- package/dist/server/schema.js.map +1 -1
- package/dist/server/services/index.d.ts +3 -0
- package/dist/server/services/index.d.ts.map +1 -1
- package/dist/server/services/index.js +3 -0
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/versions.d.ts +124 -0
- package/dist/server/services/versions.d.ts.map +1 -0
- package/dist/server/services/versions.js +182 -0
- package/dist/server/services/versions.js.map +1 -0
- package/migrations/0002_page_versions.sql +25 -0
- package/migrations/meta/0002_snapshot.json +491 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/src/contract/events.ts +5 -0
- package/src/contract/models.ts +23 -0
- package/src/contract/permissions.ts +8 -0
- package/src/contract/router.ts +39 -1
package/dist/server/index.js
CHANGED
|
@@ -2,10 +2,19 @@ import { dirname, join } from 'node:path';
|
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
import { CollabAccess, CollabAccessInput } from '@kernhq/contracts';
|
|
4
4
|
import { KernError } from '@kernhq/kernel';
|
|
5
|
+
import { and, eq } from 'drizzle-orm';
|
|
5
6
|
import { MODULE_ID, quireCapabilities, quireContract, quireEvents, quirePermissions, } from '../contract/index.js';
|
|
6
7
|
import { defineModule, defineServerModule, implement_, packageVersion } from './_impl.js';
|
|
7
|
-
import { schema } from './schema.js';
|
|
8
|
+
import { pages, schema } from './schema.js';
|
|
8
9
|
import { quireServices } from './services/index.js';
|
|
10
|
+
/**
|
|
11
|
+
* How long a page may go without an automatic version while somebody is writing in it.
|
|
12
|
+
*
|
|
13
|
+
* The collab service already throttles how often it publishes a snapshot event, so this is the
|
|
14
|
+
* second gate rather than the first: it decides how much work a restore can lose, not how much
|
|
15
|
+
* traffic the module sees.
|
|
16
|
+
*/
|
|
17
|
+
const AUTO_VERSION_INTERVAL_MS = 5 * 60_000;
|
|
9
18
|
/** These procedures are reachable only from another Kern service, never from a browser. */
|
|
10
19
|
function requireService(principal) {
|
|
11
20
|
if (principal.kind !== 'service' && !principal.instanceAdmin)
|
|
@@ -35,6 +44,57 @@ export const quireModule = defineServerModule({
|
|
|
35
44
|
schema,
|
|
36
45
|
migrationsFolder: join(dirname(fileURLToPath(import.meta.url)), '../../migrations'),
|
|
37
46
|
router: implement_,
|
|
47
|
+
subscriptions: {
|
|
48
|
+
/**
|
|
49
|
+
* A document was edited. Three things follow from that, and none of them can be done from the
|
|
50
|
+
* browser.
|
|
51
|
+
*
|
|
52
|
+
* The flattened prose is mirrored onto the row, so the tree and search can read a page without
|
|
53
|
+
* decoding a CRDT. A `page` whose draft has moved on from what readers are served is marked as
|
|
54
|
+
* having unpublished changes — which is the whole difference between a page and a live doc. And
|
|
55
|
+
* a version is taken if the last one is old enough, so history accumulates while somebody
|
|
56
|
+
* writes rather than only when they remember to press something.
|
|
57
|
+
*/
|
|
58
|
+
'collab.document.updated': async (event, kernel) => {
|
|
59
|
+
const payload = event.payload;
|
|
60
|
+
if (payload.module !== MODULE_ID || payload.type !== 'page')
|
|
61
|
+
return;
|
|
62
|
+
const svc = quireServices(kernel);
|
|
63
|
+
await kernel.database.withWorkspace(payload.workspaceId, async (tx) => {
|
|
64
|
+
const [page] = await tx
|
|
65
|
+
.select()
|
|
66
|
+
.from(pages)
|
|
67
|
+
.where(and(eq(pages.workspaceId, payload.workspaceId), eq(pages.id, payload.objectId)))
|
|
68
|
+
.limit(1);
|
|
69
|
+
// A document for a page that has been purged; the row is gone and so should the document be.
|
|
70
|
+
if (!page)
|
|
71
|
+
return;
|
|
72
|
+
await tx
|
|
73
|
+
.update(pages)
|
|
74
|
+
.set({
|
|
75
|
+
text: payload.text,
|
|
76
|
+
// A `page` diverges from what readers see; a `live` doc has nothing to diverge from.
|
|
77
|
+
hasUnpublishedChanges: page.kind === 'page' && page.publishedVersionId !== null ? true : page.hasUnpublishedChanges,
|
|
78
|
+
updatedAt: new Date(),
|
|
79
|
+
})
|
|
80
|
+
.where(and(eq(pages.workspaceId, payload.workspaceId), eq(pages.id, payload.objectId)));
|
|
81
|
+
const last = await svc.versions.lastCapturedAt(tx, payload.workspaceId, payload.objectId);
|
|
82
|
+
if (!last || Date.now() - last.getTime() > AUTO_VERSION_INTERVAL_MS) {
|
|
83
|
+
await svc.versions.capture(tx, payload.workspaceId, payload.objectId, {
|
|
84
|
+
kind: 'auto',
|
|
85
|
+
label: null,
|
|
86
|
+
authorId: null,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
await kernel.realtime.change(payload.workspaceId, {
|
|
91
|
+
module: MODULE_ID,
|
|
92
|
+
entity: 'page',
|
|
93
|
+
id: payload.objectId,
|
|
94
|
+
op: 'updated',
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
},
|
|
38
98
|
procedures: {
|
|
39
99
|
/**
|
|
40
100
|
* Whether a user may open a page's collaborative document.
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAkB,MAAM,mBAAmB,CAAA;AACnF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AACzF,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server/schema.d.ts
CHANGED
|
@@ -535,6 +535,211 @@ export declare const pages: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
535
535
|
};
|
|
536
536
|
dialect: "pg";
|
|
537
537
|
}>;
|
|
538
|
+
/**
|
|
539
|
+
* What a page looked like at a moment, and the bytes to put it back.
|
|
540
|
+
*
|
|
541
|
+
* This is the backbone of both halves of the draft model rather than a feature bolted beside it:
|
|
542
|
+
* a `page` serves `pages.published_version_id` to a reader, and a `live` doc serves the Y.Doc — one
|
|
543
|
+
* mechanism, two behaviours. Restoring, diffing and publishing all read from here.
|
|
544
|
+
*/
|
|
545
|
+
export declare const pageVersions: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
546
|
+
name: "page_versions";
|
|
547
|
+
schema: "mod_quire";
|
|
548
|
+
columns: {
|
|
549
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
550
|
+
name: "id";
|
|
551
|
+
tableName: "page_versions";
|
|
552
|
+
dataType: "string";
|
|
553
|
+
columnType: "PgUUID";
|
|
554
|
+
data: string;
|
|
555
|
+
driverParam: string;
|
|
556
|
+
notNull: true;
|
|
557
|
+
hasDefault: true;
|
|
558
|
+
isPrimaryKey: true;
|
|
559
|
+
isAutoincrement: false;
|
|
560
|
+
hasRuntimeDefault: false;
|
|
561
|
+
enumValues: undefined;
|
|
562
|
+
baseColumn: never;
|
|
563
|
+
identity: undefined;
|
|
564
|
+
generated: undefined;
|
|
565
|
+
}, {}, {}>;
|
|
566
|
+
workspaceId: import("drizzle-orm/pg-core").PgColumn<{
|
|
567
|
+
name: "workspace_id";
|
|
568
|
+
tableName: "page_versions";
|
|
569
|
+
dataType: "string";
|
|
570
|
+
columnType: "PgUUID";
|
|
571
|
+
data: string;
|
|
572
|
+
driverParam: string;
|
|
573
|
+
notNull: true;
|
|
574
|
+
hasDefault: false;
|
|
575
|
+
isPrimaryKey: false;
|
|
576
|
+
isAutoincrement: false;
|
|
577
|
+
hasRuntimeDefault: false;
|
|
578
|
+
enumValues: undefined;
|
|
579
|
+
baseColumn: never;
|
|
580
|
+
identity: undefined;
|
|
581
|
+
generated: undefined;
|
|
582
|
+
}, {}, {}>;
|
|
583
|
+
pageId: import("drizzle-orm/pg-core").PgColumn<{
|
|
584
|
+
name: "page_id";
|
|
585
|
+
tableName: "page_versions";
|
|
586
|
+
dataType: "string";
|
|
587
|
+
columnType: "PgUUID";
|
|
588
|
+
data: string;
|
|
589
|
+
driverParam: string;
|
|
590
|
+
notNull: true;
|
|
591
|
+
hasDefault: false;
|
|
592
|
+
isPrimaryKey: false;
|
|
593
|
+
isAutoincrement: false;
|
|
594
|
+
hasRuntimeDefault: false;
|
|
595
|
+
enumValues: undefined;
|
|
596
|
+
baseColumn: never;
|
|
597
|
+
identity: undefined;
|
|
598
|
+
generated: undefined;
|
|
599
|
+
}, {}, {}>;
|
|
600
|
+
kind: import("drizzle-orm/pg-core").PgColumn<{
|
|
601
|
+
name: "kind";
|
|
602
|
+
tableName: "page_versions";
|
|
603
|
+
dataType: "string";
|
|
604
|
+
columnType: "PgText";
|
|
605
|
+
data: string;
|
|
606
|
+
driverParam: string;
|
|
607
|
+
notNull: true;
|
|
608
|
+
hasDefault: true;
|
|
609
|
+
isPrimaryKey: false;
|
|
610
|
+
isAutoincrement: false;
|
|
611
|
+
hasRuntimeDefault: false;
|
|
612
|
+
enumValues: [string, ...string[]];
|
|
613
|
+
baseColumn: never;
|
|
614
|
+
identity: undefined;
|
|
615
|
+
generated: undefined;
|
|
616
|
+
}, {}, {}>;
|
|
617
|
+
label: import("drizzle-orm/pg-core").PgColumn<{
|
|
618
|
+
name: "label";
|
|
619
|
+
tableName: "page_versions";
|
|
620
|
+
dataType: "string";
|
|
621
|
+
columnType: "PgText";
|
|
622
|
+
data: string;
|
|
623
|
+
driverParam: string;
|
|
624
|
+
notNull: false;
|
|
625
|
+
hasDefault: false;
|
|
626
|
+
isPrimaryKey: false;
|
|
627
|
+
isAutoincrement: false;
|
|
628
|
+
hasRuntimeDefault: false;
|
|
629
|
+
enumValues: [string, ...string[]];
|
|
630
|
+
baseColumn: never;
|
|
631
|
+
identity: undefined;
|
|
632
|
+
generated: undefined;
|
|
633
|
+
}, {}, {}>;
|
|
634
|
+
state: import("drizzle-orm/pg-core").PgColumn<{
|
|
635
|
+
name: "state";
|
|
636
|
+
tableName: "page_versions";
|
|
637
|
+
dataType: "custom";
|
|
638
|
+
columnType: "PgCustomColumn";
|
|
639
|
+
data: Buffer<ArrayBufferLike>;
|
|
640
|
+
driverParam: Buffer<ArrayBufferLike>;
|
|
641
|
+
notNull: true;
|
|
642
|
+
hasDefault: false;
|
|
643
|
+
isPrimaryKey: false;
|
|
644
|
+
isAutoincrement: false;
|
|
645
|
+
hasRuntimeDefault: false;
|
|
646
|
+
enumValues: undefined;
|
|
647
|
+
baseColumn: never;
|
|
648
|
+
identity: undefined;
|
|
649
|
+
generated: undefined;
|
|
650
|
+
}, {}, {
|
|
651
|
+
pgColumnBuilderBrand: "PgCustomColumnBuilderBrand";
|
|
652
|
+
}>;
|
|
653
|
+
snapshot: import("drizzle-orm/pg-core").PgColumn<{
|
|
654
|
+
name: "snapshot";
|
|
655
|
+
tableName: "page_versions";
|
|
656
|
+
dataType: "custom";
|
|
657
|
+
columnType: "PgCustomColumn";
|
|
658
|
+
data: Buffer<ArrayBufferLike>;
|
|
659
|
+
driverParam: Buffer<ArrayBufferLike>;
|
|
660
|
+
notNull: false;
|
|
661
|
+
hasDefault: false;
|
|
662
|
+
isPrimaryKey: false;
|
|
663
|
+
isAutoincrement: false;
|
|
664
|
+
hasRuntimeDefault: false;
|
|
665
|
+
enumValues: undefined;
|
|
666
|
+
baseColumn: never;
|
|
667
|
+
identity: undefined;
|
|
668
|
+
generated: undefined;
|
|
669
|
+
}, {}, {
|
|
670
|
+
pgColumnBuilderBrand: "PgCustomColumnBuilderBrand";
|
|
671
|
+
}>;
|
|
672
|
+
text: import("drizzle-orm/pg-core").PgColumn<{
|
|
673
|
+
name: "text";
|
|
674
|
+
tableName: "page_versions";
|
|
675
|
+
dataType: "string";
|
|
676
|
+
columnType: "PgText";
|
|
677
|
+
data: string;
|
|
678
|
+
driverParam: string;
|
|
679
|
+
notNull: true;
|
|
680
|
+
hasDefault: true;
|
|
681
|
+
isPrimaryKey: false;
|
|
682
|
+
isAutoincrement: false;
|
|
683
|
+
hasRuntimeDefault: false;
|
|
684
|
+
enumValues: [string, ...string[]];
|
|
685
|
+
baseColumn: never;
|
|
686
|
+
identity: undefined;
|
|
687
|
+
generated: undefined;
|
|
688
|
+
}, {}, {}>;
|
|
689
|
+
size: import("drizzle-orm/pg-core").PgColumn<{
|
|
690
|
+
name: "size";
|
|
691
|
+
tableName: "page_versions";
|
|
692
|
+
dataType: "number";
|
|
693
|
+
columnType: "PgInteger";
|
|
694
|
+
data: number;
|
|
695
|
+
driverParam: string | number;
|
|
696
|
+
notNull: true;
|
|
697
|
+
hasDefault: true;
|
|
698
|
+
isPrimaryKey: false;
|
|
699
|
+
isAutoincrement: false;
|
|
700
|
+
hasRuntimeDefault: false;
|
|
701
|
+
enumValues: undefined;
|
|
702
|
+
baseColumn: never;
|
|
703
|
+
identity: undefined;
|
|
704
|
+
generated: undefined;
|
|
705
|
+
}, {}, {}>;
|
|
706
|
+
authorId: import("drizzle-orm/pg-core").PgColumn<{
|
|
707
|
+
name: "author_id";
|
|
708
|
+
tableName: "page_versions";
|
|
709
|
+
dataType: "string";
|
|
710
|
+
columnType: "PgUUID";
|
|
711
|
+
data: string;
|
|
712
|
+
driverParam: string;
|
|
713
|
+
notNull: false;
|
|
714
|
+
hasDefault: false;
|
|
715
|
+
isPrimaryKey: false;
|
|
716
|
+
isAutoincrement: false;
|
|
717
|
+
hasRuntimeDefault: false;
|
|
718
|
+
enumValues: undefined;
|
|
719
|
+
baseColumn: never;
|
|
720
|
+
identity: undefined;
|
|
721
|
+
generated: undefined;
|
|
722
|
+
}, {}, {}>;
|
|
723
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
724
|
+
name: string;
|
|
725
|
+
tableName: "page_versions";
|
|
726
|
+
dataType: "date";
|
|
727
|
+
columnType: "PgTimestamp";
|
|
728
|
+
data: Date;
|
|
729
|
+
driverParam: string;
|
|
730
|
+
notNull: true;
|
|
731
|
+
hasDefault: true;
|
|
732
|
+
isPrimaryKey: false;
|
|
733
|
+
isAutoincrement: false;
|
|
734
|
+
hasRuntimeDefault: false;
|
|
735
|
+
enumValues: undefined;
|
|
736
|
+
baseColumn: never;
|
|
737
|
+
identity: undefined;
|
|
738
|
+
generated: undefined;
|
|
739
|
+
}, {}, {}>;
|
|
740
|
+
};
|
|
741
|
+
dialect: "pg";
|
|
742
|
+
}>;
|
|
538
743
|
/** Every tenant table, so the RLS migration can be checked against one list rather than memory. */
|
|
539
|
-
export declare const TENANT_TABLES: readonly ["spaces", "pages"];
|
|
744
|
+
export declare const TENANT_TABLES: readonly ["spaces", "pages", "page_versions"];
|
|
540
745
|
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/server/schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/server/schema.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,MAAM,qDAAwB,CAAA;AAS3C,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBlB,CAAA;AAED,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8CjB,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BxB,CAAA;AAED,mGAAmG;AACnG,eAAO,MAAM,aAAa,+CAAgD,CAAA"}
|
package/dist/server/schema.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sql } from 'drizzle-orm';
|
|
2
|
-
import { boolean, index, pgSchema, text, timestamp, uniqueIndex, uuid } from 'drizzle-orm/pg-core';
|
|
2
|
+
import { boolean, customType, index, integer, pgSchema, text, timestamp, uniqueIndex, uuid, } from 'drizzle-orm/pg-core';
|
|
3
3
|
/**
|
|
4
4
|
* This module's tables, in its own Postgres schema.
|
|
5
5
|
*
|
|
@@ -13,6 +13,8 @@ import { boolean, index, pgSchema, text, timestamp, uniqueIndex, uuid } from 'dr
|
|
|
13
13
|
* drizzle-kit does not generate one.
|
|
14
14
|
*/
|
|
15
15
|
export const schema = pgSchema('mod_quire');
|
|
16
|
+
/** Yjs state is binary; drizzle has no `bytea`, so it is declared once here. */
|
|
17
|
+
const bytea = customType({ dataType: () => 'bytea' });
|
|
16
18
|
const id = () => uuid('id').primaryKey().default(sql `uuidv7()`);
|
|
17
19
|
const ws = () => uuid('workspace_id').notNull();
|
|
18
20
|
const ts = (name) => timestamp(name, { withTimezone: true });
|
|
@@ -81,6 +83,40 @@ export const pages = schema.table('pages', {
|
|
|
81
83
|
index('pages_ws_parent_idx').on(t.workspaceId, t.parentId, t.position),
|
|
82
84
|
index('pages_ws_updated_idx').on(t.workspaceId, t.updatedAt),
|
|
83
85
|
]);
|
|
86
|
+
/**
|
|
87
|
+
* What a page looked like at a moment, and the bytes to put it back.
|
|
88
|
+
*
|
|
89
|
+
* This is the backbone of both halves of the draft model rather than a feature bolted beside it:
|
|
90
|
+
* a `page` serves `pages.published_version_id` to a reader, and a `live` doc serves the Y.Doc — one
|
|
91
|
+
* mechanism, two behaviours. Restoring, diffing and publishing all read from here.
|
|
92
|
+
*/
|
|
93
|
+
export const pageVersions = schema.table('page_versions', {
|
|
94
|
+
id: id(),
|
|
95
|
+
workspaceId: ws(),
|
|
96
|
+
pageId: uuid('page_id').notNull(),
|
|
97
|
+
/**
|
|
98
|
+
* `auto` — taken on a quiet interval while somebody was writing.
|
|
99
|
+
* `publish` — what a reader is being served.
|
|
100
|
+
* `restore` — the result of putting an older version back; a restore is itself a version, so
|
|
101
|
+
* the act of restoring is never the thing that loses work.
|
|
102
|
+
* `import` — the state a page arrived with.
|
|
103
|
+
*/
|
|
104
|
+
kind: text('kind').notNull().default('auto'),
|
|
105
|
+
/** what somebody called it, when they named it on purpose */
|
|
106
|
+
label: text('label'),
|
|
107
|
+
/** `Y.encodeStateAsUpdate` — everything needed to reconstruct the document */
|
|
108
|
+
state: bytea('state').notNull(),
|
|
109
|
+
/** `Y.encodeSnapshot` — enough to render the difference against another version */
|
|
110
|
+
snapshot: bytea('snapshot'),
|
|
111
|
+
/** flattened prose, so a version list can show a line of it without decoding the CRDT */
|
|
112
|
+
text: text('text').notNull().default(''),
|
|
113
|
+
size: integer('size').notNull().default(0),
|
|
114
|
+
authorId: uuid('author_id'),
|
|
115
|
+
createdAt: ts('created_at').notNull().defaultNow(),
|
|
116
|
+
}, (t) => [
|
|
117
|
+
index('page_versions_ws_page_idx').on(t.workspaceId, t.pageId, t.createdAt),
|
|
118
|
+
index('page_versions_ws_created_idx').on(t.workspaceId, t.createdAt),
|
|
119
|
+
]);
|
|
84
120
|
/** Every tenant table, so the RLS migration can be checked against one list rather than memory. */
|
|
85
|
-
export const TENANT_TABLES = ['spaces', 'pages'];
|
|
121
|
+
export const TENANT_TABLES = ['spaces', 'pages', 'page_versions'];
|
|
86
122
|
//# sourceMappingURL=schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/server/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AACjC,OAAO,
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/server/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,14 +2,17 @@ import type { Kernel } from '@kernhq/kernel';
|
|
|
2
2
|
import { quireAccess } from './access.js';
|
|
3
3
|
import { quirePages } from './pages.js';
|
|
4
4
|
import { quireSpaces } from './spaces.js';
|
|
5
|
+
import { quireVersions } from './versions.js';
|
|
5
6
|
export interface QuireServices {
|
|
6
7
|
access: ReturnType<typeof quireAccess>;
|
|
7
8
|
spaces: ReturnType<typeof quireSpaces>;
|
|
8
9
|
pages: ReturnType<typeof quirePages>;
|
|
10
|
+
versions: ReturnType<typeof quireVersions>;
|
|
9
11
|
}
|
|
10
12
|
/** One set of services per kernel: they are stateless, and rebuilding them per request is waste. */
|
|
11
13
|
export declare function quireServices(kernel: Kernel): QuireServices;
|
|
12
14
|
export * from './access.js';
|
|
13
15
|
export * from './pages.js';
|
|
14
16
|
export * from './spaces.js';
|
|
17
|
+
export * from './versions.js';
|
|
15
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE7C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;IACtC,MAAM,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;IACtC,KAAK,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAA;IACpC,QAAQ,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;CAC3C;AAID,oGAAoG;AACpG,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAY3D;AAED,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { quireAccess } from './access.js';
|
|
2
2
|
import { quirePages } from './pages.js';
|
|
3
3
|
import { quireSpaces } from './spaces.js';
|
|
4
|
+
import { quireVersions } from './versions.js';
|
|
4
5
|
const cache = new WeakMap();
|
|
5
6
|
/** One set of services per kernel: they are stateless, and rebuilding them per request is waste. */
|
|
6
7
|
export function quireServices(kernel) {
|
|
@@ -12,6 +13,7 @@ export function quireServices(kernel) {
|
|
|
12
13
|
access,
|
|
13
14
|
spaces: quireSpaces(access),
|
|
14
15
|
pages: quirePages(access),
|
|
16
|
+
versions: quireVersions(kernel, access),
|
|
15
17
|
};
|
|
16
18
|
cache.set(kernel, services);
|
|
17
19
|
return services;
|
|
@@ -19,4 +21,5 @@ export function quireServices(kernel) {
|
|
|
19
21
|
export * from './access.js';
|
|
20
22
|
export * from './pages.js';
|
|
21
23
|
export * from './spaces.js';
|
|
24
|
+
export * from './versions.js';
|
|
22
25
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/services/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/services/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAS7C,MAAM,KAAK,GAAG,IAAI,OAAO,EAAyB,CAAA;AAElD,oGAAoG;AACpG,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAClC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC7B,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IAClC,MAAM,QAAQ,GAAkB;QAC9B,MAAM;QACN,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;QAC3B,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC;QACzB,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC;KACxC,CAAA;IACD,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IAC3B,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Principal } from '@kernhq/contracts';
|
|
2
|
+
import { type Kernel, type Tx } from '@kernhq/kernel';
|
|
3
|
+
import type { PageVersion } from '../../contract/index.js';
|
|
4
|
+
import { pageVersions } from '../schema.js';
|
|
5
|
+
import type { QuireAccess } from './access.js';
|
|
6
|
+
type VersionRow = typeof pageVersions.$inferSelect;
|
|
7
|
+
export declare function toVersion(row: VersionRow, publishedId: string | null): PageVersion;
|
|
8
|
+
export declare function quireVersions(kernel: Kernel, access: QuireAccess): {
|
|
9
|
+
/**
|
|
10
|
+
* Write down what the page says now.
|
|
11
|
+
*
|
|
12
|
+
* Returns null when the document has never been written to — a page created and never opened
|
|
13
|
+
* has nothing to version, and an empty row in the history would be a lie about somebody having
|
|
14
|
+
* saved something.
|
|
15
|
+
*/
|
|
16
|
+
capture(tx: Tx, workspaceId: string, pageId: string, opts: {
|
|
17
|
+
kind: PageVersion["kind"];
|
|
18
|
+
label?: string | null;
|
|
19
|
+
authorId?: string | null;
|
|
20
|
+
}): Promise<VersionRow | null>;
|
|
21
|
+
list(tx: Tx, workspaceId: string, pageId: string, limit: number, cursor: string | null): Promise<{
|
|
22
|
+
items: {
|
|
23
|
+
id: string;
|
|
24
|
+
workspaceId: string & import("zod").$brand<"WorkspaceId">;
|
|
25
|
+
pageId: string;
|
|
26
|
+
kind: "auto" | "publish" | "restore" | "import";
|
|
27
|
+
label: string | null;
|
|
28
|
+
preview: string;
|
|
29
|
+
size: number;
|
|
30
|
+
authorId: (string & import("zod").$brand<"UserId">) | null;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
published: boolean;
|
|
33
|
+
}[];
|
|
34
|
+
nextCursor: string | null;
|
|
35
|
+
}>;
|
|
36
|
+
row(tx: Tx, workspaceId: string, versionId: string): Promise<{
|
|
37
|
+
id: string;
|
|
38
|
+
workspaceId: string;
|
|
39
|
+
pageId: string;
|
|
40
|
+
kind: string;
|
|
41
|
+
label: string | null;
|
|
42
|
+
state: Buffer<ArrayBufferLike>;
|
|
43
|
+
snapshot: Buffer<ArrayBufferLike> | null;
|
|
44
|
+
text: string;
|
|
45
|
+
size: number;
|
|
46
|
+
authorId: string | null;
|
|
47
|
+
createdAt: Date;
|
|
48
|
+
}>;
|
|
49
|
+
/**
|
|
50
|
+
* Put an older version back.
|
|
51
|
+
*
|
|
52
|
+
* Two things make this safe to offer. The state it is about to replace is captured first, so
|
|
53
|
+
* restoring is never itself the thing that loses work; and the replacement goes through the
|
|
54
|
+
* collab service rather than the database, because `applyUpdate` would merge the two and bring
|
|
55
|
+
* every deleted paragraph back alongside the ones that replaced it.
|
|
56
|
+
*/
|
|
57
|
+
restore(tx: Tx, principal: Principal, workspaceId: string, versionId: string): Promise<{
|
|
58
|
+
id: string;
|
|
59
|
+
label: string | null;
|
|
60
|
+
pageId: string;
|
|
61
|
+
workspaceId: string;
|
|
62
|
+
createdAt: Date;
|
|
63
|
+
kind: string;
|
|
64
|
+
size: number;
|
|
65
|
+
authorId: string | null;
|
|
66
|
+
text: string;
|
|
67
|
+
state: Buffer<ArrayBufferLike>;
|
|
68
|
+
snapshot: Buffer<ArrayBufferLike> | null;
|
|
69
|
+
}>;
|
|
70
|
+
/** What a reader is served, once somebody decides it is ready. */
|
|
71
|
+
publish(tx: Tx, principal: Principal, workspaceId: string, pageId: string, label: string | null): Promise<{
|
|
72
|
+
id: string;
|
|
73
|
+
workspaceId: string;
|
|
74
|
+
spaceId: string;
|
|
75
|
+
parentId: string | null;
|
|
76
|
+
position: string;
|
|
77
|
+
kind: string;
|
|
78
|
+
title: string;
|
|
79
|
+
icon: string | null;
|
|
80
|
+
coverUrl: string | null;
|
|
81
|
+
publishedVersionId: string | null;
|
|
82
|
+
hasUnpublishedChanges: boolean;
|
|
83
|
+
text: string;
|
|
84
|
+
createdBy: string | null;
|
|
85
|
+
updatedBy: string | null;
|
|
86
|
+
createdAt: Date;
|
|
87
|
+
updatedAt: Date;
|
|
88
|
+
archivedAt: Date | null;
|
|
89
|
+
deletedAt: Date | null;
|
|
90
|
+
}>;
|
|
91
|
+
/** Throw the draft away and go back to what readers can already see. */
|
|
92
|
+
revert(tx: Tx, principal: Principal, workspaceId: string, pageId: string): Promise<{
|
|
93
|
+
id: string;
|
|
94
|
+
workspaceId: string;
|
|
95
|
+
spaceId: string;
|
|
96
|
+
parentId: string | null;
|
|
97
|
+
position: string;
|
|
98
|
+
kind: string;
|
|
99
|
+
title: string;
|
|
100
|
+
icon: string | null;
|
|
101
|
+
coverUrl: string | null;
|
|
102
|
+
publishedVersionId: string | null;
|
|
103
|
+
hasUnpublishedChanges: boolean;
|
|
104
|
+
text: string;
|
|
105
|
+
createdBy: string | null;
|
|
106
|
+
updatedBy: string | null;
|
|
107
|
+
createdAt: Date;
|
|
108
|
+
updatedAt: Date;
|
|
109
|
+
archivedAt: Date | null;
|
|
110
|
+
deletedAt: Date | null;
|
|
111
|
+
}>;
|
|
112
|
+
/** When the newest version was taken, so an automatic one is not taken every keystroke. */
|
|
113
|
+
lastCapturedAt(tx: Tx, workspaceId: string, pageId: string): Promise<Date | null>;
|
|
114
|
+
/** The current state, for anything that needs the document without opening a socket. */
|
|
115
|
+
documentState(workspaceId: string, pageId: string): Promise<{
|
|
116
|
+
name: string;
|
|
117
|
+
state: string | null;
|
|
118
|
+
size: number;
|
|
119
|
+
updatedAt: string | null;
|
|
120
|
+
}>;
|
|
121
|
+
};
|
|
122
|
+
export type QuireVersions = ReturnType<typeof quireVersions>;
|
|
123
|
+
export {};
|
|
124
|
+
//# sourceMappingURL=versions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../../src/server/services/versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAAa,KAAK,MAAM,EAAE,KAAK,EAAE,EAAU,MAAM,gBAAgB,CAAA;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAS,YAAY,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,KAAK,UAAU,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAKlD,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,CAalF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAS7D;;;;;;OAMG;gBAEG,EAAE,eACO,MAAM,UACX,MAAM,QACR;QAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GACnF,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;aAgCd,EAAE,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,UAAU,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;YAkB9E,EAAE,eAAe,MAAM,aAAa,MAAM;;;;;;;;;;;;;IAUxD;;;;;;;OAOG;gBACe,EAAE,aAAa,SAAS,eAAe,MAAM,aAAa,MAAM;;;;;;;;;;;;;IAsBlF,kEAAkE;gBAChD,EAAE,aAAa,SAAS,eAAe,MAAM,UAAU,MAAM,SAAS,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;IAyBrG,wEAAwE;eACvD,EAAE,aAAa,SAAS,eAAe,MAAM,UAAU,MAAM;;;;;;;;;;;;;;;;;;;;IAyB9E,2FAA2F;uBAClE,EAAE,eAAe,MAAM,UAAU,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAUvF,wFAAwF;+BAC7D,MAAM,UAAU,MAAM;;;;;;EAMpD;AACD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA"}
|