@rebasepro/types 0.17.3 → 0.18.1
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/README.md +4 -0
- package/dist/call_context.d.ts +20 -0
- package/dist/controllers/client.d.ts +36 -4
- package/dist/controllers/data.d.ts +120 -10
- package/dist/errors.d.ts +83 -4
- package/dist/index.es.js +522 -160
- package/dist/index.es.js.map +1 -1
- package/dist/types/admin_block.d.ts +2 -2
- package/dist/types/auth_adapter.d.ts +41 -6
- package/dist/types/backend.d.ts +48 -0
- package/dist/types/collections.d.ts +25 -1
- package/dist/types/cron.d.ts +34 -0
- package/dist/types/database_adapter.d.ts +39 -0
- package/dist/types/entity_callbacks.d.ts +14 -1
- package/dist/types/filter-operators.d.ts +24 -1
- package/dist/types/policy.d.ts +29 -1
- package/dist/types/properties.d.ts +216 -3
- package/dist/types/relations.d.ts +65 -7
- package/dist/types/resource_kinds.d.ts +173 -17
- package/dist/types/resources.d.ts +108 -7
- package/dist/types/rls-functions.d.ts +11 -0
- package/dist/types/storage_source.d.ts +12 -23
- package/package.json +24 -23
- package/src/call_context.ts +0 -120
- package/src/controllers/auth_state.ts +0 -24
- package/src/controllers/client.ts +0 -494
- package/src/controllers/collection_registry.ts +0 -62
- package/src/controllers/data.ts +0 -1012
- package/src/controllers/data_driver.ts +0 -576
- package/src/controllers/effective_role.ts +0 -4
- package/src/controllers/email.ts +0 -91
- package/src/controllers/index.ts +0 -11
- package/src/controllers/storage.ts +0 -252
- package/src/errors.ts +0 -119
- package/src/index.ts +0 -5
- package/src/types/admin_block.ts +0 -209
- package/src/types/api_keys.ts +0 -108
- package/src/types/auth_adapter.ts +0 -580
- package/src/types/backend.ts +0 -987
- package/src/types/backup.ts +0 -26
- package/src/types/channel_bus.ts +0 -202
- package/src/types/chips.ts +0 -34
- package/src/types/collection_contract.ts +0 -278
- package/src/types/collections.ts +0 -763
- package/src/types/component_ref.ts +0 -92
- package/src/types/cron.ts +0 -213
- package/src/types/data_source.ts +0 -357
- package/src/types/database_adapter.ts +0 -267
- package/src/types/entities.ts +0 -226
- package/src/types/entity_callbacks.ts +0 -229
- package/src/types/filter-operators.ts +0 -444
- package/src/types/history.ts +0 -66
- package/src/types/index.ts +0 -36
- package/src/types/indexes.ts +0 -180
- package/src/types/policy.ts +0 -328
- package/src/types/postgres_introspection.ts +0 -101
- package/src/types/project_manifest.ts +0 -598
- package/src/types/properties.ts +0 -1368
- package/src/types/relations.ts +0 -417
- package/src/types/resource_kinds.ts +0 -390
- package/src/types/resources.ts +0 -368
- package/src/types/rls-functions.ts +0 -98
- package/src/types/schema_editing.ts +0 -157
- package/src/types/schema_version.ts +0 -112
- package/src/types/search.ts +0 -247
- package/src/types/security_rules.ts +0 -344
- package/src/types/storage_authorize.ts +0 -77
- package/src/types/storage_source.ts +0 -248
- package/src/types/websockets.ts +0 -117
- package/src/users/index.ts +0 -2
- package/src/users/user.ts +0 -69
package/README.md
CHANGED
|
@@ -8,6 +8,10 @@ Shared TypeScript type definitions and interfaces for the Rebase ecosystem.
|
|
|
8
8
|
pnpm add @rebasepro/types
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
ESM-only: `"type": "module"` with no CommonJS build, so it is loaded with
|
|
12
|
+
`import`. `require()` of it resolves only on Node 22.12+, which supports
|
|
13
|
+
`require(esm)`.
|
|
14
|
+
|
|
11
15
|
## What This Package Does
|
|
12
16
|
|
|
13
17
|
Provides the canonical type definitions used across all Rebase packages — both client-side and server-side. This is a **types-only** package with no runtime dependencies. Every other `@rebasepro/*` package depends on it.
|
package/dist/call_context.d.ts
CHANGED
|
@@ -13,6 +13,26 @@ import type { User } from "./users/index.js";
|
|
|
13
13
|
* backend process. Keeping them in one type meant every backend module that
|
|
14
14
|
* touched a callback signature transitively named the admin UI.
|
|
15
15
|
*
|
|
16
|
+
* ### When the callback runs
|
|
17
|
+
*
|
|
18
|
+
* Server-side, **every** callback around a write — `beforeSave`, the SQL,
|
|
19
|
+
* `afterSave`; `beforeDelete`, the delete, `afterDelete` — runs inside the one
|
|
20
|
+
* transaction opened for that request, and each is awaited. There is no
|
|
21
|
+
* after-commit tier: `afterSave` and `afterDelete` run *before* the commit, so a
|
|
22
|
+
* throw in either rolls the write back and the caller is answered
|
|
23
|
+
* `400 CALLBACK_REJECTED` with `details.stage` naming the hook.
|
|
24
|
+
*
|
|
25
|
+
* Two consequences worth designing around:
|
|
26
|
+
*
|
|
27
|
+
* - A callback holds the transaction open while it runs. Slow work there is a
|
|
28
|
+
* lock held and a pooled connection tied up. Anything that talks to a third
|
|
29
|
+
* party belongs on the job queue, not in the body.
|
|
30
|
+
* - Work that must survive the write being undone does not belong here at all —
|
|
31
|
+
* by construction it is not part of the write.
|
|
32
|
+
*
|
|
33
|
+
* A request-scoped `afterRead` is narrower still: its transaction is
|
|
34
|
+
* `READ ONLY`, so a write attempted from one fails with SQLSTATE `25006`.
|
|
35
|
+
*
|
|
16
36
|
* @group Hooks and utilities
|
|
17
37
|
*/
|
|
18
38
|
export type RebaseCallContext<USER extends User = User> = {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { User } from "../users/index.js";
|
|
2
|
+
import type { ResourceRef } from "../types/resources.js";
|
|
2
3
|
import type { RebaseSdkData } from "./data.js";
|
|
3
4
|
import type { EmailService } from "./email.js";
|
|
4
5
|
import type { StorageSource } from "./storage.js";
|
|
@@ -337,7 +338,23 @@ export interface RebaseClient<DB = unknown> {
|
|
|
337
338
|
* routed to the matching `StorageController`. Used to lazily wire
|
|
338
339
|
* `transport: "server"` sources on the frontend.
|
|
339
340
|
*/
|
|
340
|
-
createStorageSource?(storageId:
|
|
341
|
+
createStorageSource?(storageId: ResourceRef): StorageSource;
|
|
342
|
+
/**
|
|
343
|
+
* The storage source a bucket handle names, ready to use.
|
|
344
|
+
*
|
|
345
|
+
* ```ts
|
|
346
|
+
* import { media } from "../../config/resources";
|
|
347
|
+
* await rebase.bucket(media).putObject({ key, file });
|
|
348
|
+
* ```
|
|
349
|
+
*
|
|
350
|
+
* Named after the constructor: `bucket("media")` declares it, and
|
|
351
|
+
* `rebase.bucket(media)` reaches it — the same name, spelled once. A string
|
|
352
|
+
* key is accepted for callers that only have one. Throws on a source the
|
|
353
|
+
* backend did not register, naming the ones it did, rather than silently
|
|
354
|
+
* serving the default — the failure that used to look like an upload that
|
|
355
|
+
* worked.
|
|
356
|
+
*/
|
|
357
|
+
bucket?(source: ResourceRef): StorageSource;
|
|
341
358
|
/**
|
|
342
359
|
* Discover the storage sources declared on the backend via
|
|
343
360
|
* `GET /api/storage/sources`. Server-transport sources are auto-registered
|
|
@@ -435,8 +452,14 @@ export interface RebaseServerClient<DB = unknown> extends Omit<RebaseClient<DB>,
|
|
|
435
452
|
*/
|
|
436
453
|
dataAsAdmin: RebaseSdkData<DB>;
|
|
437
454
|
/**
|
|
438
|
-
* Server-side email service. Always present
|
|
439
|
-
*
|
|
455
|
+
* Server-side email service. Always present — including on a backend that
|
|
456
|
+
* configured no mail at all, where `send()` throws a message naming what to
|
|
457
|
+
* set rather than the property being `undefined`.
|
|
458
|
+
*
|
|
459
|
+
* It is not a no-op sender. A no-op would swallow the reset mail a user is
|
|
460
|
+
* waiting for and report success, and nothing downstream could tell that from
|
|
461
|
+
* delivery. Ask {@link EmailService.isConfigured} before sending if the call
|
|
462
|
+
* site can carry on without mail.
|
|
440
463
|
*/
|
|
441
464
|
email: EmailService;
|
|
442
465
|
/**
|
|
@@ -458,10 +481,19 @@ export interface RebaseServerClient<DB = unknown> extends Omit<RebaseClient<DB>,
|
|
|
458
481
|
* than discovering it at the call.
|
|
459
482
|
*/
|
|
460
483
|
sql(query: string, options?: {
|
|
461
|
-
database?:
|
|
484
|
+
database?: ResourceRef;
|
|
462
485
|
role?: string;
|
|
463
486
|
params?: unknown[];
|
|
464
487
|
}): Promise<Record<string, unknown>[]>;
|
|
488
|
+
/**
|
|
489
|
+
* The storage source a bucket handle names. Always present server-side.
|
|
490
|
+
*
|
|
491
|
+
* Always, for the same reason {@link RebaseServerClient.email} is: a
|
|
492
|
+
* backend with no storage configured at all answers with a refusal naming
|
|
493
|
+
* what to set, rather than with `undefined` and a `is not a function`
|
|
494
|
+
* three frames from the cause. See {@link RebaseClient.bucket}.
|
|
495
|
+
*/
|
|
496
|
+
bucket(source: ResourceRef): StorageSource;
|
|
465
497
|
}
|
|
466
498
|
/**
|
|
467
499
|
* Client-side registry for managing multiple storage sources.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { VectorSearchParams } from "./data_driver.js";
|
|
2
2
|
import type { ComputedSortField, SearchMatch } from "../types/search.js";
|
|
3
3
|
import { Entity, EntityValues } from "../types/entities.js";
|
|
4
|
-
import { WhereFilterOp, FieldPath, FilterValues, OrderBySpec } from "../types/filter-operators.js";
|
|
4
|
+
import { WhereFilterOp, FieldPath, NonColumnFieldPath, FilterValues, OrderBySpec, RelationAggregateSort } from "../types/filter-operators.js";
|
|
5
5
|
/**
|
|
6
6
|
* The element type of an array column, and the column's own type otherwise.
|
|
7
7
|
*
|
|
@@ -504,8 +504,27 @@ export type FindAllParams<M extends Record<string, unknown> = Record<string, unk
|
|
|
504
504
|
*/
|
|
505
505
|
export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
506
506
|
where<K extends keyof M & string, Op extends WhereFilterOp>(column: K, operator: Op, value: WhereValueFor<Op, M[K]>): this;
|
|
507
|
+
/**
|
|
508
|
+
* Filter on a relation path (`author.name`) or a JSON path
|
|
509
|
+
* (`metadata->>tier`).
|
|
510
|
+
*
|
|
511
|
+
* A separate overload because the value cannot be typed: neither addresses
|
|
512
|
+
* a column of `M`, so there is nothing in a generated row type to check
|
|
513
|
+
* against — the driver resolves the path and refuses what it cannot. The
|
|
514
|
+
* key is still constrained to a *path*, so a mistyped column name does not
|
|
515
|
+
* fall through to here and lose its check.
|
|
516
|
+
*
|
|
517
|
+
* `find({ where })` has accepted both all along ({@link FieldPath}); the
|
|
518
|
+
* builder did not, so the documented relation-path filters were compile
|
|
519
|
+
* errors on a typed client.
|
|
520
|
+
*/
|
|
521
|
+
where(column: NonColumnFieldPath, operator: WhereFilterOp, value: unknown): this;
|
|
507
522
|
where(logicalCondition: LogicalCondition): this;
|
|
508
|
-
|
|
523
|
+
/**
|
|
524
|
+
* Sort by a column, a relation or JSON path, `_score`, or an aggregate over
|
|
525
|
+
* a to-many relation — the same key set {@link FindParams.orderBy} takes.
|
|
526
|
+
*/
|
|
527
|
+
orderBy(column: FieldPath<M> | ComputedSortField | RelationAggregateSort, direction?: "asc" | "desc"): this;
|
|
509
528
|
limit(count: number): this;
|
|
510
529
|
offset(count: number): this;
|
|
511
530
|
search(searchString: string, options?: {
|
|
@@ -526,6 +545,24 @@ export interface SDKQueryBuilderInterface<M extends Record<string, unknown> = Re
|
|
|
526
545
|
}): this;
|
|
527
546
|
include(...relations: string[]): this;
|
|
528
547
|
find(): Promise<FindResult<M>>;
|
|
548
|
+
/**
|
|
549
|
+
* Page through everything this query matches, one row at a time.
|
|
550
|
+
*
|
|
551
|
+
* The same walker {@link SDKCollectionClient.iterate} uses, so the ceiling
|
|
552
|
+
* on `limit` is not a ceiling on what a query can read. `.limit()` set on
|
|
553
|
+
* the builder becomes the **page size** here, not a total.
|
|
554
|
+
*/
|
|
555
|
+
iterate(options?: PageWalkOptions<M>): AsyncIterableIterator<M>;
|
|
556
|
+
/**
|
|
557
|
+
* Collect everything this query matches into one array.
|
|
558
|
+
*
|
|
559
|
+
* {@link SDKCollectionClient.findAll}'s `maxRows` guard applies: an
|
|
560
|
+
* unbounded collect is a memory hazard, so it stops and says so rather than
|
|
561
|
+
* growing until the process dies.
|
|
562
|
+
*/
|
|
563
|
+
findAll(options?: PageWalkOptions<M> & {
|
|
564
|
+
maxRows?: number;
|
|
565
|
+
}): Promise<M[]>;
|
|
529
566
|
count(): Promise<number>;
|
|
530
567
|
listen(onUpdate: (data: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
|
|
531
568
|
}
|
|
@@ -588,6 +625,26 @@ export interface WriteOptions {
|
|
|
588
625
|
export interface SDKCollectionClient<M extends Record<string, unknown> = Record<string, unknown>, I = Partial<M>, U = Partial<M>> {
|
|
589
626
|
/**
|
|
590
627
|
* Find multiple records with optional filtering, pagination, and sorting.
|
|
628
|
+
*
|
|
629
|
+
* ## What a list method returns
|
|
630
|
+
*
|
|
631
|
+
* Two shapes, and one rule that tells them apart: **a window is wrapped, a
|
|
632
|
+
* whole answer is not.**
|
|
633
|
+
*
|
|
634
|
+
* - `find()` and `listen()` return {@link FindResult} — `{ data, meta }` —
|
|
635
|
+
* because they hand back *one page*. `meta.total` and `meta.hasMore` are
|
|
636
|
+
* the caller's only way to know there is more, so a bare array would lose
|
|
637
|
+
* the answer to the question the call raises.
|
|
638
|
+
* - `findAll()`, `createMany()` and `updateMany()` return a plain `M[]`,
|
|
639
|
+
* because there is nothing left over to report: the walk finished, or the
|
|
640
|
+
* batch is exactly the rows that were written. A `meta` there would be
|
|
641
|
+
* `{ total: rows.length, hasMore: false }`, which says nothing.
|
|
642
|
+
* - `iterate()` yields rows one at a time and never materialises a list at
|
|
643
|
+
* all.
|
|
644
|
+
*
|
|
645
|
+
* So `data` is not a wrapper the SDK sometimes adds and sometimes forgets —
|
|
646
|
+
* it is where the pagination metadata lives, and it is present exactly when
|
|
647
|
+
* there is some.
|
|
591
648
|
*/
|
|
592
649
|
find(params?: FindParams<M>): Promise<FindResult<M>>;
|
|
593
650
|
/**
|
|
@@ -653,6 +710,38 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
653
710
|
* Find a single record by its ID.
|
|
654
711
|
*/
|
|
655
712
|
findById(id: string | number): Promise<M | undefined>;
|
|
713
|
+
/**
|
|
714
|
+
* Read one record by its ID, or throw if it is not there.
|
|
715
|
+
*
|
|
716
|
+
* The counterpart to {@link findById}, and the one most reads want. A row
|
|
717
|
+
* fetched by an id that came from a link, a route parameter or another row
|
|
718
|
+
* is expected to exist; when it does not, that is the error case, not a
|
|
719
|
+
* value to thread through the rest of the function.
|
|
720
|
+
*
|
|
721
|
+
* `findById` returns `M | undefined`, so every caller had to prove the row
|
|
722
|
+
* existed before touching a field:
|
|
723
|
+
*
|
|
724
|
+
* ```ts
|
|
725
|
+
* const post = await rebase.data.posts.findById(id);
|
|
726
|
+
* post.title; // TS18048: 'post' is possibly 'undefined'
|
|
727
|
+
* const ok = (await rebase.data.posts.findById(id))!.title; // the `!` everyone reaches for
|
|
728
|
+
* ```
|
|
729
|
+
*
|
|
730
|
+
* With `get`, the absent case is an exception with a code you can branch on,
|
|
731
|
+
* and the happy path is typed as present:
|
|
732
|
+
*
|
|
733
|
+
* ```ts
|
|
734
|
+
* const post = await rebase.data.posts.get(id); // M, not M | undefined
|
|
735
|
+
* ```
|
|
736
|
+
*
|
|
737
|
+
* Same split as Prisma's `findUnique` / `findUniqueOrThrow`: two contracts,
|
|
738
|
+
* both wanted, named so the choice is visible at the call site.
|
|
739
|
+
*
|
|
740
|
+
* @throws {RebaseApiError} `NOT_FOUND` (status 404) when no such row exists,
|
|
741
|
+
* or is visible to the caller — row-level security makes a row the caller
|
|
742
|
+
* may not read indistinguishable from one that is not there, deliberately.
|
|
743
|
+
*/
|
|
744
|
+
get(id: string | number): Promise<M>;
|
|
656
745
|
/**
|
|
657
746
|
* Create a new record.
|
|
658
747
|
* @param data The record data to create (the collection's `Insert` shape).
|
|
@@ -702,10 +791,18 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
702
791
|
/**
|
|
703
792
|
* Update an existing record by ID.
|
|
704
793
|
* @param data The fields to update (the collection's `Update` shape).
|
|
794
|
+
* @param options Per-request write options — notably `idempotencyKey`.
|
|
705
795
|
* @returns The updated row.
|
|
706
796
|
* @throws {RebaseApiError} with status 404 when the record does not exist.
|
|
797
|
+
*
|
|
798
|
+
* `create`, `createMany`, `updateMany`, `delete` and `deleteMany` all took
|
|
799
|
+
* {@link WriteOptions}; this one did not, so the single-row update was the
|
|
800
|
+
* one write on the surface that could not be made idempotent. A client that
|
|
801
|
+
* never sees the response retries, and without a key the server cannot tell
|
|
802
|
+
* that retry from a second deliberate edit — which on a `PATCH` that
|
|
803
|
+
* increments or appends is a second edit applied.
|
|
707
804
|
*/
|
|
708
|
-
update(id: string | number, data: U): Promise<M>;
|
|
805
|
+
update(id: string | number, data: U, options?: WriteOptions): Promise<M>;
|
|
709
806
|
/**
|
|
710
807
|
* Update many records in a single request and a single transaction.
|
|
711
808
|
*
|
|
@@ -788,20 +885,33 @@ export interface SDKCollectionClient<M extends Record<string, unknown> = Record<
|
|
|
788
885
|
* does not call back. `listen` does none of that; it forwards what the
|
|
789
886
|
* socket sends.
|
|
790
887
|
*
|
|
791
|
-
*
|
|
792
|
-
*
|
|
793
|
-
*
|
|
888
|
+
* Always present. A client that cannot subscribe — one built with
|
|
889
|
+
* `realtime: false`, or on a driver with no `listenCollection` — installs a
|
|
890
|
+
* stub that throws a `RebaseClientError` naming the configuration that
|
|
891
|
+
* would make it work. It used to be optional, which made every call site
|
|
892
|
+
* either write `listen!(…)` or a null check the type system could not tell
|
|
893
|
+
* apart from a real capability question; the answer to *that* question is
|
|
894
|
+
* {@link isUnsupported}, and the answer for ordinary code is to just call
|
|
895
|
+
* it.
|
|
896
|
+
*
|
|
897
|
+
* `observe()` degrades to a single fetch instead of throwing, which is the
|
|
898
|
+
* other reason to reach for it instead.
|
|
794
899
|
*/
|
|
795
|
-
listen
|
|
900
|
+
listen(params: FindParams<M> | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
|
|
796
901
|
/** {@link listen} for a single row. Prefer `observeById()`. */
|
|
797
|
-
listenById
|
|
902
|
+
listenById(id: string | number, onUpdate: (row: M | undefined) => void, onError?: (error: Error) => void): () => void;
|
|
798
903
|
/**
|
|
799
904
|
* Count the number of records matching the given filter.
|
|
905
|
+
*
|
|
906
|
+
* Always present; see {@link listen} for what a transport that cannot serve
|
|
907
|
+
* it does instead.
|
|
800
908
|
*/
|
|
801
|
-
count
|
|
909
|
+
count(params?: FindParams<M>): Promise<number>;
|
|
802
910
|
where<K extends keyof M & string, Op extends WhereFilterOp>(column: K, operator: Op, value: WhereValueFor<Op, M[K]>): SDKQueryBuilderInterface<M>;
|
|
911
|
+
/** A relation path (`author.name`) or a JSON path (`metadata->>tier`). */
|
|
912
|
+
where(column: NonColumnFieldPath, operator: WhereFilterOp, value: unknown): SDKQueryBuilderInterface<M>;
|
|
803
913
|
where(logicalCondition: LogicalCondition): SDKQueryBuilderInterface<M>;
|
|
804
|
-
orderBy(column:
|
|
914
|
+
orderBy(column: FieldPath<M> | ComputedSortField | RelationAggregateSort, direction?: "asc" | "desc"): SDKQueryBuilderInterface<M>;
|
|
805
915
|
limit(count: number): SDKQueryBuilderInterface<M>;
|
|
806
916
|
offset(count: number): SDKQueryBuilderInterface<M>;
|
|
807
917
|
search(searchString: string, options?: {
|
package/dist/errors.d.ts
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
*
|
|
24
24
|
* @group Errors
|
|
25
25
|
*/
|
|
26
|
-
export type RebaseErrorCode = "BAD_REQUEST" | "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "CONFLICT" | "INTERNAL_ERROR" | "SERVICE_UNAVAILABLE" | "DB_PERMISSION_DENIED" | "SCHEMA_DRIFT" | (string & {});
|
|
26
|
+
export type RebaseErrorCode = "BAD_REQUEST" | "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "CONFLICT" | "INTERNAL_ERROR" | "SERVICE_UNAVAILABLE" | "NETWORK_ERROR" | "OFFLINE" | "DB_PERMISSION_DENIED" | "SCHEMA_DRIFT" | (string & {});
|
|
27
27
|
/**
|
|
28
28
|
* Structured initializer for {@link RebaseApiError}.
|
|
29
29
|
*
|
|
@@ -32,14 +32,41 @@ export type RebaseErrorCode = "BAD_REQUEST" | "UNAUTHORIZED" | "FORBIDDEN" | "NO
|
|
|
32
32
|
export interface RebaseErrorInit {
|
|
33
33
|
/**
|
|
34
34
|
* HTTP status code, when the error originated from an HTTP response.
|
|
35
|
-
*
|
|
36
|
-
*
|
|
35
|
+
*
|
|
36
|
+
* Three states, and they mean different things:
|
|
37
|
+
*
|
|
38
|
+
* - a real status — the server answered, and this is what it said;
|
|
39
|
+
* - **`0`** — the request never reached a server: DNS, a refused
|
|
40
|
+
* connection, CORS, an abort. `XMLHttpRequest` has always spelled that
|
|
41
|
+
* `0`, and a fabricated 5xx would be indistinguishable from one the
|
|
42
|
+
* server actually sent. The original failure is on `cause`;
|
|
43
|
+
* - `undefined` — nothing was sent at all: a realtime/WebSocket failure,
|
|
44
|
+
* or a client-side logic error raised before any request.
|
|
37
45
|
*/
|
|
38
46
|
status?: number;
|
|
39
47
|
/** Stable, machine-readable error code. See {@link RebaseErrorCode}. */
|
|
40
48
|
code?: RebaseErrorCode;
|
|
41
49
|
/** Structured error payload returned by the server, when present. */
|
|
42
50
|
details?: unknown;
|
|
51
|
+
/**
|
|
52
|
+
* The server's correlation id for the request that failed, when it sent
|
|
53
|
+
* one — the `requestId` in the error envelope, which also comes back on the
|
|
54
|
+
* `X-Request-ID` header.
|
|
55
|
+
*
|
|
56
|
+
* The envelope has carried it for a while; the client dropped it on the
|
|
57
|
+
* floor, so a bug report from an app could never quote the one string that
|
|
58
|
+
* finds the server-side line.
|
|
59
|
+
*/
|
|
60
|
+
requestId?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Seconds to wait before retrying, from the response's `Retry-After`
|
|
63
|
+
* header. Present on a 429 and on some 503s.
|
|
64
|
+
*
|
|
65
|
+
* Also dropped. The offline queue's own backoff therefore ignored a server
|
|
66
|
+
* that had said exactly how long to wait — the one number that turns a
|
|
67
|
+
* retry storm into a queue that drains.
|
|
68
|
+
*/
|
|
69
|
+
retryAfterSeconds?: number;
|
|
43
70
|
/** The underlying error this one wraps, if any. */
|
|
44
71
|
cause?: unknown;
|
|
45
72
|
}
|
|
@@ -74,6 +101,10 @@ export declare class RebaseApiError extends Error {
|
|
|
74
101
|
readonly code?: RebaseErrorCode;
|
|
75
102
|
/** Structured error payload from the server, when present. */
|
|
76
103
|
readonly details?: unknown;
|
|
104
|
+
/** See {@link RebaseErrorInit.requestId}. Quote it in a bug report. */
|
|
105
|
+
readonly requestId?: string;
|
|
106
|
+
/** See {@link RebaseErrorInit.retryAfterSeconds}. */
|
|
107
|
+
readonly retryAfterSeconds?: number;
|
|
77
108
|
constructor(message: string, init?: RebaseErrorInit);
|
|
78
109
|
}
|
|
79
110
|
/**
|
|
@@ -86,5 +117,53 @@ export declare class RebaseApiError extends Error {
|
|
|
86
117
|
* @group Errors
|
|
87
118
|
*/
|
|
88
119
|
export declare class RebaseClientError extends RebaseApiError {
|
|
89
|
-
|
|
120
|
+
/**
|
|
121
|
+
* `init` is the same one {@link RebaseApiError} takes, and it is what makes
|
|
122
|
+
* `code` reachable at all.
|
|
123
|
+
*
|
|
124
|
+
* The constructor used to accept a message and nothing else, so every
|
|
125
|
+
* client-side failure — an undefined filter value, an unknown accessor,
|
|
126
|
+
* `listen()` on a client built with `realtime: false`, a function name with
|
|
127
|
+
* a `/` in it, `refreshSession()` while signed out — arrived with `code ===
|
|
128
|
+
* undefined`. The documented `switch (e.code)` in this file's own example
|
|
129
|
+
* fell to `default: throw e` for all of them, and the only client-side error
|
|
130
|
+
* that *did* carry a code was `OFFLINE`, because that one path minted a
|
|
131
|
+
* `RebaseApiError` instead.
|
|
132
|
+
*/
|
|
133
|
+
constructor(message: string, init?: RebaseErrorInit);
|
|
90
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Build the stub a client installs for a contract method it cannot serve.
|
|
137
|
+
*
|
|
138
|
+
* `listen`, `listenById` and `count` are part of `SDKCollectionClient`, not
|
|
139
|
+
* optional extras — a caller should be able to write
|
|
140
|
+
* `client.data.posts.count()` without asking first, and a transport that cannot
|
|
141
|
+
* serve it should answer with a sentence naming the configuration that would,
|
|
142
|
+
* rather than with `undefined is not a function` at the call site. Where the
|
|
143
|
+
* transport genuinely cannot (a client built with `realtime: false`, a driver
|
|
144
|
+
* with no `listenCollection`), it installs one of these instead of omitting the
|
|
145
|
+
* method.
|
|
146
|
+
*
|
|
147
|
+
* @param message What to tell the caller, naming the fix.
|
|
148
|
+
* @group Errors
|
|
149
|
+
*/
|
|
150
|
+
export declare function unsupportedMethod<F>(message: string): F;
|
|
151
|
+
/**
|
|
152
|
+
* Can this method actually do anything?
|
|
153
|
+
*
|
|
154
|
+
* `true` for a stub from {@link unsupportedMethod} **and** for a method that is
|
|
155
|
+
* simply not there — a partial client, a hand-built test double, an
|
|
156
|
+
* implementation written against an older shape of the interface. Both mean the
|
|
157
|
+
* same thing to a caller, so both answer the same way, and an adapter that
|
|
158
|
+
* checks this cannot be caught out by either.
|
|
159
|
+
*
|
|
160
|
+
* Ordinary code does not need it: calling the method and letting it throw is
|
|
161
|
+
* the normal path. Adapters do — the admin panel chooses between subscribing
|
|
162
|
+
* and a one-shot `find()` by asking whether the client can listen, and a UI
|
|
163
|
+
* that subscribes into a throw is worse than one that polls. This is the
|
|
164
|
+
* question `if (accessor.listen)` used to be asking, made explicit now that the
|
|
165
|
+
* method is always there to call.
|
|
166
|
+
*
|
|
167
|
+
* @group Errors
|
|
168
|
+
*/
|
|
169
|
+
export declare function isUnsupported(method: unknown): boolean;
|