backlex 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +43 -0
- package/dist/chunk-U2MHWV2E.js +44 -0
- package/dist/chunk-UIUS57OR.js +15 -0
- package/dist/index.d.ts +569 -0
- package/dist/index.js +857 -0
- package/dist/types-CbcbXGiA.d.ts +247 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +1 -0
- package/dist/webhook.d.ts +39 -0
- package/dist/webhook.js +1 -0
- package/package.json +50 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
import { L as ListQuery, k as ListResponse, C as Condition, f as DurationParts, R as RelativeNow, A as AggregateQuery, a as AggregateRow, S as SearchQuery, m as SearchResponse, I as ImportSummary, h as ItemQuery, i as ItemResponse, d as BatchResponse, c as BatchOperation, g as ItemEvent, l as ResumableUploadResult, D as DeviceToken, P as PhoneNumber, j as JobStatus, J as Job, F as FlagState } from './types-CbcbXGiA.js';
|
|
2
|
+
export { B as BacklexError, U as Upload, n as UploadStatus } from './types-CbcbXGiA.js';
|
|
3
|
+
export { VerifyWebhookOptions, verifyWebhook } from './webhook.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Offline-first sync for a single collection.
|
|
7
|
+
*
|
|
8
|
+
* Pulls the server changefeed (`GET /api/items/:slug/changes`) into a local
|
|
9
|
+
* store, keeps it live over SSE, and lets the app read/write while offline:
|
|
10
|
+
* writes apply optimistically to the local store and queue, then flush through
|
|
11
|
+
* the batch endpoint on reconnect. Conflicts resolve last-write-wins by
|
|
12
|
+
* `updated_at`, with locally-queued (not-yet-flushed) writes held until they
|
|
13
|
+
* land.
|
|
14
|
+
*
|
|
15
|
+
* The store is pluggable — `memoryStore()` works anywhere; `indexedDbStore()`
|
|
16
|
+
* persists across reloads in the browser.
|
|
17
|
+
*/
|
|
18
|
+
type QueuedOp = {
|
|
19
|
+
kind: "create";
|
|
20
|
+
tempId: string;
|
|
21
|
+
data: Record<string, unknown>;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "update";
|
|
24
|
+
id: string;
|
|
25
|
+
data: Record<string, unknown>;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "delete";
|
|
28
|
+
id: string;
|
|
29
|
+
};
|
|
30
|
+
interface SyncStore {
|
|
31
|
+
get(id: string): Promise<Record<string, unknown> | undefined>;
|
|
32
|
+
set(id: string, row: Record<string, unknown>): Promise<void>;
|
|
33
|
+
remove(id: string): Promise<void>;
|
|
34
|
+
all(): Promise<Record<string, unknown>[]>;
|
|
35
|
+
getMeta(key: string): Promise<string | null>;
|
|
36
|
+
setMeta(key: string, value: string): Promise<void>;
|
|
37
|
+
queueGet(): Promise<QueuedOp[]>;
|
|
38
|
+
queueSet(ops: QueuedOp[]): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
/** In-memory store — non-persistent; the default and the testing baseline. */
|
|
41
|
+
declare const memoryStore: () => SyncStore;
|
|
42
|
+
/** IndexedDB-backed store (browser). One object store for rows + one for meta;
|
|
43
|
+
* the write queue lives under a meta key. Falls back to throwing if IndexedDB
|
|
44
|
+
* is unavailable — use `memoryStore()` outside the browser. */
|
|
45
|
+
declare const indexedDbStore: (opts: {
|
|
46
|
+
collection: string;
|
|
47
|
+
dbName?: string;
|
|
48
|
+
}) => SyncStore;
|
|
49
|
+
/** The subset of the backlex client `createSync` needs. The full client satisfies it. */
|
|
50
|
+
interface SyncClientLike {
|
|
51
|
+
request: <T>(method: string, path: string, body?: unknown) => Promise<T>;
|
|
52
|
+
subscribe: (channel: string, onEvent: (e: {
|
|
53
|
+
event: "created" | "updated" | "deleted";
|
|
54
|
+
data: Record<string, unknown>;
|
|
55
|
+
}) => void, onError?: (err: unknown) => void) => () => void;
|
|
56
|
+
}
|
|
57
|
+
interface SyncOptions {
|
|
58
|
+
collection: string;
|
|
59
|
+
store?: SyncStore;
|
|
60
|
+
/** Primary-key field. Default `id`. */
|
|
61
|
+
pk?: string;
|
|
62
|
+
/** Rows per changefeed page. Default 200. */
|
|
63
|
+
pageSize?: number;
|
|
64
|
+
/** Called after the local store changes (pull / live / local write). */
|
|
65
|
+
onChange?: () => void;
|
|
66
|
+
}
|
|
67
|
+
declare const createSync: (client: SyncClientLike, options: SyncOptions) => {
|
|
68
|
+
pull: () => Promise<number>;
|
|
69
|
+
flush: () => Promise<void>;
|
|
70
|
+
live: () => (() => void);
|
|
71
|
+
start: () => Promise<void>;
|
|
72
|
+
stop: () => void;
|
|
73
|
+
getAll: () => Promise<Record<string, unknown>[]>;
|
|
74
|
+
get: (id: string) => Promise<Record<string, unknown> | undefined>;
|
|
75
|
+
create: (data: Record<string, unknown>) => Promise<string>;
|
|
76
|
+
update: (id: string, data: Record<string, unknown>) => Promise<void>;
|
|
77
|
+
remove: (id: string) => Promise<void>;
|
|
78
|
+
store: SyncStore;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Type-safe fluent query builder — a Drizzle/Supabase-style ergonomics layer
|
|
83
|
+
* that COMPILES to the canonical JSON `Condition` / `ListQuery` the REST API
|
|
84
|
+
* already speaks. It is NOT a new wire format: `.toQuery()` returns a plain
|
|
85
|
+
* `ListQuery`, so everything (permissions, AI plans, serialization) stays on
|
|
86
|
+
* the one JSON grammar.
|
|
87
|
+
*
|
|
88
|
+
* const { data } = await client.from<Order>("orders").query()
|
|
89
|
+
* .where(f => f.and(
|
|
90
|
+
* f.eq("status", "active"),
|
|
91
|
+
* f.gte("total", 100),
|
|
92
|
+
* f.rel("customer", c => c.eq("tier", "gold")), // → "customer.tier"
|
|
93
|
+
* f.gte("placed_at", f.now({ sub: { months: 1 } })),
|
|
94
|
+
* ))
|
|
95
|
+
* .select("id", "total", "customer.name")
|
|
96
|
+
* .orderBy("-placed_at", "id")
|
|
97
|
+
* .limit(50)
|
|
98
|
+
* .list();
|
|
99
|
+
*
|
|
100
|
+
* Field args are typed `keyof T | (string & {})` — autocomplete for known
|
|
101
|
+
* columns, dotted relation paths still allowed, no codegen required.
|
|
102
|
+
*/
|
|
103
|
+
/** A known column of `T`, or any string (dotted relation paths, computed). */
|
|
104
|
+
type FieldKey<T> = (keyof T & string) | (string & {});
|
|
105
|
+
/** `field` ascending, or `-field` descending. */
|
|
106
|
+
type SortKey<T> = FieldKey<T> | `-${string}`;
|
|
107
|
+
interface FilterBuilder<T> {
|
|
108
|
+
eq(field: FieldKey<T>, value: unknown): Condition;
|
|
109
|
+
neq(field: FieldKey<T>, value: unknown): Condition;
|
|
110
|
+
gt(field: FieldKey<T>, value: unknown): Condition;
|
|
111
|
+
gte(field: FieldKey<T>, value: unknown): Condition;
|
|
112
|
+
lt(field: FieldKey<T>, value: unknown): Condition;
|
|
113
|
+
lte(field: FieldKey<T>, value: unknown): Condition;
|
|
114
|
+
in(field: FieldKey<T>, values: unknown[]): Condition;
|
|
115
|
+
nin(field: FieldKey<T>, values: unknown[]): Condition;
|
|
116
|
+
between(field: FieldKey<T>, lo: unknown, hi: unknown): Condition;
|
|
117
|
+
isNull(field: FieldKey<T>, isNull?: boolean): Condition;
|
|
118
|
+
empty(field: FieldKey<T>): Condition;
|
|
119
|
+
nempty(field: FieldKey<T>): Condition;
|
|
120
|
+
contains(field: FieldKey<T>, value: string): Condition;
|
|
121
|
+
icontains(field: FieldKey<T>, value: string): Condition;
|
|
122
|
+
startsWith(field: FieldKey<T>, value: string): Condition;
|
|
123
|
+
endsWith(field: FieldKey<T>, value: string): Condition;
|
|
124
|
+
and(...conds: Condition[]): Condition;
|
|
125
|
+
or(...conds: Condition[]): Condition;
|
|
126
|
+
not(cond: Condition): Condition;
|
|
127
|
+
/** Traverse a relation: keys produced by `build` are prefixed with `head.`. */
|
|
128
|
+
rel<R = Record<string, unknown>>(head: FieldKey<T>, build: (f: FilterBuilder<R>) => Condition): Condition;
|
|
129
|
+
/** Relative-date value, e.g. `f.now({ sub: { months: 1 } })`. */
|
|
130
|
+
now(opts?: {
|
|
131
|
+
add?: DurationParts;
|
|
132
|
+
sub?: DurationParts;
|
|
133
|
+
}): RelativeNow;
|
|
134
|
+
}
|
|
135
|
+
declare class QueryBuilder<T extends Record<string, unknown>> {
|
|
136
|
+
private readonly listFn;
|
|
137
|
+
private _filter?;
|
|
138
|
+
private _sort;
|
|
139
|
+
private _fields;
|
|
140
|
+
private _expand;
|
|
141
|
+
private _limit?;
|
|
142
|
+
private _offset?;
|
|
143
|
+
private _meta?;
|
|
144
|
+
private _locale?;
|
|
145
|
+
private _q?;
|
|
146
|
+
constructor(listFn: (q: ListQuery) => Promise<ListResponse<T>>);
|
|
147
|
+
where(build: (f: FilterBuilder<T>) => Condition): this;
|
|
148
|
+
/** Replace the filter with a raw canonical condition (escape hatch). */
|
|
149
|
+
filter(cond: Condition): this;
|
|
150
|
+
select(...fields: FieldKey<T>[]): this;
|
|
151
|
+
orderBy(...sorts: SortKey<T>[]): this;
|
|
152
|
+
/** Inline single-hop relations (replaces each FK with the related object). */
|
|
153
|
+
expand(...rels: FieldKey<T>[]): this;
|
|
154
|
+
/** Project `i18n_text` fields to one locale, or `"*"` for the full map. */
|
|
155
|
+
locale(loc: string): this;
|
|
156
|
+
/** Free-text search across readable text fields. */
|
|
157
|
+
search(text: string): this;
|
|
158
|
+
limit(n: number): this;
|
|
159
|
+
offset(n: number): this;
|
|
160
|
+
withMeta(m: "filter_count" | "total_count" | "*"): this;
|
|
161
|
+
/** Assemble the plain `ListQuery` — the canonical JSON the REST API takes. */
|
|
162
|
+
toQuery(): ListQuery;
|
|
163
|
+
list(): Promise<ListResponse<T>>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
interface ClientOptions {
|
|
167
|
+
url: string;
|
|
168
|
+
/** Static API key (`pak_...`) for server-to-server calls. Browser apps
|
|
169
|
+
* should rely on the cookie session / a workspace session token and omit
|
|
170
|
+
* this. */
|
|
171
|
+
apiKey?: string;
|
|
172
|
+
/**
|
|
173
|
+
* Workspace slug. When set, the client operates in **app mode**: `auth.*`
|
|
174
|
+
* targets that workspace's own auth surface (`/api/t/<slug>/auth/*`, the
|
|
175
|
+
* "auth as a service" pool — distinct from the admin/control-plane auth),
|
|
176
|
+
* and the session token returned by `auth.signUp` / `auth.signIn` is
|
|
177
|
+
* captured and sent as `Authorization: Bearer <token>` on every subsequent
|
|
178
|
+
* request (data + auth). Persist it across page loads with `auth.getToken()`
|
|
179
|
+
* / restore it with `auth.setToken()`.
|
|
180
|
+
*/
|
|
181
|
+
workspace?: string;
|
|
182
|
+
/** Restore a previously-saved workspace session token (app mode). */
|
|
183
|
+
token?: string;
|
|
184
|
+
/**
|
|
185
|
+
* Scope every request to a specific tenant/workspace by sending the
|
|
186
|
+
* `X-Backlex-Tenant` header (slug or id). Needed for anonymous public reads
|
|
187
|
+
* and for a `pak_` key addressing a tenant other than its home one. The server
|
|
188
|
+
* ignores it for app-mode bearer sessions (the tenant comes from the session).
|
|
189
|
+
*/
|
|
190
|
+
tenant?: string;
|
|
191
|
+
/** Optional fetch override (testing / Node polyfill). */
|
|
192
|
+
fetch?: typeof fetch;
|
|
193
|
+
}
|
|
194
|
+
interface AuthUser {
|
|
195
|
+
id: string;
|
|
196
|
+
email: string;
|
|
197
|
+
name?: string | null;
|
|
198
|
+
image?: string | null;
|
|
199
|
+
}
|
|
200
|
+
interface AuthResult {
|
|
201
|
+
user: AuthUser;
|
|
202
|
+
token?: string;
|
|
203
|
+
}
|
|
204
|
+
interface AuthSession {
|
|
205
|
+
id: string;
|
|
206
|
+
token: string;
|
|
207
|
+
userId: string;
|
|
208
|
+
expiresAt: string;
|
|
209
|
+
ipAddress?: string | null;
|
|
210
|
+
userAgent?: string | null;
|
|
211
|
+
createdAt: string;
|
|
212
|
+
updatedAt: string;
|
|
213
|
+
}
|
|
214
|
+
interface PublicProvider {
|
|
215
|
+
id: string;
|
|
216
|
+
kind: "credential" | "magic-link" | "email-otp" | "passkey" | "social";
|
|
217
|
+
label: string;
|
|
218
|
+
enabled: boolean;
|
|
219
|
+
}
|
|
220
|
+
interface AuthSurface {
|
|
221
|
+
tenantId: string | null;
|
|
222
|
+
providers: PublicProvider[];
|
|
223
|
+
policy: {
|
|
224
|
+
openSignup: boolean;
|
|
225
|
+
requireEmailVerification: boolean;
|
|
226
|
+
} & Record<string, unknown>;
|
|
227
|
+
}
|
|
228
|
+
/** The per-collection data API returned by `client.from<T>(slug)`. Exported so
|
|
229
|
+
* generated SDKs (see `backlex gen-types --sdk`) and apps can name the shape. */
|
|
230
|
+
interface CollectionClient<T extends Record<string, unknown>> {
|
|
231
|
+
list(q?: ListQuery): Promise<ListResponse<T>>;
|
|
232
|
+
/** Fluent, type-safe query builder that compiles to `ListQuery`. */
|
|
233
|
+
query(): QueryBuilder<T>;
|
|
234
|
+
/** Run a single-function aggregate (count/sum/avg/min/max), optionally grouped. */
|
|
235
|
+
aggregate(body: AggregateQuery): Promise<{
|
|
236
|
+
data: AggregateRow[];
|
|
237
|
+
}>;
|
|
238
|
+
/** Relevance search — full-text, vector, or `hybrid` (RRF). Requires the
|
|
239
|
+
* matching capability enabled on the collection. Rows come back best-first
|
|
240
|
+
* with the caller's read permission + tenant scope enforced. */
|
|
241
|
+
search(body: SearchQuery): Promise<SearchResponse<T>>;
|
|
242
|
+
/** Export every readable row as a JSON or CSV string. */
|
|
243
|
+
exportItems(format?: "json" | "csv"): Promise<string>;
|
|
244
|
+
/** Bulk-import rows from a JSON array (or a raw JSON/CSV string). */
|
|
245
|
+
importItems(body: string | Partial<T>[], format?: "json" | "csv"): Promise<ImportSummary>;
|
|
246
|
+
one(id: string, opts?: ItemQuery): Promise<ItemResponse<T>>;
|
|
247
|
+
create(data: Partial<T>): Promise<ItemResponse<T>>;
|
|
248
|
+
update(id: string, patch: Partial<T>): Promise<ItemResponse<T>>;
|
|
249
|
+
delete(id: string): Promise<{
|
|
250
|
+
ok: boolean;
|
|
251
|
+
}>;
|
|
252
|
+
createMany(rows: Partial<T>[], opts?: {
|
|
253
|
+
atomic?: boolean;
|
|
254
|
+
}): Promise<BatchResponse<T>>;
|
|
255
|
+
updateMany(updates: {
|
|
256
|
+
id: string;
|
|
257
|
+
data: Partial<T>;
|
|
258
|
+
}[], opts?: {
|
|
259
|
+
atomic?: boolean;
|
|
260
|
+
}): Promise<BatchResponse<T>>;
|
|
261
|
+
deleteMany(ids: string[], opts?: {
|
|
262
|
+
atomic?: boolean;
|
|
263
|
+
}): Promise<BatchResponse<T>>;
|
|
264
|
+
batch(operations: BatchOperation<T>[], opts?: {
|
|
265
|
+
atomic?: boolean;
|
|
266
|
+
}): Promise<BatchResponse<T>>;
|
|
267
|
+
publish(id: string): Promise<ItemResponse<T>>;
|
|
268
|
+
unpublish(id: string): Promise<ItemResponse<T>>;
|
|
269
|
+
schedulePublish(id: string, at: Date | string | null): Promise<ItemResponse<T>>;
|
|
270
|
+
}
|
|
271
|
+
declare const createClient: (opts: ClientOptions) => {
|
|
272
|
+
from: <T extends Record<string, unknown>>(slug: string) => CollectionClient<T>;
|
|
273
|
+
subscribe: <T = Record<string, unknown>>(channel: string, onEvent: (e: ItemEvent<T>) => void, onError?: (err: unknown) => void) => (() => void);
|
|
274
|
+
auth: {
|
|
275
|
+
/** Email + password sign-up. In app mode this creates a *workspace* end-
|
|
276
|
+
* user (in `app_users`), not a control-plane account. */
|
|
277
|
+
signUp: (input: {
|
|
278
|
+
email: string;
|
|
279
|
+
password: string;
|
|
280
|
+
name?: string;
|
|
281
|
+
}) => Promise<AuthResult>;
|
|
282
|
+
/** Email + password sign-in. */
|
|
283
|
+
signIn: (input: {
|
|
284
|
+
email: string;
|
|
285
|
+
password: string;
|
|
286
|
+
}) => Promise<AuthResult>;
|
|
287
|
+
/**
|
|
288
|
+
* Begin an OAuth sign-in. Returns `{ url }` — the provider's authorize
|
|
289
|
+
* page — which a browser app should navigate to (`location.href = url`).
|
|
290
|
+
* `provider` must be one of the ids returned by `auth.providers()`.
|
|
291
|
+
*/
|
|
292
|
+
signInSocial: (provider: string, input?: {
|
|
293
|
+
callbackURL?: string;
|
|
294
|
+
errorCallbackURL?: string;
|
|
295
|
+
}) => Promise<{
|
|
296
|
+
url: string;
|
|
297
|
+
redirect: boolean;
|
|
298
|
+
}>;
|
|
299
|
+
/** Send a one-time sign-in link by email (requires the `magic` provider
|
|
300
|
+
* to be enabled for the workspace). */
|
|
301
|
+
signInMagicLink: (input: {
|
|
302
|
+
email: string;
|
|
303
|
+
callbackURL?: string;
|
|
304
|
+
}) => Promise<{
|
|
305
|
+
status: boolean;
|
|
306
|
+
}>;
|
|
307
|
+
/** Email a one-time numeric code (requires the `email-otp` provider). `type`
|
|
308
|
+
* defaults to `"sign-in"`; use `"email-verification"` / `"forget-password"`
|
|
309
|
+
* for those flows. Complete a sign-in with `signInEmailOTP`. */
|
|
310
|
+
sendVerificationOTP: (input: {
|
|
311
|
+
email: string;
|
|
312
|
+
type?: "sign-in" | "email-verification" | "forget-password";
|
|
313
|
+
}) => Promise<{
|
|
314
|
+
success: boolean;
|
|
315
|
+
}>;
|
|
316
|
+
/** Complete an email-OTP sign-in with the code from `sendVerificationOTP`. In
|
|
317
|
+
* app mode the returned session token is captured and replayed as a bearer. */
|
|
318
|
+
signInEmailOTP: (input: {
|
|
319
|
+
email: string;
|
|
320
|
+
otp: string;
|
|
321
|
+
}) => Promise<AuthResult>;
|
|
322
|
+
/** Send a password-reset email. `redirectTo` is the link the email points at. */
|
|
323
|
+
requestPasswordReset: (input: {
|
|
324
|
+
email: string;
|
|
325
|
+
redirectTo?: string;
|
|
326
|
+
}) => Promise<{
|
|
327
|
+
status: boolean;
|
|
328
|
+
}>;
|
|
329
|
+
/** Complete a reset with the token from the email and a new password. */
|
|
330
|
+
resetPassword: (input: {
|
|
331
|
+
newPassword: string;
|
|
332
|
+
token: string;
|
|
333
|
+
}) => Promise<{
|
|
334
|
+
status: boolean;
|
|
335
|
+
}>;
|
|
336
|
+
/** Mint a fresh short-lived access JWT from the stored session token (app
|
|
337
|
+
* mode). The SDK's own requests keep using the session token; use this when a
|
|
338
|
+
* downstream service needs a proper access token. */
|
|
339
|
+
refresh: () => Promise<{
|
|
340
|
+
accessToken: string;
|
|
341
|
+
refreshToken: string;
|
|
342
|
+
expiresIn: number;
|
|
343
|
+
tokenType: string;
|
|
344
|
+
}>;
|
|
345
|
+
/** Change the signed-in user's password (requires the current password). */
|
|
346
|
+
changePassword: (input: {
|
|
347
|
+
newPassword: string;
|
|
348
|
+
currentPassword: string;
|
|
349
|
+
revokeOtherSessions?: boolean;
|
|
350
|
+
}) => Promise<Record<string, unknown>>;
|
|
351
|
+
/** Update the signed-in user's profile (e.g. `{ name, image }`). */
|
|
352
|
+
updateUser: (attributes: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
353
|
+
/** Send an email-verification link to the signed-in (or named) user. */
|
|
354
|
+
sendVerificationEmail: (input: {
|
|
355
|
+
email: string;
|
|
356
|
+
callbackURL?: string;
|
|
357
|
+
}) => Promise<{
|
|
358
|
+
status: boolean;
|
|
359
|
+
}>;
|
|
360
|
+
signOut: () => Promise<{
|
|
361
|
+
success: boolean;
|
|
362
|
+
}>;
|
|
363
|
+
/** Current session, or `{ user: null }`. */
|
|
364
|
+
getSession: () => Promise<{
|
|
365
|
+
user: AuthUser | null;
|
|
366
|
+
} & Record<string, unknown>>;
|
|
367
|
+
/** List the signed-in user's active sessions (one row per device/login). */
|
|
368
|
+
listSessions: () => Promise<AuthSession[]>;
|
|
369
|
+
/** Revoke one session by its `token` (from `listSessions`). */
|
|
370
|
+
revokeSession: (input: {
|
|
371
|
+
token: string;
|
|
372
|
+
}) => Promise<{
|
|
373
|
+
status: boolean;
|
|
374
|
+
}>;
|
|
375
|
+
/** Revoke every session **except** the current one (sign out other devices). */
|
|
376
|
+
revokeOtherSessions: () => Promise<{
|
|
377
|
+
status: boolean;
|
|
378
|
+
}>;
|
|
379
|
+
/** Revoke **all** sessions, including the current one. */
|
|
380
|
+
revokeSessions: () => Promise<{
|
|
381
|
+
status: boolean;
|
|
382
|
+
}>;
|
|
383
|
+
/** Public description of this workspace's auth surface (provider list +
|
|
384
|
+
* policy flags) — what a sign-in screen needs to render. No secrets. */
|
|
385
|
+
providers: () => Promise<AuthSurface>;
|
|
386
|
+
/** The current workspace session token (app mode) — persist this across
|
|
387
|
+
* reloads and pass it back via `createClient({ token })`. */
|
|
388
|
+
getToken: () => string | null;
|
|
389
|
+
/** Restore a workspace session token (app mode). */
|
|
390
|
+
setToken: (token: string | null) => void;
|
|
391
|
+
};
|
|
392
|
+
storage: {
|
|
393
|
+
list: (prefix?: string) => Promise<{
|
|
394
|
+
data: {
|
|
395
|
+
key: string;
|
|
396
|
+
size: number;
|
|
397
|
+
contentType?: string;
|
|
398
|
+
ownerId: string | null;
|
|
399
|
+
uploadedAt: string;
|
|
400
|
+
}[];
|
|
401
|
+
}>;
|
|
402
|
+
put: (key: string, body: BodyInit, contentType?: string, folderId?: string) => Promise<any>;
|
|
403
|
+
download: (key: string) => Promise<Response>;
|
|
404
|
+
delete: (key: string) => Promise<{
|
|
405
|
+
ok: boolean;
|
|
406
|
+
}>;
|
|
407
|
+
/**
|
|
408
|
+
* Resumable upload (TUS 1.0.0). Splits `data` into chunks and PATCHes them
|
|
409
|
+
* to `/api/uploads`, resuming from the server's committed offset after a
|
|
410
|
+
* transient failure. `data` may be a `Blob`/`File`, `ArrayBuffer`, or
|
|
411
|
+
* `Uint8Array`. Returns the final key + the TUS session `location` (persist
|
|
412
|
+
* it to resume across page reloads via `resumeUpload`). The standard TUS
|
|
413
|
+
* protocol means Uppy / tus-js-client can also target `/api/uploads`.
|
|
414
|
+
*/
|
|
415
|
+
uploadResumable: (input: {
|
|
416
|
+
key: string;
|
|
417
|
+
data: Blob | ArrayBuffer | Uint8Array;
|
|
418
|
+
contentType?: string;
|
|
419
|
+
folderId?: string;
|
|
420
|
+
/** Bytes per PATCH. Default 8 MiB (object stores need ≥5 MiB non-final parts). */
|
|
421
|
+
chunkSize?: number;
|
|
422
|
+
onProgress?: (sent: number, total: number) => void;
|
|
423
|
+
signal?: AbortSignal;
|
|
424
|
+
}) => Promise<ResumableUploadResult>;
|
|
425
|
+
/** Resume a previously-started resumable upload at the server's offset. */
|
|
426
|
+
resumeUpload: (location: string, data: Blob | ArrayBuffer | Uint8Array, opts2?: {
|
|
427
|
+
chunkSize?: number;
|
|
428
|
+
onProgress?: (sent: number, total: number) => void;
|
|
429
|
+
signal?: AbortSignal;
|
|
430
|
+
}) => Promise<void>;
|
|
431
|
+
};
|
|
432
|
+
messaging: {
|
|
433
|
+
/** Register (or refresh) the current user's push device. Re-registering the
|
|
434
|
+
* same token reactivates it and updates last-seen, so call this on every
|
|
435
|
+
* app launch. `web-push` requires `keys` (the VAPID subscription keys). */
|
|
436
|
+
registerDevice: (input: {
|
|
437
|
+
platform: "fcm" | "apns" | "web-push";
|
|
438
|
+
token: string;
|
|
439
|
+
keys?: {
|
|
440
|
+
p256dh: string;
|
|
441
|
+
auth: string;
|
|
442
|
+
};
|
|
443
|
+
deviceName?: string;
|
|
444
|
+
}) => Promise<{
|
|
445
|
+
data: {
|
|
446
|
+
id: string;
|
|
447
|
+
};
|
|
448
|
+
}>;
|
|
449
|
+
/** Remove one of the caller's registered devices by id. */
|
|
450
|
+
unregister: (id: string) => Promise<{
|
|
451
|
+
ok: boolean;
|
|
452
|
+
}>;
|
|
453
|
+
/** List the caller's registered devices. */
|
|
454
|
+
listDevices: () => Promise<{
|
|
455
|
+
data: DeviceToken[];
|
|
456
|
+
}>;
|
|
457
|
+
/** Register (or refresh) the current user's phone number for SMS. Number
|
|
458
|
+
* must be E.164 (e.g. "+14155552671"). Re-registering reactivates it. */
|
|
459
|
+
registerPhone: (input: {
|
|
460
|
+
phoneNumber: string;
|
|
461
|
+
}) => Promise<{
|
|
462
|
+
data: {
|
|
463
|
+
id: string;
|
|
464
|
+
};
|
|
465
|
+
}>;
|
|
466
|
+
/** Remove one of the caller's registered phone numbers by id. */
|
|
467
|
+
unregisterPhone: (id: string) => Promise<{
|
|
468
|
+
ok: boolean;
|
|
469
|
+
}>;
|
|
470
|
+
/** List the caller's registered phone numbers. */
|
|
471
|
+
listPhones: () => Promise<{
|
|
472
|
+
data: PhoneNumber[];
|
|
473
|
+
}>;
|
|
474
|
+
};
|
|
475
|
+
jobs: {
|
|
476
|
+
/** Enqueue a durable background job. `type` is `function` (run a named
|
|
477
|
+
* function with `payload.name` + `payload.input`) or `webhook.deliver`.
|
|
478
|
+
* Jobs retry with backoff and dead-letter after `maxAttempts`. Pass
|
|
479
|
+
* `runAt` (ISO string) to schedule for later. Admin-scoped. */
|
|
480
|
+
enqueue: (input: {
|
|
481
|
+
type: "function" | "webhook.deliver";
|
|
482
|
+
payload?: Record<string, unknown>;
|
|
483
|
+
queue?: string;
|
|
484
|
+
runAt?: string;
|
|
485
|
+
maxAttempts?: number;
|
|
486
|
+
priority?: number;
|
|
487
|
+
}) => Promise<{
|
|
488
|
+
id: string;
|
|
489
|
+
}>;
|
|
490
|
+
/** List jobs (newest first), optionally filtered by queue/status. */
|
|
491
|
+
list: (q?: {
|
|
492
|
+
queue?: string;
|
|
493
|
+
status?: JobStatus;
|
|
494
|
+
limit?: number;
|
|
495
|
+
}) => Promise<{
|
|
496
|
+
jobs: Job[];
|
|
497
|
+
}>;
|
|
498
|
+
/** Fetch a single job by id. */
|
|
499
|
+
get: (id: string) => Promise<Job>;
|
|
500
|
+
/** Requeue a failed / dead-lettered / cancelled job to run again. */
|
|
501
|
+
retry: (id: string) => Promise<{
|
|
502
|
+
ok: boolean;
|
|
503
|
+
}>;
|
|
504
|
+
/** Cancel a pending job. */
|
|
505
|
+
cancel: (id: string) => Promise<{
|
|
506
|
+
ok: boolean;
|
|
507
|
+
}>;
|
|
508
|
+
/** Delete a job row. */
|
|
509
|
+
remove: (id: string) => Promise<{
|
|
510
|
+
ok: boolean;
|
|
511
|
+
}>;
|
|
512
|
+
};
|
|
513
|
+
flags: {
|
|
514
|
+
/** Fetch + cache the evaluated flag map. */
|
|
515
|
+
all: () => Promise<Record<string, FlagState>>;
|
|
516
|
+
/** Resolved value for a flag (remote config payload), or `undefined`. Uses
|
|
517
|
+
* the cache if `all()` was already called this session; pass
|
|
518
|
+
* `{ refresh: true }` to force a re-fetch. */
|
|
519
|
+
get: (key: string, opts?: {
|
|
520
|
+
refresh?: boolean;
|
|
521
|
+
}) => Promise<unknown>;
|
|
522
|
+
/** Whether a flag is on for the caller. */
|
|
523
|
+
isEnabled: (key: string, opts?: {
|
|
524
|
+
refresh?: boolean;
|
|
525
|
+
}) => Promise<boolean>;
|
|
526
|
+
};
|
|
527
|
+
sync: (options: SyncOptions) => {
|
|
528
|
+
pull: () => Promise<number>;
|
|
529
|
+
flush: () => Promise<void>;
|
|
530
|
+
live: () => (() => void);
|
|
531
|
+
start: () => Promise<void>;
|
|
532
|
+
stop: () => void;
|
|
533
|
+
getAll: () => Promise<Record<string, unknown>[]>;
|
|
534
|
+
get: (id: string) => Promise<Record<string, unknown> | undefined>;
|
|
535
|
+
create: (data: Record<string, unknown>) => Promise<string>;
|
|
536
|
+
update: (id: string, data: Record<string, unknown>) => Promise<void>;
|
|
537
|
+
remove: (id: string) => Promise<void>;
|
|
538
|
+
store: SyncStore;
|
|
539
|
+
};
|
|
540
|
+
/** Raw escape hatch — issues a request with auth headers applied. */
|
|
541
|
+
request: <T>(method: string, path: string, body?: unknown, extraHeaders?: Record<string, string>) => Promise<T>;
|
|
542
|
+
};
|
|
543
|
+
/** A registry mapping each collection slug to its row type — the shape
|
|
544
|
+
* `backlex gen-types --sdk` emits as `Collections`. */
|
|
545
|
+
type CollectionsMap = Record<string, Record<string, unknown>>;
|
|
546
|
+
/** `{ [slug]: CollectionClient<Row> }` — the typed `collections` accessor. */
|
|
547
|
+
type TypedCollections<R extends CollectionsMap> = {
|
|
548
|
+
[K in keyof R]: CollectionClient<R[K]>;
|
|
549
|
+
};
|
|
550
|
+
/** A `BacklexClient` augmented with a strongly-typed `collections` accessor,
|
|
551
|
+
* so `db.collections.<slug>.list()` returns `ListResponse<Row>`. */
|
|
552
|
+
type TypedClient<R extends CollectionsMap> = BacklexClient & {
|
|
553
|
+
collections: TypedCollections<R>;
|
|
554
|
+
};
|
|
555
|
+
/**
|
|
556
|
+
* Wrap a client with a typed `collections` accessor keyed by collection slug.
|
|
557
|
+
* Generated SDKs call this with the generated `Collections` registry:
|
|
558
|
+
*
|
|
559
|
+
* export const createTypedClient = (opts: ClientOptions) =>
|
|
560
|
+
* typedCollections<Collections>(createClient(opts));
|
|
561
|
+
*
|
|
562
|
+
* Access is a thin proxy over `client.from(slug)` — no per-collection runtime
|
|
563
|
+
* code is generated; all the type information lives in `R`.
|
|
564
|
+
*/
|
|
565
|
+
declare const typedCollections: <R extends CollectionsMap>(client: BacklexClient) => TypedClient<R>;
|
|
566
|
+
|
|
567
|
+
type BacklexClient = ReturnType<typeof createClient>;
|
|
568
|
+
|
|
569
|
+
export { AggregateQuery, AggregateRow, type BacklexClient, BatchOperation, BatchResponse, type ClientOptions, type CollectionClient, type CollectionsMap, DeviceToken, type FieldKey, type FilterBuilder, FlagState, ImportSummary, ItemEvent, ItemQuery, ItemResponse, Job, JobStatus, ListQuery, ListResponse, PhoneNumber, QueryBuilder, type QueuedOp, ResumableUploadResult, SearchQuery, SearchResponse, type SortKey, type SyncOptions, type SyncStore, type TypedClient, type TypedCollections, createClient, createSync, indexedDbStore, memoryStore, typedCollections };
|