@qaecy/cue-sdk 0.0.3 → 0.0.4
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/cue-Cl66hB4E.js +346 -0
- package/index.d.ts +2 -1
- package/index.js +5 -4
- package/lib/api.d.ts +5 -0
- package/lib/cue.d.ts +2 -0
- package/lib/models.d.ts +30 -0
- package/lib/profile.d.ts +36 -0
- package/lib/project.d.ts +5 -0
- package/lib/sync.d.ts +9 -1
- package/node.js +183 -6563
- package/package.json +7 -2
- package/index-CV1OX3eG.js +0 -20390
package/cue-Cl66hB4E.js
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { initializeApp as D } from "firebase/app";
|
|
2
|
+
import { getAuth as S, connectAuthEmulator as C, signInWithEmailAndPassword as v, GoogleAuthProvider as P, OAuthProvider as U, signInWithPopup as T, signInWithCustomToken as O, signOut as j, onAuthStateChanged as K, fetchSignInMethodsForEmail as N, linkWithPopup as R, unlink as q, reauthenticateWithCredential as y, EmailAuthProvider as m, updatePassword as $, linkWithCredential as H, verifyBeforeUpdateEmail as x, sendEmailVerification as L } from "firebase/auth";
|
|
3
|
+
import { getFirestore as b, connectFirestoreEmulator as A, doc as _, collection as o, getDoc as f, setDoc as E, getDocs as u, query as h, where as l, serverTimestamp as W, increment as F, addDoc as z, deleteDoc as B, limit as J } from "firebase/firestore";
|
|
4
|
+
import { nanoid as M } from "nanoid";
|
|
5
|
+
const G = "microsoft.com";
|
|
6
|
+
class Q {
|
|
7
|
+
_auth;
|
|
8
|
+
_endpoints;
|
|
9
|
+
constructor(t, e = !1, r) {
|
|
10
|
+
this._auth = S(t), this._endpoints = r, e && C(this._auth, r.authEmulatorUrl, {
|
|
11
|
+
disableWarnings: !0
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
async signIn(t, e) {
|
|
15
|
+
if (t === "password") {
|
|
16
|
+
if (!e)
|
|
17
|
+
throw new Error("credentials are required for password sign-in");
|
|
18
|
+
return (await v(
|
|
19
|
+
this._auth,
|
|
20
|
+
e.email,
|
|
21
|
+
e.password
|
|
22
|
+
)).user;
|
|
23
|
+
}
|
|
24
|
+
const r = t === "google" ? new P() : new U(G);
|
|
25
|
+
return (await T(this._auth, r)).user;
|
|
26
|
+
}
|
|
27
|
+
/** Sign in with a Cue API key */
|
|
28
|
+
async signInWithApiKey(t, e) {
|
|
29
|
+
const r = await fetch(this._endpoints.tokenUrl, {
|
|
30
|
+
method: "GET",
|
|
31
|
+
headers: {
|
|
32
|
+
"x-project-id": e,
|
|
33
|
+
"cue-api-key": t
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
if (!r.ok)
|
|
37
|
+
throw new Error(`Failed to fetch custom token: ${r.statusText}`);
|
|
38
|
+
const { token: s } = await r.json();
|
|
39
|
+
return (await O(this._auth, s)).user;
|
|
40
|
+
}
|
|
41
|
+
/** Sign out the current user */
|
|
42
|
+
async signOut() {
|
|
43
|
+
await j(this._auth);
|
|
44
|
+
}
|
|
45
|
+
/** Currently signed-in user, or null if not authenticated */
|
|
46
|
+
get currentUser() {
|
|
47
|
+
return this._auth.currentUser;
|
|
48
|
+
}
|
|
49
|
+
/** Subscribe to authentication state changes. Returns an unsubscribe function. */
|
|
50
|
+
onAuthStateChanged(t) {
|
|
51
|
+
return K(this._auth, t);
|
|
52
|
+
}
|
|
53
|
+
/** Get the Firebase ID token for the current user, or null if not authenticated */
|
|
54
|
+
async getToken(t = !1) {
|
|
55
|
+
const e = this._auth.currentUser;
|
|
56
|
+
return e ? e.getIdToken(t) : null;
|
|
57
|
+
}
|
|
58
|
+
/** Raw Firebase Auth instance, for advanced use cases */
|
|
59
|
+
get firebaseAuth() {
|
|
60
|
+
return this._auth;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const V = "/assistant/search", Y = "/triplestore/query";
|
|
64
|
+
class X {
|
|
65
|
+
constructor(t, e, r, s) {
|
|
66
|
+
this._auth = t, this._gatewayUrl = e, this.projects = r, this.sync = s;
|
|
67
|
+
}
|
|
68
|
+
_auth;
|
|
69
|
+
_gatewayUrl;
|
|
70
|
+
projects;
|
|
71
|
+
sync;
|
|
72
|
+
async _authHeaders() {
|
|
73
|
+
return this.getAuthHeaders();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Returns standard authentication headers for the current user.
|
|
77
|
+
* Useful when calling Cue-backed services directly (e.g. the GIS proxy).
|
|
78
|
+
*/
|
|
79
|
+
async getAuthHeaders() {
|
|
80
|
+
const t = await this._auth.getToken();
|
|
81
|
+
if (!t) throw new Error("Not authenticated. Call cue.auth.signIn() first.");
|
|
82
|
+
return {
|
|
83
|
+
Authorization: `Bearer ${t}`,
|
|
84
|
+
"Content-Type": "application/json"
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Search project documents using natural language.
|
|
89
|
+
* The user must be authenticated before calling this.
|
|
90
|
+
*/
|
|
91
|
+
async search(t) {
|
|
92
|
+
const e = await this._authHeaders(), r = await fetch(`${this._gatewayUrl}${V}`, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: e,
|
|
95
|
+
body: JSON.stringify({
|
|
96
|
+
term: t.term,
|
|
97
|
+
projectId: t.projectId,
|
|
98
|
+
categories: t.categories ?? []
|
|
99
|
+
})
|
|
100
|
+
});
|
|
101
|
+
if (!r.ok)
|
|
102
|
+
throw new Error(`Search request failed: ${r.status} ${r.statusText}`);
|
|
103
|
+
return r.json();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Execute a SPARQL query against the project's triplestore.
|
|
107
|
+
* The user must be authenticated before calling this.
|
|
108
|
+
*/
|
|
109
|
+
async sparql(t, e) {
|
|
110
|
+
const r = await this._authHeaders(), s = await fetch(`${this._gatewayUrl}${Y}`, {
|
|
111
|
+
method: "POST",
|
|
112
|
+
headers: r,
|
|
113
|
+
body: JSON.stringify({ query: t, projectId: e })
|
|
114
|
+
});
|
|
115
|
+
if (!s.ok)
|
|
116
|
+
throw new Error(`SPARQL query failed: ${s.status} ${s.statusText}`);
|
|
117
|
+
return s.json();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const w = "projects";
|
|
121
|
+
class Z {
|
|
122
|
+
constructor(t, e, r = !1, s) {
|
|
123
|
+
if (this._auth = t, this._db = b(e), r) {
|
|
124
|
+
const a = s?.firestoreEmulatorHost ?? "localhost", i = s?.firestoreEmulatorPort ?? 8080;
|
|
125
|
+
A(this._db, a, i);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
_auth;
|
|
129
|
+
_db;
|
|
130
|
+
_requireUser() {
|
|
131
|
+
const t = this._auth.currentUser;
|
|
132
|
+
if (!t) throw new Error("Not authenticated. Call cue.auth.signIn() first.");
|
|
133
|
+
return t.uid;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Create a new project. The authenticated user is automatically set as admin, syncer, and member.
|
|
137
|
+
* Throws if a project with the given ID already exists.
|
|
138
|
+
*/
|
|
139
|
+
async createProject(t) {
|
|
140
|
+
const e = this._requireUser(), r = t.id ?? crypto.randomUUID(), s = (/* @__PURE__ */ new Date()).toISOString(), a = { views: [], chatDisabled: !1 }, i = _(o(this._db, w), r);
|
|
141
|
+
if ((await f(i)).exists())
|
|
142
|
+
throw new Error(`Project with ID "${r}" already exists.`);
|
|
143
|
+
const c = {
|
|
144
|
+
id: r,
|
|
145
|
+
name: t.name,
|
|
146
|
+
organizationID: t.organizationID,
|
|
147
|
+
created: s,
|
|
148
|
+
lastSync: null,
|
|
149
|
+
isPublic: !1,
|
|
150
|
+
members: [e],
|
|
151
|
+
syncers: [e],
|
|
152
|
+
admins: [e],
|
|
153
|
+
alternativeIDs: [r],
|
|
154
|
+
projectSettings: a
|
|
155
|
+
};
|
|
156
|
+
return await E(i, c), c;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* List all projects where the authenticated user appears in the members, syncers, or admins array.
|
|
160
|
+
* Runs three parallel Firestore queries and deduplicates by project ID.
|
|
161
|
+
*/
|
|
162
|
+
async listProjects() {
|
|
163
|
+
const t = this._requireUser(), e = o(this._db, w), [r, s, a] = await Promise.all([
|
|
164
|
+
u(h(e, l("members", "array-contains", t))),
|
|
165
|
+
u(h(e, l("syncers", "array-contains", t))),
|
|
166
|
+
u(h(e, l("admins", "array-contains", t)))
|
|
167
|
+
]), i = /* @__PURE__ */ new Set(), d = [];
|
|
168
|
+
for (const c of [r, s, a])
|
|
169
|
+
for (const k of c.docs) {
|
|
170
|
+
const p = k.data();
|
|
171
|
+
i.has(p.id) || (i.add(p.id), d.push(p));
|
|
172
|
+
}
|
|
173
|
+
return d;
|
|
174
|
+
}
|
|
175
|
+
/** Fetch a single project by ID. Returns null if not found. */
|
|
176
|
+
async getProject(t) {
|
|
177
|
+
const e = _(o(this._db, w), t), r = await f(e);
|
|
178
|
+
return r.exists() ? r.data() : null;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Atomically increments `unitsConsumed` on the top-level `clientSync/{projectId}`
|
|
182
|
+
* document, creating it if it doesn't exist. Intended for pre-flight checks.
|
|
183
|
+
*/
|
|
184
|
+
async incrementUnitsConsumed(t, e, r) {
|
|
185
|
+
if (e <= 0) return;
|
|
186
|
+
const s = _(this._db, "clientSync", t);
|
|
187
|
+
await E(s, {
|
|
188
|
+
unitsConsumed: F(e),
|
|
189
|
+
lastUpdated: W(),
|
|
190
|
+
lastUserId: r
|
|
191
|
+
}, { merge: !0 });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const g = "apiKeys";
|
|
195
|
+
class tt {
|
|
196
|
+
constructor(t, e, r, s, a) {
|
|
197
|
+
this._auth = t, this._db = b(e), r && A(this._db, s, a);
|
|
198
|
+
}
|
|
199
|
+
_auth;
|
|
200
|
+
_db;
|
|
201
|
+
_apiKeyDocRef;
|
|
202
|
+
/** Whether the current user has an active API key. */
|
|
203
|
+
async hasAPIKey() {
|
|
204
|
+
const t = this._auth.currentUser?.uid;
|
|
205
|
+
return t ? this._checkIfUserHasAPIKey(t) : !1;
|
|
206
|
+
}
|
|
207
|
+
/** Returns the sign-in methods registered for the current user's email. */
|
|
208
|
+
async getSignInMethods() {
|
|
209
|
+
const t = this._auth.currentUser;
|
|
210
|
+
if (!t?.email) throw new Error("User has no e-mail");
|
|
211
|
+
return N(this._auth.firebaseAuth, t.email);
|
|
212
|
+
}
|
|
213
|
+
/** Builds a human-readable label from a Firebase UserInfo provider entry. */
|
|
214
|
+
buildProviderLabel(t) {
|
|
215
|
+
return t.displayName && t.email ? `${t.displayName} (${t.email})` : t.displayName ?? t.email ?? "-";
|
|
216
|
+
}
|
|
217
|
+
/** Returns SSO accounts linked to the current user (excludes password). */
|
|
218
|
+
getSSOAccounts() {
|
|
219
|
+
const t = this._auth.currentUser;
|
|
220
|
+
return t ? t.providerData.filter((e) => e.providerId !== "password").map((e) => ({ id: e.providerId, label: this.buildProviderLabel(e) })) : [];
|
|
221
|
+
}
|
|
222
|
+
/** Links a Google or Microsoft provider to the current account via popup. Returns the new provider label. */
|
|
223
|
+
async linkProvider(t) {
|
|
224
|
+
const e = this._requireUser(), r = t === "google.com" ? new P() : new U(t), a = (await R(e, r)).user.providerData.find(
|
|
225
|
+
(i) => i.providerId === t
|
|
226
|
+
);
|
|
227
|
+
return a ? this.buildProviderLabel(a) : "-";
|
|
228
|
+
}
|
|
229
|
+
/** Unlinks a provider from the current account. */
|
|
230
|
+
async unlinkProvider(t) {
|
|
231
|
+
await q(this._requireUser(), t);
|
|
232
|
+
}
|
|
233
|
+
/** Changes the password. Reauthenticates first. */
|
|
234
|
+
async updatePassword(t, e) {
|
|
235
|
+
const r = this._requireUser();
|
|
236
|
+
if (!r.email) throw new Error("User has no e-mail");
|
|
237
|
+
await y(
|
|
238
|
+
r,
|
|
239
|
+
m.credential(r.email, t)
|
|
240
|
+
), await $(r, e);
|
|
241
|
+
}
|
|
242
|
+
/** Adds (sets) a password for an account that currently only uses SSO. */
|
|
243
|
+
async addPassword(t) {
|
|
244
|
+
const e = this._requireUser();
|
|
245
|
+
if (!e.email) throw new Error("User has no e-mail");
|
|
246
|
+
await H(e, m.credential(e.email, t));
|
|
247
|
+
}
|
|
248
|
+
/** Requests an e-mail change. Sends a verification e-mail to the new address. */
|
|
249
|
+
async updateEmail(t, e) {
|
|
250
|
+
const r = this._requireUser();
|
|
251
|
+
if (!r.email) throw new Error("User e-mail not available");
|
|
252
|
+
await y(
|
|
253
|
+
r,
|
|
254
|
+
m.credential(r.email, e)
|
|
255
|
+
), await x(r, t), await L(r);
|
|
256
|
+
}
|
|
257
|
+
/** Creates a new API key for the current user. */
|
|
258
|
+
async createAPIKey(t) {
|
|
259
|
+
const e = this._auth.currentUser?.uid;
|
|
260
|
+
if (!e) throw new Error("User not authenticated");
|
|
261
|
+
const r = { key: `cue-${M(150)}`, uid: e, expiration: t }, s = o(this._db, g);
|
|
262
|
+
return this._apiKeyDocRef = await z(s, r), r;
|
|
263
|
+
}
|
|
264
|
+
/** Revokes the current user's API key. */
|
|
265
|
+
async revokeAPIKey() {
|
|
266
|
+
if (!this._apiKeyDocRef) throw new Error("No API key document reference");
|
|
267
|
+
await B(this._apiKeyDocRef), this._apiKeyDocRef = void 0;
|
|
268
|
+
}
|
|
269
|
+
/** Fetches the current user's existing API key. */
|
|
270
|
+
async requestAPIKey() {
|
|
271
|
+
if (!this._apiKeyDocRef) throw new Error("No API key document reference");
|
|
272
|
+
const t = (await f(this._apiKeyDocRef)).data();
|
|
273
|
+
return { key: t.key, expiration: t.expiration };
|
|
274
|
+
}
|
|
275
|
+
async _checkIfUserHasAPIKey(t) {
|
|
276
|
+
const e = o(this._db, g), r = h(e, l("uid", "==", t), J(1)), s = await u(r);
|
|
277
|
+
return s.empty || (this._apiKeyDocRef = s.docs[0].ref), !s.empty;
|
|
278
|
+
}
|
|
279
|
+
_requireUser() {
|
|
280
|
+
const t = this._auth.currentUser;
|
|
281
|
+
if (!t) throw new Error("Not authenticated");
|
|
282
|
+
return t;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const I = "qaecy-mvp-406413", et = "734737865998", rt = {
|
|
286
|
+
production: {
|
|
287
|
+
gatewayUrl: "https://accessors-api-gateway-ueyeemwf2a-oa.a.run.app",
|
|
288
|
+
tokenUrl: "https://accessors-api-gateway-ueyeemwf2a-oa.a.run.app/token",
|
|
289
|
+
authEmulatorUrl: "http://localhost:9099",
|
|
290
|
+
storageEmulatorHost: "localhost",
|
|
291
|
+
storageEmulatorPort: 9199,
|
|
292
|
+
firestoreEmulatorHost: "localhost",
|
|
293
|
+
firestoreEmulatorPort: 8080
|
|
294
|
+
},
|
|
295
|
+
emulator: {
|
|
296
|
+
gatewayUrl: "http://localhost:8093",
|
|
297
|
+
tokenUrl: "http://localhost:8093/token",
|
|
298
|
+
authEmulatorUrl: "http://localhost:9099",
|
|
299
|
+
storageEmulatorHost: "localhost",
|
|
300
|
+
storageEmulatorPort: 9199,
|
|
301
|
+
firestoreEmulatorHost: "localhost",
|
|
302
|
+
firestoreEmulatorPort: 8080
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
class nt {
|
|
306
|
+
auth;
|
|
307
|
+
api;
|
|
308
|
+
profile;
|
|
309
|
+
_app;
|
|
310
|
+
_endpoints;
|
|
311
|
+
_isEmulator;
|
|
312
|
+
constructor(t) {
|
|
313
|
+
const e = t.environment ?? "production";
|
|
314
|
+
this._endpoints = { ...rt[e], ...t.endpoints }, this._isEmulator = e === "emulator", this._app = D({
|
|
315
|
+
apiKey: t.apiKey,
|
|
316
|
+
appId: t.appId,
|
|
317
|
+
measurementId: t.measurementId,
|
|
318
|
+
authDomain: `${I}.firebaseapp.com`,
|
|
319
|
+
projectId: I,
|
|
320
|
+
messagingSenderId: et
|
|
321
|
+
}), this.auth = new Q(this._app, this._isEmulator, this._endpoints);
|
|
322
|
+
const r = new Z(this.auth, this._app, this._isEmulator, this._endpoints);
|
|
323
|
+
this.api = this._buildApi(r), this.profile = new tt(
|
|
324
|
+
this.auth,
|
|
325
|
+
this._app,
|
|
326
|
+
this._isEmulator,
|
|
327
|
+
this._endpoints.firestoreEmulatorHost,
|
|
328
|
+
this._endpoints.firestoreEmulatorPort
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
/** Override in subclasses to provide a custom CueApi (e.g. with sync). */
|
|
332
|
+
_buildApi(t) {
|
|
333
|
+
return new X(this.auth, this._endpoints.gatewayUrl, t);
|
|
334
|
+
}
|
|
335
|
+
/** Convenience: get the current user's Firebase ID token */
|
|
336
|
+
getToken(t = !1) {
|
|
337
|
+
return this.auth.getToken(t);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
export {
|
|
341
|
+
nt as C,
|
|
342
|
+
X as a,
|
|
343
|
+
Q as b,
|
|
344
|
+
tt as c,
|
|
345
|
+
Z as d
|
|
346
|
+
};
|
package/index.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ export { Cue } from './lib/cue';
|
|
|
2
2
|
export { CueAuth } from './lib/auth';
|
|
3
3
|
export { CueApi } from './lib/api';
|
|
4
4
|
export { CueProjects } from './lib/project';
|
|
5
|
-
export
|
|
5
|
+
export { CueProfile } from './lib/profile';
|
|
6
|
+
export type { CueSdkConfig, SsoProvider, PasswordCredentials, SearchRequest, SearchResponse, SearchSource, ProjectData, ProjectSettings, CreateProjectOptions, SyncOptions, SyncResult, ScanOutputRecord, ProfileSSOAccount, APIKeyInfo, APIKeyDoc, } from './lib/models';
|
|
6
7
|
export type { AuthStateListener, Unsubscribe } from './lib/auth';
|
package/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as s, a as u, b as C, c as o, d as r } from "./cue-Cl66hB4E.js";
|
|
2
2
|
export {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
s as Cue,
|
|
4
|
+
u as CueApi,
|
|
5
5
|
C as CueAuth,
|
|
6
|
-
o as
|
|
6
|
+
o as CueProfile,
|
|
7
|
+
r as CueProjects
|
|
7
8
|
};
|
package/lib/api.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ export declare class CueApi {
|
|
|
9
9
|
readonly sync?: CueSyncApi | undefined;
|
|
10
10
|
constructor(_auth: CueAuth, _gatewayUrl: string, projects: CueProjects, sync?: CueSyncApi | undefined);
|
|
11
11
|
private _authHeaders;
|
|
12
|
+
/**
|
|
13
|
+
* Returns standard authentication headers for the current user.
|
|
14
|
+
* Useful when calling Cue-backed services directly (e.g. the GIS proxy).
|
|
15
|
+
*/
|
|
16
|
+
getAuthHeaders(): Promise<Record<string, string>>;
|
|
12
17
|
/**
|
|
13
18
|
* Search project documents using natural language.
|
|
14
19
|
* The user must be authenticated before calling this.
|
package/lib/cue.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { FirebaseApp } from 'firebase/app';
|
|
|
2
2
|
import { CueAuth } from './auth';
|
|
3
3
|
import { CueApi } from './api';
|
|
4
4
|
import { CueProjects } from './project';
|
|
5
|
+
import { CueProfile } from './profile';
|
|
5
6
|
import { CueEndpoints, CueSdkConfig } from './models';
|
|
6
7
|
/**
|
|
7
8
|
* Main entry point for the QAECY SDK (browser-safe).
|
|
@@ -15,6 +16,7 @@ import { CueEndpoints, CueSdkConfig } from './models';
|
|
|
15
16
|
export declare class Cue {
|
|
16
17
|
readonly auth: CueAuth;
|
|
17
18
|
readonly api: CueApi;
|
|
19
|
+
readonly profile: CueProfile;
|
|
18
20
|
protected readonly _app: FirebaseApp;
|
|
19
21
|
protected readonly _endpoints: CueEndpoints;
|
|
20
22
|
protected readonly _isEmulator: boolean;
|
package/lib/models.d.ts
CHANGED
|
@@ -95,6 +95,21 @@ export interface SyncOptions {
|
|
|
95
95
|
/** Enable verbose logging */
|
|
96
96
|
verbose?: boolean;
|
|
97
97
|
}
|
|
98
|
+
/** Per-extension cost breakdown returned by {@link CueSyncApi.scanCost}. */
|
|
99
|
+
export interface ScanOutputRecord {
|
|
100
|
+
/** File extension (without leading dot), e.g. `"pdf"`, `"ifc"`. */
|
|
101
|
+
ext: string;
|
|
102
|
+
/** Number of files with this extension. */
|
|
103
|
+
count: number;
|
|
104
|
+
/** Share of this extension among supported files (0–100). */
|
|
105
|
+
percentOfFiltered: number;
|
|
106
|
+
/** Share of this extension among all files (0–100). */
|
|
107
|
+
percentOfAll: number;
|
|
108
|
+
/** Billable units for this extension (e.g. pages for PDFs, rows for spreadsheets). */
|
|
109
|
+
units: number;
|
|
110
|
+
/** Total size of files with this extension in megabytes. */
|
|
111
|
+
sizeMb: number;
|
|
112
|
+
}
|
|
98
113
|
export interface SyncResult {
|
|
99
114
|
/** Number of files successfully synced in this run */
|
|
100
115
|
syncCount: number;
|
|
@@ -108,4 +123,19 @@ export interface SyncResult {
|
|
|
108
123
|
totalSize: number;
|
|
109
124
|
/** Whether any RDF metadata was written */
|
|
110
125
|
rdfWritten: boolean;
|
|
126
|
+
/** Total billable units consumed across all successfully uploaded files in this run */
|
|
127
|
+
unitsConsumed: number;
|
|
128
|
+
}
|
|
129
|
+
export interface ProfileSSOAccount {
|
|
130
|
+
id: string;
|
|
131
|
+
label: string;
|
|
132
|
+
}
|
|
133
|
+
export interface APIKeyInfo {
|
|
134
|
+
key: string;
|
|
135
|
+
expiration: string;
|
|
136
|
+
}
|
|
137
|
+
export interface APIKeyDoc {
|
|
138
|
+
key: string;
|
|
139
|
+
uid: string;
|
|
140
|
+
expiration: string;
|
|
111
141
|
}
|
package/lib/profile.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { UserInfo } from 'firebase/auth';
|
|
2
|
+
import { FirebaseApp } from 'firebase/app';
|
|
3
|
+
import { APIKeyDoc, APIKeyInfo, ProfileSSOAccount } from './models';
|
|
4
|
+
import { CueAuth } from './auth';
|
|
5
|
+
export declare class CueProfile {
|
|
6
|
+
private readonly _auth;
|
|
7
|
+
private readonly _db;
|
|
8
|
+
private _apiKeyDocRef?;
|
|
9
|
+
constructor(_auth: CueAuth, app: FirebaseApp, useEmulator: boolean, emulatorHost: string, emulatorPort: number);
|
|
10
|
+
/** Whether the current user has an active API key. */
|
|
11
|
+
hasAPIKey(): Promise<boolean>;
|
|
12
|
+
/** Returns the sign-in methods registered for the current user's email. */
|
|
13
|
+
getSignInMethods(): Promise<string[]>;
|
|
14
|
+
/** Builds a human-readable label from a Firebase UserInfo provider entry. */
|
|
15
|
+
buildProviderLabel(userInfo: UserInfo): string;
|
|
16
|
+
/** Returns SSO accounts linked to the current user (excludes password). */
|
|
17
|
+
getSSOAccounts(): ProfileSSOAccount[];
|
|
18
|
+
/** Links a Google or Microsoft provider to the current account via popup. Returns the new provider label. */
|
|
19
|
+
linkProvider(ssoProvider: string): Promise<string>;
|
|
20
|
+
/** Unlinks a provider from the current account. */
|
|
21
|
+
unlinkProvider(providerId: string): Promise<void>;
|
|
22
|
+
/** Changes the password. Reauthenticates first. */
|
|
23
|
+
updatePassword(currentPassword: string, newPassword: string): Promise<void>;
|
|
24
|
+
/** Adds (sets) a password for an account that currently only uses SSO. */
|
|
25
|
+
addPassword(password: string): Promise<void>;
|
|
26
|
+
/** Requests an e-mail change. Sends a verification e-mail to the new address. */
|
|
27
|
+
updateEmail(newEmail: string, password: string): Promise<void>;
|
|
28
|
+
/** Creates a new API key for the current user. */
|
|
29
|
+
createAPIKey(expiration: string): Promise<APIKeyDoc>;
|
|
30
|
+
/** Revokes the current user's API key. */
|
|
31
|
+
revokeAPIKey(): Promise<void>;
|
|
32
|
+
/** Fetches the current user's existing API key. */
|
|
33
|
+
requestAPIKey(): Promise<APIKeyInfo>;
|
|
34
|
+
private _checkIfUserHasAPIKey;
|
|
35
|
+
private _requireUser;
|
|
36
|
+
}
|
package/lib/project.d.ts
CHANGED
|
@@ -18,4 +18,9 @@ export declare class CueProjects {
|
|
|
18
18
|
listProjects(): Promise<ProjectData[]>;
|
|
19
19
|
/** Fetch a single project by ID. Returns null if not found. */
|
|
20
20
|
getProject(projectId: string): Promise<ProjectData | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Atomically increments `unitsConsumed` on the top-level `clientSync/{projectId}`
|
|
23
|
+
* document, creating it if it doesn't exist. Intended for pre-flight checks.
|
|
24
|
+
*/
|
|
25
|
+
incrementUnitsConsumed(projectId: string, units: number, userId: string): Promise<void>;
|
|
21
26
|
}
|
package/lib/sync.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { CueBlobStorage } from 'js-databases';
|
|
|
2
2
|
import { LocalFile } from 'js-sync-tools';
|
|
3
3
|
import { CueAuth } from './auth';
|
|
4
4
|
import { CueProjects } from './project';
|
|
5
|
-
import { SyncOptions, SyncResult } from './models';
|
|
5
|
+
import { ScanOutputRecord, SyncOptions, SyncResult } from './models';
|
|
6
6
|
export declare class CueSyncApi {
|
|
7
7
|
private readonly _auth;
|
|
8
8
|
private readonly _projects;
|
|
@@ -17,5 +17,13 @@ export declare class CueSyncApi {
|
|
|
17
17
|
private _listRemoteFiles;
|
|
18
18
|
private _getGraphFiles;
|
|
19
19
|
private _uploadRdfMetadata;
|
|
20
|
+
/**
|
|
21
|
+
* Scans `localFiles` and returns a per-extension cost breakdown.
|
|
22
|
+
*
|
|
23
|
+
* Each {@link ScanOutputRecord} contains `units` — the billable metric for
|
|
24
|
+
* that extension (e.g. pages for PDFs, rows for spreadsheets) — which can be
|
|
25
|
+
* shown to the user before or after calling {@link sync}.
|
|
26
|
+
*/
|
|
27
|
+
scanCost(localFiles: LocalFile[]): Promise<ScanOutputRecord[]>;
|
|
20
28
|
private _logProgress;
|
|
21
29
|
}
|