@qaecy/cue-sdk 0.0.37 → 0.0.39

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/lib/models.d.ts CHANGED
@@ -128,6 +128,17 @@ export interface ProjectSettings {
128
128
  /** Processing tier determining credit costs. Defaults to "l" if not set. */
129
129
  tier?: 's' | 'm' | 'l';
130
130
  }
131
+ /** One daily snapshot in `QleverStats.history` — a calendar day this index's stats were (re)computed. */
132
+ export interface QleverStatsHistoryEntry {
133
+ /** UTC calendar day, `YYYY-MM-DD`. */
134
+ date: string;
135
+ numDocuments: number | null;
136
+ numTriples: number | null;
137
+ numSubjects: number | null;
138
+ numPredicates: number | null;
139
+ numObjects: number | null;
140
+ indexSizeBytes: number | null;
141
+ }
131
142
  export interface QleverStats {
132
143
  /** ISO timestamp of when this index was first created (init or clone) — null for indexes built before this field existed. */
133
144
  created: string | null;
@@ -148,6 +159,8 @@ export interface QleverStats {
148
159
  /** Percentage of entity mentions that are resolved: (resolved / total) * 100 */
149
160
  resolutionPct: number | null;
150
161
  avgEntitiesPerDoc: number | null;
162
+ /** One entry per calendar day this index's stats were (re)computed, oldest first. Frozen while the index is idled. */
163
+ history: QleverStatsHistoryEntry[];
151
164
  }
152
165
  export interface ProjectData {
153
166
  id: string;
@@ -161,6 +174,9 @@ export interface ProjectData {
161
174
  alternativeIDs: string[];
162
175
  projectSettings: ProjectSettings;
163
176
  qleverStats?: QleverStats | null;
177
+ /** Set by a superadmin's soft delete — the project doc, index, and storage remain intact. */
178
+ deleted?: boolean;
179
+ deletedAt?: string | null;
164
180
  }
165
181
  export interface CreateProjectOptions {
166
182
  /** The organization this project belongs to */
@@ -180,6 +196,18 @@ export interface CreateProjectOptions {
180
196
  /** Processing tier determining credit costs. */
181
197
  tier?: 's' | 'm' | 'l';
182
198
  }
199
+ export interface ProjectLocation {
200
+ lat: number;
201
+ lng: number;
202
+ }
203
+ /**
204
+ * Portal-only project metadata (currently just an optional map location) —
205
+ * deliberately kept off `ProjectData`/Firestore, stored as its own small blob
206
+ * instead (see `CueProjects.getProjectMetadata`/`setProjectMetadata`).
207
+ */
208
+ export interface ProjectMetadata {
209
+ location?: ProjectLocation | null;
210
+ }
183
211
  export interface SyncProgress {
184
212
  percent: number;
185
213
  syncCount: number;
@@ -309,7 +337,153 @@ export interface OrganizationData {
309
337
  admins: string[];
310
338
  members: string[];
311
339
  alternativeIDs: string[];
312
- domain: string;
340
+ domains: string[];
341
+ }
342
+ /** One organisation matched by `CueAdmin.searchOrganizations`. */
343
+ export interface AdminOrgSearchResult {
344
+ id: string;
345
+ name: string;
346
+ created: string | null;
347
+ adminCount: number;
348
+ /** Admins and members deduplicated — an admin is also counted as a member. */
349
+ memberCount: number;
350
+ planType: 'freemium' | 'custom';
351
+ planStatus: 'active' | 'pendingPayment' | 'cancelled';
352
+ }
353
+ /** One user matched by `CueAdmin.searchUsers`, or listed by `listSuperadmins`. */
354
+ export interface AdminUserSearchResult {
355
+ uid: string;
356
+ name: string;
357
+ email: string;
358
+ }
359
+ /** One project matched by `CueAdmin.searchProjects`, with its owning org resolved. */
360
+ export interface AdminProjectSearchResult {
361
+ id: string;
362
+ name: string;
363
+ organizationID: string;
364
+ orgName: string;
365
+ created: string | null;
366
+ /** Admins, syncers and members deduplicated. */
367
+ memberCount: number;
368
+ /** Set when a superadmin has soft-deleted this project. */
369
+ deleted: boolean;
370
+ }
371
+ /** An organisation the looked-up user belongs to. */
372
+ export interface AdminUserOrgSummary {
373
+ id: string;
374
+ name: string;
375
+ isAdmin: boolean;
376
+ }
377
+ /** A project the looked-up user belongs to, with the highest role they hold on it. */
378
+ export interface AdminUserProjectSummary {
379
+ id: string;
380
+ name: string;
381
+ organizationID: string;
382
+ /** Falls back to `organizationID` when the org couldn't be resolved (guest access). */
383
+ orgName: string;
384
+ role: 'admin' | 'syncer' | 'member';
385
+ }
386
+ /**
387
+ * Full profile for one user, from `CueAdmin.getUserDetail`. Auth-record fields
388
+ * (`disabled`, `created`, `providers`, …) fall back to defaults when the
389
+ * Firestore user doc has outlived its Firebase Auth user.
390
+ */
391
+ export interface AdminUserDetail {
392
+ uid: string;
393
+ name: string;
394
+ email: string;
395
+ isSuperadmin: boolean;
396
+ disabled: boolean;
397
+ emailVerified: boolean;
398
+ created: string | null;
399
+ lastSignIn: string | null;
400
+ providers: string[];
401
+ organizations: AdminUserOrgSummary[];
402
+ projects: AdminUserProjectSummary[];
403
+ }
404
+ /** An org the deleted user belonged to, captured at delete time — see {@link AdminDeletedUserSummary}. */
405
+ export interface AdminDeletedUserOrgRef {
406
+ orgId: string;
407
+ orgName: string;
408
+ role: 'admin' | 'member';
409
+ }
410
+ /** A project the deleted user belonged to, captured at delete time — see {@link AdminDeletedUserSummary}. */
411
+ export interface AdminDeletedUserProjectRef {
412
+ projectId: string;
413
+ projectName: string;
414
+ organizationID: string;
415
+ role: 'admin' | 'syncer' | 'member';
416
+ }
417
+ /**
418
+ * One archived deletion, from `CueAdmin.listDeletedUsers`. `restoredAt` is set
419
+ * once a superadmin has restored the account — the record is kept either way
420
+ * as an audit trail.
421
+ */
422
+ export interface AdminDeletedUserSummary {
423
+ uid: string;
424
+ name: string;
425
+ email: string;
426
+ isSuperadmin: boolean;
427
+ deletedAt: string;
428
+ deletedBy: string;
429
+ orgs: AdminDeletedUserOrgRef[];
430
+ projects: AdminDeletedUserProjectRef[];
431
+ restoredAt?: string;
432
+ restoredBy?: string;
433
+ }
434
+ /** Result of `CueAdmin.restoreUser` — orgs/projects that no longer exist and so couldn't be re-granted. */
435
+ export interface AdminRestoreUserResult {
436
+ skippedOrgs: string[];
437
+ skippedProjects: string[];
438
+ }
439
+ /** Result of `CueAdmin.createOrganization`. */
440
+ export interface AdminOrganization {
441
+ id: string;
442
+ name: string;
443
+ created: string;
444
+ admins: string[];
445
+ members: string[];
446
+ domains: string[];
447
+ }
448
+ /**
449
+ * One archived org deletion, from `CueAdmin.listDeletedOrganizations`. Unlike a
450
+ * deleted user, the org doc itself is never removed — it stays in Firestore
451
+ * flagged `deleted`, with `admins`/`members` intact as the relationship
452
+ * snapshot a restore re-grants.
453
+ */
454
+ export interface AdminDeletedOrganizationSummary {
455
+ id: string;
456
+ name: string;
457
+ deletedAt: string;
458
+ deletedBy: string;
459
+ /** Members who had no other org membership at delete time, so were soft-deleted along with the org. */
460
+ cascadeDeletedUserIds: string[];
461
+ /** Projects under the org that were soft-deleted along with it. */
462
+ cascadeDeletedProjectIds: string[];
463
+ }
464
+ /** Result of `CueAdmin.restoreOrganization` — ids that couldn't be re-granted (already independently deleted/restored). */
465
+ export interface AdminRestoreOrganizationResult {
466
+ restoredProjectIds: string[];
467
+ skippedProjectIds: string[];
468
+ restoredUserIds: string[];
469
+ skippedUserIds: string[];
470
+ }
471
+ /** A user with no organisation (`listUsersWithoutOrg`) or no project (`listUsersWithoutProject`) membership. */
472
+ export interface AdminOrphanedUser {
473
+ uid: string;
474
+ name: string;
475
+ email: string;
476
+ }
477
+ /** A project with no members/syncers/admins (`listProjectsWithoutUsers`) or specifically no admin (`listProjectsWithoutAdmins`). */
478
+ export interface AdminOrphanedProject {
479
+ id: string;
480
+ name: string;
481
+ organizationID: string;
482
+ }
483
+ /** An organisation with no members (`listOrgsWithoutUsers`) or specifically no admin (`listOrgsWithoutAdmins`). */
484
+ export interface AdminOrphanedOrganization {
485
+ id: string;
486
+ name: string;
313
487
  }
314
488
  /** Org's current plan — no Stripe ids exposed to the frontend. */
315
489
  export interface OrgPlanSummary {
@@ -355,6 +529,54 @@ export interface FileTypeConsumptionDto {
355
529
  }
356
530
  /** Per-file-extension breakdown for one project within a given period — see {@link CueProfile.getProjectFileTypeBreakdown}. */
357
531
  export type FileTypeBreakdownDto = Record<string, FileTypeConsumptionDto>;
532
+ /** Requests through one gateway route on one day/month. */
533
+ export interface RouteTrafficDto {
534
+ route: string;
535
+ count: number;
536
+ avgLatencyMs: number;
537
+ /** Keyed by HTTP status code as a string, e.g. `{ '200': 5120, '404': 3 }`. */
538
+ statusCounts: Record<string, number>;
539
+ }
540
+ export interface DayTrafficDto {
541
+ /** `YYYY-MM-DD` (UTC). */
542
+ day: string;
543
+ routes: RouteTrafficDto[];
544
+ }
545
+ export interface MonthTrafficDto {
546
+ /** `YYYY-MM` (UTC). */
547
+ month: string;
548
+ routes: RouteTrafficDto[];
549
+ }
550
+ /** Gateway traffic for one project — see {@link CueProfile.getProjectTrafficReport}. */
551
+ export interface TrafficReportDto {
552
+ days: DayTrafficDto[];
553
+ /** Rolled-up totals for months entirely outside the day-level retention window. */
554
+ months: MonthTrafficDto[];
555
+ }
556
+ /** Opens of one portal view on one day/month. */
557
+ export interface ViewUsageDto {
558
+ /** Route path template, e.g. `projects/:id/files` — never a resolved URL. */
559
+ view: string;
560
+ count: number;
561
+ /** Opens keyed by user id. */
562
+ byUser: Record<string, number>;
563
+ }
564
+ export interface DayUsageDto {
565
+ /** `YYYY-MM-DD` (UTC). */
566
+ day: string;
567
+ views: ViewUsageDto[];
568
+ }
569
+ export interface MonthUsageDto {
570
+ /** `YYYY-MM` (UTC). */
571
+ month: string;
572
+ views: ViewUsageDto[];
573
+ }
574
+ /** Portal view opens for one project — see {@link CueProfile.getProjectUsageReport}. */
575
+ export interface UsageReportDto {
576
+ days: DayUsageDto[];
577
+ /** Rolled-up totals for months entirely outside the day-level retention window. */
578
+ months: MonthUsageDto[];
579
+ }
358
580
  export interface ProfileSSOAccount {
359
581
  id: string;
360
582
  label: string;
@@ -442,12 +664,105 @@ export interface RDFWritingDoc {
442
664
  firstRDFWrite: string;
443
665
  lastRDFWrite: string;
444
666
  }
445
- export type ProcessingStage = 'idle' | 'writing' | 'loading' | 'enriching';
667
+ /**
668
+ * `processing` covers the upload→artifact window: a file has been uploaded and a
669
+ * processor is working on it, but no `.ttl` exists yet so none of the RDF
670
+ * write/load/resolution tracking has begun. It is the *lowest*-precedence stage,
671
+ * so a project already committing RDF never appears to fall back to it.
672
+ */
673
+ export type ProcessingStage = 'idle' | 'processing' | 'writing' | 'loading' | 'enriching';
674
+ /**
675
+ * Lifecycle of a single uploaded document.
676
+ *
677
+ * - `uploaded` — in storage, no processor output yet
678
+ * - `processing` — a processor has emitted artifacts (markdown, images, fragments)
679
+ * - `extracting` — RDF exists but is not all committed to the ledger
680
+ * - `stored` — every `.ttl` produced so far is committed
681
+ * - `failed` — processing errored
682
+ *
683
+ * `stored` is not strictly final: an enricher producing further RDF later moves
684
+ * the document back to `extracting`, which is a faithful description of reality
685
+ * rather than a bug.
686
+ */
687
+ export type DocumentProcessingStage = 'uploaded' | 'processing' | 'extracting' | 'stored' | 'failed';
688
+ /** Per-document pipeline progress for one uploaded file. */
689
+ export interface DocumentProgress {
690
+ documentUUID: string;
691
+ /** Original upload name, e.g. `Rotated_wall.ifc`. */
692
+ fileName: string;
693
+ suffix: string;
694
+ sizeBytes: number;
695
+ stage: DocumentProcessingStage;
696
+ uploadedAt: string;
697
+ updatedAt: string;
698
+ finishedAt?: string;
699
+ /**
700
+ * Services that have produced output for this document, in first-seen order
701
+ * (e.g. `['processors-bim-files', 'enrichers-semantic-extraction']`). This is
702
+ * what lets the UI say *which step* a file is on.
703
+ */
704
+ contributors: string[];
705
+ rdfCount: number;
706
+ rdfStoredCount: number;
707
+ error?: string;
708
+ }
709
+ /** Counts-only per-project rollup, streamed by {@link CueProcessingApi.watchMyStatus}. */
710
+ export interface ProjectProcessingSummary {
711
+ projectId: string;
712
+ stage: ProcessingStage;
713
+ pendingDocumentCount: number;
714
+ failedDocumentCount: number;
715
+ lastActivityAt?: string;
716
+ }
717
+ /**
718
+ * Cross-project processing rollup for every project the signed-in user belongs
719
+ * to — backs a global "still working" indicator such as a badge on the header's
720
+ * project selector, which must keep updating after any per-project view closes.
721
+ */
722
+ export interface MyProcessingStatus {
723
+ projects: ProjectProcessingSummary[];
724
+ /** Sum of `pendingDocumentCount` across `projects`. */
725
+ totalPendingDocumentCount: number;
726
+ /**
727
+ * True when the user belongs to more projects than the server watches on one
728
+ * connection, so the totals cover only the watched subset. Render the count as
729
+ * approximate (e.g. `99+`) when set.
730
+ */
731
+ truncated?: boolean;
732
+ }
733
+ /** Lifecycle of a superadmin document-reprocess request. */
734
+ export type ReprocessJobStatus = 'queued' | 'purging-rdf' | 'purging-blobs' | 'publishing' | 'succeeded' | 'failed';
735
+ /**
736
+ * Progress of one document reprocess (`POST /commands/document/:uuid/reprocess`),
737
+ * pushed on the same socket as the rest of the pipeline status.
738
+ */
739
+ export interface DocumentReprocessJob {
740
+ processId: string;
741
+ /** Project id — named `space_id` to match the pipeline's Firestore convention. */
742
+ space_id: string;
743
+ documentUUID: string;
744
+ requestedBy: string;
745
+ requestedAt: string;
746
+ status: ReprocessJobStatus;
747
+ /** Named graphs that were resolved for the document and retracted. */
748
+ graphs?: string[];
749
+ quadsRetracted?: number;
750
+ blobsDeleted?: number;
751
+ publishedTopics?: string[];
752
+ /** Sub-steps requested but not run (e.g. `retrigger` unreachable). */
753
+ skipped?: string[];
754
+ error?: string;
755
+ finishedAt?: string;
756
+ }
446
757
  /**
447
758
  * Aggregated, per-project pipeline status pushed live by the `accessors-data-views`
448
759
  * processing-status WebSocket (see `CueProcessingApi.watchStatus`). Shape mirrors
449
760
  * `cue-ui`'s `ProcessingStatus` (views/project-settings/models.ts) so it can be
450
761
  * passed straight through to `<cue-project-settings>` / `<cue-portal-upload>`.
762
+ *
763
+ * `reprocessJobs` is the one field cue-ui does not mirror — it is only consumed by
764
+ * cue-portal's resource viewer, and an extra property stays assignable to cue-ui's
765
+ * narrower interface.
451
766
  */
452
767
  export interface ProcessingStatus {
453
768
  stage: ProcessingStage;
@@ -460,6 +775,27 @@ export interface ProcessingStatus {
460
775
  lastResolutionActivityAt?: string;
461
776
  enrichmentTotalBatches?: number;
462
777
  enrichmentCompletedBatches?: number;
778
+ /** Canonical-resolver's own per-category dedup progress, separate from mention-resolver's batches above. */
779
+ canonicalResolutionCategoriesTotal?: number;
780
+ canonicalResolutionCategoriesCompleted?: number;
781
+ /** Document reprocess jobs for this project, most recently requested first. */
782
+ reprocessJobs?: DocumentReprocessJob[];
783
+ /**
784
+ * Per-document progress, newest upload first. Bounded server-side, so treat
785
+ * this as "the recent ones" and rely on the counts below for totals.
786
+ */
787
+ documents?: DocumentProgress[];
788
+ /**
789
+ * Documents not yet in a terminal stage. Exact even when `documents` was
790
+ * truncated. Optional because a client may be talking to a data-views
791
+ * deployment predating per-document tracking, which omits it — treat absent as
792
+ * "unknown", not zero.
793
+ */
794
+ pendingDocumentCount?: number;
795
+ /** Documents whose processing failed. Exact. Absent on older servers. */
796
+ failedDocumentCount?: number;
797
+ /** True when `documents` was capped server-side; the counts stay exact. */
798
+ documentsTruncated?: boolean;
463
799
  }
464
800
  export interface ViewDefinition {
465
801
  id: string;
@@ -16,13 +16,17 @@ export interface Privileges {
16
16
  editContentCategories: boolean;
17
17
  editPublicReposAvailableToAgent: boolean;
18
18
  editTier: boolean;
19
+ hardDeleteProject: boolean;
19
20
  inviteUserToProject: boolean;
20
21
  rebuildIndex: boolean;
21
22
  refreshStats: boolean;
22
23
  renameDocuments: boolean;
24
+ restoreProject: boolean;
25
+ softDeleteProject: boolean;
23
26
  uploadDocuments: boolean;
24
27
  viewAdvancedStats: boolean;
25
28
  viewCredits: boolean;
29
+ viewUsageStats: boolean;
26
30
  viewEntities: boolean;
27
31
  }
28
32
  /**
@@ -1,16 +1,22 @@
1
1
  import { CueAuth } from './auth';
2
2
  import { ReadonlySignal } from './signal';
3
- import { ProcessingStatus } from './models';
3
+ import { MyProcessingStatus, ProcessingStatus } from './models';
4
4
  export interface ProcessingStatusWatcher {
5
5
  /** Live pipeline status for the watched project; `undefined` until the first message arrives. */
6
6
  status: ReadonlySignal<ProcessingStatus | undefined>;
7
7
  /** Stops the subscription and closes the underlying WebSocket. */
8
8
  close(): void;
9
9
  }
10
+ export interface MyProcessingStatusWatcher {
11
+ /** Live cross-project rollup; `undefined` until the first message arrives. */
12
+ status: ReadonlySignal<MyProcessingStatus | undefined>;
13
+ /** Stops the subscription and closes the underlying WebSocket. */
14
+ close(): void;
15
+ }
10
16
  /**
11
17
  * Live pipeline-progress status, pushed by the `accessors-data-views`
12
- * processing-status WebSocket. Backs the upload modal and project-settings
13
- * "processing" indicators in the portal.
18
+ * processing-status WebSockets. Backs the upload modal, the project-settings
19
+ * "processing" indicators, and the header's cross-project badge.
14
20
  */
15
21
  export declare class CueProcessingApi {
16
22
  private readonly _auth;
@@ -22,4 +28,24 @@ export declare class CueProcessingApi {
22
28
  * is called.
23
29
  */
24
30
  watchStatus(projectId: string): ProcessingStatusWatcher;
31
+ /**
32
+ * Opens a live subscription to the signed-in user's cross-project processing
33
+ * rollup — every project they belong to, as counts.
34
+ *
35
+ * Intended to be opened **once at app-shell level** and kept for the session:
36
+ * it is what lets a header badge keep counting while no project view is open.
37
+ * Unlike {@link watchStatus} it takes no projectId — the server resolves
38
+ * memberships from the authenticated identity.
39
+ *
40
+ * Membership is resolved at connect time, so a project created or shared with
41
+ * the user mid-session appears after a reconnect rather than immediately.
42
+ */
43
+ watchMyStatus(): MyProcessingStatusWatcher;
44
+ /**
45
+ * Shared socket lifecycle: token fetch, connect, JSON parse, auto-reconnect.
46
+ *
47
+ * `params` are appended alongside the auth token. The token has to ride in the
48
+ * query string because browsers cannot set headers on a WebSocket handshake.
49
+ */
50
+ private _open;
25
51
  }
package/lib/profile.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { UserInfo } from 'firebase/auth';
2
2
  import { FirebaseApp } from 'firebase/app';
3
- import { APIKeyDoc, APIKeyInfo, FileTypeBreakdownDto, OrgConsumptionReportDto, OrgCreditsDto, OrgMember, OrganizationData, ProfileSSOAccount } from './models';
3
+ import { APIKeyDoc, APIKeyInfo, FileTypeBreakdownDto, OrgConsumptionReportDto, OrgCreditsDto, OrgMember, OrganizationData, ProfileSSOAccount, TrafficReportDto, UsageReportDto } from './models';
4
4
  import { CueAuth } from './auth';
5
5
  import { ReadonlySignal } from './signal';
6
6
  export declare class CueProfile {
@@ -50,6 +50,8 @@ export declare class CueProfile {
50
50
  })[]>;
51
51
  /** Returns all members of the given organisation. Caller must be an org admin or superadmin. */
52
52
  getOrgMembers(orgId: string): Promise<OrgMember[]>;
53
+ /** Returns just the given organisation's admins. Caller must be a member (or admin/superadmin). */
54
+ getOrgAdmins(orgId: string): Promise<OrgMember[]>;
53
55
  /** Adds a new member to the organisation. Caller must be an org admin or superadmin. */
54
56
  addOrgMember(orgId: string, member: {
55
57
  name: string;
@@ -64,8 +66,15 @@ export declare class CueProfile {
64
66
  * Returns the organisation's shared credit pool: `purchased`, `consumed`
65
67
  * (summed across every project the org owns), and `available`. Caller must
66
68
  * be an org admin or superadmin.
69
+ *
70
+ * The backend serves this from a short-lived cache, because computing it
71
+ * scans storage once per project in the org. Pass `{ refresh: true }` when the
72
+ * figure must be exact — before spending credits, or right after an upload —
73
+ * and accept that the call then takes as long as the computation does.
67
74
  */
68
- getOrgCredits(orgId: string): Promise<OrgCreditsDto>;
75
+ getOrgCredits(orgId: string, opts?: {
76
+ refresh?: boolean;
77
+ }): Promise<OrgCreditsDto>;
69
78
  /**
70
79
  * Per-project, per-month consumption breakdown for the org — for reporting/export, not
71
80
  * the balance itself (use {@link getOrgCredits} for that). Caller must be an org admin
@@ -81,8 +90,27 @@ export declare class CueProfile {
81
90
  * or superadmin.
82
91
  */
83
92
  getProjectFileTypeBreakdown(orgId: string, projectId: string, from: string, to: string): Promise<FileTypeBreakdownDto>;
93
+ /**
94
+ * Gateway traffic for one project within `[from, to)` (UTC `YYYY-MM-DD`, `to`
95
+ * exclusive). Superadmin-facing; caller must be an org admin or superadmin.
96
+ *
97
+ * Reads a stored aggregate rather than recomputing, so it is cheap — but it is
98
+ * still a round trip per call, so fetch it when the user asks for it, not on
99
+ * every page load.
100
+ */
101
+ getProjectTrafficReport(orgId: string, projectId: string, from?: string, to?: string): Promise<TrafficReportDto>;
102
+ /**
103
+ * Portal view opens for one project within `[from, to)` (UTC `YYYY-MM-DD`, `to`
104
+ * exclusive) — the counterpart to {@link getProjectTrafficReport}, recorded by
105
+ * the frontend rather than the gateway. Same authorization and cost profile.
106
+ */
107
+ getProjectUsageReport(orgId: string, projectId: string, from?: string, to?: string): Promise<UsageReportDto>;
108
+ /** `?from=…&to=…`, or `''` when unbounded — the backend treats missing bounds as "everything". */
109
+ private _rangeQuery;
84
110
  /** Manual/support credit grant to an organisation's shared pool. Superadmins only — org admins self-serve via `startOrgCheckout`. */
85
111
  topUpOrgCredits(orgId: string, amount: number): Promise<void>;
112
+ /** Manual/support credit withdrawal from an organisation's shared pool (e.g. correcting an over-grant). Superadmins only. */
113
+ withdrawOrgCredits(orgId: string, amount: number): Promise<void>;
86
114
  /**
87
115
  * Starts a self-serve Stripe checkout for a one-time credit top-up.
88
116
  * Returns the hosted checkout URL to redirect the user to; credits are
@@ -134,4 +162,18 @@ export declare class CueProfile {
134
162
  * force-refreshed token to see the updated value.
135
163
  */
136
164
  latestTermsAccepted(): Promise<string | null>;
165
+ /**
166
+ * Record that the current user has been shown (and dismissed) the usage-analytics
167
+ * notice. Sets an `analyticsNotice` custom claim on the token — independent of
168
+ * `terms`, since this is a lightweight acknowledgement, not a blocking agreement.
169
+ */
170
+ acceptAnalyticsNotice(version: string): Promise<void>;
171
+ /**
172
+ * Returns the analytics-notice version the current user has acknowledged (e.g.
173
+ * `"v1"`), or `null` if they haven't yet. Reads from the cached ID token — call
174
+ * after `acceptAnalyticsNotice()` with a force-refreshed token to see the update
175
+ * within the same session (not required if you just hide the banner locally on
176
+ * dismiss, since this only needs to be correct on the *next* sign-in).
177
+ */
178
+ latestAnalyticsNoticeAccepted(): Promise<string | null>;
137
179
  }
package/lib/project.d.ts CHANGED
@@ -1,12 +1,11 @@
1
1
  import { FirebaseApp } from 'firebase/app';
2
2
  import { CueAuth } from './auth';
3
- import { CreateProjectOptions, CueEndpoints, ProjectData } from './models';
3
+ import { CreateProjectOptions, CueEndpoints, ProjectData, ProjectMetadata } from './models';
4
4
  import { ReadonlySignal } from './signal';
5
5
  type ProjectRole = 'admin' | 'syncer' | 'member';
6
6
  export declare class CueProjects {
7
7
  private readonly _auth;
8
8
  private readonly _db;
9
- private readonly _functions;
10
9
  private readonly _gatewayUrl;
11
10
  private readonly _projects;
12
11
  /**
@@ -38,7 +37,9 @@ export declare class CueProjects {
38
37
  */
39
38
  incrementUnitsConsumed(projectId: string, units: number, userId: string): Promise<void>;
40
39
  /**
41
- * Invite a user to a project by email. Returns the invited user's uid and display name.
40
+ * Invite a user to a project by email. Returns the invited user's uid.
41
+ * Throws if no account exists yet for that email — the gateway route supports
42
+ * a pending-invitation flow for that case, but no client surfaces it yet.
42
43
  */
43
44
  inviteUserToProject(email: string, projectId: string, role: ProjectRole): Promise<{
44
45
  uid: string;
@@ -50,7 +51,23 @@ export declare class CueProjects {
50
51
  removeUserFromProject(uid: string, projectId: string): Promise<void>;
51
52
  /**
52
53
  * Delete a project by ID. Requires superadmin privileges on the server.
54
+ * Soft delete (default) flags the project as deleted, hiding it from listings
55
+ * while leaving its data, index, and storage intact. Hard delete permanently
56
+ * drops the graph index, the Firestore document, and the project's storage.
53
57
  */
54
- deleteProject(projectId: string): Promise<void>;
58
+ deleteProject(projectId: string, hard?: boolean): Promise<void>;
59
+ /**
60
+ * Restore a soft-deleted project by ID. Requires superadmin privileges on the server.
61
+ * Resolves with a server-provided status message.
62
+ */
63
+ restoreProject(projectId: string): Promise<string>;
64
+ /**
65
+ * Reads a project's portal-only metadata (currently just an optional map
66
+ * location) — kept off `ProjectData` on purpose, see {@link ProjectMetadata}.
67
+ * Returns `{}` if none has been set yet.
68
+ */
69
+ getProjectMetadata(projectId: string): Promise<ProjectMetadata>;
70
+ /** Sets a project's portal-only metadata. Omit a field to leave it untouched, `null` to clear it. */
71
+ setProjectMetadata(projectId: string, metadata: ProjectMetadata): Promise<void>;
55
72
  }
56
73
  export {};
@@ -0,0 +1,19 @@
1
+ import { CueAuth } from './auth';
2
+ /**
3
+ * Records portal view-opens for usage reporting (per-user, per-view, per-project) —
4
+ * fed into the same GCS-aggregate pipeline as gateway traffic tracking, but written
5
+ * by the frontend directly instead of Kong's `http-log` plugin. See
6
+ * apps/writers/commands/src/app/admin/usage/usage-ingest.service.ts.
7
+ */
8
+ export declare class CueUsageStats {
9
+ private readonly _auth;
10
+ private readonly _gatewayUrl;
11
+ constructor(_auth: CueAuth, _gatewayUrl: string);
12
+ /**
13
+ * Fire-and-forget: records that the current user opened `view` (a route path
14
+ * template, e.g. `projects/:id/files` — never a literal resolved URL/resource id),
15
+ * optionally scoped to `projectId`. Never throws — an analytics call must not
16
+ * break navigation; failures are only logged.
17
+ */
18
+ recordView(view: string, projectId?: string): void;
19
+ }