@qaecy/cue-sdk 0.0.6 → 0.0.8

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.
@@ -0,0 +1,53 @@
1
+ import { ReadonlySignal } from './signal';
2
+ /** Roles ordered from highest to lowest privilege. */
3
+ declare const ROLE_HIERARCHY: readonly ["superadmin", "admin", "syncer", "member"];
4
+ export type UserProjectRole = (typeof ROLE_HIERARCHY)[number];
5
+ export interface Privileges {
6
+ changeContentCategories: boolean;
7
+ createEntities: boolean;
8
+ createProvider: boolean;
9
+ deleteDocuments: boolean;
10
+ deleteUserFromProject: boolean;
11
+ downloadDocuments: boolean;
12
+ editContentCategories: boolean;
13
+ editPublicReposAvailableToAgent: boolean;
14
+ editTier: boolean;
15
+ inviteUserToProject: boolean;
16
+ renameDocuments: boolean;
17
+ uploadDocuments: boolean;
18
+ viewEntities: boolean;
19
+ }
20
+ /** Minimum role required for each privilege. */
21
+ export declare const REQUIRED_ROLES: Record<keyof Privileges, UserProjectRole>;
22
+ /**
23
+ * Manages role-based access control for the current user + selected project.
24
+ *
25
+ * - Call `setProjectRoles()` whenever the selected project changes.
26
+ * - Read `privileges` (a `ReadonlySignal<Privileges>`) for reactive access.
27
+ *
28
+ * @example
29
+ * cue.privileges.setProjectRoles(['admin']);
30
+ * const canUpload = cue.privileges.privileges.get().uploadDocuments; // true
31
+ */
32
+ export declare class CuePrivileges {
33
+ private readonly _isSuperAdmin;
34
+ private readonly _projectRoles;
35
+ /**
36
+ * Reactive signal — current user's privileges for the selected project.
37
+ * Recomputes automatically when `setProjectRoles()` is called or when
38
+ * the `isSuperAdmin` signal changes.
39
+ */
40
+ readonly privileges: ReadonlySignal<Privileges>;
41
+ constructor(_isSuperAdmin: ReadonlySignal<boolean>);
42
+ /**
43
+ * Set the user's roles for the currently selected project.
44
+ *
45
+ * Roles are expanded along the hierarchy: `admin` automatically includes
46
+ * `syncer` and `member`; `syncer` includes `member`. Pass an empty array
47
+ * to reset to the lowest privilege level.
48
+ */
49
+ setProjectRoles(roles: UserProjectRole[]): void;
50
+ private _expand;
51
+ private _compute;
52
+ }
53
+ export {};
package/lib/profile.d.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  import { UserInfo } from 'firebase/auth';
2
2
  import { FirebaseApp } from 'firebase/app';
3
- import { APIKeyDoc, APIKeyInfo, ProfileSSOAccount } from './models';
3
+ import { APIKeyDoc, APIKeyInfo, OrgMember, OrganizationData, ProfileSSOAccount } from './models';
4
4
  import { CueAuth } from './auth';
