@rebasepro/server 0.14.0 → 0.14.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.
Files changed (58) hide show
  1. package/dist/api/rest/query-parser.d.ts +37 -1
  2. package/dist/api/rest/write-validation.d.ts +26 -0
  3. package/dist/auth/index.d.ts +3 -1
  4. package/dist/auth/interfaces.d.ts +14 -1
  5. package/dist/auth/jwks-routes.d.ts +17 -0
  6. package/dist/auth/jwt-keys.d.ts +108 -0
  7. package/dist/auth/jwt.d.ts +62 -2
  8. package/dist/{auth-CYoPVf-E.js → auth-BobZVd0j.js} +142 -167
  9. package/dist/auth-BobZVd0j.js.map +1 -0
  10. package/dist/boot/boot.d.ts +36 -50
  11. package/dist/boot/ddl-bootstrap.d.ts +15 -0
  12. package/dist/boot/env.d.ts +20 -0
  13. package/dist/boot/provision.d.ts +182 -0
  14. package/dist/boot/role.d.ts +88 -0
  15. package/dist/{cron-store-Dvr4Y1sZ.js → cron-store-CB1x-Ken.js} +3 -3
  16. package/dist/{cron-store-Dvr4Y1sZ.js.map → cron-store-CB1x-Ken.js.map} +1 -1
  17. package/dist/{ddl-bootstrap-BhXbTnBl.js → ddl-bootstrap-Cywoj8Ta.js} +40 -2
  18. package/dist/ddl-bootstrap-Cywoj8Ta.js.map +1 -0
  19. package/dist/env.d.ts +2 -0
  20. package/dist/functions/proxy.d.ts +41 -0
  21. package/dist/functions/selection.d.ts +45 -0
  22. package/dist/index.d.ts +8 -3
  23. package/dist/index.es.js +1113 -661
  24. package/dist/index.es.js.map +1 -1
  25. package/dist/init/shutdown.d.ts +4 -0
  26. package/dist/init/surfaces.d.ts +79 -0
  27. package/dist/init.d.ts +121 -1
  28. package/dist/jobs/index.d.ts +5 -0
  29. package/dist/jobs/job-queue.d.ts +14 -0
  30. package/dist/jobs/job-store.d.ts +22 -0
  31. package/dist/jobs/types.d.ts +125 -0
  32. package/dist/jobs-DR4SjGrD.js +326 -0
  33. package/dist/jobs-DR4SjGrD.js.map +1 -0
  34. package/dist/{jwt-_IFqfTOg.js → jwt-VJyXTdQQ.js} +447 -11
  35. package/dist/jwt-VJyXTdQQ.js.map +1 -0
  36. package/dist/{openapi-generator-DPKtUC9X.js → openapi-generator-DQeQ_q2f.js} +68 -3
  37. package/dist/openapi-generator-DQeQ_q2f.js.map +1 -0
  38. package/dist/proxy-Bj5DVllb.js +139 -0
  39. package/dist/proxy-Bj5DVllb.js.map +1 -0
  40. package/dist/{request-timeout-RivJsME0.js → request-timeout-BuFoEKwT.js} +6 -3
  41. package/dist/request-timeout-BuFoEKwT.js.map +1 -0
  42. package/dist/selection-_z6TM1DB.js +64 -0
  43. package/dist/selection-_z6TM1DB.js.map +1 -0
  44. package/dist/services/webhook-service.d.ts +43 -5
  45. package/dist/{src-C7rkDGxA.js → src-8XDWyDfR.js} +84 -13
  46. package/dist/src-8XDWyDfR.js.map +1 -0
  47. package/dist/src-Cz9nMgUR.js.map +1 -1
  48. package/dist/storage/keys.d.ts +17 -0
  49. package/dist/storage/routes.d.ts +1 -1
  50. package/dist/storage/storage-registry.d.ts +46 -4
  51. package/dist/storage/tus-handler.d.ts +1 -1
  52. package/package.json +5 -5
  53. package/dist/auth-CYoPVf-E.js.map +0 -1
  54. package/dist/ddl-bootstrap-BhXbTnBl.js.map +0 -1
  55. package/dist/jwt-_IFqfTOg.js.map +0 -1
  56. package/dist/openapi-generator-DPKtUC9X.js.map +0 -1
  57. package/dist/request-timeout-RivJsME0.js.map +0 -1
  58. package/dist/src-C7rkDGxA.js.map +0 -1
