@secrecy/lib 1.81.0 → 1.83.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -158,6 +158,14 @@ export class SecrecyCloudClient {
158
158
  return folder;
159
159
  }
160
160
  async node({ id, deleted, } = {}) {
161
+ const node = await this.#client.apiClient.cloud.nodeById.query({
162
+ id,
163
+ deleted,
164
+ fromIdentityPubKey: this.#client.currentIdentity.identityPubKey,
165
+ });
166
+ return await apiNodeToExternal(node, this.#client.keyPairs);
167
+ }
168
+ async nodeFull({ id, deleted, } = {}) {
161
169
  const node = await this.#client.apiClient.cloud.nodeFullById.query({
162
170
  id,
163
171
  deleted,
@@ -166,12 +174,46 @@ export class SecrecyCloudClient {
166
174
  return await apiNodeToExternalNodeFull(node, this.#client.keyPairs);
167
175
  }
168
176
  async nodes({ ids, deleted, }) {
169
- const nodes = await this.#client.apiClient.cloud.nodeFullByIds.query({
177
+ const apiNodes = await this.#client.apiClient.cloud.nodeByIds.query({
178
+ ids,
179
+ deleted,
180
+ fromIdentityPubKey: this.#client.currentIdentity.identityPubKey,
181
+ });
182
+ const errors = apiNodes.missingIds.map((id) => `Node ${id} not found`);
183
+ const decryptedNodes = await Promise.allSettled(apiNodes.nodes.map((node) => apiNodeToExternal(node, this.#client.keyPairs)));
184
+ const nodes = decryptedNodes
185
+ .filter((result) => result.status === 'fulfilled')
186
+ .map((result) => result.value);
187
+ const errorNodes = decryptedNodes
188
+ .filter((result) => result.status === 'rejected')
189
+ .map((result) => result.reason);
190
+ errors.push(...errorNodes.map((err) => typeof err === 'string'
191
+ ? err
192
+ : err instanceof Error
193
+ ? err.message
194
+ : JSON.stringify(err)));
195
+ return { nodes, errors };
196
+ }
197
+ async nodesFull({ ids, deleted, }) {
198
+ const apiNodes = await this.#client.apiClient.cloud.nodeFullByIds.query({
170
199
  ids,
171
200
  deleted,
172
201
  fromIdentityPubKey: this.#client.currentIdentity.identityPubKey,
173
202
  });
174
- return await Promise.all(nodes.nodes.map((node) => apiNodeToExternalNodeFull(node, this.#client.keyPairs)));
203
+ const errors = apiNodes.missingIds.map((id) => `Node ${id} not found`);
204
+ const decryptedNodes = await Promise.allSettled(apiNodes.nodes.map((node) => apiNodeToExternalNodeFull(node, this.#client.keyPairs)));
205
+ const nodes = decryptedNodes
206
+ .filter((result) => result.status === 'fulfilled')
207
+ .map((result) => result.value);
208
+ const errorNodes = decryptedNodes
209
+ .filter((result) => result.status === 'rejected')
210
+ .map((result) => result.reason);
211
+ errors.push(...errorNodes.map((err) => typeof err === 'string'
212
+ ? err
213
+ : err instanceof Error
214
+ ? err.message
215
+ : JSON.stringify(err)));
216
+ return { nodes, errors };
175
217
  }
176
218
  async dataMetadata({ id }) {
177
219
  const data = await this.#client.apiClient.cloud.dataById.query({
@@ -1,3 +1,4 @@
1
+ import { publicKeysCache } from '../cache.js';
1
2
  import { encryptCryptoBox, generateCryptoBoxKeyPair, sodium, } from '../index.js';
2
3
  export class SecrecyGroupClient {
3
4
  #client;
@@ -57,4 +58,35 @@ export class SecrecyGroupClient {
57
58
  async updateMember(input) {
58
59
  return this.#client.apiClient.group.updateMember.mutate(input);
59
60
  }
61
+ async publicKeys(input) {
62
+ const groupIds = Array.isArray(input) ? input : [input];
63
+ if (groupIds.length === 0) {
64
+ return {};
65
+ }
66
+ const publicKeys = Object.fromEntries(groupIds
67
+ .map((groupId) => [
68
+ groupId,
69
+ publicKeysCache.get(`groupPublicKey:${groupId}`),
70
+ ])
71
+ .filter(([_, key]) => key !== undefined));
72
+ const missingKeys = [
73
+ ...new Set(groupIds.filter((groupId) => publicKeys[groupId] === undefined)),
74
+ ];
75
+ if (missingKeys.length > 0) {
76
+ const groupKeysMap = await this.#client.apiClient.group.publicKeys.query({
77
+ groupIds: missingKeys,
78
+ });
79
+ if ('publicKey' in groupKeysMap) {
80
+ throw Error('Should not happen!');
81
+ }
82
+ if (Object.keys(groupKeysMap.publicKeys).length !== missingKeys.length) {
83
+ throw new Error("Unable to load some user's public keys!");
84
+ }
85
+ for (const [groupId, publicKey] of Object.entries(groupKeysMap.publicKeys)) {
86
+ publicKeys[groupId] = publicKey;
87
+ publicKeysCache.set(`groupPublicKey:${groupId}`, publicKey);
88
+ }
89
+ }
90
+ return publicKeys;
91
+ }
60
92
  }
@@ -51,11 +51,25 @@ export declare class SecrecyCloudClient {
51
51
  node({ id, deleted, }?: {
52
52
  id?: string | null | undefined;
53
53
  deleted?: boolean | null | undefined;
54
+ }): Promise<Node>;
55
+ nodeFull({ id, deleted, }?: {
56
+ id?: string | null | undefined;
57
+ deleted?: boolean | null | undefined;
54
58
  }): Promise<NodeFull>;
55
59
  nodes({ ids, deleted, }: {
56
60
  ids: string[];
57
61
  deleted?: boolean | null | undefined;
58
- }): Promise<NodeFull[]>;
62
+ }): Promise<{
63
+ nodes: Node[];
64
+ errors: string[];
65
+ }>;
66
+ nodesFull({ ids, deleted, }: {
67
+ ids: string[];
68
+ deleted?: boolean | null | undefined;
69
+ }): Promise<{
70
+ nodes: NodeFull[];
71
+ errors: string[];
72
+ }>;
59
73
  dataMetadata({ id }: {
60
74
  id: string;
61
75
  }): Promise<DataMetadata>;
@@ -12,4 +12,5 @@ export declare class SecrecyGroupClient {
12
12
  transferOwnership(input: RouterInputs['group']['transferOwnership']): Promise<RouterOutputs['group']['transferOwnership']>;
13
13
  update(input: RouterInputs['group']['update']): Promise<RouterOutputs['group']['update']>;
14
14
  updateMember(input: RouterInputs['group']['updateMember']): Promise<RouterOutputs['group']['updateMember']>;
15
+ publicKeys(input: string[]): Promise<Record<string, string>>;
15
16
  }
@@ -2257,6 +2257,7 @@ export declare const createTRPCClient: (opts: CreateTrpcClientOptions) => import
2257
2257
  sizeEncrypted: bigint;
2258
2258
  };
2259
2259
  })[];
2260
+ missingIds: string[];
2260
2261
  };
2261
2262
  meta: any;
2262
2263
  }>;
@@ -2665,6 +2666,7 @@ export declare const createTRPCClient: (opts: CreateTrpcClientOptions) => import
2665
2666
  nameKey: string | null;
2666
2667
  }[];
