@indigoai-us/hq-cloud 5.1.8 → 5.1.9
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.
- package/dist/bin/sync-runner.d.ts +26 -3
- package/dist/bin/sync-runner.d.ts.map +1 -1
- package/dist/bin/sync-runner.js +77 -2
- package/dist/bin/sync-runner.js.map +1 -1
- package/dist/bin/sync-runner.test.js +165 -9
- package/dist/bin/sync-runner.test.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/vault-client.d.ts +43 -0
- package/dist/vault-client.d.ts.map +1 -1
- package/dist/vault-client.js +53 -0
- package/dist/vault-client.js.map +1 -1
- package/dist/vault-client.test.js +135 -0
- package/dist/vault-client.test.js.map +1 -1
- package/package.json +1 -1
- package/src/bin/sync-runner.test.ts +200 -13
- package/src/bin/sync-runner.ts +114 -5
- package/src/index.ts +1 -0
- package/src/vault-client.test.ts +173 -0
- package/src/vault-client.ts +78 -0
package/src/vault-client.ts
CHANGED
|
@@ -105,10 +105,21 @@ export interface EntityInfo {
|
|
|
105
105
|
uid: string;
|
|
106
106
|
slug: string;
|
|
107
107
|
type: string;
|
|
108
|
+
/** Human-readable display name — surfaced in UIs that list companies. */
|
|
109
|
+
name?: string;
|
|
108
110
|
bucketName?: string;
|
|
109
111
|
status: string;
|
|
110
112
|
}
|
|
111
113
|
|
|
114
|
+
export interface PendingInviteByEmail {
|
|
115
|
+
membershipKey: string;
|
|
116
|
+
companyUid: string;
|
|
117
|
+
role: MembershipRole;
|
|
118
|
+
inviteToken?: string;
|
|
119
|
+
invitedBy: string;
|
|
120
|
+
invitedAt: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
112
123
|
export interface CreateEntityInput {
|
|
113
124
|
type: "person" | "company";
|
|
114
125
|
slug: string;
|
|
@@ -238,6 +249,31 @@ export class VaultClient {
|
|
|
238
249
|
return data.memberships;
|
|
239
250
|
}
|
|
240
251
|
|
|
252
|
+
/**
|
|
253
|
+
* List the caller's email-keyed pending invites. Server reads the email
|
|
254
|
+
* from the Cognito JWT, so no parameters are needed client-side.
|
|
255
|
+
*
|
|
256
|
+
* Used on first sign-in (installer + sync-runner) to detect invites that
|
|
257
|
+
* were sent to the caller's email before they had a person entity. Pair
|
|
258
|
+
* with {@link claimPendingInvitesByEmail} to rewrite those rows once the
|
|
259
|
+
* person exists.
|
|
260
|
+
*/
|
|
261
|
+
async listMyPendingInvitesByEmail(): Promise<PendingInviteByEmail[]> {
|
|
262
|
+
const data = await this.get<{ invites: PendingInviteByEmail[] }>(
|
|
263
|
+
"/membership/pending-by-email",
|
|
264
|
+
);
|
|
265
|
+
return data.invites ?? [];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Rewrite every email-keyed pending invite for the caller's email so it
|
|
270
|
+
* becomes personUid-keyed. Idempotent — zero-cost for returning users who
|
|
271
|
+
* have no pending invites. The caller's email is inferred from the JWT.
|
|
272
|
+
*/
|
|
273
|
+
async claimPendingInvitesByEmail(personUid: string): Promise<void> {
|
|
274
|
+
await this.post("/membership/claim-by-email", { personUid });
|
|
275
|
+
}
|
|
276
|
+
|
|
241
277
|
async listMembersOfCompany(companyUid: string): Promise<Membership[]> {
|
|
242
278
|
const data = await this.get<{ members: Membership[] }>(
|
|
243
279
|
`/membership/company/${encodeURIComponent(companyUid)}`,
|
|
@@ -279,8 +315,50 @@ export class VaultClient {
|
|
|
279
315
|
const data = await this.post<CreateEntityResult>("/entity", input);
|
|
280
316
|
return data.entity;
|
|
281
317
|
},
|
|
318
|
+
|
|
319
|
+
/** Return every entity of `type` owned by the caller (scoped by JWT). */
|
|
320
|
+
listByType: async (type: string): Promise<EntityInfo[]> => {
|
|
321
|
+
const data = await this.get<{ entities: EntityInfo[] }>(
|
|
322
|
+
`/entity/by-type/${encodeURIComponent(type)}`,
|
|
323
|
+
);
|
|
324
|
+
return data.entities ?? [];
|
|
325
|
+
},
|
|
282
326
|
};
|
|
283
327
|
|
|
328
|
+
// -- Identity bootstrap ---------------------------------------------------
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Return the caller's person entity, creating it if one does not exist.
|
|
332
|
+
*
|
|
333
|
+
* Mirrors the installer's `ensurePersonEntity` bootstrap (`vault-handoff.ts`):
|
|
334
|
+
* pre-condition for {@link claimPendingInvitesByEmail}, which needs a
|
|
335
|
+
* concrete `personUid` to rewrite the email-keyed rows against.
|
|
336
|
+
*
|
|
337
|
+
* The slug is derived from `displayName`; if slugification yields an empty
|
|
338
|
+
* string, falls back to `user-<last-8-of-ownerSub>` so the POST always has
|
|
339
|
+
* a non-empty slug.
|
|
340
|
+
*/
|
|
341
|
+
async ensureMyPersonEntity(hints: {
|
|
342
|
+
ownerSub: string;
|
|
343
|
+
displayName: string;
|
|
344
|
+
}): Promise<EntityInfo> {
|
|
345
|
+
const existing = await this.entity.listByType("person");
|
|
346
|
+
if (existing.length > 0) return existing[0];
|
|
347
|
+
|
|
348
|
+
const slug =
|
|
349
|
+
hints.displayName
|
|
350
|
+
.toLowerCase()
|
|
351
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
352
|
+
.replace(/^-+|-+$/g, "")
|
|
353
|
+
.slice(0, 63) || `user-${hints.ownerSub.slice(-8).toLowerCase()}`;
|
|
354
|
+
|
|
355
|
+
return this.entity.create({
|
|
356
|
+
type: "person",
|
|
357
|
+
name: hints.displayName,
|
|
358
|
+
slug,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
284
362
|
// -- Provisioning operations (VLT-2) -----------------------------------------
|
|
285
363
|
|
|
286
364
|
async provisionBucket(companyUid: string): Promise<{ bucketName: string; kmsKeyId: string }> {
|