@indigoai-us/hq-cloud 5.21.0 → 5.23.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 (77) hide show
  1. package/dist/index.d.ts +10 -4
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +10 -2
  4. package/dist/index.js.map +1 -1
  5. package/dist/journal.d.ts +76 -1
  6. package/dist/journal.d.ts.map +1 -1
  7. package/dist/journal.js +148 -1
  8. package/dist/journal.js.map +1 -1
  9. package/dist/journal.test.js +251 -5
  10. package/dist/journal.test.js.map +1 -1
  11. package/dist/prefix-coalesce.d.ts +38 -0
  12. package/dist/prefix-coalesce.d.ts.map +1 -0
  13. package/dist/prefix-coalesce.js +69 -0
  14. package/dist/prefix-coalesce.js.map +1 -0
  15. package/dist/prefix-coalesce.test.d.ts +2 -0
  16. package/dist/prefix-coalesce.test.d.ts.map +1 -0
  17. package/dist/prefix-coalesce.test.js +77 -0
  18. package/dist/prefix-coalesce.test.js.map +1 -0
  19. package/dist/public-surface.test.d.ts +15 -0
  20. package/dist/public-surface.test.d.ts.map +1 -0
  21. package/dist/public-surface.test.js +105 -0
  22. package/dist/public-surface.test.js.map +1 -0
  23. package/dist/remote-pull.d.ts +145 -1
  24. package/dist/remote-pull.d.ts.map +1 -1
  25. package/dist/remote-pull.js +258 -1
  26. package/dist/remote-pull.js.map +1 -1
  27. package/dist/remote-pull.test.js +470 -2
  28. package/dist/remote-pull.test.js.map +1 -1
  29. package/dist/schemas/source-channels.d.ts +14 -0
  30. package/dist/schemas/source-channels.d.ts.map +1 -1
  31. package/dist/schemas/source-channels.js +16 -0
  32. package/dist/schemas/source-channels.js.map +1 -1
  33. package/dist/scope-shrink.d.ts +109 -0
  34. package/dist/scope-shrink.d.ts.map +1 -0
  35. package/dist/scope-shrink.js +196 -0
  36. package/dist/scope-shrink.js.map +1 -0
  37. package/dist/scope-shrink.test.d.ts +13 -0
  38. package/dist/scope-shrink.test.d.ts.map +1 -0
  39. package/dist/scope-shrink.test.js +342 -0
  40. package/dist/scope-shrink.test.js.map +1 -0
  41. package/dist/sources/get.d.ts.map +1 -1
  42. package/dist/sources/get.js +6 -3
  43. package/dist/sources/get.js.map +1 -1
  44. package/dist/sources/get.test.js +7 -7
  45. package/dist/sources/get.test.js.map +1 -1
  46. package/dist/sources/list.d.ts.map +1 -1
  47. package/dist/sources/list.js +4 -2
  48. package/dist/sources/list.js.map +1 -1
  49. package/dist/sources/list.test.js +6 -6
  50. package/dist/sources/list.test.js.map +1 -1
  51. package/dist/types.d.ts +48 -1
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/vault-client.d.ts +178 -0
  54. package/dist/vault-client.d.ts.map +1 -1
  55. package/dist/vault-client.js +73 -0
  56. package/dist/vault-client.js.map +1 -1
  57. package/dist/vault-client.test.js +226 -0
  58. package/dist/vault-client.test.js.map +1 -1
  59. package/package.json +1 -1
  60. package/src/index.ts +68 -0
  61. package/src/journal.test.ts +284 -5
  62. package/src/journal.ts +167 -2
  63. package/src/prefix-coalesce.test.ts +95 -0
  64. package/src/prefix-coalesce.ts +72 -0
  65. package/src/public-surface.test.ts +112 -0
  66. package/src/remote-pull.test.ts +540 -3
  67. package/src/remote-pull.ts +419 -2
  68. package/src/schemas/source-channels.ts +17 -0
  69. package/src/scope-shrink.test.ts +402 -0
  70. package/src/scope-shrink.ts +264 -0
  71. package/src/sources/get.test.ts +7 -7
  72. package/src/sources/get.ts +6 -3
  73. package/src/sources/list.test.ts +6 -6
  74. package/src/sources/list.ts +4 -2
  75. package/src/types.ts +49 -1
  76. package/src/vault-client.test.ts +335 -0
  77. package/src/vault-client.ts +223 -0
