@rebasepro/types 0.17.3-canary.gdd23447 → 0.18.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.
Files changed (71) hide show
  1. package/README.md +4 -0
  2. package/dist/call_context.d.ts +20 -0
  3. package/dist/controllers/client.d.ts +36 -4
  4. package/dist/controllers/data.d.ts +120 -10
  5. package/dist/errors.d.ts +83 -4
  6. package/dist/index.es.js +522 -160
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/types/admin_block.d.ts +2 -2
  9. package/dist/types/auth_adapter.d.ts +41 -6
  10. package/dist/types/backend.d.ts +48 -0
  11. package/dist/types/collections.d.ts +25 -1
  12. package/dist/types/cron.d.ts +34 -0
  13. package/dist/types/database_adapter.d.ts +39 -0
  14. package/dist/types/entity_callbacks.d.ts +14 -1
  15. package/dist/types/filter-operators.d.ts +24 -1
  16. package/dist/types/policy.d.ts +29 -1
  17. package/dist/types/properties.d.ts +216 -3
  18. package/dist/types/relations.d.ts +65 -7
  19. package/dist/types/resource_kinds.d.ts +173 -17
  20. package/dist/types/resources.d.ts +108 -7
  21. package/dist/types/rls-functions.d.ts +11 -0
  22. package/dist/types/storage_source.d.ts +12 -23
  23. package/package.json +24 -23
  24. package/src/call_context.ts +0 -120
  25. package/src/controllers/auth_state.ts +0 -24
  26. package/src/controllers/client.ts +0 -494
  27. package/src/controllers/collection_registry.ts +0 -62
  28. package/src/controllers/data.ts +0 -1012
  29. package/src/controllers/data_driver.ts +0 -576
  30. package/src/controllers/effective_role.ts +0 -4
  31. package/src/controllers/email.ts +0 -91
  32. package/src/controllers/index.ts +0 -11
  33. package/src/controllers/storage.ts +0 -252
  34. package/src/errors.ts +0 -119
  35. package/src/index.ts +0 -5
  36. package/src/types/admin_block.ts +0 -209
  37. package/src/types/api_keys.ts +0 -108
  38. package/src/types/auth_adapter.ts +0 -580
  39. package/src/types/backend.ts +0 -987
  40. package/src/types/backup.ts +0 -26
  41. package/src/types/channel_bus.ts +0 -202
  42. package/src/types/chips.ts +0 -34
  43. package/src/types/collection_contract.ts +0 -278
  44. package/src/types/collections.ts +0 -763
  45. package/src/types/component_ref.ts +0 -92
  46. package/src/types/cron.ts +0 -213
  47. package/src/types/data_source.ts +0 -357
  48. package/src/types/database_adapter.ts +0 -267
  49. package/src/types/entities.ts +0 -226
  50. package/src/types/entity_callbacks.ts +0 -229
  51. package/src/types/filter-operators.ts +0 -444
  52. package/src/types/history.ts +0 -66
  53. package/src/types/index.ts +0 -36
  54. package/src/types/indexes.ts +0 -180
  55. package/src/types/policy.ts +0 -328
  56. package/src/types/postgres_introspection.ts +0 -101
  57. package/src/types/project_manifest.ts +0 -598
  58. package/src/types/properties.ts +0 -1368
  59. package/src/types/relations.ts +0 -417
  60. package/src/types/resource_kinds.ts +0 -390
  61. package/src/types/resources.ts +0 -368
  62. package/src/types/rls-functions.ts +0 -98
  63. package/src/types/schema_editing.ts +0 -157
  64. package/src/types/schema_version.ts +0 -112
  65. package/src/types/search.ts +0 -247
  66. package/src/types/security_rules.ts +0 -344
  67. package/src/types/storage_authorize.ts +0 -77
  68. package/src/types/storage_source.ts +0 -248
  69. package/src/types/websockets.ts +0 -117
  70. package/src/users/index.ts +0 -2
  71. 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.
@@ -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: string): StorageSource;
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 server-side (a no-op sender is
439
- * wired when SMTP is not configured).
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?: string;
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
- orderBy(column: (keyof M & string) | ComputedSortField, direction?: "asc" | "desc"): this;
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
- * Optional because it is only present when realtime is enabled. `observe()`
792
- * is not it degrades to a single fetchwhich is the other reason to
793
- * reach for it instead.
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?(params: FindParams<M> | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
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?(id: string | number, onUpdate: (row: M | undefined) => void, onError?: (error: Error) => void): () => void;
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?(params?: FindParams<M>): Promise<number>;
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: (keyof M & string) | ComputedSortField, direction?: "asc" | "desc"): SDKQueryBuilderInterface<M>;
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
- * Left `undefined` for realtime/WebSocket, network, and client-side
36
- * logic errors that have no HTTP status.
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
- constructor(message: string);
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;