@ours.network/sdk 2.0.0 → 3.0.1

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.
Files changed (92) hide show
  1. package/README.md +23 -2
  2. package/dist/api/contacts.js +1 -1
  3. package/dist/api/files.d.ts +4 -6
  4. package/dist/api/files.js +1 -1
  5. package/dist/api/history.d.ts +11 -0
  6. package/dist/api/history.js +2 -0
  7. package/dist/api/identity.js +1 -1
  8. package/dist/api/messaging.d.ts +6 -7
  9. package/dist/api/messaging.js +1 -1
  10. package/dist/api/profile.js +1 -1
  11. package/dist/api/types.d.ts +21 -69
  12. package/dist/book.js +1 -1
  13. package/dist/boot.js +1 -1
  14. package/dist/chunk-3NTV3JFP.js +4 -0
  15. package/dist/chunk-4DWIX7KY.js +2 -0
  16. package/dist/chunk-54BIUFRS.js +2 -0
  17. package/dist/{chunk-YDCAL5R3.js → chunk-5WE5G2CD.js} +1 -1
  18. package/dist/chunk-6XZYUNSM.js +2 -0
  19. package/dist/chunk-DYQHWN7X.js +165 -0
  20. package/dist/{chunk-3KI5FM4I.js → chunk-FOFYSUCT.js} +1 -1
  21. package/dist/chunk-GVEBDMN6.js +2 -0
  22. package/dist/chunk-HEWVNFUK.js +2 -0
  23. package/dist/{chunk-OPCXNIGD.js → chunk-IWY6MRSV.js} +1 -1
  24. package/dist/chunk-JOKNFUW3.js +4 -0
  25. package/dist/chunk-JTBQO6IT.js +2 -0
  26. package/dist/{chunk-TIIFYDXJ.js → chunk-K3NRXUJW.js} +1 -1
  27. package/dist/chunk-O2QIPLR6.js +2 -0
  28. package/dist/chunk-PLCNB2IO.js +2 -0
  29. package/dist/{chunk-OA7XXAFG.js → chunk-PMSTI7RY.js} +1 -1
  30. package/dist/{chunk-6SMQG6NV.js → chunk-S24UCZDR.js} +1 -1
  31. package/dist/{chunk-CQDCCH6N.js → chunk-SQ4M4QQA.js} +1 -1
  32. package/dist/chunk-VNZYANLS.js +2 -0
  33. package/dist/chunk-WFONSX5L.js +4 -0
  34. package/dist/{chunk-SGTVMU5E.js → chunk-WSEDMA2W.js} +1 -1
  35. package/dist/{chunk-WWTR33CX.js → chunk-YBNUNQNM.js} +1 -1
  36. package/dist/chunk-YZJB6DZI.js +2 -0
  37. package/dist/{chunk-ENJRQKGS.js → chunk-Z5IFINRU.js} +1 -1
  38. package/dist/chunk-ZWUFPR6V.js +2 -0
  39. package/dist/client/http.d.ts +6 -8
  40. package/dist/client/http.js +1 -1
  41. package/dist/client/select.js +1 -1
  42. package/dist/client.js +1 -1
  43. package/dist/cluster/control.js +1 -1
  44. package/dist/cluster/manifest.js +1 -1
  45. package/dist/connector.js +1 -1
  46. package/dist/events.d.ts +6 -12
  47. package/dist/events.js +1 -1
  48. package/dist/gc.js +1 -1
  49. package/dist/history.d.ts +187 -0
  50. package/dist/history.js +2 -0
  51. package/dist/http/api-routes.d.ts +4 -6
  52. package/dist/http/api-routes.js +1 -1
  53. package/dist/http/server.js +1 -1
  54. package/dist/identity/hierarchy.js +1 -1
  55. package/dist/identity/lease.js +1 -1
  56. package/dist/identity/lifecycle.js +1 -1
  57. package/dist/identity/model.d.ts +0 -1
  58. package/dist/identity/model.js +1 -1
  59. package/dist/identity/provision.js +1 -1
  60. package/dist/index.js +1 -1
  61. package/dist/messaging/send.d.ts +8 -2
  62. package/dist/messaging/send.js +1 -1
  63. package/dist/mufl/handlers.js +1 -1
  64. package/dist/mufl/tx.js +1 -1
  65. package/dist/mufl_code/{7962BB01B1D3E782A1F80B083A900AEC30BAC8F8CE79282B31821802B94A39B6.muflo → 351F16D444E6DAA252D4A8D829D17204360D9015FEF670ACE68FB4747BB3B14E.muflo} +0 -0
  66. package/dist/notify.d.ts +0 -1
  67. package/dist/notify.js +1 -1
  68. package/dist/render/adapt-to-json.d.ts +0 -5
  69. package/dist/render/adapt-to-json.js +1 -1
  70. package/dist/runtime/env.js +1 -1
  71. package/dist/state.js +1 -1
  72. package/dist/sweeps.js +1 -1
  73. package/dist/uploads.js +1 -1
  74. package/package.json +6 -4
  75. package/dist/api/conversations.d.ts +0 -48
  76. package/dist/api/conversations.js +0 -2
  77. package/dist/chunk-4IGLXDJS.js +0 -2
  78. package/dist/chunk-CUMFIDHH.js +0 -2
  79. package/dist/chunk-DVYJ3STO.js +0 -2
  80. package/dist/chunk-LKFYUCN7.js +0 -2
  81. package/dist/chunk-OCHXHPQZ.js +0 -2
  82. package/dist/chunk-QSDEMIZQ.js +0 -2
  83. package/dist/chunk-TNTHPI3A.js +0 -2
  84. package/dist/chunk-UH4CZUMI.js +0 -2
  85. package/dist/chunk-VJGMISQ5.js +0 -2
  86. package/dist/chunk-WU5WT7LA.js +0 -6
  87. package/dist/chunk-XL6UKHPU.js +0 -5
  88. package/dist/chunk-XYU2DSWR.js +0 -2
  89. package/dist/chunk-YDWSAX43.js +0 -2
  90. package/dist/chunk-ZGPYTIOX.js +0 -2
  91. package/dist/inbox.d.ts +0 -38
  92. package/dist/inbox.js +0 -2
package/README.md CHANGED
@@ -42,6 +42,26 @@ Old `autoStart` JSON and `OURS_AUTOSTART` are ignored in SDK 2. Start the daemon
42
42
  with `ours daemon start` or install its per-user service with
43
43
  `ours daemon install-service`.
44
44
 
45
+ ## Message and file history
46
+
47
+ Application payloads are stored by the daemon, outside the MUFL packet. Each
48
+ identity has a `history.sqlite3` database and immutable content-addressed file
49
+ blobs. Incoming rows are unread until `getMessages({ limit })` or
50
+ `getFiles({ wire_ids, limit })` selects and marks exactly that batch read.
51
+ Persistent history is available through `listHistory`, `getHistoryItem`,
52
+ `listFiles`, and `getFileInfo`; `fetchFile` streams stored bytes from the daemon.
53
+
54
+ This design intentionally does not coordinate protocol delivery receipts with
55
+ the filesystem write. A process or local-storage failure after protocol
56
+ acceptance can therefore lose an item even if its sender considers it delivered.
57
+ There is no packet fallback, host outbox, implicit retry queue, or defer API.
58
+
59
+ This is a breaking storage epoch with no migration. A daemon that finds an old
60
+ packet format refuses startup and leaves it untouched. Before upgrading, stop
61
+ applications, make any desired manual backup, remove the old daemon state
62
+ yourself, and start clean. Identities, contacts, invites, pending payloads, and
63
+ history in old state are not carried forward; installers never delete them.
64
+
45
65
  ## Internal singleton contract
46
66
 
47
67
  The CLI bundle acquires a cross-process lock before importing any module that
@@ -70,8 +90,9 @@ ownership boundary.
70
90
 
71
91
  ## Requirements
72
92
 
73
- Node ≥ 20. The MUFL packet is compiled from `mufl_code/`, which pins the
74
- `ours-mufl-core` submodule — clone with `--recurse-submodules`.
93
+ Node ≥ 20. The daemon uses the native `better-sqlite3` runtime dependency. The
94
+ MUFL packet is compiled from `mufl_code/`, which pins the `ours-mufl-core`
95
+ submodule — clone with `--recurse-submodules`.
75
96
 
76
97
  ## Build and test
77
98
 
@@ -1,2 +1,2 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
- import{a,b,c,d,e,f,g,h,i,j}from"../chunk-QSDEMIZQ.js";import"../chunk-ENJRQKGS.js";import"../chunk-TNTHPI3A.js";import"../chunk-65KGEJBX.js";import"../chunk-TIIFYDXJ.js";import"../chunk-6SMQG6NV.js";import"../chunk-CQDCCH6N.js";import"../chunk-XL6UKHPU.js";import"../chunk-YRPUM6JG.js";import"../chunk-WU5WT7LA.js";import"../chunk-DIRW7I4S.js";import"../chunk-YDCAL5R3.js";import"../chunk-OCHXHPQZ.js";import"../chunk-OPCXNIGD.js";import"../chunk-ZHH3PWEW.js";import"../chunk-LKFYUCN7.js";import"../chunk-Y3VPZJTG.js";import"../chunk-P55RJGZU.js";import"../chunk-XYU2DSWR.js";import"../chunk-WS6UFNKF.js";export{d as addContact,a as generateInvite,e as listContacts,b as listInvites,f as listLocalContactBook,h as removeContact,i as renameContact,j as respondToIntroduction,c as revokeInvite,g as setLocalBookPolicy};
2
+ import{a,b,c,d,e,f,g,h,i,j}from"../chunk-O2QIPLR6.js";import"../chunk-Z5IFINRU.js";import"../chunk-HEWVNFUK.js";import"../chunk-JOKNFUW3.js";import"../chunk-DIRW7I4S.js";import"../chunk-65KGEJBX.js";import"../chunk-K3NRXUJW.js";import"../chunk-S24UCZDR.js";import"../chunk-SQ4M4QQA.js";import"../chunk-YZJB6DZI.js";import"../chunk-YRPUM6JG.js";import"../chunk-3NTV3JFP.js";import"../chunk-5WE5G2CD.js";import"../chunk-ZWUFPR6V.js";import"../chunk-IWY6MRSV.js";import"../chunk-ZHH3PWEW.js";import"../chunk-Y3VPZJTG.js";import"../chunk-DYQHWN7X.js";import"../chunk-JTBQO6IT.js";import"../chunk-WS6UFNKF.js";export{d as addContact,a as generateInvite,e as listContacts,b as listInvites,f as listLocalContactBook,h as removeContact,i as renameContact,j as respondToIntroduction,c as revokeInvite,g as setLocalBookPolicy};
@@ -1,13 +1,11 @@
1
- import { type IncomingFileMeta } from '../render/adapt-to-json.js';
2
- import type { DeferResult, GetFilesResult, SaveFileNotice, SessionContext } from './types.js';
1
+ import { type HistoryFile } from '../history.js';
2
+ import type { GetFilesResult, SaveFileNotice, SessionContext } from './types.js';
3
3
  export type * from './types.js';
4
- export declare function listIncomingFiles(ctx: SessionContext): Promise<IncomingFileMeta[]>;
4
+ export declare function listIncomingFiles(ctx: SessionContext): Promise<HistoryFile[]>;
5
5
  export declare function getFiles(ctx: SessionContext, a?: {
6
6
  wire_ids?: string[];
7
+ limit?: number;
7
8
  }): Promise<GetFilesResult>;
8
9
  export declare function saveFileFallbackNotice(ctx: SessionContext, a: {
9
10
  wire_id: string;
10
11
  }): SaveFileNotice;