2667
2668
  })[];
2669
+ missingIds: string[];
2668
2670
  };
2669
2671
  meta: any;
2670
2672
  }>;
@@ -6367,6 +6369,19 @@ export declare const createTRPCClient: (opts: CreateTrpcClientOptions) => import
6367
6369
  };
6368
6370
  meta: any;
6369
6371
  }>;
6372
+ publicKeys: import("@trpc/server").TRPCQueryProcedure<{
6373
+ input: {
6374
+ groupId: string;
6375
+ } | {
6376
+ groupIds: string[];
6377
+ };
6378
+ output: {
6379
+ publicKey: string;
6380
+ } | {
6381
+ publicKeys: Record<string, string>;
6382
+ };
6383
+ meta: any;
6384
+ }>;
6370
6385
  }>;
6371
6386
  }>>;
6372
6387
  export declare const getTrpcGuestClient: ({ url }?: {
@@ -8619,6 +8634,7 @@ export declare const getTrpcGuestClient: ({ url }?: {
8619
8634
  sizeEncrypted: bigint;
8620
8635
  };
8621
8636
  })[];
8637
+ missingIds: string[];
8622
8638
  };
8623
8639
  meta: any;
8624
8640
  }>;
@@ -9027,6 +9043,7 @@ export declare const getTrpcGuestClient: ({ url }?: {
9027
9043
  nameKey: string | null;
9028
9044
  }[];
9029
9045
  })[];
9046
+ missingIds: string[];
9030
9047
  };
9031
9048
  meta: any;
9032
9049
  }>;
@@ -12729,6 +12746,19 @@ export declare const getTrpcGuestClient: ({ url }?: {
12729
12746
  };
12730
12747
  meta: any;
12731
12748
  }>;
12749
+ publicKeys: import("@trpc/server").TRPCQueryProcedure<{
12750
+ input: {
12751
+ groupId: string;
12752
+ } | {
12753
+ groupIds: string[];
12754
+ };
12755
+ output: {
12756
+ publicKey: string;
12757
+ } | {
12758
+ publicKeys: Record<string, string>;
12759
+ };
12760
+ meta: any;
12761
+ }>;
12732
12762
  }>;
12733
12763
  }>>;
12734
12764
  export type ApiClient = ReturnType<typeof createTRPCClient>;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@secrecy/lib",
3
3
  "author": "Anonymize <anonymize@gmail.com>",
4
4
  "description": "Anonymize Secrecy Library",
5
- "version": "1.81.0",
5
+ "version": "1.83.0",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/anonymize-org/lib.git"
@@ -76,7 +76,7 @@
76
76
  },
77
77
  "dependencies": {
78
78
  "@js-temporal/polyfill": "^0.5.1",
79
- "@secrecy/trpc-api-types": "1.36.0",
79
+ "@secrecy/trpc-api-types": "1.38.0",
80
80
  "@trpc/client": "11.6.0",
81
81
  "@trpc/server": "^11.6.0",
82
82
  "@types/libsodium-wrappers-sumo": "^0.7.8",