5
5
  export declare class CueProfile {
6
6
  private readonly _auth;
7
- private readonly _db;
8
- private _apiKeyDocRef?;
9
- constructor(_auth: CueAuth, app: FirebaseApp, useEmulator: boolean, emulatorHost: string, emulatorPort: number);
7
+ private readonly _gatewayUrl;
8
+ private readonly _functions;
9
+ constructor(_auth: CueAuth, app: FirebaseApp, useEmulator: boolean, _gatewayUrl: string);
10
+ private _url;
11
+ private _fetch;
10
12
  /** Whether the current user has an active API key. */
11
13
  hasAPIKey(): Promise<boolean>;
12
14
  /** Returns the sign-in methods registered for the current user's email. */
@@ -31,6 +33,21 @@ export declare class CueProfile {
31
33
  revokeAPIKey(): Promise<void>;
32
34
  /** Fetches the current user's existing API key. */
33
35
  requestAPIKey(): Promise<APIKeyInfo>;
34
- private _checkIfUserHasAPIKey;
36
+ /** Returns organizations the current user is a member of. */
37
+ listOrganizations(): Promise<(Pick<OrganizationData, 'id' | 'name'> & {
38
+ isAdmin: boolean;
39
+ })[]>;
40
+ /** Returns all members of the given organisation. Caller must be an org admin or superadmin. */
41
+ getOrgMembers(orgId: string): Promise<OrgMember[]>;
35
42
  private _requireUser;
43
+ /**
44
+ * Fetch display name and email for a list of user UIDs.
45
+ * Uses the `getUserInfo` Firebase callable function.
46
+ */
47
+ getUserInfo(uids: string[]): Promise<Record<string, {
48
+ name: string;
49
+ email: string;
50
+ }>>;
51
+ /** Record that the current user has accepted the terms of service. */
52
+ acceptTerms(): Promise<void>;
36
53
  }
@@ -0,0 +1,107 @@
1
+ import { CueApi } from './api';
2
+ import { CueProjectSchema } from './schema';
3
+ import { CueProjectEntities } from './entities';
4
+ import { CueProjectDocuments } from './documents';
5
+ import { ReadonlySignal } from './signal';
6
+ import { QueryCache, SearchOptions, SearchResponse, CategoryDef, RelationshipDef, EntityDetailedData, EntityRelationships, ProjectEntitiesData, DocumentInfo, ProjectDocumentsData } from './models';
7
+ export interface CueProjectViewOptions {
8
+ language: string;
9
+ queryCache?: QueryCache;
10
+ /** Override the RDF resource base URL. Defaults to `https://cue.qaecy.com/r/`. */
11
+ rdfBase?: string;
12
+ /** Graph engine type from projectSettings.graph.type (e.g. 'qlever' or 'fuseki'). */
13
+ graphType?: string;
14
+ }
15
+ /**
16
+ * Framework-agnostic facade over `CueProjectSchema`, `CueProjectEntities`, and
17
+ * `CueProjectDocuments`. Exposes a flat, ergonomic API for all knowledge-graph
18
+ * view state needed by the portal.
19
+ *
20
+ * Create via `cue.createProjectView()` rather than constructing directly — the
21
+ * factory wires the active `QueryCache` automatically.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const view = cue.createProjectView('my-project', { language: 'en' });
26
+ * view.entityInfoMap.subscribe(map => render(map));
27
+ * view.requestEntityData(['uuid1', 'uuid2']);
28
+ * ```
29
+ */
30
+ export declare class CueProjectView {
31
+ private readonly _api;
32
+ private readonly _projectId;
33
+ /** Direct access to the schema data class (available categories / relationships). */
34
+ readonly schema: CueProjectSchema;
35
+ /** Direct access to the entity data class. */
36
+ readonly entities: CueProjectEntities;
37
+ /** Direct access to the document data class. */
38
+ readonly documents: CueProjectDocuments;
39
+ /** Available content category definitions for this project. Auto-fetched on init. */
40
+ readonly availableContentCategories: ReadonlySignal<CategoryDef[]>;
41
+ /** Available entity category definitions for this project. Auto-fetched on init. */
42
+ readonly availableEntityCategories: ReadonlySignal<CategoryDef[]>;
43
+ /** Available entity relationship types. Auto-fetched on init. */
44
+ readonly availableEntityRelationships: ReadonlySignal<RelationshipDef[]>;
45
+ /** Merged per-entity detail map. Populated lazily via `requestEntityData()` etc. */
46
+ readonly entityInfoMap: ReadonlySignal<Record<string, EntityDetailedData>>;
47
+ /** Project-level entity co-occurrence graph. Fetched once on init. */
48
+ readonly entityGraph: ReadonlySignal<ProjectEntitiesData | undefined>;
49
+ /** Per-document info map. Populated lazily via `requestDocumentData()`. */
50
+ readonly documentInfoMap: ReadonlySignal<Record<string, DocumentInfo>>;
51
+ /** Project document overview (counts by suffix and category). Fetched on init. */
52
+ readonly projectDocumentsData: ReadonlySignal<ProjectDocumentsData | undefined>;
53
+ private readonly _searchResults;
54
+ /** The result of the most recent `search()` call. `undefined` before first search. */
55
+ readonly searchResults: ReadonlySignal<SearchResponse | undefined>;
56
+ private _destroyed;
57
+ constructor(_api: CueApi, _projectId: string, { language, queryCache, rdfBase, graphType }: CueProjectViewOptions);
58
+ /**
59
+ * Lazily batch-fetch core data (label + categories) for the given entity UUIDs.
60
+ * Already-fetched UUIDs are skipped. Populates `entityInfoMap`.
61
+ */
62
+ requestEntityData(uuids: string[], includeMentionCount?: boolean): void;
63
+ /**
64
+ * Lazily fetch OSM location data for the given entity UUIDs.
65
+ * Already-fetched UUIDs are skipped. Populates `entityInfoMap` geometry fields.
66
+ */
67
+ requestEntityLocations(uuids: string[]): Promise<void>;
68
+ /**
69
+ * Fetch incoming and outgoing relationships for a single entity IRI.
70
+ * Result is stored in `entityInfoMap[uuid].relationshipData`.
71
+ */
72
+ fetchEntityRelationships(iri: string): Promise<EntityRelationships>;
73
+ /**
74
+ * Fetch UUIDs of documents that reference the given entity IRI.
75
+ * Result is stored in `entityInfoMap[uuid].documentRefs`.
76
+ */
77
+ fetchEntityDocuments(iri: string): Promise<string[]>;
78
+ /** Constructs the full RDF IRI for an entity UUID. */
79
+ entityIri(uuid: string): string;
80
+ /**
81
+ * Lazily batch-fetch document info for the given UUIDs.
82
+ * Already-fetched UUIDs are skipped. Populates `documentInfoMap`.
83
+ */
84
+ requestDocumentData(uuids: string[]): void;
85
+ /**
86
+ * Run a natural-language search against the project.
87
+ * The result is stored in `searchResults` and replaces any previous result.
88
+ */
89
+ search(term: string, options?: SearchOptions): Promise<void>;
90
+ /**
91
+ * Switch the active language for schema labels and document text fields.
92
+ * Schema responses are cached per language (instant if previously loaded).
93
+ * The document info map is cleared and lazily re-populated on next access.
94
+ */
95
+ setLanguage(lang: string): void;
96
+ /**
97
+ * Reset all entity and document state and re-fetch the project overview.
98
+ * Prefer creating a fresh `CueProjectView` when switching projects.
99
+ * Use `reset()` only when the same project's data needs to be invalidated.
100
+ */
101
+ reset(): void;
102
+ /**
103
+ * Tear down this view instance. Clears all reactive state and blocks further
104
+ * updates. Call from the Angular adapter's `ngOnDestroy` or equivalent.
105
+ */
106
+ destroy(): void;
107
+ }
package/lib/project.d.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  import { FirebaseApp } from 'firebase/app';
2
2
  import { CueAuth } from './auth';
3
3
  import { CreateProjectOptions, CueEndpoints, ProjectData } from './models';
4
+ type ProjectRole = 'admin' | 'syncer' | 'member';
4
5
  export declare class CueProjects {
5
6
  private readonly _auth;
6
7
  private readonly _db;
8
+ private readonly _functions;
9
+ private readonly _gatewayUrl;
7
10
  constructor(_auth: CueAuth, app: FirebaseApp, useEmulator?: boolean, endpoints?: CueEndpoints);
8
11
  private _requireUser;
9
12
  /**
@@ -12,8 +15,8 @@ export declare class CueProjects {
12
15
  */
13
16
  createProject(options: CreateProjectOptions): Promise<ProjectData>;
14
17
  /**
15
- * List all projects where the authenticated user appears in the members, syncers, or admins array.
16
- * Runs three parallel Firestore queries and deduplicates by project ID.
18
+ * List all projects where the authenticated user appears in the members array.
19
+ * Access is gated by Firestore rules which check membership.
17
20
  */
18
21
  listProjects(): Promise<ProjectData[]>;
19
22
  /** Fetch a single project by ID. Returns null if not found. */
@@ -23,4 +26,16 @@ export declare class CueProjects {
23
26
  * document, creating it if it doesn't exist. Intended for pre-flight checks.
24
27
  */
25
28
  incrementUnitsConsumed(projectId: string, units: number, userId: string): Promise<void>;
29
+ /**
30
+ * Invite a user to a project by email. Returns the invited user's uid and display name.
31
+ */
32
+ inviteUserToProject(email: string, projectId: string, role: ProjectRole): Promise<{
33
+ uid: string;
34
+ name?: string;
35
+ }>;
36
+ /** Change an existing member's role on a project. */
37
+ changeUserRoleOnProject(uid: string, projectId: string, role: ProjectRole): Promise<void>;
38
+ /** Remove a member from a project. */
39
+ removeUserFromProject(uid: string, projectId: string): Promise<void>;
26
40
  }
41
+ export {};
@@ -0,0 +1,66 @@
1
+ import { CueApi } from './api';
2
+ import { ReadonlySignal } from './signal';
3
+ import { CategoryDef, QueryCache, RelationshipDef } from './models';
4
+ /**
5
+ * Holds the schema for a single project: available content categories,
6
+ * entity categories, and entity relationship types.
7
+ *
8
+ * Data is fetched lazily on construction and cached per language so that
9
+ * switching back to a previously loaded language is instant.
10
+ *
11
+ * ### Reactive paradigm
12
+ * All three collections are exposed as `ReadonlySignal<T>`. Framework adapters
13
+ * (e.g. Angular) should bridge these to their own reactive primitives using
14
+ * `subscribe()`.
15
+ *
16
+ * ### Lifecycle
17
+ * One `CueProjectSchema` instance should be created per project. It is owned
18
+ * by the higher-level `CueProjectView` and shares the same `CueApi` instance.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const schema = new CueProjectSchema(cue.api, projectId, 'en');
23
+ * schema.availableContentCategories.get(); // CategoryDef[]
24
+ * schema.setLanguage('da'); // loads from cache or re-fetches
25
+ * await schema.refresh(); // force re-fetch current language
26
+ * ```
27
+ */
28
+ export declare class CueProjectSchema {
29
+ private readonly _api;
30
+ private readonly _projectId;
31
+ private readonly _queryCache?;
32
+ private readonly _graphType?;
33
+ private readonly _cache;
34
+ private readonly _language;
35
+ private readonly _contentCategories;
36
+ private readonly _entityCategories;
37
+ private readonly _relationships;
38
+ /** Currently active content categories for the selected language. */
39
+ readonly availableContentCategories: ReadonlySignal<CategoryDef[]>;
40
+ /** Currently active entity categories for the selected language. */
41
+ readonly availableEntityCategories: ReadonlySignal<CategoryDef[]>;
42
+ /** Currently active entity relationship types for the selected language. */
43
+ readonly availableEntityRelationships: ReadonlySignal<RelationshipDef[]>;
44
+ constructor(_api: CueApi, _projectId: string, language: string, _queryCache?: QueryCache | undefined, _graphType?: string | undefined);
45
+ /** Returns the currently active language. */
46
+ get language(): string;
47
+ /**
48
+ * Switch the active language. If the data for this language has already been
49
+ * fetched it is applied immediately from cache; otherwise a new SPARQL fetch
50
+ * is triggered.
51
+ */
52
+ setLanguage(lang: string): void;
53
+ /**
54
+ * Force a re-fetch for the current language, bypassing the cache.
55
+ * Useful when the triplestore data has changed.
56
+ */
57
+ refresh(): Promise<void>;
58
+ private _load;
59
+ private _apply;
60
+ private _fetchCategories;
61
+ private _buildCategoriesQuery;
62
+ private _runCategoriesQuery;
63
+ private _fetchRelationships;
64
+ private _buildRelationshipsQuery;
65
+ private _runRelationshipsQuery;
66
+ }
@@ -0,0 +1,54 @@
1
+ import { QueryCache } from './models';
2
+ /** A reactive value that can be read and subscribed to. */
3
+ export interface ReadonlySignal<T> {
4
+ /** Returns the current value. */
5
+ get(): T;
6
+ /**
7
+ * Register a listener that is called whenever the value changes.
8
+ * Returns an unsubscribe function.
9
+ */
10
+ subscribe(listener: () => void): () => void;
11
+ }
12
+ /** A writable reactive state container. */
13
+ export declare class CueSignal<T> implements ReadonlySignal<T> {
14
+ private _value;
15
+ private _listeners;
16
+ constructor(initial: T);
17
+ get(): T;
18
+ set(value: T): void;
19
+ subscribe(listener: () => void): () => void;
20
+ /** Returns a read-only view of this signal. */
21
+ asReadonly(): ReadonlySignal<T>;
22
+ }
23
+ /**
24
+ * Creates a derived read-only signal from one or more source signals.
25
+ * The compute function is evaluated lazily and cached until a dependency changes.
26
+ *
27
+ * @param deps Source signals to watch.
28
+ * @param compute Function that computes the derived value; must be pure.
29
+ * @returns A `ReadonlySignal` with a `destroy()` method to stop tracking deps.
30
+ */
31
+ export declare function cueComputed<T>(deps: ReadonlySignal<unknown>[], compute: () => T): ReadonlySignal<T> & {
32
+ destroy(): void;
33
+ };
34
+ /**
35
+ * Stale-while-revalidate helper for SPARQL queries.
36
+ *
37
+ * 1. If `cache` is provided and has a stored result for `cacheKey`, calls
38
+ * `onData(staleData, true)` immediately (synchronously relative to the await).
39
+ * 2. Fires `fetchFresh()` to get current data from the triplestore.
40
+ * 3. Calls `onData(freshData, false)`.
41
+ * 4. Writes the fresh result to `cache` only if it differs from the stale
42
+ * result (content-addressed via `contextBasedGuid`).
43
+ * 5. Returns the fresh data.
44
+ *
45
+ * If no `cache` is provided the function simply fetches and calls `onData`
46
+ * once, transparently.
47
+ *
48
+ * @param query The SPARQL query string — also used as cache key input.
49
+ * @param fetchFresh Function that executes the query and returns the result.
50
+ * @param onData Called once with stale data (if available) and once with
51
+ * fresh data.
52
+ * @param cache Optional {@link QueryCache} implementation.
53
+ */
54
+ export declare function staleWhileRevalidate<T>(query: string, fetchFresh: () => Promise<T>, onData: (data: T, isStale: boolean) => void, cache?: QueryCache): Promise<T>;
package/lib/sync.d.ts CHANGED
@@ -4,6 +4,15 @@ import { CueAuth } from './auth';
4
4
  import { CueApi } from './api';
5
5
  import { CueProjects } from './project';
6
6
  import { ScanOutputRecord, SyncOptions, SyncPreview, SyncResult } from './models';
7
+ /**
8
+ * Configure the URL from which the WASM scanner assets are loaded in browser environments.
9
+ * Call this once during app initialisation (e.g. Angular APP_INITIALIZER) before any credit
10
+ * calculations are requested.
11
+ *
12
+ * @param baseUrl - URL prefix for `dir_scanner_wasm_bg.wasm` and `dir_scanner_wasm.mjs`,
13
+ * e.g. `'/assets/wasm'` or `'https://cdn.example.com/wasm'`.
14
+ */
15
+ export declare function configureScanWasm(baseUrl: string): void;
7
16
  export declare class CueSyncApi {
8
17
  private readonly _auth;
9
18
  private readonly _projects;
@@ -14,14 +23,33 @@ export declare class CueSyncApi {
14
23
  private _pendingItems;
15
24
  private _pendingSpaceId;
16
25
  private _flushTimer;
26
+ private _legacy;
17
27
  constructor(_auth: CueAuth, _projects: CueProjects, _blob: CueBlobStorage, _gatewayUrl: string);
18
28
  /** @internal Injected by CueApi after construction to avoid circular dependency. */
19
29
  _bindApi(api: CueApi): void;
20
30
  /**
21
- * Flushes any pending metadata items from a previous interrupted sync.
22
- * Safe to call even when there is nothing new to upload.
31
+ * Initialises browser-mode sync for a project space.
32
+ * - Flushes any metadata items that were queued but not sent in a previous session
33
+ * (persisted in `localStorage`).
34
+ * - Starts the 60-second periodic flush timer.
35
+ *
36
+ * Call this once when the file manager component is created (or when the active
37
+ * project changes) so that interrupted uploads are recovered immediately.
38
+ */
39
+ initBrowserSync(spaceId: string): Promise<void>;
40
+ /**
41
+ * Pushes filesystem-structure metadata for all provided files directly to the
42
+ * commands API, without checking what is already on the remote or accounting for
43
+ * credits. Use this when you want to force-write metadata for every file in a
44
+ * local path (e.g. to repair missing graph data after a migration).
45
+ */
46
+ pushAllMetadata(localFiles: LocalFile[], options: Pick<SyncOptions, 'spaceId' | 'providerId' | 'verbose' | 'legacy'>): Promise<void>;
47
+ /**
48
+ * Flushes any pending file-location metadata from a previously interrupted sync.
49
+ * Safe to call even when there are no new files to upload (e.g. when the process
50
+ * died after uploading to blob storage but before the commands-API batch POST).
23
51
  */
24
- flushPendingMetadata(spaceId: string, verbose?: boolean): Promise<void>;
52
+ flushPendingMetadata(spaceId: string, verbose?: boolean, legacy?: boolean): Promise<void>;
25
53
  /**
26
54
  * Returns a preview of what would be synced: cost breakdown for new files only,
27
55
  * units required, and units still available. Use this before calling {@link sync}
@@ -34,6 +62,12 @@ export declare class CueSyncApi {
34
62
  private _getGraphFiles;
35
63
  private _initPendingBatch;
36
64
  private _queueFileLocation;
65
+ /**
66
+ * Flush all queued file-location items to the commands API in a single batch.
67
+ * Call this once after a group of `syncBrowserFile` calls completes so that
68
+ * all items are sent together rather than one POST per file.
69
+ */
70
+ drainPending(): Promise<void>;
37
71
  private _drainPending;
38
72
  private _flushBatch;
39
73
  private _postFssBatch;
@@ -46,6 +80,44 @@ export declare class CueSyncApi {
46
80
  * shown to the user before or after calling {@link sync}.
47
81
  */
48
82
  scanCost(localFiles: LocalFile[]): Promise<ScanOutputRecord[]>;
83
+ /**
84
+ * Compute the credit cost for a set of local files without uploading anything.
85
+ * Intended for browser use where the full {@link previewSync} (which requires a
86
+ * remote file listing) would be too heavy for a quick estimate.
87
+ *
88
+ * @param localFiles - Files to analyse. Each entry must carry `data` when
89
+ * called from a browser context.
90
+ * @param spaceId - Project/space identifier used to fetch the tier settings.
91
+ * @returns Per-extension cost breakdown and the number of credits currently
92
+ * available in the project.
93
+ */
94
+ computeCredits(localFiles: LocalFile[], spaceId: string): Promise<{
95
+ costRecords: ScanOutputRecord[];
96
+ creditsToConsume: number;
97
+ creditsAvailable: number;
98
+ }>;
99
+ /**
100
+ * Upload a single browser-supplied file and write its metadata to the knowledge graph.
101
+ *
102
+ * Unlike {@link sync} (which performs a full remote comparison), this method is
103
+ * designed for the web file-manager flow where the user has already confirmed the
104
+ * upload via the credit modal. The file's binary data must be provided in
105
+ * `file.data`; the `file.fullPath` field is ignored.
106
+ *
107
+ * Cancellation is supported via `options.signal`. Aborting the signal cancels
108
+ * the Firebase Storage upload; metadata is never written for a cancelled upload.
109
+ *
110
+ * @param file - `LocalFile` with `data` populated (e.g. from `File.arrayBuffer()`).
111
+ * @param options - Upload options including project/provider/user context and an
112
+ * optional `AbortSignal` for cancellation and `onProgress` for tracking.
113
+ */
114
+ syncBrowserFile(file: LocalFile, options: {
115
+ spaceId: string;
116
+ providerId: string;
117
+ userId: string;
118
+ signal?: AbortSignal;
119
+ onProgress?: (percent: number) => void;
120
+ }): Promise<void>;
49
121
  private _fetchTierNames;
50
122
  private _fetchUnitCreditMap;
51
123
  private _logProgress;