@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.
@@ -538,6 +538,10 @@ function tokenHash(token) {
538
538
  function subjectHash(actorUserId) {
539
539
  return new Bun.CryptoHasher("sha256").update(actorUserId).digest("hex");
540
540
  }
541
+ function lifecycleTombstoneEmail(actorUserId) {
542
+ const hash = new Bun.CryptoHasher("sha256").update("docsmint:privacy-tombstone:v1\x00").update(actorUserId).digest("hex");
543
+ return `deleted-${hash}@invalid.local`;
544
+ }
541
545
  function checksumLine(hash, record) {
542
546
  hash.update(`${JSON.stringify(record)}
543
547
  `, "utf8");
@@ -634,6 +638,77 @@ function createPersistentLifecycleService(runtime, database, hostSteps = []) {
634
638
  checksumLine(hash, manifest);
635
639
  recordCount += 1;
636
640
  yield manifest;
641
+ const actor = await withActor(ctx.actorUserId, (tx) => tx.select({
642
+ id: users.id,
643
+ email: users.email,
644
+ name: users.name,
645
+ emailVerified: users.emailVerified,
646
+ image: users.image,
647
+ createdAt: users.createdAt,
648
+ updatedAt: users.updatedAt
649
+ }).from(users).where(eq(users.id, ctx.actorUserId)).limit(1));
650
+ for (const profile of actor) {
651
+ const record = {
652
+ type: "data",
653
+ domain: "account",
654
+ resourceType: "user",
655
+ resourceId: profile.id,
656
+ workspaceId: null,
657
+ payload: {
658
+ email: profile.email,
659
+ name: profile.name,
660
+ emailVerified: profile.emailVerified,
661
+ image: profile.image,
662
+ createdAt: profile.createdAt,
663
+ updatedAt: profile.updatedAt
664
+ }
665
+ };
666
+ checksumLine(hash, record);
667
+ recordCount += 1;
668
+ yield record;
669
+ }
670
+ const actorFolders = await withActor(ctx.actorUserId, (tx) => tx.select().from(folders).where(eq(folders.ownerId, ctx.actorUserId)));
671
+ for (const folder of actorFolders) {
672
+ const record = {
673
+ type: "data",
674
+ domain: "folders",
675
+ resourceType: "folder",
676
+ resourceId: folder.id,
677
+ workspaceId: folder.workspaceId,
678
+ payload: folder
679
+ };
680
+ checksumLine(hash, record);
681
+ recordCount += 1;
682
+ yield record;
683
+ }
684
+ const actorTags = await withActor(ctx.actorUserId, (tx) => tx.select().from(tags).where(eq(tags.ownerId, ctx.actorUserId)));
685
+ for (const tag of actorTags) {
686
+ const record = {
687
+ type: "data",
688
+ domain: "tags",
689
+ resourceType: "tag",
690
+ resourceId: tag.id,
691
+ workspaceId: tag.workspaceId,
692
+ payload: tag
693
+ };
694
+ checksumLine(hash, record);
695
+ recordCount += 1;
696
+ yield record;
697
+ }
698
+ const actorCategories = await withActor(ctx.actorUserId, (tx) => tx.select().from(categories).where(eq(categories.ownerId, ctx.actorUserId)));
699
+ for (const category of actorCategories) {
700
+ const record = {
701
+ type: "data",
702
+ domain: "categories",
703
+ resourceType: "category",
704
+ resourceId: category.id,
705
+ workspaceId: category.workspaceId,
706
+ payload: category
707
+ };
708
+ checksumLine(hash, record);
709
+ recordCount += 1;
710
+ yield record;
711
+ }
637
712
  const ownedDocuments = await withActor(ctx.actorUserId, (tx) => tx.select().from(documents).where(eq(documents.ownerId, ctx.actorUserId)));
638
713
  for (const document of ownedDocuments) {
639
714
  throwIfAborted(ctx.signal);
@@ -733,12 +808,24 @@ function createPersistentLifecycleService(runtime, database, hostSteps = []) {
733
808
  storageKey: attachments.storageKey
734
809
  }).from(attachments).where(inArray(attachments.documentId, documentIds))) : [];
735
810
  await runStep(operation, ctx.actorUserId, leaseOwner, "delete_attachment_objects", deletedByDomain, () => runtime.deleteObjects(objectRows.map((row) => row.storageKey), ctx.signal));
811
+ await runStep(operation, ctx.actorUserId, leaseOwner, "remove_subject_folders", deletedByDomain, () => dbDelete((tx) => tx.delete(folders).where(eq(folders.ownerId, ctx.actorUserId)).returning({ id: folders.id })));
812
+ await runStep(operation, ctx.actorUserId, leaseOwner, "remove_subject_tags", deletedByDomain, () => dbDelete((tx) => tx.delete(tags).where(eq(tags.ownerId, ctx.actorUserId)).returning({ id: tags.id })));
813
+ await runStep(operation, ctx.actorUserId, leaseOwner, "remove_subject_categories", deletedByDomain, () => dbDelete((tx) => tx.delete(categories).where(eq(categories.ownerId, ctx.actorUserId)).returning({ id: categories.id })));
736
814
  await runStep(operation, ctx.actorUserId, leaseOwner, "remove_attachment_rows", deletedByDomain, () => objectRows.length ? dbDelete((tx) => tx.delete(attachments).where(inArray(attachments.id, objectRows.map((row) => row.id))).returning({ id: attachments.id })) : Promise.resolve(0));
737
815
  await runStep(operation, ctx.actorUserId, leaseOwner, "remove_subject_documents", deletedByDomain, () => dbDelete((tx) => tx.delete(documents).where(eq(documents.ownerId, ctx.actorUserId)).returning({ id: documents.id })));
738
816
  await runStep(operation, ctx.actorUserId, leaseOwner, "clear_redis_state", deletedByDomain, () => runtime.clearAccountRedisState(ctx.actorUserId, ctx.signal));
739
817
  for (const step of orderedSteps)
740
818
  if (step.purge)
741
819
  await runStep(operation, ctx.actorUserId, leaseOwner, `host:${step.id}`, deletedByDomain, async () => (await step.purge?.(ctx))?.deletedCount ?? 0);
820
+ await runStep(operation, ctx.actorUserId, leaseOwner, "remove_auth_sessions", deletedByDomain, () => dbDelete((tx) => tx.delete(sessions).where(eq(sessions.userId, ctx.actorUserId)).returning({ id: sessions.id })));
821
+ await runStep(operation, ctx.actorUserId, leaseOwner, "remove_auth_accounts", deletedByDomain, () => dbDelete((tx) => tx.delete(accounts).where(eq(accounts.userId, ctx.actorUserId)).returning({ id: accounts.id })));
822
+ await runStep(operation, ctx.actorUserId, leaseOwner, "tombstone_subject_user", deletedByDomain, () => dbDelete((tx) => tx.update(users).set({
823
+ email: lifecycleTombstoneEmail(ctx.actorUserId),
824
+ name: null,
825
+ image: null,
826
+ emailVerified: false,
827
+ updatedAt: new Date
828
+ }).where(eq(users.id, ctx.actorUserId)).returning({ id: users.id })));
742
829
  await runStep(operation, ctx.actorUserId, leaseOwner, "write_deletion_audit", deletedByDomain, async () => {
743
830
  await withActor(ctx.actorUserId, (tx) => tx.insert(auditLog).values({
744
831
  actorId: ctx.actorUserId,
@@ -803,6 +890,7 @@ function createPersistentLifecycleRuntime(options) {
803
890
  }
804
891
  export {
805
892
  requireLeaseWrite,
893
+ lifecycleTombstoneEmail,
806
894
  createPersistentLifecycleService,
807
895
  createPersistentLifecycleRuntime,
808
896
  bindPersistentLifecycle,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hiai-gg/docsmint",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "type": "module",
5
5
  "browser": {
6
6
  "./dist/backend-launcher.js": false,
@@ -10,7 +10,8 @@
10
10
  "./dist/pipeline-cancellation.js": false,
11
11
  "./dist/storage-quota.js": false,
12
12
  "./dist/workspace.js": false,
13
- "./dist/backend-pipeline-cancellation.js": false
13
+ "./dist/backend-pipeline-cancellation.js": false,
14
+ "./dist/backend-account-runtime-cleanup.js": false
14
15
  },
15
16
  "license": "Apache-2.0",
16
17
  "description": "The lightweight, AI-native self-hosted knowledge base — built-in RAG, hybrid semantic search, and a clean REST API for AI agents.",
@@ -306,6 +307,11 @@
306
307
  "browser": "./dist/server-only-browser-entry.js",
307
308
  "import": "./dist/backend-pipeline-cancellation.js",
308
309
  "types": "./dist/backend-pipeline-cancellation.d.ts"
310
+ },
311
+ "./backend/account-runtime-cleanup": {
312
+ "browser": "./dist/server-only-browser-entry.js",
313
+ "import": "./dist/backend-account-runtime-cleanup.js",
314
+ "types": "./dist/backend-account-runtime-cleanup.d.ts"
309
315
  }
310
316
  },
311
317
  "bin": {
@@ -352,12 +358,12 @@
352
358
  "@modelcontextprotocol/sdk": "^1.12.1",
353
359
  "bullmq": "^5.80.2",
354
360
  "commander": "^13.1.0",
361
+ "ioredis": "^5.11.1",
355
362
  "zod": "^4.0.0"
356
363
  },
357
364
  "peerDependencies": {
358
365
  "drizzle-orm": "^0.45.2",
359
366
  "postgres": "^3.4.9",
360
- "ioredis": "^5.4.0",
361
367
  "@aws-sdk/client-s3": "^3.0.0",
362
368
  "pino": "^10.0.0",
363
369
  "@sveltejs/kit": "^2.68.0",
@@ -370,9 +376,6 @@
370
376
  "postgres": {
371
377
  "optional": true
372
378
  },
373
- "ioredis": {
374
- "optional": true
375
- },
376
379
  "@aws-sdk/client-s3": {
377
380
  "optional": true
378
381
  },
@@ -24,7 +24,7 @@ import { registerSearch } from "./commands/search.js";
24
24
  import { registerSnapshot } from "./commands/snapshot.js";
25
25
  import { registerUpdate } from "./commands/update.js";
26
26
 
27
- const VERSION = "0.4.4";
27
+ const VERSION = "0.4.6";
28
28
 
29
29
  const program = new Command();
30
30
  program
@@ -35,7 +35,7 @@ interface McpToolResult {
35
35
 
36
36
  const server = new McpServer({
37
37
  name: "hiai-docs",
38
- version: "0.4.4",
38
+ version: "0.4.6",
39
39
  });
40
40
 
41
41
  /**