@@ -151,6 +151,137 @@ export interface CreateEntityResult {
151
151
  entity: EntityInfo;
152
152
  }
153
153
 
154
+ // -- Browse-vs-sync types (US-002, US-003, US-004) -----------------------
155
+
156
+ /**
157
+ * Source kind for an explicit per-company file-ACL grant. Mirrors the
158
+ * server enum in hq-pro `vault-service/handlers/files-grants.ts`.
159
+ *
160
+ * `'open'` collapses two server-side shapes that are indistinguishable to
161
+ * the caller — the legacy `acl.open === true` floor and an explicit
162
+ * `granteeType: 'company-wide'` row. Both mean "every active member of
163
+ * this company sees this prefix".
164
+ */
165
+ export type GrantSource = "person" | "email" | "group" | "open";
166
+
167
+ /** Permission level surfaced on a grant row. Matches `AclPermission`. */
168
+ export type GrantPermission = "read" | "write" | "admin";
169
+
170
+ /**
171
+ * One row in the response of `GET /v1/files/grants?company={uid}`.
172
+ *
173
+ * Role-bypass (owner/admin) entries are intentionally excluded by the
174
+ * server — this is the caller's EXPLICIT grant graph, not the full set
175
+ * of prefixes they can touch by virtue of role.
176
+ */
177
+ export interface ExplicitGrant {
178
+ companyUid: string;
179
+ path: string;
180
+ permission: GrantPermission;
181
+ source: GrantSource;
182
+ }
183
+
184
+ /**
185
+ * Effective sync mode for a single membership. Mirrors the server's
186
+ * resolved view from `GET /v1/memberships/{id}/sync-config`:
187
+ *
188
+ * - `shared` — sync only `shared/` and the caller's `personal/` prefix
189
+ * - `all` — sync every prefix the caller has read access to
190
+ * - `custom` — sync the explicit `customPaths` list (server validates)
191
+ *
192
+ * `isDefault: true` means no row exists in DDB and the server is
193
+ * falling back to its built-in default (currently `'all'` for legacy
194
+ * memberships created pre-US-003). When `true`, `updatedAt`/`updatedBy`
195
+ * are absent because there's no row to attribute.
196
+ */
197
+ export type SyncMode = "shared" | "all" | "custom";
198
+
199
+ export interface MembershipSyncConfig {
200
+ membershipId: string;
201
+ syncMode: SyncMode;
202
+ customPaths?: string[];
203
+ /**
204
+ * `true` when the server returned the built-in default because no
205
+ * sync-config row exists for this membership. PUT always returns
206
+ * `false` — writing the row is what makes it non-default.
207
+ */
208
+ isDefault: boolean;
209
+ /** Present only when a sync-config row exists (i.e. `isDefault: false`). */
210
+ updatedAt?: string;
211
+ /** Present only when a sync-config row exists. PersonUid of the writer. */
212
+ updatedBy?: string;
213
+ }
214
+
215
+ /**
216
+ * Input shape for {@link VaultClient.setMembershipSyncConfig}. The server
217
+ * validates the combination — `customPaths` is required when `syncMode`
218
+ * is `'custom'` and rejected otherwise.
219
+ */
220
+ export interface SetMembershipSyncConfigInput {
221
+ syncMode: SyncMode;
222
+ customPaths?: string[];
223
+ }
224
+
225
+ // -- Raw vend (legacy POST /vend, purpose-aware after US-009) -------------
226
+
227
+ /**
228
+ * Why the caller is requesting STS-scoped credentials. Mirrors the
229
+ * hq-pro vault-service enum (`src/vault-service/policy-builder.ts`).
230
+ *
231
+ * - `'sync'` — background machine sync. Role-bypass MUST NOT widen
232
+ * the path set: credentials are scoped to exactly the requested
233
+ * paths (which the sync engine has already narrowed via US-005).
234
+ * - `'browse'` — interactive exploration (hq-console Explore,
235
+ * `hq files browse`, admin spelunking). Admin/owner role-bypass
236
+ * APPLIES — the caller may receive credentials covering paths
237
+ * beyond their explicit ACL grants.
238
+ *
239
+ * The server defaults missing/empty to `'sync'` (the safer choice).
240
+ * The client doesn't mirror that default — every caller should be
241
+ * explicit about its intent so audit rows are accurate.
242
+ */
243
+ export type VendPurpose = "sync" | "browse";
244
+
245
+ export type VaultOperation = "read-only" | "read-write" | "staged-write";
246
+
247
+ /**
248
+ * Input shape for {@link VaultClient.vend}. The server validates
249
+ * combinations — e.g. `purpose: 'sync'` rejects bucket-wide `'*'` paths
250
+ * as defense in depth against role-bypass widening on the sync path.
251
+ */
252
+ export interface VendInput {
253
+ paths: string[];
254
+ operations: VaultOperation;
255
+ /** Why these credentials are being vended. See {@link VendPurpose}. */
256
+ purpose: VendPurpose;
257
+ /** STS session lifetime in seconds. Server default is 900 (15m). */
258
+ duration?: number;
259
+ }
260
+
261
+ export interface VendCredentials {
262
+ accessKeyId: string;
263
+ secretAccessKey: string;
264
+ sessionToken: string;
265
+ /** ISO-8601 STS-native expiration string. */
266
+ expiration: string;
267
+ }
268
+
269
+ export interface VendResult {
270
+ credentials: VendCredentials;
271
+ /** Echo of the server-resolved paths after ACL intersection. */
272
+ paths: string[];
273
+ operations: VaultOperation;
274
+ /** Echo of the effective purpose (server-defaulted to 'sync' if absent). */
275
+ purpose: VendPurpose;
276
+ /**
277
+ * Size of the rendered IAM session policy in characters. Lets the
278
+ * caller detect when it's nearing the 2048-char IAM ceiling so it can
279
+ * fan out across multiple vends or shrink its path set.
280
+ */
281
+ policySize: number;
282
+ requestId?: string;
283
+ }
284
+
154
285
  // -- STS child vending (VLT-8) --------------------------------------------
