@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.
@@ -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 }> {