@rebasepro/cli 0.12.1-canary.gf5f1d39 → 0.13.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/bin/rebase.js +27 -1
- package/dist/bundle.d.ts +36 -0
- package/dist/commands/cloud/context.d.ts +78 -0
- package/dist/commands/cloud/deploy.d.ts +64 -0
- package/dist/commands/cloud/index.d.ts +23 -0
- package/dist/commands/cloud/projects.d.ts +32 -1
- package/dist/commands/dev.d.ts +16 -0
- package/dist/commands/telemetry.d.ts +9 -0
- package/dist/index.es.js +974 -69
- package/dist/index.es.js.map +1 -1
- package/dist/telemetry/consent.d.ts +38 -0
- package/dist/telemetry/identity.d.ts +69 -0
- package/dist/telemetry/index.d.ts +72 -0
- package/dist/telemetry/payload.d.ts +78 -0
- package/dist/telemetry/project.d.ts +34 -0
- package/package.json +11 -11
- package/templates/overlays/baas/backend/package.json +2 -2
- package/templates/overlays/baas/package.json +1 -2
- package/templates/template/backend/package.json +2 -2
- package/templates/template/config/collections/index.ts +9 -1
- package/templates/template/frontend/package.json +3 -3
- package/templates/template/frontend/src/App.tsx +2 -1
- package/templates/template/frontend/src/main.tsx +2 -1
- package/templates/template/frontend/vite.config.ts +0 -1
- package/templates/template/package.json +1 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { TelemetryEventName } from "./payload";
|
|
2
|
+
/**
|
|
3
|
+
* Asking, and what the question looks like.
|
|
4
|
+
*
|
|
5
|
+
* ## Why the prompt comes *after* the work
|
|
6
|
+
*
|
|
7
|
+
* The first `rebase init` on a machine is the event most worth having, and it
|
|
8
|
+
* is the one where no consent exists yet. Asking before scaffolding puts a
|
|
9
|
+
* privacy negotiation in front of someone who has not yet seen the tool do
|
|
10
|
+
* anything — the worst possible moment, and a reliable way to get a reflexive
|
|
11
|
+
* no.
|
|
12
|
+
*
|
|
13
|
+
* So the question is asked once the project exists and the user has seen it
|
|
14
|
+
* work. The event's data is still in memory at that point, so nothing is lost
|
|
15
|
+
* by waiting, and — this is the part that matters — **nothing has been
|
|
16
|
+
* transmitted or written**. Declining leaves no id, no file, no record.
|
|
17
|
+
*
|
|
18
|
+
* ## Why the payload is shown rather than described
|
|
19
|
+
*
|
|
20
|
+
* "Anonymous usage data" is a phrase that has been used to mean almost
|
|
21
|
+
* anything. Printing the exact JSON costs four lines of output and replaces a
|
|
22
|
+
* claim the user has to take on faith with something they can read. It is also
|
|
23
|
+
* the same builder the sender uses, so it cannot drift into a comfortable
|
|
24
|
+
* fiction.
|
|
25
|
+
*/
|
|
26
|
+
/** True when we may ask: no decision recorded, and nothing else forbids it. */
|
|
27
|
+
export declare function shouldPrompt(env?: NodeJS.ProcessEnv): boolean;
|
|
28
|
+
export declare function renderPreview(event: TelemetryEventName, properties: Record<string, unknown>): string;
|
|
29
|
+
/**
|
|
30
|
+
* Ask, record the answer, and report it.
|
|
31
|
+
*
|
|
32
|
+
* Never throws and never blocks a non-interactive run: `rebase init --yes` in
|
|
33
|
+
* CI must behave exactly as it does today, which means not asking and not
|
|
34
|
+
* sending.
|
|
35
|
+
*/
|
|
36
|
+
export declare function promptForConsent(event: TelemetryEventName, properties: Record<string, unknown>): Promise<boolean>;
|
|
37
|
+
/** Human-readable current state, for `rebase telemetry status`. */
|
|
38
|
+
export declare function describeState(env?: NodeJS.ProcessEnv): string;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who is reporting, and where that is remembered.
|
|
3
|
+
*
|
|
4
|
+
* Two identifiers, because they answer two different questions and conflating
|
|
5
|
+
* them would make the answers wrong:
|
|
6
|
+
*
|
|
7
|
+
* - `machineId` — one developer's machine. Lives beside the cloud credentials
|
|
8
|
+
* in `~/.rebase/`, so it survives across every project they scaffold.
|
|
9
|
+
* - `projectId` — one *checkout*. Lives in the project's gitignored
|
|
10
|
+
* `.rebase/`, next to `cloud.json` and `state.json`.
|
|
11
|
+
*
|
|
12
|
+
* Without the split, a developer trying five templates in an afternoon reads as
|
|
13
|
+
* five installations. With it, that is one machine and five projects, which is
|
|
14
|
+
* the shape the funnel actually needs.
|
|
15
|
+
*
|
|
16
|
+
* ## Why `projectId` is not committed
|
|
17
|
+
*
|
|
18
|
+
* `rebase.json` is checked in, and a stable identifier sitting in a public
|
|
19
|
+
* repository is a correlation handle for anyone who finds it — it ties a named
|
|
20
|
+
* organisation to whatever that id did. `.rebase/` is gitignored, so the id
|
|
21
|
+
* stays on the machine that generated it. It also makes the unit honest: what
|
|
22
|
+
* is being counted is a developer working on a project, not the project.
|
|
23
|
+
*
|
|
24
|
+
* ## Why both are random
|
|
25
|
+
*
|
|
26
|
+
* Neither is derived from a hostname, a database name, an email or a machine
|
|
27
|
+
* fingerprint. Hashing any of those only *looks* anonymous — the space of real
|
|
28
|
+
* hostnames is small enough to brute-force a salted hash back to the original
|
|
29
|
+
* in minutes. A random UUID carries no information at all and does the same job.
|
|
30
|
+
*/
|
|
31
|
+
/** Bumped when the stored shape changes in a way old CLIs cannot read. */
|
|
32
|
+
export declare const TELEMETRY_CONFIG_VERSION = 1;
|
|
33
|
+
export type TelemetryConfig = {
|
|
34
|
+
version: number;
|
|
35
|
+
/**
|
|
36
|
+
* `undefined` means never asked — which is *not* the same as declining, and
|
|
37
|
+
* is the only state in which anything may prompt.
|
|
38
|
+
*/
|
|
39
|
+
enabled?: boolean;
|
|
40
|
+
machineId?: string;
|
|
41
|
+
/** When the choice was made, so a later release can tell stale consent from fresh. */
|
|
42
|
+
decidedAt?: string;
|
|
43
|
+
};
|
|
44
|
+
export declare function configPath(): string;
|
|
45
|
+
export declare function readConfig(): TelemetryConfig;
|
|
46
|
+
export declare function writeConfig(config: TelemetryConfig): void;
|
|
47
|
+
/**
|
|
48
|
+
* The machine's id, generating and persisting one on first use.
|
|
49
|
+
*
|
|
50
|
+
* Only called once consent exists — an id written before the user agreed would
|
|
51
|
+
* be a record we had no right to create, even unsent.
|
|
52
|
+
*/
|
|
53
|
+
export declare function ensureMachineId(): string;
|
|
54
|
+
/**
|
|
55
|
+
* The checkout's id, generating one if this project has none.
|
|
56
|
+
*
|
|
57
|
+
* The directory is created when it is missing, but **only** where a
|
|
58
|
+
* `rebase.json` proves this really is a project root. An earlier version
|
|
59
|
+
* required `.rebase/` to already exist, on the assumption that `rebase init`
|
|
60
|
+
* created it — it does not. It is written only when a scaffold is linked to
|
|
61
|
+
* Rebase Cloud, so every self-hosted project reported no `projectId` at all,
|
|
62
|
+
* for ever. That silently broke the funnel this id exists for, on exactly the
|
|
63
|
+
* population the telemetry is meant to learn about.
|
|
64
|
+
*
|
|
65
|
+
* The `rebase.json` check is what keeps the fix from being "scatter `.rebase/`
|
|
66
|
+
* wherever a command happens to run": no manifest, no project, no directory,
|
|
67
|
+
* and the event simply reports no project.
|
|
68
|
+
*/
|
|
69
|
+
export declare function ensureProjectId(projectRoot: string): string | undefined;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { TelemetryEvent, TelemetryEventName } from "./payload";
|
|
2
|
+
export { TELEMETRY_SCHEMA_VERSION, bucket, durationBucket, errorClass, buildEvent, sanitize } from "./payload";
|
|
3
|
+
export type { TelemetryEvent, TelemetryEventName, TelemetryValue } from "./payload";
|
|
4
|
+
export { configPath, readConfig, writeConfig } from "./identity";
|
|
5
|
+
export type { TelemetryConfig } from "./identity";
|
|
6
|
+
export { readProjectPolicy } from "./project";
|
|
7
|
+
export type { ProjectTelemetryPolicy } from "./project";
|
|
8
|
+
/**
|
|
9
|
+
* Where events go. Overridable so a fork can point at its own collector, and so
|
|
10
|
+
* the tests never touch the network.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_TELEMETRY_ENDPOINT = "https://app.rebase.pro/api/functions/telemetry";
|
|
13
|
+
export declare function endpoint(): string;
|
|
14
|
+
/** Why nothing would be sent right now, or `null` when it would. */
|
|
15
|
+
export type SuppressionReason = "not_asked" | "declined" | "do_not_track" | "rebase_telemetry_disabled" | "ci" | "project_opt_out";
|
|
16
|
+
/**
|
|
17
|
+
* The one function that decides whether anything leaves the machine.
|
|
18
|
+
*
|
|
19
|
+
* Every path is a refusal except the last, which is the point: consent is
|
|
20
|
+
* opt-in, so the default answer at every branch — never asked, unreadable
|
|
21
|
+
* config, a set env var, a CI runner — is no.
|
|
22
|
+
*
|
|
23
|
+
* `DO_NOT_TRACK` is honoured because it is the cross-tool convention
|
|
24
|
+
* (consoledonottrack.com); a user who has set it globally has already answered
|
|
25
|
+
* this question and should not be asked again by us.
|
|
26
|
+
*
|
|
27
|
+
* `CI` is refused for a different reason: a build runner is not a person, and
|
|
28
|
+
* counting one is both useless and misleading. A single pipeline re-running on
|
|
29
|
+
* every push would otherwise outweigh every real developer in the data.
|
|
30
|
+
*
|
|
31
|
+
* A project's own `"telemetry": false` is checked *before* the machine setting,
|
|
32
|
+
* because it has to beat an individual opt-in to be worth anything — see
|
|
33
|
+
* project.ts on why the reverse is refused.
|
|
34
|
+
*/
|
|
35
|
+
export declare function suppressionReason(env?: NodeJS.ProcessEnv, cwd?: string): SuppressionReason | null;
|
|
36
|
+
export declare function isEnabled(env?: NodeJS.ProcessEnv, cwd?: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Record the user's answer. `false` is final — nothing prompts again.
|
|
39
|
+
*
|
|
40
|
+
* Returns whether the choice could actually be persisted. A read-only or full
|
|
41
|
+
* home directory makes `writeConfig` throw, and the direction of that failure
|
|
42
|
+
* matters enormously: someone turning sharing **off** who sees a stack trace,
|
|
43
|
+
* or worse sees nothing, is left sharing. The caller is expected to say so and
|
|
44
|
+
* point at `REBASE_TELEMETRY_DISABLED`, which needs no disk.
|
|
45
|
+
*/
|
|
46
|
+
export declare function setConsent(enabled: boolean): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Build the event that *would* be sent, without sending it.
|
|
49
|
+
*
|
|
50
|
+
* This is what `rebase telemetry show` prints, and it is deliberately the same
|
|
51
|
+
* function the sender uses — a preview assembled by separate code is a promise
|
|
52
|
+
* that drifts. Returns `null` when nothing would be sent, so the command can
|
|
53
|
+
* say why instead of showing a payload that is never going anywhere.
|
|
54
|
+
*/
|
|
55
|
+
export declare function previewEvent(event: TelemetryEventName, properties?: Record<string, unknown>, projectRoot?: string): TelemetryEvent | null;
|
|
56
|
+
/**
|
|
57
|
+
* Send one event, or quietly do nothing.
|
|
58
|
+
*
|
|
59
|
+
* Three properties this must hold, in order of importance:
|
|
60
|
+
*
|
|
61
|
+
* 1. **It never throws.** Telemetry failing is not a reason for `rebase dev`
|
|
62
|
+
* to fail. Every error is swallowed.
|
|
63
|
+
* 2. **It never blocks meaningfully.** A two-second ceiling, after which the
|
|
64
|
+
* command carries on regardless — a collector having a bad day must not
|
|
65
|
+
* become the CLI hanging.
|
|
66
|
+
* 3. **It never sends without consent.** Enforced here rather than at the call
|
|
67
|
+
* sites, so a new call site cannot get it wrong.
|
|
68
|
+
*/
|
|
69
|
+
export declare function recordEvent(event: TelemetryEventName, properties?: Record<string, unknown>, options?: {
|
|
70
|
+
projectRoot?: string;
|
|
71
|
+
timeoutMs?: number;
|
|
72
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every field that may ever leave the machine, and nothing else.
|
|
3
|
+
*
|
|
4
|
+
* ## The rule this file exists to enforce
|
|
5
|
+
*
|
|
6
|
+
* **No value here may be free text.** Every property is either a number, a
|
|
7
|
+
* boolean, or a string drawn from a set enumerated in this file. That is not
|
|
8
|
+
* fussiness — free text is the mechanism by which telemetry leaks. An error
|
|
9
|
+
* message carries `/Users/francesco/rebase/...`, which is a real person's name.
|
|
10
|
+
* A collection name carries a customer's product vocabulary. A database URL
|
|
11
|
+
* carries a password. None of those are things anyone intends to send; they
|
|
12
|
+
* arrive by being interpolated into a string that a well-meaning field was
|
|
13
|
+
* happy to accept.
|
|
14
|
+
*
|
|
15
|
+
* So the payload is closed by construction. Adding a field means adding it
|
|
16
|
+
* here, where the review question — "can this ever contain something the user
|
|
17
|
+
* typed?" — is unavoidable.
|
|
18
|
+
*
|
|
19
|
+
* ## What is deliberately absent
|
|
20
|
+
*
|
|
21
|
+
* Project names, directory paths, collection or table names, hostnames,
|
|
22
|
+
* database URLs, error messages, stack traces, email addresses, exact row or
|
|
23
|
+
* user counts. Anything that would let a payload be traced to an organisation
|
|
24
|
+
* rather than to an anonymous id.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Bumped whenever a field is added, removed or changes meaning.
|
|
28
|
+
*
|
|
29
|
+
* Sent with every event so the receiving end can reject or migrate old shapes,
|
|
30
|
+
* and so `rebase telemetry show` can state which contract the user agreed to.
|
|
31
|
+
*/
|
|
32
|
+
export declare const TELEMETRY_SCHEMA_VERSION = 1;
|
|
33
|
+
/** The events the CLI reports. Closed set — a name not listed cannot be sent. */
|
|
34
|
+
export type TelemetryEventName = "cli.init" | "cli.dev" | "cli.deploy" | "cli.schema_generate" | "cli.db_push" | "cli.error";
|
|
35
|
+
/** A single non-free-text value. */
|
|
36
|
+
export type TelemetryValue = string | number | boolean;
|
|
37
|
+
export type TelemetryEvent = {
|
|
38
|
+
schema: number;
|
|
39
|
+
event: TelemetryEventName;
|
|
40
|
+
/** Random per machine — see identity.ts on why it is not derived. */
|
|
41
|
+
machineId: string;
|
|
42
|
+
/** Random per checkout. Absent when the command ran outside a project. */
|
|
43
|
+
projectId?: string;
|
|
44
|
+
/** The CLI's own version, so old releases can be told apart. */
|
|
45
|
+
cliVersion: string;
|
|
46
|
+
/** Coarse platform facts, for the support matrix. */
|
|
47
|
+
nodeMajor: number;
|
|
48
|
+
platform: NodeJS.Platform;
|
|
49
|
+
arch: string;
|
|
50
|
+
/** UTC, second precision. Not a device clock reading anyone can fingerprint. */
|
|
51
|
+
at: string;
|
|
52
|
+
properties: Record<string, TelemetryValue>;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Buckets rather than exact counts.
|
|
56
|
+
*
|
|
57
|
+
* An exact figure is a surprisingly good fingerprint — "this install has 37
|
|
58
|
+
* collections" narrows the field a great deal when combined with a version and
|
|
59
|
+
* a driver. A bucket answers "roughly how big" without doing that.
|
|
60
|
+
*/
|
|
61
|
+
export declare function bucket(value: number): string;
|
|
62
|
+
/** Duration in coarse bands — enough to see "slow", not enough to fingerprint. */
|
|
63
|
+
export declare function durationBucket(ms: number): string;
|
|
64
|
+
/**
|
|
65
|
+
* An error reduced to something safe to transmit.
|
|
66
|
+
*
|
|
67
|
+
* The message and the stack are discarded, always. What survives is the
|
|
68
|
+
* constructor name and, for the errors that carry one, a `code` — both of which
|
|
69
|
+
* come from the program rather than from anything the user typed or named.
|
|
70
|
+
* `EACCES` is useful and safe; "cannot write /Users/francesco/clients/acme" is
|
|
71
|
+
* neither.
|
|
72
|
+
*/
|
|
73
|
+
export declare function errorClass(error: unknown): string;
|
|
74
|
+
export declare function sanitize(properties: Record<string, unknown>): Record<string, TelemetryValue>;
|
|
75
|
+
export declare function buildEvent(event: TelemetryEventName, properties: Record<string, unknown>, identity: {
|
|
76
|
+
machineId: string;
|
|
77
|
+
projectId?: string;
|
|
78
|
+
}): TelemetryEvent;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A repository's own policy on usage sharing.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this is deliberately one-directional
|
|
5
|
+
*
|
|
6
|
+
* `rebase.json` is committed, so whatever it says applies to everyone who
|
|
7
|
+
* clones the repository — including people who have never seen our prompt. That
|
|
8
|
+
* makes it the right place for exactly one of the two answers:
|
|
9
|
+
*
|
|
10
|
+
* - **`false` is honoured**, and beats an individual's opt-in. An organisation
|
|
11
|
+
* restricting its own repository is setting policy for work done on its
|
|
12
|
+
* behalf, which is theirs to set. It is the same shape as a committed
|
|
13
|
+
* `.npmrc`.
|
|
14
|
+
* - **`true` is ignored**, and says so. It would be one developer answering a
|
|
15
|
+
* privacy question for every colleague who later clones the repo — consent
|
|
16
|
+
* by proxy, which is the precise thing opt-in exists to prevent.
|
|
17
|
+
*
|
|
18
|
+
* The asymmetry is the whole feature. A symmetric flag would be a worse version
|
|
19
|
+
* of the machine-level setting, and a quietly-obeyed `true` would be a way to
|
|
20
|
+
* enrol people without asking them.
|
|
21
|
+
*
|
|
22
|
+
* Read straight from the file rather than through `parseManifest`, for two
|
|
23
|
+
* reasons: the parser builds a typed object and drops keys it does not model,
|
|
24
|
+
* and a manifest too malformed to parse must still be able to switch telemetry
|
|
25
|
+
* off. A repository that says no should be obeyed even when it is broken.
|
|
26
|
+
*/
|
|
27
|
+
export type ProjectTelemetryPolicy =
|
|
28
|
+
/** `"telemetry": false` — suppress, regardless of the machine setting. */
|
|
29
|
+
"opt_out"
|
|
30
|
+
/** `"telemetry": true` — refused; the machine setting still decides. */
|
|
31
|
+
| "ignored_opt_in"
|
|
32
|
+
/** No manifest, no key, or an unreadable one. */
|
|
33
|
+
| "unset";
|
|
34
|
+
export declare function readProjectPolicy(startDir?: string): ProjectTelemetryPolicy;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Developer tools for Rebase projects",
|
|
5
5
|
"main": "./dist/index.es.js",
|
|
6
6
|
"module": "./dist/index.es.js",
|
|
@@ -31,20 +31,20 @@
|
|
|
31
31
|
"execa": "^9.6.1",
|
|
32
32
|
"inquirer": "14.0.2",
|
|
33
33
|
"jiti": "^2.7.0",
|
|
34
|
-
"@rebasepro/agent-skills": "0.
|
|
35
|
-
"@rebasepro/client": "0.
|
|
36
|
-
"@rebasepro/
|
|
37
|
-
"@rebasepro/
|
|
38
|
-
"@rebasepro/
|
|
39
|
-
"@rebasepro/server-postgres": "0.
|
|
34
|
+
"@rebasepro/agent-skills": "0.13.0",
|
|
35
|
+
"@rebasepro/client": "0.13.0",
|
|
36
|
+
"@rebasepro/codegen": "0.13.0",
|
|
37
|
+
"@rebasepro/types": "0.13.0",
|
|
38
|
+
"@rebasepro/server": "0.13.0",
|
|
39
|
+
"@rebasepro/server-postgres": "0.13.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@types/node": "^
|
|
42
|
+
"@types/node": "^26.1.2",
|
|
43
43
|
"@types/pg": "^8.20.0",
|
|
44
|
-
"pg": "^8.
|
|
44
|
+
"pg": "^8.22.0",
|
|
45
45
|
"typescript": "^6.0.3",
|
|
46
|
-
"vite": "^8.
|
|
47
|
-
"vitest": "4.1.
|
|
46
|
+
"vite": "^8.1.5",
|
|
47
|
+
"vitest": "4.1.10"
|
|
48
48
|
},
|
|
49
49
|
"files": [
|
|
50
50
|
"bin/",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"@rebasepro/server-postgres": "workspace:*",
|
|
12
12
|
"@rebasepro/types": "workspace:*",
|
|
13
13
|
"drizzle-orm": "^0.45.2",
|
|
14
|
-
"hono": "^4.12.
|
|
15
|
-
"@hono/node-server": "^
|
|
14
|
+
"hono": "^4.12.27",
|
|
15
|
+
"@hono/node-server": "^2.0.12",
|
|
16
16
|
"pg": "^8.11.3",
|
|
17
17
|
"ws": "^8.16.0",
|
|
18
18
|
"dotenv": "^16.0.0",
|
|
@@ -17,12 +17,11 @@
|
|
|
17
17
|
"generate:sdk": "rebase generate-sdk",
|
|
18
18
|
"skills:install": "rebase skills install",
|
|
19
19
|
"example": "tsx scripts/example.ts",
|
|
20
|
-
"deploy": "rebase
|
|
20
|
+
"deploy": "rebase cloud deploy"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@rebasepro/cli": "workspace:*",
|
|
24
24
|
"@rebasepro/types": "workspace:*",
|
|
25
|
-
"concurrently": "^8.2.2",
|
|
26
25
|
"tsx": "^4.20.6",
|
|
27
26
|
"typescript": "^5.9.2"
|
|
28
27
|
},
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"@rebasepro/server-postgres": "workspace:*",
|
|
14
14
|
"@rebasepro/types": "workspace:*",
|
|
15
15
|
"drizzle-orm": "^0.45.2",
|
|
16
|
-
"hono": "^4.12.
|
|
17
|
-
"@hono/node-server": "^
|
|
16
|
+
"hono": "^4.12.27",
|
|
17
|
+
"@hono/node-server": "^2.0.12",
|
|
18
18
|
"pg": "^8.11.3",
|
|
19
19
|
"ws": "^8.16.0",
|
|
20
20
|
"dotenv": "^16.0.0",
|
|
@@ -8,7 +8,15 @@ export const collections = [postsCollection, authorsCollection, tagsCollection,
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Applied to any collection in this directory that declares no
|
|
11
|
-
* `securityRules` of its own:
|
|
11
|
+
* `securityRules` of its own: every signed-in user reads every row, only
|
|
12
|
+
* admins write.
|
|
13
|
+
*
|
|
14
|
+
* `access: "public"` is about ROWS, not about who may call the API — it means
|
|
15
|
+
* "no row filter", not "no login". A request with no token is still answered
|
|
16
|
+
* 401 by the API before RLS is ever consulted. To serve readers who are not
|
|
17
|
+
* signed in (a public website reading this backend), set `AUTH_REQUIRE=false`
|
|
18
|
+
* in the backend's environment; access then rests entirely on these rules,
|
|
19
|
+
* which is what they are for.
|
|
12
20
|
*
|
|
13
21
|
* These live here, next to the collections, because `rebase db push`
|
|
14
22
|
* generates the Postgres policies from these files — that is what actually
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"{{PROJECT_NAME}}-config": "*",
|
|
16
16
|
"react": "^19.0.0",
|
|
17
17
|
"react-dom": "^19.0.0",
|
|
18
|
-
"react-router": "^
|
|
19
|
-
"react-router-dom": "^7.0.0",
|
|
18
|
+
"react-router": "^8.3.0",
|
|
20
19
|
"react-compiler-runtime": "^1.0.0",
|
|
21
|
-
"@fontsource/
|
|
20
|
+
"@fontsource-variable/inter": "^5.3.0",
|
|
21
|
+
"@fontsource-variable/instrument-sans": "^5.3.0"
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"dev": "vite --mode development",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
import "@fontsource/jetbrains-mono";
|
|
4
|
-
import "@fontsource/
|
|
4
|
+
import "@fontsource-variable/inter";
|
|
5
|
+
import "@fontsource-variable/instrument-sans";
|
|
5
6
|
|
|
6
7
|
import { Rebase, RebaseAuth, useRebaseAuthController } from "@rebasepro/app";
|
|
7
8
|
import { RebaseAdmin, RebaseShell } from "@rebasepro/admin";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import ReactDOM from "react-dom/client";
|
|
3
|
-
import { createBrowserRouter
|
|
3
|
+
import { createBrowserRouter } from "react-router";
|
|
4
|
+
import { RouterProvider } from "react-router/dom";
|
|
4
5
|
import { App } from "./App";
|
|
5
6
|
import "./index.css";
|
|
6
7
|
|
|
@@ -20,12 +20,11 @@
|
|
|
20
20
|
"schema:generate": "rebase schema generate --collections ../config/collections",
|
|
21
21
|
"generate:sdk": "rebase generate-sdk",
|
|
22
22
|
"skills:install": "rebase skills install",
|
|
23
|
-
"deploy": "rebase
|
|
23
|
+
"deploy": "rebase cloud deploy"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@rebasepro/cli": "workspace:*",
|
|
27
27
|
"@rebasepro/types": "workspace:*",
|
|
28
|
-
"concurrently": "^8.2.2",
|
|
29
28
|
"typescript": "^5.9.2"
|
|
30
29
|
},
|
|
31
30
|
"engines": {
|