@qaecy/cue-sdk 0.0.5 → 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,346 @@
1
+ # Cue SDK — Portal Migration
2
+
3
+ > **Goal:** All server communication in cue-portal flows through `js-cue-sdk`, replacing direct usage of `js-firebase` and `cue-repos`.
4
+
5
+ ---
6
+
7
+ ## Current State
8
+
9
+ | Layer | Status |
10
+ |-------|--------|
11
+ | **js-cue-sdk** — `Cue`, `CueAuth`, `CueProjects`, `CueProfile`, `CuePrivileges`, `CueCache` | ✅ Active — all major modules built |
12
+ | **js-databases** — `IDocStore`, `FirestoreDocStore`, `CueBlobStorage` | ✅ All repos delegating to these |
13
+ | **cue-repos** (Angular) — now thin adapters over the SDK | ✅ Migrated |
14
+ | **js-firebase** (`CueFirebase`) | Kept — CLI, widget, admin depend on it |
15
+ | **cue-views** (Angular) — SPARQL + entity/doc signals | 🔄 In progress — core data classes built, facade + adapters pending |
16
+
17
+ **Remaining `js-firebase` imports in the portal:**
18
+ - `libs/ng/cue-repos/src/lib/firebase.service.ts` — intentional (this IS the `CueFirebase` wrapper)
19
+ - `apps/frontend/cue-portal/src/main.ts` — app bootstrap; addressed in Final phase
20
+
21
+ ---
22
+
23
+ ## Remaining Work
24
+
25
+ ### Phase 6 — Knowledge Graph View State (`CueProjectView`)
26
+
27
+ Full investigation of `cue-views` services completed. The three heaviest SPARQL data classes are already built in `js-cue-sdk`. What remains is a thin facade, the Angular adapter wiring, and gateway API additions for the remaining services.
28
+
29
+ #### Coverage summary — `cue-views` services vs SDK
30
+
31
+ | `cue-views` service | SDK status | Owner after migration |
32
+ |---|---|---|
33
+ | `TriplestoreService` | ✅ Replaced by `CueApi.sparql()` | SDK |
34
+ | `AvailableCategoriesService` | ✅ Replaced by `CueProjectSchema` | Angular bridge |
35
+ | `ProjectDocumentsService` | ✅ Replaced by `CueProjectDocuments.fetchOverview()` | Angular bridge |
36
+ | `DocumentInfoService` (SPARQL) | ✅ Replaced by `CueProjectDocuments.requestDocumentData()` | Angular bridge; callbacks stay Angular |
37
+ | `EntityInfoService` (core) | ✅ Replaced by `CueProjectEntities` | Angular bridge |
38
+ | `DocumentDuplicatesService` | ⚠️ Count covered; full path list not yet in SDK | Needs `CueProjectDocuments.fetchDuplicates()` |
39
+ | `DocumentEntitiesService` | ❌ Not covered | Needs new SDK read queries + `CueApi` write methods |
40
+ | `RelatedService` | ❌ Not covered | Needs `CueApi.relatedDocuments()` |
41
+ | `ContentCategoryService` | ❌ Not covered | Needs `CueApi.changeContentCategory()` |
42
+ | `AgentService` | ❌ Not covered | Needs `CueApi.streamPlan()` / `CueApi.streamAct()` |
43
+ | `ResourceService` | ❌ Not covered | Per-document viewer; stays Angular or becomes `CueDocumentResource` |
44
+ | `FileLocationsService` | ❌ Not covered | Low priority; stays Angular or becomes private helper |
45
+ | `FileContentService` | ❌ Not covered | Depends on `FileRepo`; stays Angular-layer |
46
+ | `CueViewsService` | N/A — config/context root | Angular adapter responsibility |
47
+ | `CommandsService` | N/A — thin facade | Angular adapter responsibility |
48
+
49
+ ---
50
+
51
+ #### Phase 6a — `CueProjectView` facade _(next step)_
52
+
53
+ Create `libs/js/cue-sdk/src/lib/project-view.ts` — a single class that composes `CueProjectSchema`, `CueProjectEntities`, and `CueProjectDocuments` and adds `search()`.
54
+
55
+ ```ts
56
+ const view = cue.createProjectView(projectId, { language: 'en', queryCache });
57
+
58
+ // Proxied signals from sub-classes
59
+ view.availableContentCategories // → schema.availableContentCategories
60
+ view.availableEntityCategories // → schema.availableEntityCategories
61
+ view.availableEntityRelationships // → schema.availableEntityRelationships
62
+ view.entityInfoMap // → entities.entityInfoMap
63
+ view.entityGraph // → entities.entityGraph
64
+ view.documentInfoMap // → documents.documentInfoMap
65
+ view.projectDocumentsData // → documents.projectDocumentsData
66
+
67
+ // Proxied methods
68
+ view.requestEntityData(ids, includeMentionCount?)
69
+ view.requestEntityLocations(ids)
70
+ view.fetchEntityRelationships(iri)
71
+ view.fetchEntityDocuments(iri)
72
+ view.requestDocumentData(ids)
73
+
74
+ // New: search
75
+ view.searchResults // ReadonlySignal<DocumentRef[]>
76
+ view.search(term, options?) // Calls CueApi.search(), appends to searchResults
77
+
78
+ // Lifecycle
79
+ view.setLanguage(lang) // Calls schema.setLanguage(); docs.setLanguage()
80
+ view.destroy() // Tears down subscriptions
81
+ ```
82
+
83
+ `Cue` gains a factory method:
84
+ ```ts
85
+ cue.createProjectView(projectId: string, opts: { language: string, queryCache?: QueryCache }): CueProjectView
86
+ ```
87
+
88
+ **Files to create/modify:**
89
+ - `libs/js/cue-sdk/src/lib/project-view.ts` — new `CueProjectView` class
90
+ - `libs/js/cue-sdk/src/lib/cue.ts` — add `createProjectView()` method
91
+ - `libs/js/cue-sdk/src/index.ts` — export `CueProjectView` + related types
92
+
93
+ ---
94
+
95
+ #### Phase 6b — Angular adapters in `cue-views`
96
+
97
+ Replace the heavy Angular services with thin bridges that subscribe to SDK signals and forward method calls. Each bridge service creates/receives a `CueProjectView` instance from the Angular DI tree.
98
+
99
+ | Angular service | Migration action |
100
+ |---|---|
101
+ | `AvailableCategoriesService` | Replace with computed signals bridging `view.availableContentCategories` etc. via `toSignal(obs)` or `subscribe()` |
102
+ | `ProjectDocumentsService` | Replace signal with bridge to `view.projectDocumentsData`; call `view.fetchOverview()` on project init |
103
+ | `DocumentInfoService` | Delegate `requestDocumentData()` to `view`; keep `documentListHandlers` callbacks (download, navigate) Angular-side |
104
+ | `EntityInfoService` | Delegate all 4 public methods to `view`; bridge `entityInfoMap` and `entityGraph` signals |
105
+ | `TriplestoreService` | Remove — callers switch to `CueApi.sparql()` directly or via `view` |
106
+
107
+ The Angular adapter pattern:
108
+ ```ts
109
+ // In cue-views Angular service
110
+ readonly entityInfoMap = toSignal(
111
+ new Observable(obs => this._view.entityInfoMap.subscribe(v => obs.next(v)))
112
+ );
113
+ ```
114
+
115
+ ---
116
+
117
+ #### Phase 6c — Gateway API additions (`CueApi`)
118
+
119
+ These are needed before the remaining `cue-views` services can be bridged:
120
+
121
+ | Method | Source service | HTTP call |
122
+ |---|---|---|
123
+ | `CueApi.relatedDocuments(contentUUID, k)` | `RelatedService` | `POST {gatewayURL}/endpoints.relatedDocuments` |
124
+ | `CueApi.changeContentCategory(payload)` | `ContentCategoryService` | `PATCH {gatewayURL}/endpoints.contentCategoryChange` |
125
+ | `CueApi.streamPlan(prompt, cb)` | `AgentService` | Streaming `POST {gatewayURL}/endpoints.agentPlan` via `fetchStream()` |
126
+ | `CueApi.streamAct(plan, cb)` | `AgentService` | Streaming `POST {gatewayURL}/endpoints.agentAct` via `fetchStream()` |
127
+ | `CueApi.saveEntityMentions(payload)` | `DocumentEntitiesService` | `POST/DELETE {gatewayURL}/endpoints.entityMentionBatch` |
128
+ | `CueApi.saveSelectors(payload)` | `DocumentEntitiesService` | `POST {gatewayURL}/endpoints.selectorBatch` |
129
+
130
+ The `gatewayURL` and project-scoped `Authorization`/`x-project-id` headers are already in `CueApi` — these are additive methods only.
131
+
132
+ ---
133
+
134
+ #### Phase 6d — SDK data additions
135
+
136
+ Small additions to existing SDK classes:
137
+
138
+ - **`CueProjectDocuments.fetchDuplicates()`** — returns `Record<uuid, string[]>` (all file paths per content UUID where count > 1). `DocumentDuplicatesService` currently holds an in-memory project-keyed cache of this.
139
+ - **`CueProjectEntities` — document-entity reads** — fetch all `qcy:mentions` IRIs for a given `contentIRI`, with `qcy:value` and `qcy:hasEntityCategory`. Currently only in `DocumentEntitiesService`.
140
+ - **`CueProjectEntities` or new `CueDocumentResource`** — type detection (`SELECT ?cl WHERE { <iri> a ?cl }`) + file metadata fetch for per-document-viewer panel. Currently in `ResourceService`.
141
+
142
+ ---
143
+
144
+ #### Phase 6e — `cue-views` cleanup
145
+
146
+ After 6a–6d, the remaining Angular services that have no SDK equivalent are either:
147
+ - **Kept as-is** (framework-specific): `FileContentService` (depends on `FileRepo`), `ResourceService` viewer composition, `DocumentListHandlers` callbacks
148
+ - **Deleted** once bridge services are verified: `TriplestoreService`, `AvailableCategoriesService`, `ProjectDocumentsService`
149
+
150
+ ---
151
+
152
+ ### Final — Remove `js-firebase` from portal bootstrap
153
+
154
+ Replace `main.ts` Firebase init + `FirebaseService` with pure SDK init. `cue-repos` services become either collapsed into the SDK or thin DI wrappers with no direct Firebase imports.
155
+
156
+ ---
157
+
158
+
159
+ ## Verification Plan
160
+
161
+ After each phase, verify with the following checklist. Run `npx nx build cue-portal` as the baseline — all items below are functional smoke tests.
162
+
163
+ ### ✅ Phase 2–5 (already done — verify these haven't regressed)
164
+
165
+ | Area | How to verify |
166
+ |------|--------------|
167
+ | **Auth signals** | Sign in; confirm `cue.auth.user.get()` returns the user, `cue.auth.token.get()` returns a JWT, `cue.auth.isSuperAdmin.get()` reflects the claim |
168
+ | **Privileges** | Select a project where the user is `admin`; confirm `cue.privileges.privileges.get().uploadDocuments === true`; `PrivilegesService.privileges()` should match |
169
+ | **Cloud functions** | In Settings → Members: invite a user, change role, remove — all three `CueProjects` callables should fire without error |
170
+ | **Cache (write)** | Run a SPARQL query with caching enabled; confirm a `.json.gz` file appears in the `db_persistence_eu_west6` bucket at `portal/projects/{pid}/queries/{id}.json.gz` |
171
+ | **Cache (read)** | Run the same query again; confirm it loads from cache (no SPARQL call in the network tab) |
172
+ | **Agent session cache** | Run an agent interaction; confirm `portal/projects/{pid}/agent/{id}.json.gz` is written |
173
+ | **Doc types** | `ProjectDoc`, `UserDoc`, `OrganizationDoc`, `RDFWritingDoc`, `ViewDefinition` all importable from `js-cue-sdk` without errors |
174
+ | **`nx graph`** | `cue-repos` should only have one edge to `js-firebase` (via `firebase.service.ts`) |
175
+
176
+ ### 🔲 Phase 6a — `CueProjectView` facade
177
+
178
+ | Area | How to verify |
179
+ |------|--------------|
180
+ | **Category signals** | Open a project; `view.availableContentCategories.get()` and `view.availableEntityCategories.get()` return non-empty arrays |
181
+ | **Entity graph** | `view.entityGraph.get()` returns the full entity graph after project init |
182
+ | **Entity detail** | Call `view.requestEntityData(['<uuid>'])` then read `view.entityInfoMap.get()['<uuid>']` — `value` and `categories` populated |
183
+ | **Entity relationships** | Call `view.fetchEntityRelationships('<iri>')` and confirm incoming/outgoing edges |
184
+ | **Entity documents** | Call `view.fetchEntityDocuments('<iri>')` and confirm document UUIDs |
185
+ | **Document data** | Call `view.requestDocumentData(['<id>'])` then read `view.documentInfoMap.get()['<id>']` |
186
+ | **Project documents overview** | `view.projectDocumentsData.get()` returns `documentsBySuffix` and `documentsByContentCategory` |
187
+ | **Search** | Call `view.search('test')` and confirm `view.searchResults.get()` accumulates results |
188
+ | **Language change** | Call `view.setLanguage('da')` and confirm category labels switch |
189
+ | **Stale-while-revalidate** | With a warm `QueryCache`, confirm the signal fires twice — first with stale data, then fresh |
190
+ | **Destroy** | Call `view.destroy()` and confirm no further signal updates |
191
+
192
+ ### ✅ Phase 6b — Angular adapters
193
+
194
+ **Completed.** All 4 `cue-views` services bridged to SDK signals. Build verified (`nx build ng-cue-views` passes). Also fixed a pre-existing ng-packagr `rootDir` issue in `cue-repos` and `cue-views` by overriding `js-cue-sdk` path to dist in `tsconfig.lib.prod.json`.
195
+
196
+ | Area | Status |
197
+ |------|--------|
198
+ | `CueViewsService` — owns `CueProjectView` signal, effects for project/language change | ✅ |
199
+ | `AvailableCategoriesService` — bridges `view.availableContentCategories/EntityCategories/EntityRelationships` | ✅ |
200
+ | `ProjectDocumentsService` — bridges `view.projectDocumentsData` | ✅ |
201
+ | `DocumentInfoService` — bridges `view.documentInfoMap`; keeps `documentListHandlers` Angular-side | ✅ |
202
+ | `EntityInfoService` — bridges `view.entityInfoMap` + `entityGraph`; delegates all 4 methods to view | ✅ |
203
+ | `cue-repos/tsconfig.lib.prod.json` — path override to dist to fix ng-packagr TS6059 | ✅ |
204
+ | `cue-views/tsconfig.lib.prod.json` — same fix | ✅ |
205
+
206
+ ### 🔲 Phase 6c — Gateway API additions
207
+
208
+ | Area | How to verify |
209
+ |------|--------------|
210
+ | **Related documents** | Call `cue.api.relatedDocuments(uuid, 10)` from console; confirm response array with `relevance` scores |
211
+ | **Content category change** | Change a document's content category; confirm PATCH fires and SPARQL reflects the update |
212
+ | **Agent plan streaming** | Trigger agent plan build; confirm streaming chunks arrive and plan signal updates incrementally |
213
+ | **Agent act streaming** | Execute a plan; confirm streaming result chunks arrive and final result is saved via `CueCache` |
214
+
215
+ ### 🔲 Phase 6d — SDK data additions
216
+
217
+ | Area | How to verify |
218
+ |------|--------------|
219
+ | **Duplicate list** | `view.documents.fetchDuplicates()` returns a map of content UUIDs → array of file paths |
220
+ | **Document entity reads** | `view.entities.fetchDocumentMentions(contentIRI)` returns entity IRIs with labels and categories |
221
+
222
+ ### 🔲 Final (portal bootstrap migration — pending)
223
+
224
+ | Area | How to verify |
225
+ |------|--------------|
226
+ | **`nx graph`** | `cue-portal` has zero edges to `js-firebase` |
227
+ | **Cold load** | Full page refresh — auth state restores, project loads, entities visible |
228
+ | **Emulator** | `nx run cue-portal:serve` with emulator; all Firestore + Storage + Auth calls route correctly |
229
+
230
+ ---
231
+
232
+ ## Architecture Decisions
233
+
234
+ **`js-firebase` stays** — CLI, widget, and admin depend on it directly and always will. The portal's dependency shrinks to the single `FirebaseService` wrapper.
235
+
236
+ **`js-databases` as the abstraction boundary** — `IDocStore` and `CueBlobStorage` are Firebase-agnostic. Switching storage provider only requires changing the backing class in `CueFirebase._init()`.
237
+
238
+ **Vanilla signals in the SDK** — `CueSignal<T>` + `cueComputed()` in `signal.ts`. No external signal library. Angular adapters bridge to Angular signals via `effect(onCleanup => ...)` + `subscribe()`.
239
+
240
+ **`UploadTask` escape hatch** — `FileRepo.uploadRawFile` still returns a native Firebase `UploadTask` because `cue-views/handlers.service.ts` depends on `task.on('state_changed', ...)` for per-file upload progress. Resolved in Phase 6.
241
+
242
+ **`CueCache` uses `firebase/storage` directly** — only needs the `persistence` bucket; no need to instantiate all 6 buckets via `CueBlobStorage`.
243
+
244
+ ---
245
+
246
+ ## SDK Module Reference
247
+
248
+ | Module | Class | Exposed as | Key members |
249
+ |--------|-------|-----------|-------------|
250
+ | `auth.ts` | `CueAuth` | `cue.auth` | `user`, `token`, `isSuperAdmin`, `userIds` (all `ReadonlySignal`); `signIn()`, `signOut()`, `signInWithRedirect()`, `checkRedirectResult()`, `checkSuperAdmin()`, `getToken()`, `authenticatedFetch()` |
251
+ | `privileges.ts` | `CuePrivileges` | `cue.privileges` | `privileges: ReadonlySignal<Privileges>`; `setProjectRoles(roles)` |
252
+ | `project.ts` | `CueProjects` | `cue.projects` | `inviteUserToProject()`, `changeUserRoleOnProject()`, `removeUserFromProject()` |
253
+ | `profile.ts` | `CueProfile` | `cue.profile` | `getUserInfo(uids)`, `acceptTerms()`, API key management |
254
+ | `cache.ts` | `CueCache` | `cue.cache` | `getQueryCache`, `setQueryCache`, `getAgentSessionCache`, `setAgentSessionCache`, `getUserProjectCache`, `setUserProjectCache` |
255
+ | `signal.ts` | `CueSignal<T>` | exported | Writable reactive state; `get()`, `set()`, `subscribe()` |
256
+ | `signal.ts` | `cueComputed()` | exported | Derived read-only signal from deps |
257
+ | `signal.ts` | `staleWhileRevalidate()` | exported | Serve stale cache data first, then revalidate; generic `QueryCache` interface |
258
+ | `api.ts` | `CueApi` | `cue.api` | `search()`, `sparql()`, `sync` (Node only) |
259
+ | `schema.ts` | `CueProjectSchema` | `view.schema` | `availableContentCategories`, `availableEntityCategories`, `availableEntityRelationships` (all `ReadonlySignal`); `setLanguage()`, `refresh()` |
260
+ | `entities.ts` | `CueProjectEntities` | `view.entities` | `entityInfoMap`, `entityGraph` (all `ReadonlySignal`); `requestEntityData()`, `requestEntityLocations()`, `fetchEntityRelationships()`, `fetchEntityDocuments()`, `entityIri()`, `reset()` |
261
+ | `documents.ts` | `CueProjectDocuments` | `view.documents` | `documentInfoMap`, `projectDocumentsData` (all `ReadonlySignal`); `requestDocumentData()`, `fetchOverview()`, `setLanguage()`, `reset()` |
262
+ | `project-view.ts` _(pending)_ | `CueProjectView` | `cue.createProjectView()` | Facade over schema + entities + documents; adds `search()`, `searchResults`, `setLanguage()`, `destroy()` |
263
+
264
+ ---
265
+
266
+ ## Firestore Collections Reference
267
+
268
+ | Collection | Document type | Owner |
269
+ |-----------|--------------|-------|
270
+ | `projects` | `ProjectDoc` | `ProjectRepo` → `docStore` |
271
+ | `users` | `UserDoc` | `UserRepo` → `docStore` |
272
+ | `organizations` | `OrganizationDoc` | `OrganizationRepo` → `docStore` |
273
+ | `apiKeys` | `APIKeyDoc` | `APIKeysRepo` → `docStore` |
274
+ | `rdfWriting` | `RDFWritingDoc` | `RDFWritingRepo` → `docStore` |
275
+ | `tiers` | `TierDoc` | `FirebaseService` (raw, portal doesn't use) |
276
+ | `userTermsAcceptance` | `{ uid, timestamp }` | `FirebaseService` (raw) |
277
+ | `chatSessions` | `ChatSessionDoc` | `FirebaseService` (raw) |
278
+
279
+ ## Storage Buckets Reference
280
+
281
+ | Bucket name | Key | Owner |
282
+ |-------------|-----|-------|
283
+ | `cue_raw_eu_west6` | `raw` | `FileRepo` → `blobStore` |
284
+ | `cue_processed_eu_west6` | `processed` | `FileRepo` → `blobStore` |
285
+ | `cue_logs_eu_west6` | `logs` | `FileRepo` → `blobStore` |
286
+ | `cue_public_eu_west6` | `public` | `FileRepo` → `blobStore` |
287
+ | `db_persistence_eu_west6` | `persistence` | `CueCache` (via `firebase/storage` directly) |
288
+ | `cue_chat_sessions_eu_west6` | `chatSessions` | `FileRepo` → `blobStore` |
289
+
290
+ ---
291
+
292
+ ## Completed Work (archive)
293
+
294
+ ### Phase 6 (partial) — Knowledge Graph data classes
295
+
296
+ | Class | File | Replaces |
297
+ |---|---|---|
298
+ | `CueProjectSchema` | `schema.ts` | `AvailableCategoriesService` |
299
+ | `CueProjectEntities` | `entities.ts` | `EntityInfoService` |
300
+ | `CueProjectDocuments` | `documents.ts` | `ProjectDocumentsService` + `DocumentInfoService` (SPARQL) |
301
+
302
+ All three classes:
303
+ - Accept `CueApi` + `projectId` — no Angular dependencies
304
+ - Use `CueSignal<T>` / `cueComputed()` — framework-agnostic reactive signals
305
+ - Accept optional `QueryCache` for stale-while-revalidate caching via `staleWhileRevalidate()`
306
+ - Use `js/prefixes` (`qaecyPrefixes`, `prefixCC`) — no inline namespace constants
307
+ - Exported from `libs/js/cue-sdk/src/index.ts`
308
+
309
+ `staleWhileRevalidate<T>(query, fetchFresh, onData, cache?)` helper added to `signal.ts`:
310
+ - Serves cached (stale) data immediately via `cache.get(key)` then fires `onData(stale, true)`
311
+ - Fetches fresh data, fires `onData(fresh, false)`, writes to cache only if data changed
312
+ - Cache key is `contextBasedGuid(query)` (deterministic UUID v5 hash)
313
+
314
+ ---
315
+
316
+ ### `js-databases` — Provider-agnostic storage layer
317
+
318
+ - `IDocStore` interface + `FirestoreDocStore` implementation
319
+ - `CueBlobStorage` covers all 6 named buckets and all file operations
320
+ - `CueFirebase` constructs and exposes `docStore` + `blobStore`
321
+
322
+ ### `js-cue-sdk` additions
323
+
324
+ - **`Cue.fromApp(app, config?)`** — static factory that reuses an existing `FirebaseApp` (portal shares auth session with SDK without a second login)
325
+ - **`CueSignal<T>` + `cueComputed()`** — vanilla framework-agnostic reactive primitives
326
+ - **`CueAuth` signals** — `user`, `token`, `isSuperAdmin`, `userIds` all reactive via `onIdTokenChanged`
327
+ - **`CuePrivileges`** — role expansion (`admin → [admin, syncer, member]`), `REQUIRED_ROLES`, `privileges` signal auto-recomputes when roles or superadmin status changes
328
+ - **`CueProjects`** cloud function wrappers: `inviteUserToProject`, `changeUserRoleOnProject`, `removeUserFromProject`
329
+ - **`CueProfile`** cloud function wrappers: `getUserInfo`, `acceptTerms`
330
+ - **`CueCache`** — gzip cache over `db_persistence_eu_west6`; uses `CompressionStream`/`DecompressionStream` (web standard, no `fflate` in SDK)
331
+ - **Doc types in SDK models** — `ProjectDoc`, `OrganizationDoc`, `UserDoc`, `RDFWritingDoc`, `ViewDefinition` (type aliases/interfaces; classes remain in `js-firebase` for CLI/admin)
332
+
333
+ ### `cue-repos` — Angular adapters
334
+
335
+ | Service / Repo | Before | After |
336
+ |----------------|--------|-------|
337
+ | All 5 doc repos | Raw `CollectionReference` + `onSnapshot` | `docStore.subscribeToCollection/Doc` |
338
+ | `FileRepo` | Raw `firebase/storage` calls | `blobStore.*` |
339
+ | `CacheRepo` | 200-line `fflate`-based gzip impl | 40-line delegate to `cue.cache` |
340
+ | `PrivilegesService` | Owned all role logic | Thin adapter — syncs from `cue.privileges` signal |
341
+ | `CueSdkService` | — | New: `sdk: Signal<Cue \| undefined>` via `Cue.fromApp()` |
342
+ | `settings.component.ts` | Used `FirebaseService` | Uses `CueSdkService → sdk.projects.*` |
343
+ | `UsersRepo` | Used `FirebaseService.functionGetUserInfo` | Uses `sdk.profile.getUserInfo()` |
344
+
345
+ Doc type imports in `cue-repos` and portal services moved from `js-firebase` → `js-cue-sdk` (7 files, type-only).
346
+
package/README.md CHANGED
@@ -12,9 +12,14 @@ npm install @qaecy/cue-sdk firebase
12
12
 
13
13
  ## Quick start
14
14
 
15
+ ### Demo app
15
16
  ```typescript
16
17
  import { Cue } from '@qaecy/cue-sdk';
17
18
 
19
+ // Use default demo app (prints a warning — fine for evaluation)
20
+ const cue = new Cue();
21
+
22
+ // Or supply your own configuration
18
23
  const cue = new Cue({
19
24
  apiKey: 'YOUR_FIREBASE_API_KEY',
20
25
  appId: 'YOUR_FIREBASE_APP_ID',
@@ -53,9 +58,9 @@ await cue.auth.signOut();
53
58
 
54
59
  | Option | Type | Required | Description |
55
60
  |---|---|---|---|
56
- | `apiKey` | `string` | | Firebase API key |
57
- | `appId` | `string` | | Firebase App ID |
58
- | `measurementId` | `string` | | Firebase Measurement ID |
61
+ | `apiKey` | `string` | | Firebase API key (defaults to QAECY demo app) |
62
+ | `appId` | `string` | | Firebase App ID (defaults to QAECY demo app) |
63
+ | `measurementId` | `string` | | Firebase Measurement ID (defaults to QAECY demo app) |
59
64
  | `environment` | `'production' \| 'emulator'` | — | Target environment (default: `'production'`) |
60
65
  | `endpoints` | `Partial<CueEndpoints>` | — | Override individual endpoint URLs (takes precedence over `environment`) |
61
66
 
@@ -240,6 +245,48 @@ Access the raw Firebase `Auth` instance for advanced use cases:
240
245
  const firebaseAuth = cue.auth.firebaseAuth;
241
246
  ```
242
247
 
248
+ ## E2E tests
249
+
250
+ The SDK ships integration tests in `e2e/` that run against the local Firebase emulator stack.
251
+
252
+ ### Prerequisites
253
+
254
+ Start the frontend emulator stack from the `e2e` repo (requires Docker):
255
+
256
+ ```bash
257
+ # From /path/to/e2e
258
+ docker compose up firebase-emulator frontend-seed
259
+ ```
260
+
261
+ This spins up Firebase Auth, Firestore, and Storage emulators and seeds the following password-enabled test accounts:
262
+
263
+ | Email | Password | Role |
264
+ |-------|----------|------|
265
+ | `front-regular@example.com` | `Test1234!` | member |
266
+ | `front-super@example.com` | `Test1234!` | superadmin |
267
+
268
+ ### Run
269
+
270
+ ```bash
271
+ npx nx run js-cue-sdk:e2e
272
+ ```
273
+
274
+ Or directly with vitest (from `libs/js/cue-sdk/`):
275
+
276
+ ```bash
277
+ npx vitest run --config vitest.e2e.config.mts
278
+ ```
279
+
280
+ ### What is tested
281
+
282
+ | Suite | Tests |
283
+ |-------|-------|
284
+ | `CueAuth — reactive signals` | `user`, `token`, `isSuperAdmin` (false), `checkSuperAdmin()`, `userIds` |
285
+ | `CueProfile — password management` | `getSignInMethods`, `updatePassword` → sign-in with new pw, old pw rejected, restore |
286
+ | `CueAuth — superadmin claim` | `isSuperAdmin` signal (true), `checkSuperAdmin()` (true) |
287
+
288
+ ---
289
+
243
290
  ## License
244
291
 
245
292
  MIT