@rebasepro/types 0.12.0 → 0.12.1-canary.g181d0fe

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.
@@ -611,6 +611,25 @@ export interface BackendBootstrapper {
611
611
  ensureCollectionSchema?(collections: unknown[], driverResult: InitializedDriver, log?: (message: string) => void): Promise<{
612
612
  applied: number;
613
613
  }>;
614
+ /**
615
+ * Apply the collections' row-level-security policies, additively and
616
+ * idempotently — the companion to {@link ensureCollectionSchema}.
617
+ *
618
+ * That method creates the tables; a table with RLS disabled and no policies
619
+ * is not servable, because authenticated requests run as a restricted role:
620
+ * a read with no `SELECT` policy returns nothing (a public collection
621
+ * answers 401) and a write with no `INSERT`/`UPDATE` policy is denied. The
622
+ * `db push` CLI applies these from the same collections, but it cannot reach
623
+ * a managed tenant's in-cluster database — the runtime, already connected,
624
+ * is the only thing that can.
625
+ *
626
+ * MUST be idempotent (re-run on every boot) and MUST NOT be destructive.
627
+ * Runs after auth initialization, because the generated policies call the
628
+ * `auth.*` helper functions and `CREATE POLICY` validates they exist.
629
+ */
630
+ ensureCollectionPolicies?(collections: unknown[], driverResult: InitializedDriver, log?: (message: string) => void): Promise<{
631
+ applied: number;
632
+ }>;
614
633
  /**
615
634
  * Initialize WebSocket server for realtime operations.
616
635
  */
@@ -26,6 +26,37 @@ export interface CronJobDefinition {
26
26
  * considered timed-out. Default: 300 (5 min).
27
27
  */
28
28
  timeoutSeconds?: number;
29
+ /**
30
+ * How far back to look, on startup, for a slot that elapsed while no
31
+ * instance was holding a timer for it. Off by default.
32
+ *
33
+ * The scheduler drives jobs with in-process `setTimeout` and computes the
34
+ * next slot from *now* on every boot, so a slot only fires if some instance
35
+ * happened to be alive and ticking when it came round. That is not a
36
+ * scale-to-zero problem: a platform that recycles containers — Cloud Run
37
+ * rotating an instance under `--min-instances 1`, a rolling deploy, a crash
38
+ * loop — drops any slot that falls inside the changeover, and the
39
+ * replacement schedules the slot *after* it. The run is skipped in silence.
40
+ *
41
+ * Set this to a window comfortably wider than a restart (a few minutes for
42
+ * a frequent job; an hour or more for a daily one) and startup will run a
43
+ * slot it finds unclaimed inside that window.
44
+ *
45
+ * Two deliberate limits:
46
+ *
47
+ * - **Only the most recent missed slot runs.** Booting after a six-hour
48
+ * outage catches an hourly job up once, not six times. Catch-up exists to
49
+ * stop a run going missing, not to replay history.
50
+ * - **A claims-capable store is required.** Catch-up is skipped entirely
51
+ * when the store has no `tryClaimRun` (or no store is attached), because
52
+ * the claim is the only thing that distinguishes "this slot never ran"
53
+ * from "this slot already ran on the instance I am replacing". Without
54
+ * it, an instance recycled every 30 minutes would re-run the same hourly
55
+ * job every time it booted.
56
+ *
57
+ * @example catchUpWindowSeconds: 3600 // daily job: tolerate an hour of downtime
58
+ */
59
+ catchUpWindowSeconds?: number;
29
60
  /**
30
61
  * The handler function executed on each tick.
31
62
  * Receives a context object with the data driver and logger.
@@ -67,6 +67,32 @@ export interface DatabaseAdapter {
67
67
  * Initialize WebSocket server for realtime operations.
68
68
  */
69
69
  initializeWebsockets?(server: unknown, realtimeService: RealtimeProvider, driver: DataDriver, config?: unknown): Promise<void> | void;
70
+ /**
71
+ * Bring the database's collection tables up to date, additively — the boot
72
+ * companion to `db push`. See `BackendBootstrapper.ensureCollectionSchema`
73
+ * for the contract (create-only; never drop, narrow, or rewrite).
74
+ *
75
+ * Optional, and MUST be forwarded by any wrapper that turns this adapter
76
+ * into a `BackendBootstrapper`: the runtime calls it through the bootstrapper
77
+ * at boot, and a wrapper that silently omits it leaves a managed tenant
78
+ * 500ing every data route with no create step ever having run.
79
+ */
80
+ ensureCollectionSchema?(collections: unknown[], driverResult: InitializedDriver, log?: (message: string) => void): Promise<{
81
+ applied: number;
82
+ }>;
83
+ /**
84
+ * Apply the collections' RLS policies (ENABLE ROW LEVEL SECURITY + the
85
+ * `securityRules` compiled to `CREATE POLICY`) — the boot companion to the
86
+ * policy half of `db push`. Idempotent; see
87
+ * `BackendBootstrapper.ensureCollectionPolicies`.
88
+ *
89
+ * Same forwarding requirement as `ensureCollectionSchema`: without the
90
+ * policies, tables exist but every user-context read is denied (a public
91
+ * collection answers 401).
92
+ */
93
+ ensureCollectionPolicies?(collections: unknown[], driverResult: InitializedDriver, log?: (message: string) => void): Promise<{
94
+ applied: number;
95
+ }>;
70
96
  /**
71
97
  * Return admin capabilities for this database (SQL editor, schema browser, branching).
72
98
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/types",
3
3
  "type": "module",
4
- "version": "0.12.0",
4
+ "version": "0.12.1-canary.g181d0fe",
5
5
  "description": "Rebase type definitions — shared interfaces and controller types",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/rebaseco"
@@ -39,14 +39,14 @@
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/jest": "^30.0.0",
42
- "@types/node": "^25.9.3",
42
+ "@types/node": "^26.1.2",
43
43
  "@types/object-hash": "^3.0.6",
44
44
  "@types/react-measure": "^2.0.12",
45
45
  "hono": "^4.12.27",
46
46
  "jest": "^30.4.2",
47
- "ts-jest": "^29.4.11",
47
+ "ts-jest": "^29.4.12",
48
48
  "typescript": "^6.0.3",
49
- "vite": "^8.0.16"
49
+ "vite": "^8.1.5"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "hono": "^4.12.27"
@@ -94,6 +94,21 @@ export interface AuthClient {
94
94
  * Manually refresh the session token
95
95
  */
96
96
  refreshSession(): Promise<RebaseSession>;
97
+
98
+ /**
99
+ * Whether a session could exist that this client has not loaded yet.
100
+ *
101
+ * `false` means the only way this client can hold a session is an explicit
102
+ * sign-in during this page's lifetime: it neither persists sessions nor
103
+ * carries an httpOnly auth cookie, so there is nothing on disk or in the
104
+ * browser to restore from. A caller that would otherwise probe the server
105
+ * — `getUser()` on mount, say — can skip it, because the answer is already
106
+ * known and the request can only ever fail.
107
+ *
108
+ * Optional so that alternative {@link AuthClient} implementations need not
109
+ * supply it; treat a missing implementation as "unknown, go ahead and ask".
110
+ */
111
+ canRestoreSession?: () => boolean;
97
112
  }
98
113
 
99
114
  // ─── Admin API ───────────────────────────────────────────────────────────────
@@ -321,6 +336,17 @@ export interface RebaseClient<DB = unknown> {
321
336
  /** Base HTTP URL of the backend server */
322
337
  baseUrl?: string;
323
338
 
339
+ /**
340
+ * The path every API route is mounted under, appended to {@link baseUrl}.
341
+ *
342
+ * `"/api"` unless the backend was configured with a different `basePath`
343
+ * and the client told to match. Exposed because code that builds a URL by
344
+ * hand — rather than going through the client's own methods — otherwise has
345
+ * to guess, and guessing `/api` is wrong for exactly the projects that set
346
+ * the option.
347
+ */
348
+ apiPath?: string;
349
+
324
350
  /** WebSocket client for realtime subscriptions */
325
351
  ws?: RebaseWebSocket;
326
352
 
@@ -439,6 +465,17 @@ export interface RebaseBrowserClient<DB = unknown> {
439
465
  /** Base HTTP URL of the backend server */
440
466
  baseUrl?: string;
441
467
 
468
+ /**
469
+ * The path every API route is mounted under, appended to {@link baseUrl}.
470
+ *
471
+ * `"/api"` unless the backend was configured with a different `basePath`
472
+ * and the client told to match. Exposed because code that builds a URL by
473
+ * hand — rather than going through the client's own methods — otherwise has
474
+ * to guess, and guessing `/api` is wrong for exactly the projects that set
475
+ * the option.
476
+ */
477
+ apiPath?: string;
478
+
442
479
  /** WebSocket client for realtime subscriptions */
443
480
  ws?: RebaseWebSocket;
444
481
 
@@ -798,6 +798,28 @@ export interface BackendBootstrapper {
798
798
  log?: (message: string) => void
799
799
  ): Promise<{ applied: number }>;
800
800
 
801
+ /**
802
+ * Apply the collections' row-level-security policies, additively and
803
+ * idempotently — the companion to {@link ensureCollectionSchema}.
804
+ *
805
+ * That method creates the tables; a table with RLS disabled and no policies
806
+ * is not servable, because authenticated requests run as a restricted role:
807
+ * a read with no `SELECT` policy returns nothing (a public collection
808
+ * answers 401) and a write with no `INSERT`/`UPDATE` policy is denied. The
809
+ * `db push` CLI applies these from the same collections, but it cannot reach
810
+ * a managed tenant's in-cluster database — the runtime, already connected,
811
+ * is the only thing that can.
812
+ *
813
+ * MUST be idempotent (re-run on every boot) and MUST NOT be destructive.
814
+ * Runs after auth initialization, because the generated policies call the
815
+ * `auth.*` helper functions and `CREATE POLICY` validates they exist.
816
+ */
817
+ ensureCollectionPolicies?(
818
+ collections: unknown[],
819
+ driverResult: InitializedDriver,
820
+ log?: (message: string) => void
821
+ ): Promise<{ applied: number }>;
822
+
801
823
  /**
802
824
  * Initialize WebSocket server for realtime operations.
803
825
  */
package/src/types/cron.ts CHANGED
@@ -38,6 +38,38 @@ export interface CronJobDefinition {
38
38
  */
39
39
  timeoutSeconds?: number;
40
40
 
41
+ /**
42
+ * How far back to look, on startup, for a slot that elapsed while no
43
+ * instance was holding a timer for it. Off by default.
44
+ *
45
+ * The scheduler drives jobs with in-process `setTimeout` and computes the
46
+ * next slot from *now* on every boot, so a slot only fires if some instance
47
+ * happened to be alive and ticking when it came round. That is not a
48
+ * scale-to-zero problem: a platform that recycles containers — Cloud Run
49
+ * rotating an instance under `--min-instances 1`, a rolling deploy, a crash
50
+ * loop — drops any slot that falls inside the changeover, and the
51
+ * replacement schedules the slot *after* it. The run is skipped in silence.
52
+ *
53
+ * Set this to a window comfortably wider than a restart (a few minutes for
54
+ * a frequent job; an hour or more for a daily one) and startup will run a
55
+ * slot it finds unclaimed inside that window.
56
+ *
57
+ * Two deliberate limits:
58
+ *
59
+ * - **Only the most recent missed slot runs.** Booting after a six-hour
60
+ * outage catches an hourly job up once, not six times. Catch-up exists to
61
+ * stop a run going missing, not to replay history.
62
+ * - **A claims-capable store is required.** Catch-up is skipped entirely
63
+ * when the store has no `tryClaimRun` (or no store is attached), because
64
+ * the claim is the only thing that distinguishes "this slot never ran"
65
+ * from "this slot already ran on the instance I am replacing". Without
66
+ * it, an instance recycled every 30 minutes would re-run the same hourly
67
+ * job every time it booted.
68
+ *
69
+ * @example catchUpWindowSeconds: 3600 // daily job: tolerate an hour of downtime
70
+ */
71
+ catchUpWindowSeconds?: number;
72
+
41
73
  /**
42
74
  * The handler function executed on each tick.
43
75
  * Receives a context object with the data driver and logger.
@@ -90,6 +90,38 @@ export interface DatabaseAdapter {
90
90
  config?: unknown,
91
91
  ): Promise<void> | void;
92
92
 
93
+ /**
94
+ * Bring the database's collection tables up to date, additively — the boot
95
+ * companion to `db push`. See `BackendBootstrapper.ensureCollectionSchema`
96
+ * for the contract (create-only; never drop, narrow, or rewrite).
97
+ *
98
+ * Optional, and MUST be forwarded by any wrapper that turns this adapter
99
+ * into a `BackendBootstrapper`: the runtime calls it through the bootstrapper
100
+ * at boot, and a wrapper that silently omits it leaves a managed tenant
101
+ * 500ing every data route with no create step ever having run.
102
+ */
103
+ ensureCollectionSchema?(
104
+ collections: unknown[],
105
+ driverResult: InitializedDriver,
106
+ log?: (message: string) => void,
107
+ ): Promise<{ applied: number }>;
108
+
109
+ /**
110
+ * Apply the collections' RLS policies (ENABLE ROW LEVEL SECURITY + the
111
+ * `securityRules` compiled to `CREATE POLICY`) — the boot companion to the
112
+ * policy half of `db push`. Idempotent; see
113
+ * `BackendBootstrapper.ensureCollectionPolicies`.
114
+ *
115
+ * Same forwarding requirement as `ensureCollectionSchema`: without the
116
+ * policies, tables exist but every user-context read is denied (a public
117
+ * collection answers 401).
118
+ */
119
+ ensureCollectionPolicies?(
120
+ collections: unknown[],
121
+ driverResult: InitializedDriver,
122
+ log?: (message: string) => void,
123
+ ): Promise<{ applied: number }>;
124
+
93
125
  /**
94
126
  * Return admin capabilities for this database (SQL editor, schema browser, branching).
95
127
  */