@@ -1,3 +1,12 @@
1
+ import type { JobQueueClient } from "../jobs/types";
2
+ /**
3
+ * The task name a queued webhook delivery is stored under.
4
+ *
5
+ * Namespaced, and frozen: it is written into `rebase.jobs` rows that outlive
6
+ * the deploy that wrote them, so renaming it would strand every delivery
7
+ * already queued under the old name until they dead-lettered.
8
+ */
9
+ export declare const WEBHOOK_DELIVERY_TASK = "rebase.webhook.deliver";
1
10
  export interface WebhookConfig {
2
11
  id: string;
3
12
  url: string;
@@ -43,6 +52,14 @@ export interface WebhookDispatcherOptions {
43
52
  * `dns.lookup`; injected by tests so a unit suite never asks a resolver.
44
53
  */
45
54
  lookup?: (hostname: string) => Promise<string[]>;
55
+ /**
56
+ * Where {@link WebhookDispatcher.enqueueEntityChange} puts deliveries.
57
+ *
58
+ * Without it they go to an in-memory array that a crash or a deploy
59
+ * empties. With it they are rows, retried with backoff by a worker that
60
+ * may not even be the process that queued them.
61
+ */
62
+ jobQueue?: JobQueueClient;
46
63
  }
47
64
  export declare class WebhookDispatcher {
48
65
  private webhooks;
@@ -77,16 +94,37 @@ export declare class WebhookDispatcher {
77
94
  * for a third party. It also means a receiver that is down can no longer
78
95
  * fail the customer's write.
79
96
  *
80
- * The cost, stated plainly: the queue is in-process and in-memory. A crash
81
- * or a deploy between the enqueue and the delivery drops the event, and a
82
- * receiver may see the notification a few milliseconds before the row it
83
- * describes is committed. Use {@link flush} on shutdown, and
84
- * `onDelivery` to record failures.
97
+ * The cost, when no `jobQueue` is configured: the queue is in-process and
98
+ * in-memory. A crash or a deploy between the enqueue and the delivery drops
99
+ * the event, and a receiver may see the notification a few milliseconds
100
+ * before the row it describes is committed. Use {@link flush} on shutdown,
101
+ * and `onDelivery` to record failures.
102
+ *
103
+ * With `jobQueue` set, only the second half of that remains: the delivery
104
+ * becomes a row in `rebase.jobs` and survives the crash, the deploy and the
105
+ * pod being rescheduled.
85
106
  */
86
107
  enqueueEntityChange(table: string, event: "INSERT" | "UPDATE" | "DELETE", id: string, entity: Record<string, unknown> | null, previousEntity?: Record<string, unknown> | null): void;
108
+ /**
109
+ * Deliver one queued job, as the worker runs it.
110
+ *
111
+ * One attempt, and it throws on failure. The retries belong to the queue
112
+ * now: keeping both would multiply — three in-process attempts inside each
113
+ * of three job attempts is nine deliveries and about two minutes of holding
114
+ * a worker slot — and only the queue's retries survive a restart, which is
115
+ * the whole reason for moving.
116
+ */
117
+ deliverQueuedJob(job: {
118
+ webhookId: string;
119
+ event: string;
120
+ payload: Record<string, unknown>;
121
+ }): Promise<void>;
87
122
  /**
88
123
  * Wait for every queued delivery to finish. For graceful shutdown, and for
89
124
  * tests that need to observe what {@link enqueueEntityChange} sent.
125
+ *
126
+ * In-process deliveries only — with a `jobQueue` configured there is
127
+ * nothing here to wait for, because the deliveries are rows.
90
128
  */
91
129
  flush(): Promise<void>;
92
130
  private startDraining;
@@ -3078,6 +3078,70 @@ var CollectionRegistry = class {
3078
3078
  }
3079
3079
  };
3080
3080
  //#endregion
3081
+ //#region ../common/src/data/sort-dialect.ts
3082
+ /**
3083
+ * Sort-order wire codec.
3084
+ *
3085
+ * This is the ONLY module that knows about the colon-delimited wire format
3086
+ * (`"field:direction"`) used in HTTP query parameters, and about the JSON-array
3087
+ * form that carries a multi-column sort over the same parameter.
3088
+ * Everything else speaks {@link OrderByTuple} exclusively.
3089
+ *
3090
+ * Mirrors the filter architecture in `filter-dialect.ts`.
3091
+ *
3092
+ * @module
3093
+ */
3094
+ /**
3095
+ * Collapse the one-key and many-key spellings of a sort into the list form.
3096
+ *
3097
+ * `["a", "desc"]` and `[["a", "desc"]]` mean the same thing and normalize to
3098
+ * the same value; the two are told apart by whether the first element is
3099
+ * itself an array, which no field name ever is.
3100
+ *
3101
+ * @returns The keys in order of significance, or `undefined` for no sort. An
3102
+ * empty list also returns `undefined` — "sort by nothing" is no sort, and
3103
+ * letting `[]` through would have every layer below re-deciding what it meant.
3104
+ */
3105
+ function normalizeOrderBy(orderBy) {
3106
+ if (!orderBy || orderBy.length === 0) return void 0;
3107
+ const list = Array.isArray(orderBy[0]) ? orderBy : [orderBy];
3108
+ return list.length > 0 ? list : void 0;
3109
+ }
3110
+ /**
3111
+ * Serialize a sort to the wire.
3112
+ *
3113
+ * A single key keeps the `"field:direction"` shorthand it has always used —
3114
+ * short, readable in a URL, and what every existing client and test expects.
3115
+ * Several keys are emitted as the canonical JSON array the server already
3116
+ * accepts, because the shorthand has no separator to spare: a comma-joined
3117
+ * `"a:asc,b:desc"` parses as one field named `a` with the direction
3118
+ * `"asc,b:desc"`, which the server refuses.
3119
+ *
3120
+ * **Runtime tolerance:** if the input is already a well-formed wire string
3121
+ * (from an untyped JS caller), it is returned unchanged.
3122
+ * This is undocumented tolerance, not public API — don't rely on it.
3123
+ *
3124
+ * @param orderBy - A canonical tuple or list of tuples, or at runtime
3125
+ * possibly a pre-serialized string (undocumented tolerance).
3126
+ * @returns The wire-format string, or `undefined` if the input is falsy.
3127
+ *
3128
+ * @remarks
3129
+ * Field names containing `:` are representable in the tuple form but
3130
+ * **not** in the single-key wire encoding — this is an inherent limitation of
3131
+ * the colon-delimited shorthand and is not resolved here.
3132
+ */
3133
+ function serializeOrderBy(orderBy) {
3134
+ if (!orderBy) return void 0;
3135
+ if (typeof orderBy === "string") return orderBy;
3136
+ const list = normalizeOrderBy(orderBy);
3137
+ if (!list) return void 0;
3138
+ if (list.length === 1) return `${list[0][0]}:${list[0][1]}`;
3139
+ return JSON.stringify(list.map(([field, direction]) => ({
3140
+ field,
3141
+ direction
3142
+ })));
3143
+ }
3144
+ //#endregion
3081
3145
  //#region ../common/src/data/query_builder.ts
3082
3146
  var QueryBuilder = class {
3083
3147
  collection;
@@ -3106,11 +3170,18 @@ var QueryBuilder = class {
3106
3170
  }
3107
3171
  /**
3108
3172
  * Order the results by a specific column.
3173
+ *
3174
+ * Called again, this adds a tie-breaker rather than replacing the sort:
3175
+ * keys apply in the order they were added.
3176
+ *
3109
3177
  * @example
3110
3178
  * client.collection('users').orderBy('createdAt', 'desc').find()
3179
+ * @example
3180
+ * client.collection('users').orderBy('roles').orderBy('createdAt', 'desc').find()
3111
3181
  */
3112
3182
  orderBy(column, direction = "asc") {
3113
- this.params.orderBy = [column, direction];
3183
+ const existing = normalizeOrderBy(this.params.orderBy) ?? [];
3184
+ this.params.orderBy = [...existing, [column, direction]];
3114
3185
  return this;
3115
3186
  }
3116
3187
  /**
@@ -3284,9 +3355,10 @@ async function* paginateFind(find, params, label = "collection") {
3284
3355
  const requestedDirection = typeof cursor === "object" && cursor !== null ? cursor.direction : void 0;
3285
3356
  let direction = "asc";
3286
3357
  if (cursorField) {
3287
- const orderBy = findParams.orderBy;
3288
- if (orderBy && orderBy[0] !== cursorField) throw new RebasePaginationError("cursor-order-mismatch", `Cannot seek on "${cursorField}" while ordering "${label}" by "${orderBy[0]}": keyset pagination only advances along the column the query is sorted by. Order by "${cursorField}", or drop the cursor and page by offset.`);
3289
- direction = requestedDirection ?? orderBy?.[1] ?? "asc";
3358
+ const orderBy = normalizeOrderBy(findParams.orderBy);
3359
+ if (orderBy && orderBy.length > 1) throw new RebasePaginationError("cursor-order-mismatch", `Cannot seek on "${cursorField}" while ordering "${label}" by ${orderBy.map(([field]) => `"${field}"`).join(", ")}: keyset pagination advances along a single column. Order by "${cursorField}" alone, or drop the cursor and page by offset.`);
3360
+ if (orderBy && orderBy[0][0] !== cursorField) throw new RebasePaginationError("cursor-order-mismatch", `Cannot seek on "${cursorField}" while ordering "${label}" by "${orderBy[0][0]}": keyset pagination only advances along the column the query is sorted by. Order by "${cursorField}", or drop the cursor and page by offset.`);
3361
+ direction = requestedDirection ?? orderBy?.[0][1] ?? "asc";
3290
3362
  findParams.orderBy = [cursorField, direction];
3291
3363
  }
3292
3364
  const seekOp = direction === "desc" ? "<" : ">";
@@ -3936,8 +4008,7 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
3936
4008
  logical: params?.logical,
3937
4009
  limit,
3938
4010
  offset: driverOffset,
3939
- orderBy: params?.orderBy?.[0],
3940
- order: params?.orderBy?.[1],
4011
+ orderBy: normalizeOrderBy(params?.orderBy),
3941
4012
  searchString: params?.searchString
3942
4013
  }, params?.include) : await driver.fetchCollection({
3943
4014
  path: slug,
@@ -3945,8 +4016,7 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
3945
4016
  offset: driverOffset,
3946
4017
  filter,
3947
4018
  logical: params?.logical,
3948
- orderBy: params?.orderBy?.[0],
3949
- order: params?.orderBy?.[1],
4019
+ orderBy: normalizeOrderBy(params?.orderBy),
3950
4020
  searchString: params?.searchString
3951
4021
  });
3952
4022
  let total = rows.length + offset;
@@ -4041,8 +4111,7 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
4041
4111
  offset: driverOffset,
4042
4112
  filter: params?.where,
4043
4113
  logical: params?.logical,
4044
- orderBy: params?.orderBy?.[0],
4045
- order: params?.orderBy?.[1],
4114
+ orderBy: normalizeOrderBy(params?.orderBy),
4046
4115
  searchString: params?.searchString,
4047
4116
  searchExplain: params?.searchExplain,
4048
4117
  onUpdate: (entities) => {
@@ -4162,8 +4231,10 @@ var SdkQueryBuilder = class {
4162
4231
  }
4163
4232
  return this;
4164
4233
  }
4234
+ /** Called again, this adds a tie-breaker rather than replacing the sort. */
4165
4235
  orderBy(column, direction = "asc") {
4166
- this.params.orderBy = [column, direction];
4236
+ const existing = normalizeOrderBy(this.params.orderBy) ?? [];
4237
+ this.params.orderBy = [...existing, [column, direction]];
4167
4238
  return this;
4168
4239
  }
4169
4240
  limit(count) {
@@ -4361,6 +4432,6 @@ function buildRoutedRebaseData({ defaultData, sources, resolveKey }) {
4361
4432
  } });
4362
4433
  }
4363
4434
  //#endregion
4364
- export { RebaseApiError as A, resolveClientListLimit as C, EntityRelation as D, EntityReference as E, GeoPoint as O, MAX_LIST_LIMIT as S, isAnonymousUid as T, resolveCollectionRelations as _, deserializeLogicalCondition as a, toSnakeCase as b, collectAllPages as c, CollectionRegistry as d, createDataSourceRegistry as f, findRelation as g, fieldKeyForColumn as h, deserializeFilter as i, RebaseClientError as j, Vector as k, paginateFind as l, getEffectiveSecurityRules as m, buildSdkData as n, serializeFilter as o, resolveDataSource as p, UnknownFilterOperatorError as r, serializeLogicalCondition as s, buildRoutedRebaseData as t, resolveFindWindow as u, buildCompositeId as v, ANONYMOUS_USER_ID as w, ListLimitError as x, resolvePrimaryKeys as y };
4435
+ export { GeoPoint as A, ListLimitError as C, isAnonymousUid as D, ANONYMOUS_USER_ID as E, RebaseApiError as M, RebaseClientError as N, EntityReference as O, toSnakeCase as S, resolveClientListLimit as T, fieldKeyForColumn as _, deserializeLogicalCondition as a, buildCompositeId as b, collectAllPages as c, normalizeOrderBy as d, serializeOrderBy as f, getEffectiveSecurityRules as g, resolveDataSource as h, deserializeFilter as i, Vector as j, EntityRelation as k, paginateFind as l, createDataSourceRegistry as m, buildSdkData as n, serializeFilter as o, CollectionRegistry as p, UnknownFilterOperatorError as r, serializeLogicalCondition as s, buildRoutedRebaseData as t, resolveFindWindow as u, findRelation as v, MAX_LIST_LIMIT as w, resolvePrimaryKeys as x, resolveCollectionRelations as y };
4365
4436
 
4366
- //# sourceMappingURL=src-C7rkDGxA.js.map
4437
+ //# sourceMappingURL=src-8XDWyDfR.js.map