@hiai-gg/docsmint 0.4.4 → 0.4.6

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.
@@ -1,10 +1,16 @@
1
1
  import {
2
+ accounts,
2
3
  attachments,
3
4
  auditLog,
5
+ categories,
4
6
  documentEmbeddings,
5
7
  documents,
8
+ folders,
6
9
  lifecycleOperations,
10
+ sessions,
7
11
  shareLinks,
12
+ tags,
13
+ users,
8
14
  versions,
9
15
  } from "@hiai-docs/db/schema";
10
16
  import type { TenantTransaction } from "@hiai-docs/db/with-tenant";
@@ -121,6 +127,14 @@ function subjectHash(actorUserId: string): string {
121
127
  return new Bun.CryptoHasher("sha256").update(actorUserId).digest("hex");
122
128
  }
123
129
 
130
+ export function lifecycleTombstoneEmail(actorUserId: string): string {
131
+ const hash = new Bun.CryptoHasher("sha256")
132
+ .update("docsmint:privacy-tombstone:v1\0")
133
+ .update(actorUserId)
134
+ .digest("hex");
135
+ return `deleted-${hash}@invalid.local`;
136
+ }
137
+
124
138
  function checksumLine(
125
139
  hash: Bun.CryptoHasher,
126
140
  record: UserDataExportRecord,
@@ -317,6 +331,92 @@ export function createPersistentLifecycleService(
317
331
  checksumLine(hash, manifest);
318
332
  recordCount += 1;
319
333
  yield manifest;
334
+ const actor = await withActor(ctx.actorUserId, (tx) =>
335
+ tx
336
+ .select({
337
+ id: users.id,
338
+ email: users.email,
339
+ name: users.name,
340
+ emailVerified: users.emailVerified,
341
+ image: users.image,
342
+ createdAt: users.createdAt,
343
+ updatedAt: users.updatedAt,
344
+ })
345
+ .from(users)
346
+ .where(eq(users.id, ctx.actorUserId))
347
+ .limit(1),
348
+ );
349
+ for (const profile of actor) {
350
+ const record: UserDataExportRecord = {
351
+ type: "data",
352
+ domain: "account",
353
+ resourceType: "user",
354
+ resourceId: profile.id,
355
+ workspaceId: null,
356
+ payload: {
357
+ email: profile.email,
358
+ name: profile.name,
359
+ emailVerified: profile.emailVerified,
360
+ image: profile.image,
361
+ createdAt: profile.createdAt,
362
+ updatedAt: profile.updatedAt,
363
+ },
364
+ };
365
+ checksumLine(hash, record);
366
+ recordCount += 1;
367
+ yield record;
368
+ }
369
+ const actorFolders = await withActor(ctx.actorUserId, (tx) =>
370
+ tx.select().from(folders).where(eq(folders.ownerId, ctx.actorUserId)),
371
+ );
372
+ for (const folder of actorFolders) {
373
+ const record: UserDataExportRecord = {
374
+ type: "data",
375
+ domain: "folders",
376
+ resourceType: "folder",
377
+ resourceId: folder.id,
378
+ workspaceId: folder.workspaceId,
379
+ payload: folder,
380
+ };
381
+ checksumLine(hash, record);
382
+ recordCount += 1;
383
+ yield record;
384
+ }
385
+ const actorTags = await withActor(ctx.actorUserId, (tx) =>
386
+ tx.select().from(tags).where(eq(tags.ownerId, ctx.actorUserId)),
387
+ );
388
+ for (const tag of actorTags) {
389
+ const record: UserDataExportRecord = {
390
+ type: "data",
391
+ domain: "tags",
392
+ resourceType: "tag",
393
+ resourceId: tag.id,
394
+ workspaceId: tag.workspaceId,
395
+ payload: tag,
396
+ };
397
+ checksumLine(hash, record);
398
+ recordCount += 1;
399
+ yield record;
400
+ }
401
+ const actorCategories = await withActor(ctx.actorUserId, (tx) =>
402
+ tx
403
+ .select()
404
+ .from(categories)
405
+ .where(eq(categories.ownerId, ctx.actorUserId)),
406
+ );
407
+ for (const category of actorCategories) {
408
+ const record: UserDataExportRecord = {
409
+ type: "data",
410
+ domain: "categories",
411
+ resourceType: "category",
412
+ resourceId: category.id,
413
+ workspaceId: category.workspaceId,
414
+ payload: category,
415
+ };
416
+ checksumLine(hash, record);
417
+ recordCount += 1;
418
+ yield record;
419
+ }
320
420
  const ownedDocuments = await withActor(ctx.actorUserId, (tx) =>
321
421
  tx
322
422
  .select()
@@ -529,6 +629,48 @@ export function createPersistentLifecycleService(
529
629
  ctx.signal,
530
630
  ),
531
631
  );
632
+ await runStep(
633
+ operation,
634
+ ctx.actorUserId,
635
+ leaseOwner,
636
+ "remove_subject_folders",
637
+ deletedByDomain,
638
+ () =>
639
+ dbDelete((tx) =>
640
+ tx
641
+ .delete(folders)
642
+ .where(eq(folders.ownerId, ctx.actorUserId))
643
+ .returning({ id: folders.id }),
644
+ ),
645
+ );
646
+ await runStep(
647
+ operation,
648
+ ctx.actorUserId,
649
+ leaseOwner,
650
+ "remove_subject_tags",
651
+ deletedByDomain,
652
+ () =>
653
+ dbDelete((tx) =>
654
+ tx
655
+ .delete(tags)
656
+ .where(eq(tags.ownerId, ctx.actorUserId))
657
+ .returning({ id: tags.id }),
658
+ ),
659
+ );
660
+ await runStep(
661
+ operation,
662
+ ctx.actorUserId,
663
+ leaseOwner,
664
+ "remove_subject_categories",
665
+ deletedByDomain,
666
+ () =>
667
+ dbDelete((tx) =>
668
+ tx
669
+ .delete(categories)
670
+ .where(eq(categories.ownerId, ctx.actorUserId))
671
+ .returning({ id: categories.id }),
672
+ ),
673
+ );
532
674
  await runStep(
533
675
  operation,
534
676
  ctx.actorUserId,
@@ -582,6 +724,55 @@ export function createPersistentLifecycleService(
582
724
  deletedByDomain,
583
725
  async () => (await step.purge?.(ctx))?.deletedCount ?? 0,
584
726
  );
727
+ await runStep(
728
+ operation,
729
+ ctx.actorUserId,
730
+ leaseOwner,
731
+ "remove_auth_sessions",
732
+ deletedByDomain,
733
+ () =>
734
+ dbDelete((tx) =>
735
+ tx
736
+ .delete(sessions)
737
+ .where(eq(sessions.userId, ctx.actorUserId))
738
+ .returning({ id: sessions.id }),
739
+ ),
740
+ );
741
+ await runStep(
742
+ operation,
743
+ ctx.actorUserId,
744
+ leaseOwner,
745
+ "remove_auth_accounts",
746
+ deletedByDomain,
747
+ () =>
748
+ dbDelete((tx) =>
749
+ tx
750
+ .delete(accounts)
751
+ .where(eq(accounts.userId, ctx.actorUserId))
752
+ .returning({ id: accounts.id }),
753
+ ),
754
+ );
755
+ await runStep(
756
+ operation,
757
+ ctx.actorUserId,
758
+ leaseOwner,
759
+ "tombstone_subject_user",
760
+ deletedByDomain,
761
+ () =>
762
+ dbDelete((tx) =>
763
+ tx
764
+ .update(users)
765
+ .set({
766
+ email: lifecycleTombstoneEmail(ctx.actorUserId),
767
+ name: null,
768
+ image: null,
769
+ emailVerified: false,
770
+ updatedAt: new Date(),
771
+ })
772
+ .where(eq(users.id, ctx.actorUserId))
773
+ .returning({ id: users.id }),
774
+ ),
775
+ );
585
776
  await runStep(
586
777
  operation,
587
778
  ctx.actorUserId,
@@ -214361,7 +214361,7 @@ var swaggerConfig = {
214361
214361
  documentation: {
214362
214362
  info: {
214363
214363
  title: "DocsMint API",
214364
- version: "0.4.4",
214364
+ version: "0.4.6",
214365
214365
  description: "Self-hosted AI-first documentation platform. Full-text + semantic search, version history, sharing, and folder organization.",
214366
214366
  contact: { name: "HiAi-gg", url: "https://github.com/HiAi-gg/docsmint" },
214367
214367
  license: {
@@ -0,0 +1,9 @@
1
+ export type AccountRuntimeCleanup = Readonly<{
2
+ removeCollaborationState(actorUserId: string, signal?: AbortSignal): Promise<number>;
3
+ clearAccountRedisState(actorUserId: string, signal?: AbortSignal): Promise<number>;
4
+ close(): Promise<void>;
5
+ }>;
6
+ export declare function createAccountRuntimeCleanup(options: {
7
+ redisUrl: string;
8
+ databaseUrl: string;
9
+ }): AccountRuntimeCleanup;