155
286
 
156
287
  export type TaskAction = "read" | "write";
@@ -356,6 +487,71 @@ export class VaultClient {
356
487
  return data.invites;
357
488
  }
358
489
 
490
+ // -- Browse-vs-sync (US-002, US-003, US-004) -----------------------------
491
+
492
+ /**
493
+ * List the caller's EXPLICIT per-company file-ACL grants. Backed by
494
+ * `GET /v1/files/grants?company={companyUid}` (hq-pro US-002).
495
+ *
496
+ * Role-bypass (owner/admin) entries are excluded server-side — the
497
+ * response is the caller's actual grant graph, not the full set of
498
+ * prefixes they can touch by virtue of role. Used by the
499
+ * browse-vs-sync UI to render an honest grant graph and by the
500
+ * sync engine to narrow what it pulls.
501
+ *
502
+ * Returns `[]` (NOT a 404) when the caller has no explicit grants in
503
+ * this company, so call sites can treat "empty graph" as a normal
504
+ * state without catching errors.
505
+ */
506
+ async listMyExplicitGrants(companyUid: string): Promise<ExplicitGrant[]> {
507
+ const data = await this.get<{ grants: ExplicitGrant[]; computedAt: string }>(
508
+ `/v1/files/grants?company=${encodeURIComponent(companyUid)}`,
509
+ );
510
+ return data.grants ?? [];
511
+ }
512
+
513
+ /**
514
+ * Read the effective sync-mode for a single membership. Backed by
515
+ * `GET /v1/memberships/{id}/sync-config` (hq-pro US-003).
516
+ *
517
+ * The server resolves the effective view — when no row exists for the
518
+ * membership it returns the built-in default with `isDefault: true`
519
+ * and omits `updatedAt`/`updatedBy`. Callers should treat `isDefault:
520
+ * true` as "no explicit config yet" rather than special-casing 404.
521
+ *
522
+ * Authorization: caller must own the membership OR hold admin/owner
523
+ * on the company that the membership belongs to. The server 404s
524
+ * tombstoned/revoked memberships.
525
+ */
526
+ async getMembershipSyncConfig(
527
+ membershipId: string,
528
+ ): Promise<MembershipSyncConfig> {
529
+ return this.get<MembershipSyncConfig>(
530
+ `/v1/memberships/${encodeURIComponent(membershipId)}/sync-config`,
531
+ );
532
+ }
533
+
534
+ /**
535
+ * Write the sync-mode for a single membership. Backed by
536
+ * `PUT /v1/memberships/{id}/sync-config` (hq-pro US-003).
537
+ *
538
+ * Server validates: `customPaths` is required when `syncMode` is
539
+ * `'custom'` and rejected otherwise. The returned row reflects the
540
+ * persisted state with `isDefault: false` (writing the row is what
541
+ * makes it non-default) and the server-assigned `updatedAt` +
542
+ * `updatedBy`.
543
+ */
544
+ async setMembershipSyncConfig(
545
+ membershipId: string,
546
+ partial: SetMembershipSyncConfigInput,
547
+ ): Promise<MembershipSyncConfig> {
548
+ return this.request<MembershipSyncConfig>(
549
+ "PUT",
550
+ `/v1/memberships/${encodeURIComponent(membershipId)}/sync-config`,
551
+ partial,
552
+ );
553
+ }
554
+
359
555
  // -- Entity operations ----------------------------------------------------
