@keeper-security/keeper-sdk-javascript 0.1.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.
Files changed (173) hide show
  1. package/dist/auth/ConsoleAuthUI.d.ts +10 -0
  2. package/dist/auth/ConsoleAuthUI.js +152 -0
  3. package/dist/auth/ConsoleAuthUI.js.map +1 -0
  4. package/dist/auth/ConsoleLogin.d.ts +8 -0
  5. package/dist/auth/ConsoleLogin.js +266 -0
  6. package/dist/auth/ConsoleLogin.js.map +1 -0
  7. package/dist/auth/SessionManager.d.ts +66 -0
  8. package/dist/auth/SessionManager.js +211 -0
  9. package/dist/auth/SessionManager.js.map +1 -0
  10. package/dist/index.d.ts +17 -0
  11. package/dist/index.js +61 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/records/RecordOperations.d.ts +79 -0
  14. package/dist/records/RecordOperations.js +346 -0
  15. package/dist/records/RecordOperations.js.map +1 -0
  16. package/dist/records/RecordUtils.d.ts +36 -0
  17. package/dist/records/RecordUtils.js +224 -0
  18. package/dist/records/RecordUtils.js.map +1 -0
  19. package/dist/sharing/Sharing.d.ts +27 -0
  20. package/dist/sharing/Sharing.js +125 -0
  21. package/dist/sharing/Sharing.js.map +1 -0
  22. package/dist/src/auth/ConsoleAuthUI.d.ts +10 -0
  23. package/dist/src/auth/ConsoleAuthUI.js +161 -0
  24. package/dist/src/auth/ConsoleAuthUI.js.map +1 -0
  25. package/dist/src/auth/ConsoleLogin.d.ts +8 -0
  26. package/dist/src/auth/ConsoleLogin.js +311 -0
  27. package/dist/src/auth/ConsoleLogin.js.map +1 -0
  28. package/dist/src/auth/SessionManager.d.ts +67 -0
  29. package/dist/src/auth/SessionManager.js +212 -0
  30. package/dist/src/auth/SessionManager.js.map +1 -0
  31. package/dist/src/folders/FolderManager.d.ts +57 -0
  32. package/dist/src/folders/FolderManager.js +108 -0
  33. package/dist/src/folders/FolderManager.js.map +1 -0
  34. package/dist/src/folders/addFolder.d.ts +32 -0
  35. package/dist/src/folders/addFolder.js +207 -0
  36. package/dist/src/folders/addFolder.js.map +1 -0
  37. package/dist/src/folders/changeDirectory.d.ts +19 -0
  38. package/dist/src/folders/changeDirectory.js +171 -0
  39. package/dist/src/folders/changeDirectory.js.map +1 -0
  40. package/dist/src/folders/deleteFolder.d.ts +17 -0
  41. package/dist/src/folders/deleteFolder.js +237 -0
  42. package/dist/src/folders/deleteFolder.js.map +1 -0
  43. package/dist/src/folders/folderHelpers.d.ts +48 -0
  44. package/dist/src/folders/folderHelpers.js +100 -0
  45. package/dist/src/folders/folderHelpers.js.map +1 -0
  46. package/dist/src/folders/folderTree.d.ts +29 -0
  47. package/dist/src/folders/folderTree.js +250 -0
  48. package/dist/src/folders/folderTree.js.map +1 -0
  49. package/dist/src/folders/getFolder.d.ts +56 -0
  50. package/dist/src/folders/getFolder.js +143 -0
  51. package/dist/src/folders/getFolder.js.map +1 -0
  52. package/dist/src/folders/listFolder.d.ts +48 -0
  53. package/dist/src/folders/listFolder.js +276 -0
  54. package/dist/src/folders/listFolder.js.map +1 -0
  55. package/dist/src/folders/updateFolder.d.ts +31 -0
  56. package/dist/src/folders/updateFolder.js +137 -0
  57. package/dist/src/folders/updateFolder.js.map +1 -0
  58. package/dist/src/index.d.ts +49 -0
  59. package/dist/src/index.js +151 -0
  60. package/dist/src/index.js.map +1 -0
  61. package/dist/src/records/RecordOperations.d.ts +80 -0
  62. package/dist/src/records/RecordOperations.js +356 -0
  63. package/dist/src/records/RecordOperations.js.map +1 -0
  64. package/dist/src/records/RecordUtils.d.ts +37 -0
  65. package/dist/src/records/RecordUtils.js +263 -0
  66. package/dist/src/records/RecordUtils.js.map +1 -0
  67. package/dist/src/records/Totp.d.ts +14 -0
  68. package/dist/src/records/Totp.js +111 -0
  69. package/dist/src/records/Totp.js.map +1 -0
  70. package/dist/src/sharedFolders/SharedFolderManager.d.ts +20 -0
  71. package/dist/src/sharedFolders/SharedFolderManager.js +33 -0
  72. package/dist/src/sharedFolders/SharedFolderManager.js.map +1 -0
  73. package/dist/src/sharedFolders/listSharedFolders.d.ts +29 -0
  74. package/dist/src/sharedFolders/listSharedFolders.js +127 -0
  75. package/dist/src/sharedFolders/listSharedFolders.js.map +1 -0
  76. package/dist/src/sharedFolders/shareFolder.d.ts +36 -0
  77. package/dist/src/sharedFolders/shareFolder.js +352 -0
  78. package/dist/src/sharedFolders/shareFolder.js.map +1 -0
  79. package/dist/src/sharing/Sharing.d.ts +50 -0
  80. package/dist/src/sharing/Sharing.js +195 -0
  81. package/dist/src/sharing/Sharing.js.map +1 -0
  82. package/dist/src/storage/InMemoryStorage.d.ts +24 -0
  83. package/dist/src/storage/InMemoryStorage.js +139 -0
  84. package/dist/src/storage/InMemoryStorage.js.map +1 -0
  85. package/dist/src/teams/TeamManager.d.ts +17 -0
  86. package/dist/src/teams/TeamManager.js +38 -0
  87. package/dist/src/teams/TeamManager.js.map +1 -0
  88. package/dist/src/teams/enterpriseData.d.ts +106 -0
  89. package/dist/src/teams/enterpriseData.js +319 -0
  90. package/dist/src/teams/enterpriseData.js.map +1 -0
  91. package/dist/src/teams/listTeams.d.ts +42 -0
  92. package/dist/src/teams/listTeams.js +308 -0
  93. package/dist/src/teams/listTeams.js.map +1 -0
  94. package/dist/src/teams/viewTeam.d.ts +35 -0
  95. package/dist/src/teams/viewTeam.js +177 -0
  96. package/dist/src/teams/viewTeam.js.map +1 -0
  97. package/dist/src/utils/Logger.d.ts +28 -0
  98. package/dist/src/utils/Logger.js +62 -0
  99. package/dist/src/utils/Logger.js.map +1 -0
  100. package/dist/src/utils/constants.d.ts +50 -0
  101. package/dist/src/utils/constants.js +64 -0
  102. package/dist/src/utils/constants.js.map +1 -0
  103. package/dist/src/utils/errors.d.ts +10 -0
  104. package/dist/src/utils/errors.js +117 -0
  105. package/dist/src/utils/errors.js.map +1 -0
  106. package/dist/src/utils/guards.d.ts +7 -0
  107. package/dist/src/utils/guards.js +29 -0
  108. package/dist/src/utils/guards.js.map +1 -0
  109. package/dist/src/utils/index.d.ts +7 -0
  110. package/dist/src/utils/index.js +39 -0
  111. package/dist/src/utils/index.js.map +1 -0
  112. package/dist/src/utils/patterns.d.ts +9 -0
  113. package/dist/src/utils/patterns.js +20 -0
  114. package/dist/src/utils/patterns.js.map +1 -0
  115. package/dist/src/utils/types.d.ts +12 -0
  116. package/dist/src/utils/types.js +3 -0
  117. package/dist/src/utils/types.js.map +1 -0
  118. package/dist/src/vault/KeeperVault.d.ts +116 -0
  119. package/dist/src/vault/KeeperVault.js +443 -0
  120. package/dist/src/vault/KeeperVault.js.map +1 -0
  121. package/dist/storage/InMemoryStorage.d.ts +24 -0
  122. package/dist/storage/InMemoryStorage.js +132 -0
  123. package/dist/storage/InMemoryStorage.js.map +1 -0
  124. package/dist/utils/Logger.d.ts +28 -0
  125. package/dist/utils/Logger.js +62 -0
  126. package/dist/utils/Logger.js.map +1 -0
  127. package/dist/utils/constants.d.ts +26 -0
  128. package/dist/utils/constants.js +37 -0
  129. package/dist/utils/constants.js.map +1 -0
  130. package/dist/utils/errors.d.ts +10 -0
  131. package/dist/utils/errors.js +117 -0
  132. package/dist/utils/errors.js.map +1 -0
  133. package/dist/utils/index.d.ts +4 -0
  134. package/dist/utils/index.js +22 -0
  135. package/dist/utils/index.js.map +1 -0
  136. package/dist/vault/KeeperVault.d.ts +72 -0
  137. package/dist/vault/KeeperVault.js +338 -0
  138. package/dist/vault/KeeperVault.js.map +1 -0
  139. package/package.json +32 -0
  140. package/src/auth/ConsoleAuthUI.ts +169 -0
  141. package/src/auth/ConsoleLogin.ts +351 -0
  142. package/src/auth/SessionManager.ts +293 -0
  143. package/src/folders/FolderManager.ts +174 -0
  144. package/src/folders/addFolder.ts +294 -0
  145. package/src/folders/changeDirectory.ts +217 -0
  146. package/src/folders/deleteFolder.ts +293 -0
  147. package/src/folders/folderHelpers.ts +99 -0
  148. package/src/folders/folderTree.ts +321 -0
  149. package/src/folders/getFolder.ts +234 -0
  150. package/src/folders/listFolder.ts +358 -0
  151. package/src/folders/updateFolder.ts +210 -0
  152. package/src/index.ts +242 -0
  153. package/src/records/RecordOperations.ts +549 -0
  154. package/src/records/RecordUtils.ts +282 -0
  155. package/src/records/Totp.ts +119 -0
  156. package/src/sharedFolders/SharedFolderManager.ts +57 -0
  157. package/src/sharedFolders/listSharedFolders.ts +173 -0
  158. package/src/sharedFolders/shareFolder.ts +457 -0
  159. package/src/sharing/Sharing.ts +282 -0
  160. package/src/storage/InMemoryStorage.ts +163 -0
  161. package/src/teams/TeamManager.ts +61 -0
  162. package/src/teams/enterpriseData.ts +453 -0
  163. package/src/teams/listTeams.ts +373 -0
  164. package/src/teams/viewTeam.ts +248 -0
  165. package/src/utils/Logger.ts +71 -0
  166. package/src/utils/constants.ts +63 -0
  167. package/src/utils/errors.ts +108 -0
  168. package/src/utils/guards.ts +24 -0
  169. package/src/utils/index.ts +22 -0
  170. package/src/utils/patterns.ts +20 -0
  171. package/src/utils/types.ts +11 -0
  172. package/src/vault/KeeperVault.ts +612 -0
  173. package/tsconfig.json +16 -0