11
- export declare function deferFiles(ctx: SessionContext, a: {
12
- file_ids: number[];
13
- }): Promise<DeferResult>;
package/dist/api/files.js CHANGED
@@ -1,2 +1,2 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
- import{a,b,c,d}from"../chunk-ZGPYTIOX.js";import"../chunk-ENJRQKGS.js";import"../chunk-TNTHPI3A.js";import"../chunk-65KGEJBX.js";import"../chunk-TIIFYDXJ.js";import"../chunk-6SMQG6NV.js";import"../chunk-CQDCCH6N.js";import"../chunk-XL6UKHPU.js";import"../chunk-YRPUM6JG.js";import"../chunk-WU5WT7LA.js";import"../chunk-DIRW7I4S.js";import"../chunk-YDCAL5R3.js";import"../chunk-OCHXHPQZ.js";import"../chunk-OPCXNIGD.js";import"../chunk-ZHH3PWEW.js";import"../chunk-LKFYUCN7.js";import"../chunk-Y3VPZJTG.js";import"../chunk-P55RJGZU.js";import"../chunk-XYU2DSWR.js";import"../chunk-WS6UFNKF.js";export{d as deferFiles,b as getFiles,a as listIncomingFiles,c as saveFileFallbackNotice};
2
+ import{a,b,c}from"../chunk-WFONSX5L.js";import"../chunk-Z5IFINRU.js";import"../chunk-HEWVNFUK.js";import"../chunk-JOKNFUW3.js";import"../chunk-DIRW7I4S.js";import"../chunk-65KGEJBX.js";import"../chunk-K3NRXUJW.js";import"../chunk-S24UCZDR.js";import"../chunk-SQ4M4QQA.js";import"../chunk-YZJB6DZI.js";import"../chunk-YRPUM6JG.js";import"../chunk-3NTV3JFP.js";import"../chunk-5WE5G2CD.js";import"../chunk-ZWUFPR6V.js";import"../chunk-IWY6MRSV.js";import"../chunk-ZHH3PWEW.js";import"../chunk-Y3VPZJTG.js";import"../chunk-DYQHWN7X.js";import"../chunk-JTBQO6IT.js";import"../chunk-WS6UFNKF.js";export{b as getFiles,a as listIncomingFiles,c as saveFileFallbackNotice};
@@ -0,0 +1,11 @@
1
+ import { type HistoryFile, type HistoryMessage, type HistoryPage, type HistoryQuery } from '../history.js';
2
+ import type { SessionContext } from './types.js';
3
+ export type * from '../history.js';
4
+ export declare function listHistory(ctx: SessionContext, query?: HistoryQuery): HistoryPage<HistoryMessage>;
5
+ export declare function getHistoryItem(ctx: SessionContext, input: {
6
+ wire_id: string;
7
+ }): HistoryMessage | null;
8
+ export declare function listFiles(ctx: SessionContext, query?: HistoryQuery): HistoryPage<HistoryFile>;
9
+ export declare function getFileInfo(ctx: SessionContext, input: {
10
+ wire_id: string;
11
+ }): HistoryFile | null;
@@ -0,0 +1,2 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import{a,b,c,d}from"../chunk-PLCNB2IO.js";import"../chunk-Z5IFINRU.js";import"../chunk-HEWVNFUK.js";import"../chunk-JOKNFUW3.js";import"../chunk-DIRW7I4S.js";import"../chunk-65KGEJBX.js";import"../chunk-K3NRXUJW.js";import"../chunk-S24UCZDR.js";import"../chunk-SQ4M4QQA.js";import"../chunk-YZJB6DZI.js";import"../chunk-YRPUM6JG.js";import"../chunk-3NTV3JFP.js";import"../chunk-5WE5G2CD.js";import"../chunk-ZWUFPR6V.js";import"../chunk-IWY6MRSV.js";import"../chunk-ZHH3PWEW.js";import"../chunk-Y3VPZJTG.js";import"../chunk-DYQHWN7X.js";import"../chunk-JTBQO6IT.js";import"../chunk-WS6UFNKF.js";export{d as getFileInfo,b as getHistoryItem,c as listFiles,a as listHistory};
@@ -1,2 +1,2 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
- import{a,b,c,d,e,f,g,h,i,j,k}from"../chunk-ENJRQKGS.js";import"../chunk-TNTHPI3A.js";import"../chunk-65KGEJBX.js";import"../chunk-TIIFYDXJ.js";import"../chunk-6SMQG6NV.js";import"../chunk-CQDCCH6N.js";import"../chunk-XL6UKHPU.js";import"../chunk-YRPUM6JG.js";import"../chunk-WU5WT7LA.js";import"../chunk-DIRW7I4S.js";import"../chunk-YDCAL5R3.js";import"../chunk-OCHXHPQZ.js";import"../chunk-OPCXNIGD.js";import"../chunk-ZHH3PWEW.js";import"../chunk-LKFYUCN7.js";import"../chunk-Y3VPZJTG.js";import"../chunk-P55RJGZU.js";import"../chunk-XYU2DSWR.js";import"../chunk-WS6UFNKF.js";export{g as chooseIdentity,d as closeTemporaryIdentityOp,b as createIdentity,e as createRootIdentity,c as createTemporaryIdentity,i as currentIdentity,f as defineLocalIdentityFile,h as listIdentities,k as releaseLease,j as removeIdentity,a as requireBound};
2
+ import{a,b,c,d,e,f,g,h,i,j,k}from"../chunk-Z5IFINRU.js";import"../chunk-HEWVNFUK.js";import"../chunk-JOKNFUW3.js";import"../chunk-DIRW7I4S.js";import"../chunk-65KGEJBX.js";import"../chunk-K3NRXUJW.js";import"../chunk-S24UCZDR.js";import"../chunk-SQ4M4QQA.js";import"../chunk-YZJB6DZI.js";import"../chunk-YRPUM6JG.js";import"../chunk-3NTV3JFP.js";import"../chunk-5WE5G2CD.js";import"../chunk-ZWUFPR6V.js";import"../chunk-IWY6MRSV.js";import"../chunk-ZHH3PWEW.js";import"../chunk-Y3VPZJTG.js";import"../chunk-DYQHWN7X.js";import"../chunk-JTBQO6IT.js";import"../chunk-WS6UFNKF.js";export{g as chooseIdentity,d as closeTemporaryIdentityOp,b as createIdentity,e as createRootIdentity,c as createTemporaryIdentity,i as currentIdentity,f as defineLocalIdentityFile,h as listIdentities,k as releaseLease,j as removeIdentity,a as requireBound};
@@ -1,5 +1,5 @@
1
- import { type InboxMsg } from '../render/adapt-to-json.js';
2
- import type { DeferResult, FileSendOutcome, MessagesPayload, SendOutcome, SessionContext } from './types.js';
1
+ import { type IncomingMessageMetadata } from '../history.js';
2
+ import type { FileSendOutcome, MessagesPayload, SendOutcome, SessionContext } from './types.js';
3
3
  export type * from './types.js';