360
556
 
361
557
  readonly entity = {
@@ -467,6 +663,33 @@ export class VaultClient {
467
663
  return data;
468
664
  }
469
665
 
666
+ // -- Raw vend (POST /vend) ------------------------------------------------
667
+
668
+ /**
669
+ * POST `/vend` — vend STS-scoped credentials for an explicit path list.
670
+ *
671
+ * This is the legacy raw-vend endpoint (distinct from `/sts/vend`,
672
+ * `/sts/vend-self`, and `/sts/vend-child`). Per US-009 it accepts a
673
+ * `purpose` discriminator that controls whether admin/owner
674
+ * role-bypass widens the resulting session policy beyond the
675
+ * caller's explicit ACL grants:
676
+ *
677
+ * - `purpose: 'browse'` — role-bypass APPLIES (interactive
678
+ * `hq files browse`, admin spelunking).
679
+ * - `purpose: 'sync'` — role-bypass SUPPRESSED (background sync;
680
+ * credentials are scoped to exactly what the caller has explicitly
681
+ * been granted, regardless of role).
682
+ *
683
+ * The server defaults missing/empty to `'sync'` but every first-party
684
+ * caller should be explicit so audit attribution is correct.
685
+ *
686
+ * Used by `hq files browse`/`hq files cat` (US-008) to peek at vault
687
+ * objects without ever materialising them under `companies/{co}/`.
688
+ */
689
+ async vend(input: VendInput): Promise<VendResult> {
690
+ return this.post<VendResult>("/vend", input);
691
+ }
692
+
470
693
  // -- STS operations (VLT-8) -----------------------------------------------
471
694
 
472
695
  readonly sts = {