@@ -0,0 +1,282 @@
1
+ import {
2
+ Auth,
3
+ Records,
4
+ Authentication,
5
+ platform,
6
+ getPublicKeysMessage,
7
+ getRecordsDetailsMessage,
8
+ webSafe64FromBytes,
9
+ recordsShareUpdateMessage,
10
+ normal64Bytes,
11
+ } from '@keeper-security/keeperapi'
12
+ import { extractErrorMessage, KeeperSdkError } from '../utils/errors'
13
+
14
+ enum ShareStatus {
15
+ Success = 'success',
16
+ PendingAccept = 'pending_accept',
17
+ MissingPublicKey = 'missing_public_key',
18
+ Error = 'error',
19
+ Unknown = 'unknown',
20
+ }
21
+
22
+ export type ShareRecordInput = {
23
+ recordUid: string
24
+ email: string
25
+ canEdit?: boolean
26
+ canShare?: boolean
27
+ }
28
+
29
+ export type ShareRecordResult = {
30
+ recordUid: string
31
+ email: string
32
+ success: boolean
33
+ status: string
34
+ message: string
35
+ }
36
+
37
+ export type RemoveShareInput = {
38
+ recordUid: string
39
+ email: string
40
+ }
41
+
42
+ export type RemoveShareResult = {
43
+ recordUid: string
44
+ email: string
45
+ success: boolean
46
+ status: string
47
+ message: string
48
+ }
49
+
50
+ type UserKeys = {
51
+ username: string
52
+ rsaPublicKey: Uint8Array | null
53
+ eccPublicKey: Uint8Array | null
54
+ errorCode: string | null
55
+ }
56
+
57
+ async function loadUserPublicKey(auth: Auth, email: string): Promise<UserKeys> {
58
+ const msg = getPublicKeysMessage({ usernames: [email] })
59
+ let response: Authentication.IGetPublicKeysResponse
60
+
61
+ try {
62
+ response = await auth.executeRest(msg)
63
+ } catch (err) {
64
+ throw new KeeperSdkError(`Failed to fetch public key for ${email}: ${extractErrorMessage(err)}`)
65
+ }
66
+
67
+ const keyResponses = response.keyResponses || []
68
+ if (keyResponses.length === 0) {
69
+ throw new KeeperSdkError(`No public key returned for ${email}`, 'missing_public_key')
70
+ }
71
+
72
+ const entry = keyResponses[0]
73
+ if (entry.errorCode) {
74
+ throw new KeeperSdkError(
75
+ `Public key lookup failed for ${email}: ${entry.errorCode} - ${entry.message || ''}`,
76
+ entry.errorCode
77
+ )
78
+ }
79
+
80
+ return {
81
+ username: entry.username || email,
82
+ rsaPublicKey: entry.publicKey && entry.publicKey.length > 0 ? (entry.publicKey as Uint8Array) : null,
83
+ eccPublicKey: entry.publicEccKey && entry.publicEccKey.length > 0 ? (entry.publicEccKey as Uint8Array) : null,
84
+ errorCode: entry.errorCode || null,
85
+ }
86
+ }
87
+
88
+ export async function shareRecord(
89
+ auth: Auth,
90
+ recordKey: Uint8Array,
91
+ input: ShareRecordInput
92
+ ): Promise<ShareRecordResult> {
93
+ const { recordUid, email, canEdit = false, canShare = false } = input
94
+
95
+ const userKeys = await loadUserPublicKey(auth, email)
96
+
97
+ let encryptedRecordKey: Uint8Array
98
+ let useEccKey = false
99
+
100
+ if (userKeys.eccPublicKey) {
101
+ encryptedRecordKey = await platform.publicEncryptEC(recordKey, userKeys.eccPublicKey)
102
+ useEccKey = true
103
+ } else if (userKeys.rsaPublicKey) {
104
+ const rsaKeyBase64 = platform.bytesToBase64(userKeys.rsaPublicKey)
105
+ encryptedRecordKey = platform.publicEncrypt(recordKey, rsaKeyBase64)
106
+ useEccKey = false
107
+ } else {
108
+ return {
109
+ recordUid,
110
+ email,
111
+ success: false,
112
+ status: ShareStatus.MissingPublicKey,
113
+ message: `No usable public key available for ${email}`,
114
+ }
115
+ }
116
+
117
+ const sharedRecord: Records.ISharedRecord = {
118
+ toUsername: email,
119
+ recordUid: normal64Bytes(recordUid),
120
+ recordKey: encryptedRecordKey,
121
+ editable: canEdit,
122
+ shareable: canShare,
123
+ useEccKey,
124
+ }
125
+
126
+ const msg = recordsShareUpdateMessage({ addSharedRecord: [sharedRecord] })
127
+
128
+ let response: Records.IRecordShareUpdateResponse
129
+ try {
130
+ response = await auth.executeRest(msg)
131
+ } catch (err) {
132
+ return {
133
+ recordUid,
134
+ email,
135
+ success: false,
136
+ status: ShareStatus.Error,
137
+ message: extractErrorMessage(err),
138
+ }
139
+ }
140
+
141
+ const addStatuses = response.addSharedRecordStatus || []
142
+ if (addStatuses.length > 0) {
143
+ const st = addStatuses[0]
144
+ const isSuccess = st.status === ShareStatus.Success || st.status === ShareStatus.PendingAccept
145
+ return {
146
+ recordUid,
147
+ email: st.username || email,
148
+ success: isSuccess,
149
+ status: st.status || ShareStatus.Unknown,
150
+ message: st.message || st.status || '',
151
+ }
152
+ }
153
+
154
+ return {
155
+ recordUid,
156
+ email,
157
+ success: true,
158
+ status: ShareStatus.Success,
159
+ message: 'Record shared successfully',
160
+ }
161
+ }
162
+
163
+ export async function removeRecordShare(auth: Auth, input: RemoveShareInput): Promise<RemoveShareResult> {
164
+ const { recordUid, email } = input
165
+
166
+ const msg = recordsShareUpdateMessage({
167
+ removeSharedRecord: [
168
+ {
169
+ toUsername: email,
170
+ recordUid: normal64Bytes(recordUid),
171
+ },
172
+ ],
173
+ })
174
+
175
+ let response: Records.IRecordShareUpdateResponse
176
+ try {
177
+ response = await auth.executeRest(msg)
178
+ } catch (err) {
179
+ return {
180
+ recordUid,
181
+ email,
182
+ success: false,
183
+ status: ShareStatus.Error,
184
+ message: extractErrorMessage(err),
185
+ }
186
+ }
187
+
188
+ const removeStatuses = response.removeSharedRecordStatus || []
189
+ if (removeStatuses.length > 0) {
190
+ const st = removeStatuses[0]
191
+ return {
192
+ recordUid,
193
+ email: st.username || email,
194
+ success: st.status === ShareStatus.Success,
195
+ status: st.status || ShareStatus.Unknown,
196
+ message: st.message || st.status || '',
197
+ }
198
+ }
199
+
200
+ return {
201
+ recordUid,
202
+ email,
203
+ success: true,
204
+ status: ShareStatus.Success,
205
+ message: 'Share removed successfully',
206
+ }
207
+ }
208
+
209
+ export type RecordUserPermission = {
210
+ username: string
211
+ accountUid?: string
212
+ owner: boolean
213
+ shareAdmin: boolean
214
+ shareable: boolean
215
+ editable: boolean
216
+ awaitingApproval: boolean
217
+ expiration?: number
218
+ }
219
+
220
+ export type RecordSharedFolderPermission = {
221
+ sharedFolderUid: string
222
+ resharable: boolean
223
+ editable: boolean
224
+ revision?: number
225
+ expiration?: number
226
+ }
227
+
228
+ export type RecordShareInfo = {
229
+ recordUid: string
230
+ userPermissions: RecordUserPermission[]
231
+ sharedFolderPermissions: RecordSharedFolderPermission[]
232
+ }
233
+
234
+ function bytesToUid(bytes: Uint8Array | null | undefined): string | undefined {
235
+ return bytes && bytes.length > 0 ? webSafe64FromBytes(bytes) : undefined
236
+ }
237
+
238
+ function longToNumber(value: number | { toNumber: () => number } | null | undefined): number | undefined {
239
+ if (value == null) return undefined
240
+ return typeof value === 'number' ? value : value.toNumber()
241
+ }
242
+
243
+ export async function getRecordShareInfo(auth: Auth, recordUid: string): Promise<RecordShareInfo | null> {
244
+ const msg = getRecordsDetailsMessage({
245
+ clientTime: Date.now(),
246
+ recordUid: [normal64Bytes(recordUid)],
247
+ recordDetailsInclude: Records.RecordDetailsInclude.SHARE_ONLY,
248
+ })
249
+
250
+ let response: Records.IGetRecordDataWithAccessInfoResponse
251
+ try {
252
+ response = await auth.executeRest(msg)
253
+ } catch (err) {
254
+ throw new KeeperSdkError(
255
+ `Failed to fetch share info for ${recordUid}: ${extractErrorMessage(err)}`
256
+ )
257
+ }
258
+
259
+ const detail = response.recordDataWithAccessInfo?.[0]
260
+ if (!detail) return null
261
+
262
+ const userPermissions: RecordUserPermission[] = (detail.userPermission ?? []).map((u) => ({
263
+ username: u.username || '',
264
+ accountUid: bytesToUid(u.accountUid),
265
+ owner: !!u.owner,
266
+ shareAdmin: !!u.shareAdmin,
267
+ shareable: !!u.sharable,
268
+ editable: !!u.editable,
269
+ awaitingApproval: !!u.awaitingApproval,
270
+ expiration: longToNumber(u.expiration as number | null | undefined),
271
+ }))
272
+
273
+ const sharedFolderPermissions: RecordSharedFolderPermission[] = (detail.sharedFolderPermission ?? []).map((s) => ({
274
+ sharedFolderUid: bytesToUid(s.sharedFolderUid) ?? '',
275
+ resharable: !!s.resharable,
276
+ editable: !!s.editable,
277
+ revision: longToNumber(s.revision as number | null | undefined),
278
+ expiration: longToNumber(s.expiration as number | null | undefined),
279
+ }))
280
+
281
+ return { recordUid, userPermissions, sharedFolderPermissions }
282
+ }
@@ -0,0 +1,163 @@
1
+ import type {
2
+ VaultStorage,
3
+ VaultStorageData,
4
+ VaultStorageKind,
5
+ VaultStorageResult,
6
+ Dependency,
7
+ Dependencies,
8
+ RemovedDependencies,
9
+ DRecord,
10
+ } from '@keeper-security/keeperapi'
11
+ import { webSafe64FromBytes } from '@keeper-security/keeperapi'
12
+ import { VaultObjectKind } from '../folders/folderHelpers'
13
+
14
+ export class InMemoryStorage implements VaultStorage {
15
+ private keys = new Map<string, Uint8Array>()
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- KeyStorage.saveObject<T> is unconstrained
17
+ private objects = new Map<string, any>()
18
+ private store = new Map<string, Map<string, VaultStorageData>>()
19
+ private dependenciesByParent = new Map<string, Dependency[]>()
20
+ private arrayCache = new Map<string, VaultStorageData[]>()
21
+
22
+ public async getKeyBytes(keyId: string): Promise<Uint8Array | undefined> {
23
+ return this.keys.get(keyId)
24
+ }
25
+
26
+ public async saveKeyBytes(keyId: string, key: Uint8Array): Promise<void> {
27
+ this.keys.set(keyId, key)
28
+ }
29
+
30
+ public async getObject<T>(key: string): Promise<T | undefined> {
31
+ return this.objects.get(key) as T | undefined
32
+ }
33
+
34
+ public async saveObject<T>(key: string, value: T): Promise<void> {
35
+ this.objects.set(key, value)
36
+ }
37
+
38
+ public async put(item: VaultStorageData): Promise<void> {
39
+ const kind = item.kind
40
+ if (!this.store.has(kind)) {
41
+ this.store.set(kind, new Map())
42
+ }
43
+ const uid = this.extractUid(item)
44
+ this.store.get(kind)!.set(uid, item)
45
+ this.arrayCache.delete(kind)
46
+ }
47
+
48
+ public async get<T extends VaultStorageKind>(kind: T, uid?: string): Promise<VaultStorageResult<T>> {
49
+ const kindMap = this.store.get(kind)
50
+ if (!kindMap) return undefined as VaultStorageResult<T>
51
+
52
+ if (uid) {
53
+ return kindMap.get(uid) as VaultStorageResult<T>
54
+ }
55
+ const first = kindMap.values().next()
56
+ return (first.done ? undefined : first.value) as VaultStorageResult<T>
57
+ }
58
+
59
+ public async delete(kind: VaultStorageKind, uid: string | Uint8Array): Promise<void> {
60
+ const uidStr = typeof uid === 'string' ? uid : webSafe64FromBytes(uid)
61
+ this.store.get(kind)?.delete(uidStr)
62
+ this.arrayCache.delete(kind)
63
+ }
64
+
65
+ public async clear(): Promise<void> {
66
+ this.store.clear()
67
+ this.keys.clear()
68
+ this.objects.clear()
69
+ this.dependenciesByParent.clear()
70
+ this.arrayCache.clear()
71
+ }
72
+
73
+ public async getDependencies(uid: string): Promise<Dependency[] | undefined> {
74
+ return this.dependenciesByParent.get(uid)
75
+ }
76
+
77
+ public async addDependencies(dependencies: Dependencies): Promise<void> {
78
+ for (const [parentUid, children] of Object.entries(dependencies)) {
79
+ if (!this.dependenciesByParent.has(parentUid)) {
80
+ this.dependenciesByParent.set(parentUid, [])
81
+ }
82
+ const existing = this.dependenciesByParent.get(parentUid)!
83
+ const seenChildUids = new Set(existing.map((dependency) => dependency.uid))
84
+ for (const child of children) {
85
+ if (!seenChildUids.has(child.uid)) {
86
+ existing.push(child)
87
+ seenChildUids.add(child.uid)
88
+ }
89
+ }
90
+ }
91
+ }
92
+
93
+ public async removeDependencies(dependencies: RemovedDependencies): Promise<void> {
94
+ for (const [parentUid, children] of Object.entries(dependencies)) {
95
+ if (children === '*') {
96
+ this.dependenciesByParent.delete(parentUid)
97
+ } else {
98
+ const existing = this.dependenciesByParent.get(parentUid)
99
+ if (existing) {
100
+ const removeSet = children as Set<string>
101
+ this.dependenciesByParent.set(
102
+ parentUid,
103
+ existing.filter((dependency) => !removeSet.has(dependency.uid))
104
+ )
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ public getAll<T extends VaultStorageData>(kind: VaultStorageKind): T[] {
111
+ const cached = this.arrayCache.get(kind)
112
+ if (cached) return cached as T[]
113
+
114
+ const kindMap = this.store.get(kind)
115
+ if (!kindMap) return []
116
+
117
+ const arr = Array.from(kindMap.values())
118
+ this.arrayCache.set(kind, arr)
119
+ return arr as T[]
120
+ }
121
+
122
+ public getRecords(): DRecord[] {
123
+ return this.getAll<DRecord>(VaultObjectKind.Record)
124
+ }
125
+
126
+ public getByUid<T extends VaultStorageData>(kind: VaultStorageKind, uid: string): T | undefined {
127
+ return this.store.get(kind)?.get(uid) as T | undefined
128
+ }
129
+
130
+ public getCount(kind: VaultStorageKind): number {
131
+ return this.store.get(kind)?.size ?? 0
132
+ }
133
+
134
+ private extractUid(item: VaultStorageData): string {
135
+ const record = item as VaultStorageData & {
136
+ uid?: string
137
+ token?: string
138
+ sharedFolderUid?: string
139
+ recordUid?: string
140
+ accountUid?: string | Uint8Array
141
+ teamUid?: string
142
+ }
143
+ const accountUidStr =
144
+ typeof record.accountUid === 'string'
145
+ ? record.accountUid
146
+ : record.accountUid instanceof Uint8Array
147
+ ? webSafe64FromBytes(record.accountUid)
148
+ : undefined
149
+ if (record.uid) return record.uid
150
+ if (record.token) return record.token
151
+ if (record.sharedFolderUid && record.recordUid) {
152
+ return `${record.sharedFolderUid}:${record.recordUid}`
153
+ }
154
+ if (record.sharedFolderUid && accountUidStr) {
155
+ return `${record.sharedFolderUid}:${accountUidStr}`
156
+ }
157
+ if (record.sharedFolderUid && record.teamUid) {
158
+ return `${record.sharedFolderUid}:${record.teamUid}`
159
+ }
160
+ if (item.kind === VaultObjectKind.User && accountUidStr) return accountUidStr
161
+ return '_singleton_'
162
+ }
163
+ }
@@ -0,0 +1,61 @@
1
+ import type { Auth } from '@keeper-security/keeperapi'
2
+ import { KeeperSdkError, ResultCodes } from '../utils'
3
+ import {
4
+ formatTeamsTable,
5
+ listTeams,
6
+ renderTeamsAsciiTable,
7
+ type FormatTeamsTableOptions,
8
+ type FormattedTeamsTable,
9
+ type ListTeamRow,
10
+ type ListTeamsOptions,
11
+ } from './listTeams'
12
+ import {
13
+ formatTeamView,
14
+ teamViewTable,
15
+ viewTeam,
16
+ type FormatTeamViewOptions,
17
+ type FormattedTeamViewTable,
18
+ type TeamView,
19
+ } from './viewTeam'
20
+
21
+ export type AuthProvider = () => Auth
22
+
23
+ export class TeamManager {
24
+ private readonly authProvider: AuthProvider
25
+
26
+ constructor(authProvider: AuthProvider) {
27
+ this.authProvider = authProvider
28
+ }
29
+
30
+ public async listTeams(options: ListTeamsOptions = {}): Promise<ListTeamRow[]> {
31
+ return listTeams(this.requireAuth(), options)
32
+ }
33
+
34
+ public formatTeamsTable(rows: ListTeamRow[], options: FormatTeamsTableOptions = {}): FormattedTeamsTable {
35
+ return formatTeamsTable(rows, options)
36
+ }
37
+
38
+ public renderTeamsAsciiTable(table: FormattedTeamsTable, options: { minColWidth?: number } = {}): string {
39
+ return renderTeamsAsciiTable(table, options)
40
+ }
41
+
42
+ public async viewTeam(identifier: string): Promise<TeamView> {
43
+ return viewTeam(this.requireAuth(), identifier)
44
+ }
45
+
46
+ public formatTeamView(view: TeamView, options: FormatTeamViewOptions = {}): FormattedTeamViewTable {
47
+ return formatTeamView(view, options)
48
+ }
49
+
50
+ public teamViewTable(table: FormattedTeamViewTable): string {
51
+ return teamViewTable(table)
52
+ }
53
+
54
+ private requireAuth(): Auth {
55
+ const auth = this.authProvider()
56
+ if (!auth) {
57
+ throw new KeeperSdkError('You are not logged in. Please log in first.', ResultCodes.NOT_LOGGED_IN)
58
+ }
59
+ return auth
60
+ }
61
+ }