4
4
  export declare function sendMessage(ctx: SessionContext, a: {
5
5
  contact: string;
@@ -17,8 +17,7 @@ export declare function sendFile(ctx: SessionContext, a: {
17
17
  reply_to_wire_id?: string;
18
18
  reply_to_sentence?: number;
19
19
  }): Promise<FileSendOutcome>;
20
- export declare function listIncomingMessages(ctx: SessionContext): Promise<InboxMsg[]>;
21
- export declare function getMessages(ctx: SessionContext): Promise<MessagesPayload>;
22
- export declare function deferMessages(ctx: SessionContext, a: {
23
- msg_ids: number[];
24
- }): Promise<DeferResult>;
20
+ export declare function listIncomingMessages(ctx: SessionContext): Promise<IncomingMessageMetadata[]>;
21
+ export declare function getMessages(ctx: SessionContext, input?: {
22
+ limit?: number;
23
+ }): Promise<MessagesPayload>;
@@ -1,2 +1,2 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
- import{a,b,c,d,e}from"../chunk-CUMFIDHH.js";import"../chunk-WWTR33CX.js";import"../chunk-VXVW4KJU.js";import"../chunk-YDWSAX43.js";import"../chunk-ENJRQKGS.js";import"../chunk-TNTHPI3A.js";import"../chunk-65KGEJBX.js";import"../chunk-TIIFYDXJ.js";import"../chunk-6SMQG6NV.js";import"../chunk-CQDCCH6N.js";import"../chunk-XL6UKHPU.js";import"../chunk-YRPUM6JG.js";import"../chunk-WU5WT7LA.js";import"../chunk-DIRW7I4S.js";import"../chunk-YDCAL5R3.js";import"../chunk-OCHXHPQZ.js";import"../chunk-OPCXNIGD.js";import"../chunk-ZHH3PWEW.js";import"../chunk-LKFYUCN7.js";import"../chunk-Y3VPZJTG.js";import"../chunk-P55RJGZU.js";import"../chunk-XYU2DSWR.js";import"../chunk-WS6UFNKF.js";export{e as deferMessages,d as getMessages,c as listIncomingMessages,b as sendFile,a as sendMessage};
2
+ import{a,b,c,d}from"../chunk-6XZYUNSM.js";import"../chunk-YBNUNQNM.js";import"../chunk-VXVW4KJU.js";import"../chunk-54BIUFRS.js";import"../chunk-P55RJGZU.js";import"../chunk-Z5IFINRU.js";import"../chunk-HEWVNFUK.js";import"../chunk-JOKNFUW3.js";import"../chunk-DIRW7I4S.js";import"../chunk-65KGEJBX.js";import"../chunk-K3NRXUJW.js";import"../chunk-S24UCZDR.js";import"../chunk-SQ4M4QQA.js";import"../chunk-YZJB6DZI.js";import"../chunk-YRPUM6JG.js";import"../chunk-3NTV3JFP.js";import"../chunk-5WE5G2CD.js";import"../chunk-ZWUFPR6V.js";import"../chunk-IWY6MRSV.js";import"../chunk-ZHH3PWEW.js";import"../chunk-Y3VPZJTG.js";import"../chunk-DYQHWN7X.js";import"../chunk-JTBQO6IT.js";import"../chunk-WS6UFNKF.js";export{d as getMessages,c as listIncomingMessages,b as sendFile,a as sendMessage};
@@ -1,2 +1,2 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
- import{a,b,c,d}from"../chunk-SGTVMU5E.js";import"../chunk-ENJRQKGS.js";import"../chunk-TNTHPI3A.js";import"../chunk-65KGEJBX.js";import"../chunk-TIIFYDXJ.js";import"../chunk-6SMQG6NV.js";import"../chunk-CQDCCH6N.js";import"../chunk-XL6UKHPU.js";import"../chunk-YRPUM6JG.js";import"../chunk-WU5WT7LA.js";import"../chunk-DIRW7I4S.js";import"../chunk-YDCAL5R3.js";import"../chunk-OCHXHPQZ.js";import"../chunk-OPCXNIGD.js";import"../chunk-ZHH3PWEW.js";import"../chunk-LKFYUCN7.js";import"../chunk-Y3VPZJTG.js";import"../chunk-P55RJGZU.js";import"../chunk-XYU2DSWR.js";import"../chunk-WS6UFNKF.js";export{b as advertiseMigrate,d as readvertiseOnUpgrade,a as setBio,c as setPersona};
2
+ import{a,b,c,d}from"../chunk-WSEDMA2W.js";import"../chunk-Z5IFINRU.js";import"../chunk-HEWVNFUK.js";import"../chunk-JOKNFUW3.js";import"../chunk-DIRW7I4S.js";import"../chunk-65KGEJBX.js";import"../chunk-K3NRXUJW.js";import"../chunk-S24UCZDR.js";import"../chunk-SQ4M4QQA.js";import"../chunk-YZJB6DZI.js";import"../chunk-YRPUM6JG.js";import"../chunk-3NTV3JFP.js";import"../chunk-5WE5G2CD.js";import"../chunk-ZWUFPR6V.js";import"../chunk-IWY6MRSV.js";import"../chunk-ZHH3PWEW.js";import"../chunk-Y3VPZJTG.js";import"../chunk-DYQHWN7X.js";import"../chunk-JTBQO6IT.js";import"../chunk-WS6UFNKF.js";export{b as advertiseMigrate,d as readvertiseOnUpgrade,a as setBio,c as setPersona};
@@ -1,8 +1,8 @@
1
1
  import type { TempCloseResult } from '../identity/model.js';
2
- import type { MessageJson } from '../inbox.js';
3
2
  import type { SendVerdict } from '../messaging/send.js';
3
+ import type { HistoryMessage } from '../history.js';
4
4
  import type { ContactRoot, IncomingFileMeta, InboxMsg, ReceivedFileMeta } from '../render/adapt-to-json.js';
5
- export type { ContactRoot, IncomingFileMeta, InboxMsg, MessageJson, ReceivedFileMeta };
5
+ export type { ContactRoot, IncomingFileMeta, InboxMsg, ReceivedFileMeta };
6
6
  export interface SessionContext {
7
7
  sessionId(): string;
8
8
  leaseToken(): string | undefined;
@@ -147,9 +147,23 @@ export interface AdvertiseMigrateResult {
147
147
  advertising: boolean;
148
148
  offers: number;
149
149
  }
150
- export type SendOutcome = SendVerdict | {
150
+ type TransportPendingVerdict = Extract<SendVerdict, {
151
+ kind: 'refused' | 'migrating' | 'deferred';
152
+ }>;
153
+ type TransportSentVerdict = Extract<SendVerdict, {
154
+ kind: 'e2e' | 'sent';
155
+ }> & {
156
+ sent: true;
157
+ wire_id: string;
158
+ history_stored: boolean;
159
+ };
160
+ export type SendOutcome = TransportPendingVerdict | TransportSentVerdict | {
151
161
  kind: 'introduced';
152
162
  text: string;
163
+ wireId: string;
164
+ wire_id: string;
165
+ sent: true;
166
+ history_stored: boolean;
153
167
  };
154
168
  export type FileSendOutcome = SendOutcome & {
155
169
  filename: string;
@@ -157,25 +171,8 @@ export type FileSendOutcome = SendOutcome & {
157
171
  mime: string;
158
172
  };
159
173
  export interface MessagesPayload {
160
- count: number;
161
- messages: MessageJson[];
162
- }
163
- export interface DeferResult {
164
- /**
165
- * HOW MANY WERE ACTUALLY RESTORED, which can be lower than the number of ids
166
- * you passed, with nothing wrong.
167
- *
168
- * `defer_files` only restores files in `processed` or `ready_to_delete`
169
- * (actor.mu:752); an already-unread file and an unknown id are both silently
170
- * skipped and counted zero. `deferred < ids.length` is therefore a normal
171
- * outcome of a retry, NOT an error — do not report it as one.
172
- *
173
- * NOTE THE IDENTIFIER SPLIT, because it reads as a typo and gets "fixed":
174
- * `deferFiles` takes **file_id**s while `getFiles` selects by **wire_id**.
175
- * They are different identifiers on the same file and the two surfaces
176
- * disagree on purpose — the cell keys on `$file_ids -> ids: int[]`.
177
- */
178
- deferred: string;
174
+ messages: HistoryMessage[];
175
+ remaining: number;
179
176
  }
180
177
  export interface ReadvertiseResult {
181
178
  /**
@@ -188,7 +185,7 @@ export interface ReadvertiseResult {
188
185
  * that is the phrasing someone will reach for.
189
186
  *
190
187
  * The packet's own Visualize() string, unparsed — the same rule as
191
- * `DeferResult.deferred`.
188
+ * The packet's own Visualize() string.
192
189
  */
193
190
  readvertised: string;
194
191
  }
@@ -197,6 +194,7 @@ export interface GetFilesResult {
197
194
  text: string;
198
195
  mode: 'all_unread' | 'selected';
199
196
  requested: string[] | null;
197
+ remaining: number;
200
198
  }
201
199
  export interface ReleaseLeaseResult {
202
200
  released: string[];
@@ -204,49 +202,3 @@ export interface ReleaseLeaseResult {
204
202
  export interface SaveFileNotice {
205
203
  existsOnDisk: boolean;
206
204
  }
207
- /** One entry of a per-contact conversation, oldest first. */
208
- export interface ConversationMessage {
209
- dir: 'in' | 'out';
210
- text: string;
211
- date: string;
212
- /**
213
- * THE HUMAN READ FLAG, and deliberately not the inbox's `status`. A message
214
- * can be `processed` — handed to an agent by getMessages — and still unread by
215
- * a person. Conflating the two is what would make a polling frontend send read
216
- * receipts for messages nobody looked at.
217
- */
218
- read: boolean;
219
- /** '' for pre-1.4 entries, which have no stable cross-side id. */
220
- wire_id: string;
221
- /**
222
- * What the PEER has told us about this message, for outbound entries.
223
- * MONOTONIC: null < 'delivered' < 'read', and it can never go backwards —
224
- * a duplicate or out-of-order receipt collapses to a no-op, so a peer's UI
225
- * cannot show a read message becoming unread.
226
- */
227
- receipt: 'delivered' | 'read' | null;
228
- }
229
- export interface ConversationResult {
230
- contact: string;
231
- messages: ConversationMessage[];
232
- }
233
- export interface ReceiptsResult {
234
- contact: string;
235
- /** wire_id -> state. Absent ids simply have no receipt yet. */
236
- receipts: Record<string, 'delivered' | 'read'>;
237
- }
238
- export interface MarkReadResult {
239
- contact: string;
240
- /**
241
- * HOW MANY ENTRIES TRANSITIONED, which is also how many read receipts were
242
- * emitted. Zero on a second call is the normal, correct answer — the
243
- * unread->read transition is the event, not the call — so do not treat it as
244
- * a failure.
245
- */
246
- marked: number;
247
- }
248
- export interface ConversationPolicyResult {
249
- keepHistory: boolean;
250
- /** Echoed back unchanged; this operation must never silently move it. */
251
- autoAccept: boolean;
252
- }
package/dist/book.js CHANGED
@@ -1,2 +1,2 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
- import{N as a,O as b,P as c,Q as d,R as e,S as f,T as g,U as h,V as i,W as j}from"./chunk-XL6UKHPU.js";import"./chunk-YRPUM6JG.js";import"./chunk-WU5WT7LA.js";import"./chunk-DIRW7I4S.js";import"./chunk-YDCAL5R3.js";import"./chunk-OCHXHPQZ.js";import"./chunk-OPCXNIGD.js";import"./chunk-ZHH3PWEW.js";import"./chunk-LKFYUCN7.js";import"./chunk-Y3VPZJTG.js";import"./chunk-P55RJGZU.js";import"./chunk-XYU2DSWR.js";import"./chunk-WS6UFNKF.js";export{a as bookDir,c as bookPath,f as exportAdBlob,g as exportSigningSecret,j as pinRegistrar,h as publishToBook,d as readBook,b as registrarKeyPath,i as unpublishFromBook,e as writeBook};
2
+ import{A as e,B as f,C as g,D as h,E as i,F as j,w as a,x as b,y as c,z as d}from"./chunk-YZJB6DZI.js";import"./chunk-YRPUM6JG.js";import"./chunk-3NTV3JFP.js";import"./chunk-5WE5G2CD.js";import"./chunk-ZWUFPR6V.js";import"./chunk-IWY6MRSV.js";import"./chunk-ZHH3PWEW.js";import"./chunk-Y3VPZJTG.js";import"./chunk-DYQHWN7X.js";import"./chunk-JTBQO6IT.js";import"./chunk-WS6UFNKF.js";export{a as bookDir,c as bookPath,f as exportAdBlob,g as exportSigningSecret,j as pinRegistrar,h as publishToBook,d as readBook,b as registrarKeyPath,i as unpublishFromBook,e as writeBook};
package/dist/boot.js CHANGED
@@ -1,2 +1,2 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
- import{a,b}from"./chunk-VJGMISQ5.js";import"./chunk-EHCBEY52.js";import"./chunk-TNTHPI3A.js";import"./chunk-TIIFYDXJ.js";import"./chunk-6SMQG6NV.js";import"./chunk-CQDCCH6N.js";import"./chunk-XL6UKHPU.js";import"./chunk-YRPUM6JG.js";import"./chunk-WU5WT7LA.js";import"./chunk-DIRW7I4S.js";import"./chunk-YDCAL5R3.js";import"./chunk-OCHXHPQZ.js";import"./chunk-OPCXNIGD.js";import"./chunk-ZHH3PWEW.js";import"./chunk-LKFYUCN7.js";import"./chunk-Y3VPZJTG.js";import"./chunk-P55RJGZU.js";import"./chunk-XYU2DSWR.js";import"./chunk-WS6UFNKF.js";export{b as bootWrapper,a as wrapperBooted};
2
+ import{a,b}from"./chunk-GVEBDMN6.js";import"./chunk-EHCBEY52.js";import"./chunk-HEWVNFUK.js";import"./chunk-JOKNFUW3.js";import"./chunk-DIRW7I4S.js";import"./chunk-K3NRXUJW.js";import"./chunk-S24UCZDR.js";import"./chunk-SQ4M4QQA.js";import"./chunk-YZJB6DZI.js";import"./chunk-YRPUM6JG.js";import"./chunk-3NTV3JFP.js";import"./chunk-5WE5G2CD.js";import"./chunk-ZWUFPR6V.js";import"./chunk-IWY6MRSV.js";import"./chunk-ZHH3PWEW.js";import"./chunk-Y3VPZJTG.js";import"./chunk-DYQHWN7X.js";import"./chunk-JTBQO6IT.js";import"./chunk-WS6UFNKF.js";export{b as bootWrapper,a as wrapperBooted};
@@ -0,0 +1,4 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import{k as b,l as g}from"./chunk-ZWUFPR6V.js";import{c as y,i as N,p as v}from"./chunk-IWY6MRSV.js";import{n as O,p as R}from"./chunk-DYQHWN7X.js";import{c as x,f as I,g as F}from"./chunk-JTBQO6IT.js";import{join as T}from"node:path";import*as s from"node:fs";var l=null;function U(n){l?.uninstall(),l=n===null?null:{hook:n,uninstall:x("notification",n)}}function W(n){l?.hook===n&&(l.uninstall(),l=null)}function L(n,e){F(n,e)}var V={onNotify:(n,e)=>L(n,e)},S={inbound:["message_received","file_received"],intro:["local_contact_request","pending_message"],get wake(){return[...S.inbound,...S.intro]}};function A(n){if(n===null||n==="")return null;let e=new Set;for(let r of n.split(",")){let t=r.trim();if(t==="")continue;let f=S[t];if(!f)throw new Error(t);for(let i of f)e.add(i)}return e}function M(n,e){return e===null?!0:typeof n.event=="string"&&e.has(n.event)}var p=new Map;function j(n){let e=p.get(n);if(!(!e||e.size===0))for(let r of[...e])try{r()}catch{}}function D(n,e){return new Promise(r=>{let t=p.get(n);t||(t=new Set,p.set(n,t));let f=!1,i=()=>{f||(f=!0,t.delete(a),t.size===0&&p.delete(n),clearTimeout(u),r())},a=i,u=setTimeout(i,e);t.add(a)})}var Y=new Set(["body","text","payload","data","bytes","content"]);function w(n){if(Buffer.isBuffer(n)||n instanceof Uint8Array)return;if(Array.isArray(n))return n.map(w).filter(r=>r!==void 0);if(!n||typeof n!="object")return n;let e={};for(let[r,t]of Object.entries(n)){if(Y.has(r.toLowerCase()))continue;let f=w(t);f!==void 0&&(e[r]=f)}return e}function q(n,e){let r=w(e);try{s.mkdirSync(n.dir,{recursive:!0,mode:448});let t=b(n.dir);s.appendFileSync(t,JSON.stringify(r)+`
3
+ `,{mode:384}),s.chmodSync(t,384)}catch(t){N(`[${n.name}] failed to append notifications.log:`,String(t))}j(n.name),I(n,r)}function Q(n,e){let r=n.Reduce(e);return r.IsNil()?"":Buffer.from(r.GetBinary()).toString("hex")}var C=Number(process.env.OURS_NOTIFY_LONGPOLL_MS)>0?Number(process.env.OURS_NOTIFY_LONGPOLL_MS):25e3,J=250;function H(n){try{return s.statSync(n).size}catch{return 0}}function z(n,e,r){if(r<=e)return{events:[],cursor:e};let t=Buffer.alloc(r-e),f=0;try{let c=s.openSync(n,"r");try{f=s.readSync(c,t,0,t.length,e)}finally{s.closeSync(c)}}catch{return{events:[],cursor:e}}let i=t.subarray(0,f),a=i.lastIndexOf(10);if(a===-1)return{events:[],cursor:e};let u=[];for(let c of i.subarray(0,a+1).toString("utf8").split(`
4
+ `))if(c.trim())try{u.push(JSON.parse(c))}catch{}return{events:u,cursor:e+a+1}}async function X(n,e,r,t,f=null){let i=b(T(y,r)),a=(d,m)=>{e.writableEnded||(e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({cursor:d,events:m})))},u;try{u=A(f)}catch(d){e.writableEnded||(e.writeHead(400,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:`unknown notification kind "${String(d.message)}" \u2014 known kinds: ${Object.keys(S).sort().join(", ")}`})));return}if(t===null||t==="tip"){a(H(i),[]);return}let c=parseInt(t,10);if(!Number.isFinite(c)||c<0){e.writableEnded||(e.writeHead(400,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"invalid since cursor"})));return}let o=!1;n.on("close",()=>{o=!0});let _=Date.now()+C;for(;!o;){let d=H(i);if(c>d&&(c=0),d>c){let{events:m,cursor:k}=z(i,c,d);c=k;let h=u===null?m:m.filter(E=>M(E,u));if(h.length>0){a(k,h);return}}if(Date.now()>=_)break;await D(r,Math.min(J,_-Date.now()))}o||a(c,[])}function Z(n){try{let e=O(n),r=R(n).map(i=>({file_id:String(i.file_id),sender_id:i.from.id,from:i.from.name,filename:i.filename,mime:i.mime,bytes:String(i.byte_length),date:i.date,wire_id:i.wire_id})),t={count:e.length,recent:e.slice(-10).map(i=>({from:i.from.name,msg_id:i.msg_id,date:i.date})),files:r.length,unread_files:r.slice(-10)};s.mkdirSync(n.dir,{recursive:!0,mode:448});let f=`${g(n.dir)}.tmp`;s.writeFileSync(f,JSON.stringify(t),{mode:384}),s.chmodSync(f,384),s.renameSync(f,g(n.dir))}catch(e){N(`[${n.name}] failed to refresh unread snapshot:`,String(e))}}function nn(){let n=[],e=[];try{e=s.readdirSync(y,{withFileTypes:!0})}catch{return{identities:n}}for(let r of e){if(!r.isDirectory()||v(r.name)!==null)continue;let t;try{t=JSON.parse(s.readFileSync(g(T(y,r.name)),"utf8"))}catch{continue}let f=Number.isSafeInteger(t.count)&&Number(t.count)>=0?Number(t.count):0,i=Number.isSafeInteger(t.files)&&Number(t.files)>=0?Number(t.files):0;if(f===0&&i===0)continue;let a=Array.isArray(t.recent)?t.recent.slice(-10).flatMap(c=>{if(!c||typeof c!="object")return[];let o=c;return typeof o.from!="string"||!["string","number"].includes(typeof o.msg_id)||typeof o.date!="string"?[]:[{from:o.from,msg_id:o.msg_id,date:o.date}]}):[],u=Array.isArray(t.unread_files)?t.unread_files.slice(-10).flatMap(c=>{if(!c||typeof c!="object")return[];let o=c;return typeof o.from!="string"||typeof o.filename!="string"||typeof o.mime!="string"||typeof o.wire_id!="string"?[]:[{from:o.from,filename:o.filename,mime:o.mime,wire_id:o.wire_id,...typeof o.sender_id=="string"?{sender_id:o.sender_id}:{},...["string","number"].includes(typeof o.file_id)?{file_id:o.file_id}:{},...["string","number"].includes(typeof o.bytes)?{bytes:o.bytes}:{},...typeof o.date=="string"?{date:o.date}:{}}]}):[];n.push({name:r.name,count:f,recent:a,files:i,unread_files:u})}return n.sort((r,t)=>String(r.name).localeCompare(String(t.name))),{identities:n}}export{U as a,W as b,L as c,V as d,S as e,A as f,M as g,j as h,D as i,q as j,Q as k,H as l,z as m,X as n,Z as o,nn as p};
@@ -0,0 +1,2 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import{d as a,e as l,g as c}from"./chunk-YZJB6DZI.js";import{c as o}from"./chunk-ZWUFPR6V.js";import{f as r,i as n}from"./chunk-IWY6MRSV.js";var e=null,i=!1;function s(){e||(e=setInterval(()=>{i||(i=!0,(async()=>{try{for(let t of o.values())await a(t),await l(t),await c(t)}finally{i=!1}})())},r),e.unref?.(),n(`protocol maintenance timer armed (every ${r}ms)`))}function u(){e&&(clearInterval(e),e=null)}export{s as a,u as b};
@@ -0,0 +1,2 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import{b as u,e as p}from"./chunk-SQ4M4QQA.js";import{B as m,f as l,r as f,v as c,z as w}from"./chunk-YZJB6DZI.js";import{c as s,d}from"./chunk-ZWUFPR6V.js";function x(e,t){if(!u||!s.has(u))return null;let n=s.get(t)??[...s.values()].find(r=>r.cid===t);if(!n||n.name===e.name)return null;let i=r=>r.name===u||p(r).roleId!=="";return i(e)&&i(n)?n:null}async function S(e,t,n){let i=m(t),r=await f(async a=>(await c(e,"::actor::connect_sibling",{name:t.name,target_ad:e.pw.packet.NewBinaryFromBuffer(i).Attach(a),text:n},a)).Reduce("wire_id").Visualize());return l(e),{text:`"${t.name}" was not a contact yet \u2014 connected as an intra-root sibling (delegation-cert auto-accept) and delivered the message.`,wireId:r}}async function N(e,t,n){if(!d)throw new Error(`"${t}" is not a contact, and the local contact book is unavailable.`);let i=w(),r=i[t]??Object.values(i).find(o=>o.container_id===t);if(!r)throw new Error(`"${t}" is not a contact and has no local contact-book entry. Use generate_invite/add_contact for remote peers, or list_local_contact_book to see local ones.`);if(r.container_id===e.cid)throw new Error("that contact-book entry is this identity itself.");let a=Buffer.from(r.address_document,"base64url"),g=Buffer.from(r.registrar_sig,"base64url"),y=m(e),k=await f(async o=>{let b=await c(d,"::actor::mint_introduction",{joiner_ad:d.pw.packet.NewBinaryFromBuffer(y).Attach(o),target_ad:d.pw.packet.NewBinaryFromBuffer(a).Attach(o)},o),h=Buffer.from(b.Reduce("intro").GetBinary());return(await c(e,"::actor::connect_local",{name:r.name,target_ad:e.pw.packet.NewBinaryFromBuffer(a).Attach(o),intro:e.pw.packet.NewBinaryFromBuffer(h).Attach(o),entry_sig:e.pw.packet.NewBinaryFromBuffer(g).Attach(o),text:n},o)).Reduce("wire_id").Visualize()});return l(e),{text:`"${r.name}" was not a contact yet \u2014 connected via the local contact book and sent the message with the introduction. If "${r.name}" requires approval for local introductions, delivery completes once they approve.`,wireId:k}}var q=e=>{let t=r=>!e.Reduce(r).IsNil(),n=e.Reduce("wire_id").Visualize(),i=t("sent_to")?e.Reduce("sent_to").Visualize():"";if(t("downgrade_refused"))return{kind:"refused",wireId:n,cid:i};if(t("migrating"))return{kind:"migrating",wireId:n,cid:i,queued:t("queued")?Number(e.Reduce("queued").Visualize()):0};if(t("route")){let r=t("retained")&&!e.Reduce("retained").GetBoolean();return{kind:"e2e",wireId:n,cid:i,notRetained:r}}return t("deferred")?{kind:"deferred",wireId:n,queued:t("queued")?Number(e.Reduce("queued").Visualize()):0}:{kind:"sent",wireId:n}};export{x as a,S as b,N as c,q as d};
@@ -1,2 +1,2 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
- import{c as a}from"./chunk-OCHXHPQZ.js";import{c as d,i as u}from"./chunk-OPCXNIGD.js";import{join as h}from"node:path";import*as r from"node:fs";var i=new Map,g=new Set,c=new Map,k=new Set;function E(e){if(!Number.isInteger(e)||e<=0)return!1;try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}function m(e){for(let t of i.values())if(t.token===e)return t}var f=()=>h(d,"bindings.json");function l(){try{r.mkdirSync(d,{recursive:!0});let e=`${f()}.tmp`;r.writeFileSync(e,JSON.stringify({pid:process.pid,bound:[...i.keys()],holders:[...i.values()].map(t=>({identity:t.identity,pid:t.pid}))})),r.renameSync(e,f())}catch(e){u("failed to persist bindings snapshot:",String(e))}}function _(e){let t=c.get(e)?.token;if(!t)return{code:"NOT_BOUND",error:"No identity bound to this session. Call choose_identity (or create_identity) first."};if(g.has(t))return{code:"BINDING_REASSIGNED",error:"Your identity binding was reassigned to another session. Call choose_identity again to continue."};let n=m(t);if(!n)return{code:"NOT_BOUND",error:"No identity bound to this session. Call choose_identity (or create_identity) first."};let o=a.get(n.identity);if(!o)return i.delete(n.identity),l(),{code:"BOUND_IDENTITY_GONE",error:`The bound identity "${n.identity}" no longer exists. Choose another with choose_identity.`};if(o.temp?.closing)return{code:"TEMP_CLOSING",error:`The temporary identity "${o.name}" is closing and no longer accepts work. Its contacts are being notified and its local state deleted.`};n.sid=e;let s=c.get(e)?.pid;return s&&(n.pid=s),{id:o}}function x(e,t){let n=c.get(e),o=n?.token;if(!o)return;for(let[p,y]of[...i])y.token===o&&p!==t&&i.delete(p);let s=i.get(t)?.epoch??0;i.set(t,{identity:t,token:o,pid:n?.pid??0,sid:e,epoch:s+1,boundAt:Date.now()}),g.delete(o),l()}export{i as a,g as b,c,k as d,E as e,m as f,l as g,_ as h,x as i};
2
+ import{c as a}from"./chunk-ZWUFPR6V.js";import{c as d,i as u}from"./chunk-IWY6MRSV.js";import{join as h}from"node:path";import*as r from"node:fs";var i=new Map,g=new Set,c=new Map,k=new Set;function E(e){if(!Number.isInteger(e)||e<=0)return!1;try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}function m(e){for(let t of i.values())if(t.token===e)return t}var f=()=>h(d,"bindings.json");function l(){try{r.mkdirSync(d,{recursive:!0});let e=`${f()}.tmp`;r.writeFileSync(e,JSON.stringify({pid:process.pid,bound:[...i.keys()],holders:[...i.values()].map(t=>({identity:t.identity,pid:t.pid}))})),r.renameSync(e,f())}catch(e){u("failed to persist bindings snapshot:",String(e))}}function _(e){let t=c.get(e)?.token;if(!t)return{code:"NOT_BOUND",error:"No identity bound to this session. Call choose_identity (or create_identity) first."};if(g.has(t))return{code:"BINDING_REASSIGNED",error:"Your identity binding was reassigned to another session. Call choose_identity again to continue."};let n=m(t);if(!n)return{code:"NOT_BOUND",error:"No identity bound to this session. Call choose_identity (or create_identity) first."};let o=a.get(n.identity);if(!o)return i.delete(n.identity),l(),{code:"BOUND_IDENTITY_GONE",error:`The bound identity "${n.identity}" no longer exists. Choose another with choose_identity.`};if(o.temp?.closing)return{code:"TEMP_CLOSING",error:`The temporary identity "${o.name}" is closing and no longer accepts work. Its contacts are being notified and its local state deleted.`};n.sid=e;let s=c.get(e)?.pid;return s&&(n.pid=s),{id:o}}function x(e,t){let n=c.get(e),o=n?.token;if(!o)return;for(let[p,y]of[...i])y.token===o&&p!==t&&i.delete(p);let s=i.get(t)?.epoch??0;i.set(t,{identity:t,token:o,pid:n?.pid??0,sid:e,epoch:s+1,boundAt:Date.now()}),g.delete(o),l()}export{i as a,g as b,c,k as d,E as e,m as f,l as g,_ as h,x as i};
@@ -0,0 +1,2 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import{g as D}from"./chunk-YBNUNQNM.js";import{b as L,g as V}from"./chunk-VXVW4KJU.js";import{a as T,b as C,c as q,d as F}from"./chunk-54BIUFRS.js";import{a as R}from"./chunk-P55RJGZU.js";import{a as w}from"./chunk-Z5IFINRU.js";import{A,B as U,C as E,D as N,E as O,F as P,M as l,a as I}from"./chunk-65KGEJBX.js";import{q as M,r as h,v as S}from"./chunk-YZJB6DZI.js";import{j as k,o as B}from"./chunk-3NTV3JFP.js";import{i as m}from"./chunk-IWY6MRSV.js";import{e as y,n as $,o as v}from"./chunk-DYQHWN7X.js";import{readFile as K}from"node:fs/promises";import{basename as G}from"node:path";function j(a,n){if(a)return n!==void 0?{wire_id:a,sentence:n}:{wire_id:a}}async function oe(a,n){let i=w(a),{contact:d,text:s}=n,o=j(n.reply_to_wire_id,n.reply_to_sentence);try{let e=await h(async r=>F(await S(i,"::a2a_messaging::send_message",{contact:d,text:s,...o?{reply_to:o}:{}},r)));switch(e.kind){case"refused":m(`[e2e-route] refused cid=${e.cid} wire_id=${e.wireId} (downgrade_refused)`);break;case"migrating":m(`[migration] queued cid=${e.cid} wire_id=${e.wireId} (migrating, ${e.queued} queued)`);break;case"e2e":m(`[e2e-route] cid=${e.cid} wire_id=${e.wireId} verdict=e2e (core delivered over migrated session)${e.notRetained?" NOT RETAINED (oversized)":""}`),e.notRetained&&k(i,{event:"send_not_retained",wire_id:e.wireId,kind:"message"});break;default:break}return e.kind==="sent"||e.kind==="e2e"?{...e,sent:!0,wire_id:e.wireId,history_stored:!y(i,e.wireId)}:e}catch(e){if(!/Unknown contact/.test(String(e)))throw l("send_message",String(e));try{let r=T(i,d),g=r?await C(i,r,s):await q(i,d,s);return{kind:"introduced",text:g.text,wireId:g.wireId,wire_id:g.wireId,sent:!0,history_stored:!y(i,g.wireId)}}catch(r){throw l("send_message",String(r),"FALLBACK_FAILED")}}}async function ae(a,n){let i=w(a),{contact:d,path:s,data_base64:o,upload_id:e,filename:r,mime:g}=n;if((s?1:0)+(o?1:0)+(e?1:0)!=1)throw e?N():A();let f,c,x=null;try{if(s)f=await K(s),c=r??G(s);else if(e){let t=D(i,e);if(!t)throw O(e);x=t.meta,f=t.buf,c=r??t.meta.filename}else{if(!r)throw U();f=Buffer.from(o,"base64"),c=r}}catch(t){throw t instanceof I?t:E(String(t))}let p=g??(s?R(s):x?.mime||""),b=j(n.reply_to_wire_id,n.reply_to_sentence),z=L(),u;try{u=M(t=>V({packet:{NewBinaryFromBuffer:_=>i.pw.packet.NewBinaryFromBuffer(_)},lifetime:t,filename:c,mime:p,payload:f,replyTo:b,cap:z}))}catch(t){throw t instanceof I?t:l("send_file",String(t))}if(!u.ok)throw P({filename:c,bytes:u.bytes,limit:u.cap,envelopeBytes:u.envelopeBytes,maxPayloadBytes:u.maxPayloadBytes});try{let t=await h(async _=>{let H=i.pw.packet.NewBinaryFromBuffer(f).Attach(_);return F(await S(i,"::a2a_messaging::send_file",{contact:d,filename:c,mime:p,data:H,...b?{reply_to:b}:{}},_))});switch(t.kind){case"refused":m(`[e2e-route] refused cid=${t.cid} wire_id=${t.wireId} (downgrade_refused, file)`);break;case"migrating":m(`[migration] file-defer cid=${t.cid} wire_id=${t.wireId} (migrating, not queued)`);break;case"e2e":m(`[e2e-route] cid=${t.cid} wire_id=${t.wireId} verdict=e2e file (core delivered over migrated session)${t.notRetained?" NOT RETAINED (oversized)":""}`),t.notRetained&&k(i,{event:"send_not_retained",wire_id:t.wireId,kind:"file"});break;default:break}return t.kind==="sent"||t.kind==="e2e"?{...t,filename:c,bytes:f.length,mime:p,sent:!0,wire_id:t.wireId,history_stored:!y(i,t.wireId)}:{...t,filename:c,bytes:f.length,mime:p}}catch(t){throw l("send_file",String(t))}}async function de(a){let n=w(a);try{return $(n)}catch(i){throw l("list_incoming_messages",String(i))}}async function ce(a,n={}){let i=w(a);try{let d=v(i,n);B(i);let s=new Map;for(let o of d.messages){let e=s.get(o.from.id);e||(e=[],s.set(o.from.id,e)),e.push(o.wire_id)}for(let[o,e]of s)try{await h(async r=>{await S(i,"::actor::send_read_receipts",{sender_id:o,wire_ids:e},r)})}catch(r){m(`[${i.name}] read-receipt attempt failed sender_id=${o} count=${e.length}:`,String(r))}return d}catch(d){throw l("get_messages",String(d))}}export{oe as a,ae as b,de as c,ce as d};
@@ -0,0 +1,165 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import{createHash as O,randomUUID as H}from"node:crypto";import*as o from"node:fs";import{dirname as y,join as u,resolve as S,sep as x}from"node:path";import A from"better-sqlite3";var l=200,C=50,b=2*1024*1024,D=8*1024*1024,M="history.sqlite3",N=1,m=new Map,f=new Map,p=new Map,U=t=>u(t.dir,M),Y=t=>u(t.dir,"blobs","sha256");function L(){return{write_failures:0,message_write_failures:0,file_write_failures:0,receipt_update_failures:0,last_failure_at_ms:null}}function $(t){return{...f.get(t.dir)??L()}}function K(t,e,r,n){let i=f.get(t.dir)??L();if(i.write_failures+=1,i.last_failure_at_ms=Date.now(),e==="message"?i.message_write_failures+=1:e==="file"?i.file_write_failures+=1:i.receipt_update_failures+=1,f.set(t.dir,i),n==="out"&&r){let s=p.get(t.dir);s||(s=new Set,p.set(t.dir,s)),s.add(r)}}function Q(t,e){let r=p.get(t.dir);return r?.delete(e)?(r.size===0&&p.delete(t.dir),!0):!1}function F(t){t.exec(`
3
+ CREATE TABLE IF NOT EXISTS history_meta (
4
+ key TEXT PRIMARY KEY,
5
+ value TEXT NOT NULL
6
+ );
7
+ CREATE TABLE IF NOT EXISTS wire_items (
8
+ wire_id TEXT PRIMARY KEY,
9
+ item_kind TEXT NOT NULL CHECK (item_kind IN ('message','file'))
10
+ );
11
+ CREATE TABLE IF NOT EXISTS messages (
12
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,
13
+ wire_id TEXT NOT NULL UNIQUE,
14
+ peer_cid TEXT NOT NULL,
15
+ peer_name_snapshot TEXT NOT NULL,
16
+ direction TEXT NOT NULL CHECK (direction IN ('in','out')),
17
+ body TEXT NOT NULL,
18
+ occurred_at_ms INTEGER NOT NULL,
19
+ reply_to_wire_id TEXT,
20
+ reply_to_sentence INTEGER,
21
+ encryption TEXT NOT NULL CHECK (encryption IN ('legacy','e2e')),
22
+ inbox_state TEXT NOT NULL CHECK (inbox_state IN ('pending_introduction','unread','read')),
23
+ delivery_state TEXT,
24
+ human_read_at_ms INTEGER,
25
+ inserted_at_ms INTEGER NOT NULL
26
+ );
27
+ CREATE INDEX IF NOT EXISTS messages_unread_seq ON messages(inbox_state, seq ASC);
28
+ CREATE INDEX IF NOT EXISTS messages_peer_seq ON messages(peer_cid, seq DESC);
29
+ CREATE TRIGGER IF NOT EXISTS messages_release_wire AFTER DELETE ON messages BEGIN
30
+ DELETE FROM wire_items WHERE wire_id = OLD.wire_id AND item_kind = 'message';
31
+ END;
32
+ CREATE TABLE IF NOT EXISTS files (
33
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,
34
+ wire_id TEXT NOT NULL UNIQUE,
35
+ peer_cid TEXT NOT NULL,
36
+ peer_name_snapshot TEXT NOT NULL,
37
+ direction TEXT NOT NULL CHECK (direction IN ('in','out')),
38
+ filename TEXT NOT NULL,
39
+ mime TEXT NOT NULL,
40
+ byte_length INTEGER NOT NULL,
41
+ sha256 TEXT NOT NULL,
42
+ blob_relpath TEXT NOT NULL,
43
+ occurred_at_ms INTEGER NOT NULL,
44
+ reply_to_wire_id TEXT,
45
+ reply_to_sentence INTEGER,
46
+ encryption TEXT NOT NULL CHECK (encryption IN ('legacy','e2e')),
47
+ inbox_state TEXT NOT NULL CHECK (inbox_state IN ('pending_introduction','unread','read')),
48
+ delivery_state TEXT,
49
+ human_read_at_ms INTEGER,
50
+ inserted_at_ms INTEGER NOT NULL
51
+ );
52
+ CREATE INDEX IF NOT EXISTS files_unread_seq ON files(inbox_state, seq ASC);
53
+ CREATE INDEX IF NOT EXISTS files_peer_seq ON files(peer_cid, seq DESC);
54
+ CREATE TRIGGER IF NOT EXISTS files_release_wire AFTER DELETE ON files BEGIN
55
+ DELETE FROM wire_items WHERE wire_id = OLD.wire_id AND item_kind = 'file';
56
+ END;
57
+ CREATE TABLE IF NOT EXISTS monitoring_items (
58
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,
59
+ item_id TEXT NOT NULL UNIQUE,
60
+ source_cid TEXT NOT NULL,
61
+ source_name_snapshot TEXT NOT NULL,
62
+ direction TEXT NOT NULL CHECK (direction IN ('in','out')),
63
+ peer_cid TEXT NOT NULL,
64
+ peer_name_snapshot TEXT NOT NULL,
65
+ body TEXT NOT NULL,
66
+ occurred_at_ms INTEGER NOT NULL,
67
+ queue_state TEXT NOT NULL CHECK (queue_state IN ('pending','processed')),
68
+ inserted_at_ms INTEGER NOT NULL
69
+ );
70
+ CREATE INDEX IF NOT EXISTS monitoring_pending_seq ON monitoring_items(queue_state, seq ASC);
71
+ CREATE TABLE IF NOT EXISTS control_requests (
72
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,
73
+ item_id TEXT NOT NULL UNIQUE,
74
+ sender_cid TEXT NOT NULL,
75
+ sender_name_snapshot TEXT NOT NULL,
76
+ payload TEXT NOT NULL,
77
+ occurred_at_ms INTEGER NOT NULL,
78
+ queue_state TEXT NOT NULL CHECK (queue_state IN ('pending','processed')),
79
+ inserted_at_ms INTEGER NOT NULL
80
+ );
81
+ CREATE INDEX IF NOT EXISTS control_pending_seq ON control_requests(queue_state, seq ASC);
82
+ `);let e=t.prepare("SELECT value FROM history_meta WHERE key = ?").pluck().get("schema_version");if(e!==void 0&&Number(e)!==N)throw new Error(`unsupported history database schema ${String(e)} (expected ${N})`);t.prepare("INSERT OR IGNORE INTO history_meta(key, value) VALUES (?, ?)").run("schema_version",String(N))}function d(t){let e=m.get(t.dir);if(e)return e;o.mkdirSync(t.dir,{recursive:!0,mode:448}),o.chmodSync(t.dir,448);let r=U(t),n=new A(r);try{o.chmodSync(r,384),n.pragma("journal_mode = WAL"),n.pragma("synchronous = NORMAL"),n.pragma("foreign_keys = ON"),n.pragma("busy_timeout = 5000"),F(n);for(let i of["","-wal","-shm"]){let s=`${r}${i}`;o.existsSync(s)&&o.chmodSync(s,384)}}catch(i){throw n.close(),i}return m.set(t.dir,n),n}function V(t){let e=m.get(t.dir);e&&(m.delete(t.dir),e.close())}function q(t){if(!t.wireId||t.wireId.length>256)throw new Error("invalid wire_id");if(!t.peerCid||t.peerCid.length>256)throw new Error("invalid peer cid");if(!t.peerName||t.peerName.length>512)throw new Error("invalid peer name");if(!Number.isSafeInteger(t.occurredAtMs)||t.occurredAtMs<0)throw new Error("invalid timestamp");if(t.replyToWireId!==void 0&&(!t.replyToWireId||t.replyToWireId.length>256))throw new Error("invalid reply wire_id");if(t.replyToSentence!==void 0&&(!Number.isSafeInteger(t.replyToSentence)||t.replyToSentence<1))throw new Error("invalid reply sentence")}function X(t){if(q(t),t.kind==="message"){if(Buffer.byteLength(t.body,"utf8")>b)throw new Error("message body exceeds host limit");return}if(!t.filename||t.filename.length>512||/[\0]/.test(t.filename))throw new Error("invalid filename");if(t.mime.length>512||/[\r\n\0]/.test(t.mime))throw new Error("invalid MIME type");if(t.bytes.byteLength>D)throw new Error("file exceeds host limit")}function I(t){return t.reply_to_wire_id?t.reply_to_sentence===null?{wire_id:t.reply_to_wire_id}:{wire_id:t.reply_to_wire_id,sentence:t.reply_to_sentence}:null}function h(t){return new Date(t).toISOString()}function R(t){let e={id:t.peer_cid,name:t.peer_name_snapshot};return{seq:t.seq,msg_id:t.seq,wire_id:t.wire_id,from:e,peer:e,direction:t.direction,text:t.body,body:t.body,occurred_at_ms:t.occurred_at_ms,date:h(t.occurred_at_ms),encryption:t.encryption,transport:t.encryption==="e2e"?"double_ratchet":"legacy_box",inbox_state:t.inbox_state,status:t.inbox_state,delivery_state:t.delivery_state,human_read_at_ms:t.human_read_at_ms,reply_to:I(t)}}function E(t,e){let r={id:e.peer_cid,name:e.peer_name_snapshot},n=e.mime||"application/octet-stream";return{seq:e.seq,file_id:e.seq,wire_id:e.wire_id,from:r,peer:r,direction:e.direction,filename:e.filename,mime:n,size:e.byte_length,byte_length:e.byte_length,sha256:e.sha256,occurred_at_ms:e.occurred_at_ms,date:h(e.occurred_at_ms),encryption:e.encryption,inbox_state:e.inbox_state,status:e.inbox_state,delivery_state:e.delivery_state,human_read_at_ms:e.human_read_at_ms,reply_to:I(e),blob_path:u(t.dir,e.blob_relpath),kind:n.startsWith("audio/")?"voice_message":"file"}}function k(t,e){let r=O("sha256").update(e).digest("hex"),n=u("blobs","sha256",r.slice(0,2),r),i=u(t.dir,n);if(o.mkdirSync(y(i),{recursive:!0,mode:448}),o.chmodSync(y(i),448),!o.existsSync(i)){let s=u(y(i),`.${r}.${process.pid}.${H()}.tmp`);try{o.writeFileSync(s,e,{flag:"wx",mode:384}),o.chmodSync(s,384);try{o.renameSync(s,i)}catch(a){if(!o.existsSync(i))throw a;o.rmSync(s,{force:!0})}}catch(a){try{o.rmSync(s,{force:!0})}catch{}throw a}}return o.chmodSync(i,384),{sha256:r,relpath:n}}function j(t,e){X(e);let r=d(t);if(e.direction==="out"&&e.inboxState!==void 0)throw new Error("outbound event cannot set inbox state");let n=e.direction==="in"?e.inboxState??"unread":"read",i=e.direction==="out"?"sent":null;if(e.kind==="message")return r.transaction(()=>r.prepare(`
83
+ INSERT INTO wire_items(wire_id, item_kind) VALUES (?, 'message')
84
+ ON CONFLICT(wire_id) DO NOTHING
85
+ `).run(e.wireId).changes!==1?!1:(r.prepare(`
86
+ INSERT INTO messages (
87
+ wire_id, peer_cid, peer_name_snapshot, direction, body, occurred_at_ms,
88
+ reply_to_wire_id, reply_to_sentence, encryption, inbox_state,
89
+ delivery_state, human_read_at_ms, inserted_at_ms
90
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
91
+ `).run(e.wireId,e.peerCid,e.peerName,e.direction,e.body,e.occurredAtMs,e.replyToWireId??null,e.replyToSentence??null,e.encryption,n,i,e.direction==="out"?e.occurredAtMs:null,Date.now()),!0))();if(r.prepare("SELECT 1 FROM wire_items WHERE wire_id = ?").get(e.wireId))return!1;let a=k(t,e.bytes);return r.transaction(()=>r.prepare(`
92
+ INSERT INTO wire_items(wire_id, item_kind) VALUES (?, 'file')
93
+ ON CONFLICT(wire_id) DO NOTHING
94
+ `).run(e.wireId).changes!==1?!1:(r.prepare(`
95
+ INSERT INTO files (
96
+ wire_id, peer_cid, peer_name_snapshot, direction, filename, mime,
97
+ byte_length, sha256, blob_relpath, occurred_at_ms, reply_to_wire_id,
98
+ reply_to_sentence, encryption, inbox_state, delivery_state,
99
+ human_read_at_ms, inserted_at_ms
100
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
101
+ `).run(e.wireId,e.peerCid,e.peerName,e.direction,e.filename,e.mime||"application/octet-stream",e.bytes.byteLength,a.sha256,a.relpath,e.occurredAtMs,e.replyToWireId??null,e.replyToSentence??null,e.encryption,n,i,e.direction==="out"?e.occurredAtMs:null,Date.now()),!0))()}function z(t,e){if(!e.itemId||!e.sourceCid||!e.sourceName||!e.peerCid||!e.peerName)throw new Error("invalid monitoring event metadata");if(!Number.isSafeInteger(e.occurredAtMs)||e.occurredAtMs<0)throw new Error("invalid monitoring timestamp");if(Buffer.byteLength(e.body,"utf8")>b)throw new Error("monitoring body exceeds host limit");return d(t).prepare(`
102
+ INSERT INTO monitoring_items (
103
+ item_id, source_cid, source_name_snapshot, direction, peer_cid,
104
+ peer_name_snapshot, body, occurred_at_ms, queue_state, inserted_at_ms
105
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?)
106
+ ON CONFLICT(item_id) DO NOTHING
107
+ `).run(e.itemId,e.sourceCid,e.sourceName,e.direction,e.peerCid,e.peerName,e.body,e.occurredAtMs,Date.now()).changes===1}function J(t,e){if(!e.itemId||!e.senderCid||!e.senderName)throw new Error("invalid control event metadata");if(!Number.isSafeInteger(e.occurredAtMs)||e.occurredAtMs<0)throw new Error("invalid control timestamp");if(Buffer.byteLength(e.payload,"utf8")>b)throw new Error("control payload exceeds host limit");return d(t).prepare(`
108
+ INSERT INTO control_requests (
109
+ item_id, sender_cid, sender_name_snapshot, payload,
110
+ occurred_at_ms, queue_state, inserted_at_ms
111
+ ) VALUES (?, ?, ?, ?, ?, 'pending', ?)
112
+ ON CONFLICT(item_id) DO NOTHING
113
+ `).run(e.itemId,e.senderCid,e.senderName,e.payload,e.occurredAtMs,Date.now()).changes===1}function Z(t,e){let r=d(t);return r.transaction(()=>{let n=r.prepare(`
114
+ UPDATE messages SET inbox_state = 'unread'
115
+ WHERE direction = 'in' AND peer_cid = ? AND inbox_state = 'pending_introduction'
116
+ `).run(e).changes,i=r.prepare(`
117
+ UPDATE files SET inbox_state = 'unread'
118
+ WHERE direction = 'in' AND peer_cid = ? AND inbox_state = 'pending_introduction'
119
+ `).run(e).changes;return n+i})()}function v(t,e){let r=d(t);return r.transaction(()=>{let n=r.prepare(`
120
+ DELETE FROM messages
121
+ WHERE direction = 'in' AND peer_cid = ? AND inbox_state = 'pending_introduction'
122
+ `).run(e).changes,i=r.prepare(`
123
+ DELETE FROM files
124
+ WHERE direction = 'in' AND peer_cid = ? AND inbox_state = 'pending_introduction'
125
+ `).run(e).changes;return n+i})()}function ee(t){let e=d(t);return{pending_introductions:Number(e.prepare(`
126
+ SELECT
127
+ (SELECT COUNT(*) FROM messages WHERE inbox_state = 'pending_introduction') +
128
+ (SELECT COUNT(*) FROM files WHERE inbox_state = 'pending_introduction')
129
+ `).pluck().get()),monitoring_copies:Number(e.prepare(`
130
+ SELECT COUNT(*) FROM monitoring_items WHERE queue_state = 'pending'
131
+ `).pluck().get()),control_requests:Number(e.prepare(`
132
+ SELECT COUNT(*) FROM control_requests WHERE queue_state = 'pending'
133
+ `).pluck().get())}}function T(t){let e=t??C;if(!Number.isSafeInteger(e)||e<1||e>l)throw new Error(`limit must be an integer from 1 to ${l}`);return e}function te(t){return d(t).prepare(`
134
+ SELECT seq, wire_id, peer_cid, peer_name_snapshot, occurred_at_ms,
135
+ reply_to_wire_id, reply_to_sentence, encryption
136
+ FROM messages
137
+ WHERE direction = 'in' AND inbox_state = 'unread'
138
+ ORDER BY seq ASC
139
+ `).all().map(r=>({seq:r.seq,msg_id:r.seq,wire_id:r.wire_id,from:{id:r.peer_cid,name:r.peer_name_snapshot},occurred_at_ms:r.occurred_at_ms,date:h(r.occurred_at_ms),encryption:r.encryption,inbox_state:"unread",status:"unread",reply_to:I(r)}))}function re(t,e={}){let r=d(t),n=T(e.limit);return r.transaction(()=>{let i=r.prepare(`
140
+ SELECT * FROM messages
141
+ WHERE direction = 'in' AND inbox_state = 'unread'
142
+ ORDER BY seq ASC LIMIT ?
143
+ `).all(n),s=r.prepare(`
144
+ UPDATE messages SET inbox_state = 'read'
145
+ WHERE seq = ? AND direction = 'in' AND inbox_state = 'unread'
146
+ `);for(let c of i){if(s.run(c.seq).changes!==1)throw new Error(`message row ${c.seq} changed during read batch`);c.inbox_state="read"}let a=Number(r.prepare(`
147
+ SELECT COUNT(*) FROM messages WHERE direction = 'in' AND inbox_state = 'unread'
148
+ `).pluck().get());return{messages:i.map(R),remaining:a}})()}function ie(t){return d(t).prepare(`
149
+ SELECT * FROM files WHERE direction = 'in' AND inbox_state = 'unread' ORDER BY seq ASC
150
+ `).all().map(r=>E(t,r))}function ne(t,e={}){let r=d(t),n=T(e.limit),i=e.wire_ids;return r.transaction(()=>{let s;if(i!==void 0){if(i.length<1||i.length>l)throw new Error(`wire_ids must contain 1-${l} items`);if(new Set(i).size!==i.length)throw new Error("wire_ids must not contain duplicates");let _=r.prepare(`
151
+ SELECT * FROM files WHERE wire_id = ? AND direction = 'in' AND inbox_state = 'unread'
152
+ `);if(s=i.map(g=>_.get(g)).filter(g=>!!g),s.length!==i.length)throw new Error("selected file wire_id is unknown, stale, or no longer unread")}else s=r.prepare(`
153
+ SELECT * FROM files WHERE direction = 'in' AND inbox_state = 'unread'
154
+ ORDER BY seq ASC LIMIT ?
155
+ `).all(n);let a=r.prepare(`
156
+ UPDATE files SET inbox_state = 'read'
157
+ WHERE seq = ? AND direction = 'in' AND inbox_state = 'unread'
158
+ `);for(let _ of s){if(a.run(_.seq).changes!==1)throw new Error(`file row ${_.seq} changed during read batch`);_.inbox_state="read"}let c=Number(r.prepare(`
159
+ SELECT COUNT(*) FROM files WHERE direction = 'in' AND inbox_state = 'unread'
160
+ `).pluck().get());return{files:s.map(_=>E(t,_)),remaining:c}})()}function w(t){let e=[],r=[];return t.peer_cid!==void 0&&(e.push("peer_cid = ?"),r.push(t.peer_cid)),t.direction!==void 0&&(e.push("direction = ?"),r.push(t.direction)),t.before_seq!==void 0&&(e.push("seq < ?"),r.push(t.before_seq)),{sql:e.length?`WHERE ${e.join(" AND ")}`:"",args:r}}function se(t,e={}){let r=d(t),n=T(e.limit),i=w(e),s=r.prepare(`SELECT * FROM messages ${i.sql} ORDER BY seq DESC LIMIT ?`).all(...i.args,n+1),a=s.length>n;return a&&s.pop(),{items:s.map(R),next_cursor:a?s.at(-1).seq:null}}function oe(t,e){let r=d(t).prepare("SELECT * FROM messages WHERE wire_id = ?").get(e);return r?R(r):null}function ae(t,e={}){let r=d(t),n=T(e.limit),i=w(e),s=r.prepare(`SELECT * FROM files ${i.sql} ORDER BY seq DESC LIMIT ?`).all(...i.args,n+1),a=s.length>n;return a&&s.pop(),{items:s.map(c=>E(t,c)),next_cursor:a?s.at(-1).seq:null}}function P(t,e){let r=d(t).prepare("SELECT * FROM files WHERE wire_id = ?").get(e);return r?E(t,r):null}function de(t,e){let r=P(t,e);if(!r||!o.existsSync(r.blob_path))return null;let n=S(t.dir),i=S(r.blob_path);return i.startsWith(`${n}${x}`)?i:null}function ce(t,e,r,n){let i=d(t),s=r==="read"?2:1;i.transaction(()=>{for(let c of n)for(let _ of["messages","files"])i.prepare(`
161
+ UPDATE ${_}
162
+ SET delivery_state = ?, human_read_at_ms = CASE WHEN ? = 'read' THEN COALESCE(human_read_at_ms, ?) ELSE human_read_at_ms END
163
+ WHERE wire_id = ? AND peer_cid = ? AND direction = 'out'
164
+ AND (CASE delivery_state WHEN 'read' THEN 2 WHEN 'delivered' THEN 1 WHEN 'sent' THEN 0 ELSE -1 END) < ?
165
+ `).run(r,r,Date.now(),c,e,s)})()}function _e(t){let e=d(t);return{messages:Number(e.prepare("SELECT COUNT(*) FROM messages WHERE direction='in' AND inbox_state='unread'").pluck().get()),files:Number(e.prepare("SELECT COUNT(*) FROM files WHERE direction='in' AND inbox_state='unread'").pluck().get())}}export{U as a,Y as b,$ as c,K as d,Q as e,d as f,V as g,j as h,z as i,J as j,Z as k,v as l,ee as m,te as n,re as o,ie as p,ne as q,se as r,oe as s,ae as t,P as u,de as v,ce as w,_e as x};
@@ -1,2 +1,2 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
- import{a as O}from"./chunk-OA7XXAFG.js";import{b as N,e as T}from"./chunk-WS6UFNKF.js";import{randomBytes as I}from"node:crypto";import{readFileSync as w}from"node:fs";import{homedir as x}from"node:os";import{join as v,resolve as p}from"node:path";var a=class extends Error{constructor(i,n){super(n);this.code=i;this.name="DaemonSelectionError"}},S=class extends a{constructor(i,n,d={}){super("DAEMON_UNAVAILABLE",`no ours daemon is running at ${i} for state directory ${JSON.stringify(n)}. Install the operator CLI with \`npm install --global @ours.network/cli\`, then start the shared daemon with \`ours daemon start\` or install/start its per-user service through \`ours daemon install-service\`. SDK applications attach to the shared daemon and do not start an embedded daemon.`);this.endpoint=i;this.stateDir=n;this.name="DaemonUnavailableError",d.cause!==void 0&&(this.cause=d.cause)}},b=N.port,C=T,R=".ours",k=["explicit","environment","config-file"];function _(e={}){let t=e.env??process.env,i=e.readTextFile??(h=>w(h,"utf8")),n=e.homeDir??x(),d=f(t,"OURS_INSTANCE");if(d!==void 0)throw new a("INCOHERENT_SELECTION",`OURS_INSTANCE=${JSON.stringify(d)} is set, but named daemon instances are not implemented. Select the daemon with an explicit endpoint/port option or with OURS_PORT, and unset OURS_INSTANCE.`);if(e.stateDir!==void 0&&e.expectStateDir!==void 0){let h=p(e.stateDir),D=p(e.expectStateDir);if(h!==D)throw new a("INCOHERENT_SELECTION",`stateDir ${JSON.stringify(h)} and expectStateDir ${JSON.stringify(D)} name different directories. The state directory decides which token is read; the expected one decides which daemon that token may be sent to. Reconcile them, or pass only one.`)}let r=V(e.configPath,f(t,"OURS_CONFIG")),s=r?L(r.value,i):{},o=E(e.port,F(f(t,"OURS_PORT")),s.port,b),c=E(e.stateDir??e.expectStateDir,f(t,"OURS_STATE_DIR"),s.stateDir,v(n,R)),l={value:p(c.value),source:c.source},g=e.endpoint!==void 0?{value:P(e.endpoint),source:"explicit"}:{value:`http://127.0.0.1:${o.value}`,source:o.source},m=f(t,"OURS_API_TOKEN");A({endpointSelected:e.endpoint!==void 0||o.source!=="default",endpointSource:g.source,stateDirIntentional:k.includes(l.source),stateDirSource:l.source,hasExplicitToken:e.token!==void 0&&e.token!=="",hasEnvToken:m!==void 0,requireExplicitSelection:e.requireExplicitSelection===!0,portSource:o.source});let y=U(e.token,m,s,l,i);return{baseUrl:g,port:o,stateDir:l,expectStateDir:e.expectStateDir!==void 0?p(e.expectStateDir):l.value,...y?{token:y}:{},...r?{configPath:r}:{}}}function K(e){return{baseUrl:e.baseUrl.value,baseUrlSource:e.baseUrl.source,port:e.port.value,portSource:e.port.source,stateDir:e.stateDir.value,stateDirSource:e.stateDir.source,expectStateDir:e.expectStateDir,tokenSource:e.token?.source??"none",configPath:e.configPath?.value??null}}function A(e){if(e.requireExplicitSelection){if(e.endpointSource==="default"&&e.portSource==="default")throw u(`requireExplicitSelection is set, but no daemon was selected. Pass endpoint/port, set OURS_PORT, or point OURS_CONFIG at a config file. Refusing the built-in default 127.0.0.1:${b}.`);if(!e.stateDirIntentional)throw u("requireExplicitSelection is set, but the state directory is the built-in default. Every auth-affecting field must be chosen deliberately: pass stateDir or expectStateDir, set OURS_STATE_DIR, or name a config file. Refusing before reading any token or opening any socket.")}if(e.endpointSelected&&!e.stateDirIntentional)throw u(`the endpoint was selected (source: ${e.endpointSource}) but the state directory is the built-in default. A daemon's API token belongs to one state directory, so reading the default token and sending it to a separately chosen endpoint would disclose a credential to it. Select the state directory too: stateDir, expectStateDir, OURS_STATE_DIR, or one config file. An explicit token alone is not enough \u2014 without an expected state directory there is nothing to assert the endpoint against before the token is sent.`);if(e.hasEnvToken&&!e.stateDirIntentional)throw u("OURS_API_TOKEN is set, but the state directory is the built-in default. An environment token is process-wide and authenticates to every daemon it is offered to, so it requires an explicitly expected state directory: pass stateDir or expectStateDir, or set OURS_STATE_DIR.");if(e.hasExplicitToken&&!e.stateDirIntentional)throw u("an explicit token was given, but the state directory is the built-in default, so there would be nothing to assert the daemon against before the token is sent. Pass expectStateDir (or stateDir) naming the state directory that token belongs to.")}function u(e){return new a("INCOHERENT_SELECTION",e)}function U(e,t,i,n,d){if(e!==void 0&&e!=="")return{value:e,source:"explicit"};if(t!==void 0)return{value:t,source:"environment"};let r=i.apiToken?.trim();if(r)return{value:r,source:"config-file"};try{let s=d(v(n.value,C)).trim();if(s)return{value:s,source:"token-file"}}catch{}}function L(e,t){let i;try{i=t(e)}catch{throw new a("CONFIG_UNREADABLE",`the daemon config file ${JSON.stringify(e)} could not be read.`)}let n;try{n=JSON.parse(i)}catch{throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} is not valid JSON.`)}if(n===null||typeof n!="object"||Array.isArray(n))throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} is not a JSON object.`);let d=n,r={},s=d.port;if(s!==void 0){if(typeof s!="number"||!Number.isInteger(s)||s<1||s>65535)throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} declares an invalid port; expected an integer 1-65535.`);r.port=s}let o=d.stateDir;if(o!==void 0){if(typeof o!="string"||o.trim()==="")throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} declares an invalid stateDir; expected a non-empty string.`);r.stateDir=o}let c=d.apiToken;if(c!==void 0){if(typeof c!="string"||c.trim()==="")throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} declares an invalid apiToken; expected a non-empty string.`);r.apiToken=c}let l=d.apiVisibility;if(l!==void 0){if(l!=="owner"&&l!=="shared"&&l!=="open")throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} declares an unknown apiVisibility ${JSON.stringify(l)}; expected "owner", "shared" or "open".`);r.apiVisibility=l}return r}function f(e,t){let i=e[t];if(i===void 0)return;let n=i.trim();return n===""?void 0:n}function F(e){if(e===void 0)return;let t=Number.parseInt(e,10);if(!Number.isInteger(t)||t<1||t>65535)throw new a("INCOHERENT_SELECTION",`OURS_PORT=${JSON.stringify(e)} is not a TCP port between 1 and 65535.`);return t}function P(e){return e.endsWith("/")?e.slice(0,-1):e}function E(e,t,i,n){return e!==void 0?{value:e,source:"explicit"}:t!==void 0?{value:t,source:"environment"}:i!==void 0?{value:i,source:"config-file"}:{value:n,source:"default"}}function V(e,t){if(e!==void 0)return{value:e,source:"explicit"};if(t!==void 0)return{value:t,source:"environment"}}async function $(e,t={}){let i=t.fetch??globalThis.fetch,n=new AbortController,d=setTimeout(()=>n.abort(),t.timeoutMs??5e3),r;try{let o=await i(`${e.baseUrl.value}/state-dir`,{signal:n.signal});if(!o.ok)throw new a("INCOHERENT_SELECTION",`${e.baseUrl.value}/state-dir answered HTTP ${o.status}, so the daemon at that address could not be identified. Refusing to send a credential to it.`);r=await o.json()}catch(o){throw o instanceof a?o:new S(e.baseUrl.value,e.expectStateDir,{cause:o})}finally{clearTimeout(d)}let s=typeof r.stateDir=="string"?p(r.stateDir):null;if(s===null)throw new a("INCOHERENT_SELECTION",`${e.baseUrl.value}/state-dir did not report a state directory, so this is not an ours daemon or not one this client understands. Refusing to send a credential to it.`);if(s!==e.expectStateDir)throw new a("INCOHERENT_SELECTION",`the daemon at ${e.baseUrl.value} owns state directory ${JSON.stringify(s)}, but this selection expects ${JSON.stringify(e.expectStateDir)}. The token belongs to the expected directory, so it is NOT being sent. Point the endpoint and the state directory at the same daemon.`)}async function j(e={}){let{leaseToken:t,clientPid:i,fetch:n,...d}=e,r=_(d);return await $(r,{fetch:n}),new O({url:r.baseUrl.value,leaseToken:t??I(32).toString("hex"),clientPid:i,apiToken:r.token?.value,fetch:n})}export{a,S as b,b as c,C as d,_ as e,K as f,$ as g,j as h};
2
+ import{a as O}from"./chunk-PMSTI7RY.js";import{b as N,e as T}from"./chunk-WS6UFNKF.js";import{randomBytes as I}from"node:crypto";import{readFileSync as w}from"node:fs";import{homedir as x}from"node:os";import{join as v,resolve as p}from"node:path";var a=class extends Error{constructor(i,n){super(n);this.code=i;this.name="DaemonSelectionError"}},S=class extends a{constructor(i,n,d={}){super("DAEMON_UNAVAILABLE",`no ours daemon is running at ${i} for state directory ${JSON.stringify(n)}. Install the operator CLI with \`npm install --global @ours.network/cli\`, then start the shared daemon with \`ours daemon start\` or install/start its per-user service through \`ours daemon install-service\`. SDK applications attach to the shared daemon and do not start an embedded daemon.`);this.endpoint=i;this.stateDir=n;this.name="DaemonUnavailableError",d.cause!==void 0&&(this.cause=d.cause)}},b=N.port,C=T,R=".ours",k=["explicit","environment","config-file"];function _(e={}){let t=e.env??process.env,i=e.readTextFile??(h=>w(h,"utf8")),n=e.homeDir??x(),d=f(t,"OURS_INSTANCE");if(d!==void 0)throw new a("INCOHERENT_SELECTION",`OURS_INSTANCE=${JSON.stringify(d)} is set, but named daemon instances are not implemented. Select the daemon with an explicit endpoint/port option or with OURS_PORT, and unset OURS_INSTANCE.`);if(e.stateDir!==void 0&&e.expectStateDir!==void 0){let h=p(e.stateDir),D=p(e.expectStateDir);if(h!==D)throw new a("INCOHERENT_SELECTION",`stateDir ${JSON.stringify(h)} and expectStateDir ${JSON.stringify(D)} name different directories. The state directory decides which token is read; the expected one decides which daemon that token may be sent to. Reconcile them, or pass only one.`)}let r=V(e.configPath,f(t,"OURS_CONFIG")),s=r?L(r.value,i):{},o=E(e.port,F(f(t,"OURS_PORT")),s.port,b),c=E(e.stateDir??e.expectStateDir,f(t,"OURS_STATE_DIR"),s.stateDir,v(n,R)),l={value:p(c.value),source:c.source},g=e.endpoint!==void 0?{value:P(e.endpoint),source:"explicit"}:{value:`http://127.0.0.1:${o.value}`,source:o.source},m=f(t,"OURS_API_TOKEN");A({endpointSelected:e.endpoint!==void 0||o.source!=="default",endpointSource:g.source,stateDirIntentional:k.includes(l.source),stateDirSource:l.source,hasExplicitToken:e.token!==void 0&&e.token!=="",hasEnvToken:m!==void 0,requireExplicitSelection:e.requireExplicitSelection===!0,portSource:o.source});let y=U(e.token,m,s,l,i);return{baseUrl:g,port:o,stateDir:l,expectStateDir:e.expectStateDir!==void 0?p(e.expectStateDir):l.value,...y?{token:y}:{},...r?{configPath:r}:{}}}function K(e){return{baseUrl:e.baseUrl.value,baseUrlSource:e.baseUrl.source,port:e.port.value,portSource:e.port.source,stateDir:e.stateDir.value,stateDirSource:e.stateDir.source,expectStateDir:e.expectStateDir,tokenSource:e.token?.source??"none",configPath:e.configPath?.value??null}}function A(e){if(e.requireExplicitSelection){if(e.endpointSource==="default"&&e.portSource==="default")throw u(`requireExplicitSelection is set, but no daemon was selected. Pass endpoint/port, set OURS_PORT, or point OURS_CONFIG at a config file. Refusing the built-in default 127.0.0.1:${b}.`);if(!e.stateDirIntentional)throw u("requireExplicitSelection is set, but the state directory is the built-in default. Every auth-affecting field must be chosen deliberately: pass stateDir or expectStateDir, set OURS_STATE_DIR, or name a config file. Refusing before reading any token or opening any socket.")}if(e.endpointSelected&&!e.stateDirIntentional)throw u(`the endpoint was selected (source: ${e.endpointSource}) but the state directory is the built-in default. A daemon's API token belongs to one state directory, so reading the default token and sending it to a separately chosen endpoint would disclose a credential to it. Select the state directory too: stateDir, expectStateDir, OURS_STATE_DIR, or one config file. An explicit token alone is not enough \u2014 without an expected state directory there is nothing to assert the endpoint against before the token is sent.`);if(e.hasEnvToken&&!e.stateDirIntentional)throw u("OURS_API_TOKEN is set, but the state directory is the built-in default. An environment token is process-wide and authenticates to every daemon it is offered to, so it requires an explicitly expected state directory: pass stateDir or expectStateDir, or set OURS_STATE_DIR.");if(e.hasExplicitToken&&!e.stateDirIntentional)throw u("an explicit token was given, but the state directory is the built-in default, so there would be nothing to assert the daemon against before the token is sent. Pass expectStateDir (or stateDir) naming the state directory that token belongs to.")}function u(e){return new a("INCOHERENT_SELECTION",e)}function U(e,t,i,n,d){if(e!==void 0&&e!=="")return{value:e,source:"explicit"};if(t!==void 0)return{value:t,source:"environment"};let r=i.apiToken?.trim();if(r)return{value:r,source:"config-file"};try{let s=d(v(n.value,C)).trim();if(s)return{value:s,source:"token-file"}}catch{}}function L(e,t){let i;try{i=t(e)}catch{throw new a("CONFIG_UNREADABLE",`the daemon config file ${JSON.stringify(e)} could not be read.`)}let n;try{n=JSON.parse(i)}catch{throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} is not valid JSON.`)}if(n===null||typeof n!="object"||Array.isArray(n))throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} is not a JSON object.`);let d=n,r={},s=d.port;if(s!==void 0){if(typeof s!="number"||!Number.isInteger(s)||s<1||s>65535)throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} declares an invalid port; expected an integer 1-65535.`);r.port=s}let o=d.stateDir;if(o!==void 0){if(typeof o!="string"||o.trim()==="")throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} declares an invalid stateDir; expected a non-empty string.`);r.stateDir=o}let c=d.apiToken;if(c!==void 0){if(typeof c!="string"||c.trim()==="")throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} declares an invalid apiToken; expected a non-empty string.`);r.apiToken=c}let l=d.apiVisibility;if(l!==void 0){if(l!=="owner"&&l!=="shared"&&l!=="open")throw new a("CONFIG_INVALID",`the daemon config file ${JSON.stringify(e)} declares an unknown apiVisibility ${JSON.stringify(l)}; expected "owner", "shared" or "open".`);r.apiVisibility=l}return r}function f(e,t){let i=e[t];if(i===void 0)return;let n=i.trim();return n===""?void 0:n}function F(e){if(e===void 0)return;let t=Number.parseInt(e,10);if(!Number.isInteger(t)||t<1||t>65535)throw new a("INCOHERENT_SELECTION",`OURS_PORT=${JSON.stringify(e)} is not a TCP port between 1 and 65535.`);return t}function P(e){return e.endsWith("/")?e.slice(0,-1):e}function E(e,t,i,n){return e!==void 0?{value:e,source:"explicit"}:t!==void 0?{value:t,source:"environment"}:i!==void 0?{value:i,source:"config-file"}:{value:n,source:"default"}}function V(e,t){if(e!==void 0)return{value:e,source:"explicit"};if(t!==void 0)return{value:t,source:"environment"}}async function $(e,t={}){let i=t.fetch??globalThis.fetch,n=new AbortController,d=setTimeout(()=>n.abort(),t.timeoutMs??5e3),r;try{let o=await i(`${e.baseUrl.value}/state-dir`,{signal:n.signal});if(!o.ok)throw new a("INCOHERENT_SELECTION",`${e.baseUrl.value}/state-dir answered HTTP ${o.status}, so the daemon at that address could not be identified. Refusing to send a credential to it.`);r=await o.json()}catch(o){throw o instanceof a?o:new S(e.baseUrl.value,e.expectStateDir,{cause:o})}finally{clearTimeout(d)}let s=typeof r.stateDir=="string"?p(r.stateDir):null;if(s===null)throw new a("INCOHERENT_SELECTION",`${e.baseUrl.value}/state-dir did not report a state directory, so this is not an ours daemon or not one this client understands. Refusing to send a credential to it.`);if(s!==e.expectStateDir)throw new a("INCOHERENT_SELECTION",`the daemon at ${e.baseUrl.value} owns state directory ${JSON.stringify(s)}, but this selection expects ${JSON.stringify(e.expectStateDir)}. The token belongs to the expected directory, so it is NOT being sent. Point the endpoint and the state directory at the same daemon.`)}async function j(e={}){let{leaseToken:t,clientPid:i,fetch:n,...d}=e,r=_(d);return await $(r,{fetch:n}),new O({url:r.baseUrl.value,leaseToken:t??I(32).toString("hex"),clientPid:i,apiToken:r.token?.value,fetch:n})}export{a,S as b,b as c,C as d,_ as e,K as f,$ as g,j as h};
@@ -0,0 +1,2 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import{a as H}from"./chunk-EHCBEY52.js";import{c as L,d as B}from"./chunk-HEWVNFUK.js";import{d as F}from"./chunk-K3NRXUJW.js";import{a as u,b as n,c as A,d as U,e as P,f as C}from"./chunk-SQ4M4QQA.js";import{F as M,e as h,g,j as I,l as D,m as N}from"./chunk-YZJB6DZI.js";import{a as v,b as E,c as O}from"./chunk-YRPUM6JG.js";import{j as k}from"./chunk-3NTV3JFP.js";import{g as $}from"./chunk-5WE5G2CD.js";import{a as f,b as _,c as l,d as b,p as y,q as S,u as R}from"./chunk-ZWUFPR6V.js";import{d as m,h as s,i as o}from"./chunk-IWY6MRSV.js";import{adapt_wrapper as K}from"@adapt-toolkit/sdk/executables";var T=!1;function ne(){return T}function j(){if(T)throw new Error('bootWrapper() has already run in this process. It boots the ADAPT environment, which can only be initialised once \u2014 a second call fails inside the native layer with "Failed to invoke initializer in ADAPT environment", which names neither the double init nor the caller. NOTE THAT startDaemon() CALLS bootWrapper() ITSELF: the two are alternatives, not steps. Use startDaemon() for the HTTP daemon, or bootWrapper() alone for a stdio/in-process host \u2014 never both.');T=!0,H()}async function ae(){j(),s?.update("wrapper"),O(v());let x=["--broker_address",m,"--test_mode","--logger_config","--level","INFO","--stdout","stderr","--logger_config_end"];o(`booting wrapper (unit ${E.hash.slice(0,12)}\u2026, broker ${m})`),_(await K.start(x)),f.on_packet_created_cb=e=>o(`wrapper: packet ready ${e.slice(0,12)}\u2026`),f.start();let p=Number(process.env.OURS_TEST_BOOT_HOLD_MS||"")||0;p>0&&(o(`TEST HOLD: boot window open ${p}ms (OURS_TEST_BOOT_HOLD_MS)`),await new Promise(e=>setTimeout(e,p))),s?.update("registrar");try{await N()}catch(e){o("failed to start the contact-book registrar (local contact book disabled):",String(e))}S();let i=R(),d=Math.max(0,Number(process.env.OURS_TEST_FAKE_RESTORE_COUNT||"")||0),c=Math.max(0,Number(process.env.OURS_TEST_FAKE_RESTORE_MS||"")||0),W=i.length===0&&d>0?d:i.length;s?.update("identities",{completed:0,total:W});for(let e of i)I.add(e);if(i.length===0&&d>0){o(`TEST: simulating ${d} fake identity restore(s), ${c}ms each`);for(let e=0;e<d;e++)c>0&&await new Promise(a=>setTimeout(a,c)),s?.update("identities",{completed:e+1,total:d})}else if(i.length===0)o("no persisted identities \u2014 start with create_identity");else{o(`restoring ${i.length} identit${i.length===1?"y":"ies"}: ${i.join(", ")}`);for(let[e,a]of i.entries()){try{let t=await D(a);b&&await M(t);let r=y(t.dir);r&&(t.temp=r)}catch(t){throw o(`failed to restore "${a}":`,String(t)),t}s?.update("identities",{completed:e+1,total:i.length})}}s?.update("reconciliation"),F(),u(A()),n&&!l.has(n)&&(o(`root marker names a missing identity "${n}" \u2014 clearing it`),u(null),U()),n&&o(`root identity: ${n}`);{let e=n?l.get(n):void 0;n&&!e&&o(`re-delegation on upgrade DEGRADED: root "${n}" is not among the restored identities \u2014 role certs not refreshed this boot`);let a=[];if(e)for(let t of l.values()){if(t.name===e.name)continue;let r;try{r=P(t)}catch{r=void 0}if(!(!r||!r.hasCert)){if(r.rootCid!==e.cid){o(`[${t.name}] re-delegation skipped: delegated by a different root (${r.rootCid.slice(0,12)}\u2026), not this host root \u2014 left as-is`);continue}try{await C(e,t),a.push(t)}catch(w){k(t,{event:"redelegation_failed",error:String(w).slice(0,300)}),o(`[${t.name}] boot re-delegation (upgrade cert refresh) failed:`,String(w))}}}for(let t of l.values()){await h(t),await g(t);for(let r of[1e4,3e4,9e4])setTimeout(()=>{h(t).catch(()=>{})},r),setTimeout(()=>{g(t).catch(()=>{})},r)}a.length>0&&o(`refreshed ${a.length} role delegation cert(s) against the live AD on boot`)}$(),B(),L()}export{ne as a,ae as b};
@@ -0,0 +1,2 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import{a as E}from"./chunk-JOKNFUW3.js";import{a as k,b as A,d as C}from"./chunk-SQ4M4QQA.js";import{E as x,j as y,q as T,r as I,s as _,v as R}from"./chunk-YZJB6DZI.js";import{a as l,d as u,e as d,g as S}from"./chunk-5WE5G2CD.js";import{a as v,c as m,p as w}from"./chunk-ZWUFPR6V.js";import{c as s,i as n}from"./chunk-IWY6MRSV.js";import{g as $}from"./chunk-DYQHWN7X.js";import{join as D}from"node:path";import*as i from"node:fs";function F(e){try{$(e)}catch(t){n(`closeHistory(${e.name}) failed:`,String(t))}try{v.remove_packet(e.cid)}catch(t){n(`remove_packet(${e.cid}) failed:`,String(t))}m.delete(e.name);try{x(e)}catch(t){n(`failed to unpublish "${e.name}" from the contact book:`,String(t))}l.has(e.name)&&(l.delete(e.name),S()),e.name===A&&(k(null),C());try{i.rmSync(e.dir,{recursive:!0,force:!0}),y.delete(e.name)}catch(t){return`deleting ${e.dir} failed: ${String(t)}`}return null}function L(e,t){let r=e.temp;return r?(r.closing||(r.closing=(async()=>{n(`[${e.name}] closing temporary identity (${t})`);let o=[];try{o=T(a=>E(_(e,"::a2a_messaging::list_contacts",a)))}catch(a){n(`[${e.name}] contact snapshot failed during close (continuing with local cleanup):`,String(a))}let p=0,c=0;u.add(e.name);try{for(let a of o)try{await I(async b=>{let h=(await R(e,"::a2a_messaging::remove_contact",{contact:a.container_id},b)).Reduce("notified");return h.IsNil()?!1:h.GetBoolean()})?p++:c++}catch(g){c++,n(`[${e.name}] remove-me to ${a.container_id} failed (continuing):`,String(g))}}finally{u.delete(e.name)}let f=F(e);return f?n(`[${e.name}] temporary identity close: LOCAL DELETE FAILED \u2014 ${f}`):n(`[${e.name}] temporary identity closed: ${o.length} contact(s), ${p} remove-me notice(s) queued, ${c} not sent (delivery unverified by design)`),{attempted:o.length,notified:p,failed:c,deleteError:f}})()),r.closing):Promise.reject(new Error(`identity "${e.name}" is not temporary`))}function K(){for(let e of[...m.values()]){let t=e.temp;if(!t||t.closing||d(t.owner.pid))continue;let r=l.get(e.name);r&&d(r.pid)||L(e,`stale lease \u2014 owner pid ${t.owner.pid} is dead`).catch(o=>n(`[${e.name}] stale-temp reclaim failed:`,String(o)))}}function Q(){if(i.existsSync(s))for(let e of i.readdirSync(s,{withFileTypes:!0})){if(!e.isDirectory()||m.has(e.name))continue;let t=D(s,e.name),r=w(t);if(!(!r||d(r.owner.pid)))try{i.rmSync(t,{recursive:!0,force:!0}),y.delete(e.name),n(`[${e.name}] removed orphaned temporary-identity dir (owner pid ${r.owner.pid} dead, no live packet)`)}catch(o){n(`[${e.name}] failed to remove orphaned temporary-identity dir:`,String(o))}}}export{F as a,L as b,K as c,Q as d};