@rebasepro/server 0.16.0 → 0.16.1-canary.g701140a
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/dist/api/contract-routes.d.ts +1 -1
- package/dist/api/errors.d.ts +1 -1
- package/dist/api/index.d.ts +3 -3
- package/dist/api/logs-routes.d.ts +1 -1
- package/dist/api/rest/api-generator.d.ts +2 -2
- package/dist/api/rest/index.d.ts +1 -1
- package/dist/api/rest/query-parser.d.ts +1 -1
- package/dist/api/schema-editor-routes.d.ts +1 -1
- package/dist/api/types.d.ts +3 -4
- package/dist/auth/adapter-middleware.d.ts +2 -2
- package/dist/auth/admin-roles-route.d.ts +2 -2
- package/dist/auth/admin-user-ops.d.ts +3 -3
- package/dist/auth/admin-users-route.d.ts +4 -4
- package/dist/auth/api-keys/api-key-middleware.d.ts +2 -2
- package/dist/auth/api-keys/api-key-permission-guard.d.ts +1 -1
- package/dist/auth/api-keys/api-key-routes.d.ts +2 -2
- package/dist/auth/api-keys/api-key-store.d.ts +1 -1
- package/dist/auth/api-keys/index.d.ts +9 -9
- package/dist/auth/apple-oauth.d.ts +2 -2
- package/dist/auth/auth-hooks.d.ts +3 -3
- package/dist/auth/bitbucket-oauth.d.ts +2 -2
- package/dist/auth/builtin-auth-adapter.d.ts +7 -4
- package/dist/auth/captcha.d.ts +86 -0
- package/dist/auth/cookie-utils.d.ts +2 -2
- package/dist/auth/discord-oauth.d.ts +2 -2
- package/dist/auth/facebook-oauth.d.ts +2 -2
- package/dist/auth/github-oauth.d.ts +2 -2
- package/dist/auth/gitlab-oauth.d.ts +2 -2
- package/dist/auth/google-oauth.d.ts +1 -1
- package/dist/auth/index.d.ts +56 -54
- package/dist/auth/jwks-routes.d.ts +1 -1
- package/dist/auth/jwt.d.ts +1 -1
- package/dist/auth/linkedin-oauth.d.ts +2 -2
- package/dist/auth/magic-link-routes.d.ts +10 -3
- package/dist/auth/mfa-gate.d.ts +1 -1
- package/dist/auth/mfa-routes.d.ts +3 -3
- package/dist/auth/microsoft-oauth.d.ts +2 -2
- package/dist/auth/middleware.d.ts +5 -5
- package/dist/auth/rate-limiter.d.ts +2 -2
- package/dist/auth/require-auth.d.ts +1 -1
- package/dist/auth/reset-password-admin.d.ts +4 -4
- package/dist/auth/routes.d.ts +13 -4
- package/dist/auth/session-routes.d.ts +3 -3
- package/dist/auth/slack-oauth.d.ts +2 -2
- package/dist/auth/spotify-oauth.d.ts +2 -2
- package/dist/auth/token-revocation.d.ts +2 -2
- package/dist/auth/twitter-oauth.d.ts +2 -2
- package/dist/{auth-5Et5mnUA.js → auth-B0IV-irB.js} +250 -15
- package/dist/auth-B0IV-irB.js.map +1 -0
- package/dist/backup/backup-common.d.ts +1 -1
- package/dist/backup/backup-routes.d.ts +3 -3
- package/dist/backup/index.d.ts +3 -3
- package/dist/{backup-C6ljYVTp.js → backup-BJ86ah4T.js} +2 -2
- package/dist/{backup-C6ljYVTp.js.map → backup-BJ86ah4T.js.map} +1 -1
- package/dist/boot/boot.d.ts +5 -5
- package/dist/boot/bundle.d.ts +1 -1
- package/dist/boot/driver.d.ts +1 -1
- package/dist/boot/env.d.ts +13 -1
- package/dist/boot/options.d.ts +30 -6
- package/dist/boot/role.d.ts +3 -2
- package/dist/boot/sources.d.ts +1 -1
- package/dist/collections/BackendCollectionRegistry.d.ts +1 -1
- package/dist/collections/loader.d.ts +1 -1
- package/dist/{contract-routes-DZ-LBpSL.js → contract-routes-BEq7euZg.js} +2 -2
- package/dist/contract-routes-BEq7euZg.js.map +1 -0
- package/dist/cron/cron-routes.d.ts +2 -2
- package/dist/cron/cron-scheduler.d.ts +2 -2
- package/dist/cron/index.d.ts +8 -8
- package/dist/{cron-loader-YhhQeVBM.js → cron-loader-BMvtW6-J.js} +2 -2
- package/dist/{cron-loader-YhhQeVBM.js.map → cron-loader-BMvtW6-J.js.map} +1 -1
- package/dist/{cron-routes-maM_RlUu.js → cron-routes-BvYk-Kmi.js} +2 -2
- package/dist/{cron-routes-maM_RlUu.js.map → cron-routes-BvYk-Kmi.js.map} +1 -1
- package/dist/{cron-scheduler-DIpYBmZP.js → cron-scheduler-Buf-uVam.js} +2 -2
- package/dist/{cron-scheduler-DIpYBmZP.js.map → cron-scheduler-Buf-uVam.js.map} +1 -1
- package/dist/{cron-store-DfH_4Cd9.js → cron-store-CpfttP4f.js} +3 -3
- package/dist/{cron-store-DfH_4Cd9.js.map → cron-store-CpfttP4f.js.map} +1 -1
- package/dist/{ddl-bootstrap-Cywoj8Ta.js → ddl-bootstrap-CFLhcvfQ.js} +2 -2
- package/dist/{ddl-bootstrap-Cywoj8Ta.js.map → ddl-bootstrap-CFLhcvfQ.js.map} +1 -1
- package/dist/dev-secrets.d.ts +52 -0
- package/dist/email/dev-sink.d.ts +67 -0
- package/dist/email/index.d.ts +9 -7
- package/dist/email/link-base.d.ts +1 -1
- package/dist/email/smtp-email-service.d.ts +1 -1
- package/dist/env.d.ts +1 -1
- package/dist/{errors-EBYiaJ2E.js → errors-D_LwNKRM.js} +5 -5
- package/dist/errors-D_LwNKRM.js.map +1 -0
- package/dist/{function-loader-DDS1v7YX.js → function-loader-BrLmC_-y.js} +3 -3
- package/dist/{function-loader-DDS1v7YX.js.map → function-loader-BrLmC_-y.js.map} +1 -1
- package/dist/functions/context.d.ts +141 -0
- package/dist/functions/define-function.d.ts +1 -1
- package/dist/functions/function-routes.d.ts +2 -2
- package/dist/functions/guards.d.ts +76 -0
- package/dist/functions/index.d.ts +96 -5
- package/dist/functions/index.js +919 -0
- package/dist/functions/index.js.map +1 -0
- package/dist/functions/internal.d.ts +26 -0
- package/dist/functions/proxy.d.ts +1 -1
- package/dist/functions/request-timeout.d.ts +9 -1
- package/dist/functions/runtime-env.d.ts +92 -0
- package/dist/functions/wait-until.d.ts +74 -0
- package/dist/history/history-routes.d.ts +2 -2
- package/dist/history/index.d.ts +1 -1
- package/dist/index.d.ts +63 -54
- package/dist/index.es.js +1126 -53
- package/dist/index.es.js.map +1 -1
- package/dist/init/docs.d.ts +1 -1
- package/dist/init/middlewares.d.ts +1 -1
- package/dist/init/shutdown.d.ts +4 -0
- package/dist/init/storage.d.ts +1 -1
- package/dist/init/surfaces.d.ts +10 -0
- package/dist/init.d.ts +72 -18
- package/dist/jobs/index.d.ts +5 -5
- package/dist/{jobs-CyOKXXlu.js → jobs-CSlBZ8dn.js} +3 -3
- package/dist/{jobs-CyOKXXlu.js.map → jobs-CSlBZ8dn.js.map} +1 -1
- package/dist/{jwt-DxH9fLPt.js → jwt-BbJi0TR0.js} +2 -2
- package/dist/{jwt-DxH9fLPt.js.map → jwt-BbJi0TR0.js.map} +1 -1
- package/dist/{logger-DfvF_8r-.js → logger-TdvXIGqR.js} +101 -8
- package/dist/logger-TdvXIGqR.js.map +1 -0
- package/dist/metrics/index.d.ts +1 -1
- package/dist/{proxy-Bj5DVllb.js → proxy-QJKSS-CV.js} +5 -3
- package/dist/{proxy-Bj5DVllb.js.map → proxy-QJKSS-CV.js.map} +1 -1
- package/dist/{request-timeout-BuFoEKwT.js → request-timeout-OofPCHQT.js} +17 -3
- package/dist/request-timeout-OofPCHQT.js.map +1 -0
- package/dist/rls-audit/index.d.ts +111 -0
- package/dist/{schema-editor-routes-CV9k0w3G.js → schema-editor-routes-Cax2XTRj.js} +2 -2
- package/dist/{schema-editor-routes-CV9k0w3G.js.map → schema-editor-routes-Cax2XTRj.js.map} +1 -1
- package/dist/services/webhook-service.d.ts +1 -1
- package/dist/singleton.d.ts +7 -0
- package/dist/storage/GCSStorageController.d.ts +1 -1
- package/dist/storage/LocalStorageController.d.ts +1 -1
- package/dist/storage/S3StorageController.d.ts +1 -1
- package/dist/storage/cache-headers.d.ts +87 -0
- package/dist/storage/index.d.ts +11 -11
- package/dist/storage/policies.d.ts +88 -0
- package/dist/storage/range.d.ts +63 -0
- package/dist/storage/routes.d.ts +3 -3
- package/dist/storage/storage-registry.d.ts +1 -1
- package/dist/storage/tus-handler.d.ts +2 -2
- package/dist/utils/host.d.ts +58 -0
- package/dist/utils/logger.d.ts +0 -15
- package/dist/utils/request-id.d.ts +1 -1
- package/functions/package.json +24 -0
- package/package.json +13 -7
- package/dist/auth-5Et5mnUA.js.map +0 -1
- package/dist/contract-routes-DZ-LBpSL.js.map +0 -1
- package/dist/errors-EBYiaJ2E.js.map +0 -1
- package/dist/logger-DfvF_8r-.js.map +0 -1
- package/dist/request-timeout-BuFoEKwT.js.map +0 -1
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading the request context from inside a custom function.
|
|
3
|
+
*
|
|
4
|
+
* The functions router resolves the caller's identity before any handler runs
|
|
5
|
+
* and leaves the result on the Hono context. Getting it back out used to be the
|
|
6
|
+
* user's problem, and the shape made that worse than it sounds: `HonoEnv`
|
|
7
|
+
* types `user` as `AuthResult`, a union that includes `boolean`, `null` and an
|
|
8
|
+
* index signature, because the same slot is filled by four different middlewares
|
|
9
|
+
* — JWT, service key, API key, and a user-supplied validator that may return
|
|
10
|
+
* `true`. Every example in the documentation therefore opened with
|
|
11
|
+
*
|
|
12
|
+
* const user = c.get("user") as { uid: string; roles?: string[] } | undefined;
|
|
13
|
+
*
|
|
14
|
+
* and an assertion in a security-relevant position is exactly the kind of line
|
|
15
|
+
* that gets copied once and then never re-examined. It is also wrong in one
|
|
16
|
+
* case that occurs in practice: a custom validator returning `true` stores
|
|
17
|
+
* `{ uid: "default", roles: [] }`, which the assertion above types as having a
|
|
18
|
+
* `uid` — true here, but nothing checks it.
|
|
19
|
+
*
|
|
20
|
+
* These accessors do the narrowing once, in the framework, where it can be
|
|
21
|
+
* tested. They are also **runtime-neutral by construction** — no crypto, no
|
|
22
|
+
* token parsing, no I/O, nothing but property reads on an object another
|
|
23
|
+
* middleware already populated. That is what lets them live in
|
|
24
|
+
* `@rebasepro/server/functions` and run unchanged on a host that has no Node
|
|
25
|
+
* built-ins.
|
|
26
|
+
*
|
|
27
|
+
* @module
|
|
28
|
+
*/
|
|
29
|
+
import type { Context } from "hono";
|
|
30
|
+
import type { DataDriver } from "@rebasepro/types";
|
|
31
|
+
import type { HonoEnv } from "../api/types.js";
|
|
32
|
+
import type { ApiKeyMasked } from "../auth/api-keys/api-key-types.js";
|
|
33
|
+
/**
|
|
34
|
+
* The caller, as a custom function sees them.
|
|
35
|
+
*
|
|
36
|
+
* A narrowed view of whatever the auth middleware resolved: `uid` and `roles`
|
|
37
|
+
* are guaranteed, and the index signature keeps any extra claims the token or
|
|
38
|
+
* the adapter carried (`email`, `org_id`, anything a custom validator added)
|
|
39
|
+
* reachable without a cast.
|
|
40
|
+
*/
|
|
41
|
+
export interface FunctionUser {
|
|
42
|
+
/** Stable id of the caller. `"service"` for service-key and API-key callers. */
|
|
43
|
+
uid: string;
|
|
44
|
+
/** Roles as resolved for this request. Never `undefined` — an empty array instead. */
|
|
45
|
+
roles: string[];
|
|
46
|
+
/** Present when the identity carried one. Not every auth method does. */
|
|
47
|
+
email?: string;
|
|
48
|
+
/** Any further claim the token, adapter or validator supplied. */
|
|
49
|
+
[claim: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
/** Anything with a Hono-style `.get`, so these work on any `Context` shape. */
|
|
52
|
+
type CtxLike = Context<HonoEnv> | Context;
|
|
53
|
+
/**
|
|
54
|
+
* The authenticated caller, or `undefined` for an anonymous request.
|
|
55
|
+
*
|
|
56
|
+
* **`undefined` is not a permission decision.** The functions router mounts its
|
|
57
|
+
* auth middleware with `requireAuth: false` on purpose — a webhook receiver has
|
|
58
|
+
* no token to send — so an anonymous caller reaches the handler and reads
|
|
59
|
+
* `undefined` here while the handler runs on regardless. Use {@link requireAuth}
|
|
60
|
+
* (or a `!user` branch that returns 401) to make it a decision.
|
|
61
|
+
*
|
|
62
|
+
* A caller who presented a *bad* token never gets this far: both auth
|
|
63
|
+
* middlewares reject an unverifiable token with 401 before the router is
|
|
64
|
+
* reached, precisely so an expired session cannot be silently downgraded to an
|
|
65
|
+
* anonymous one.
|
|
66
|
+
*/
|
|
67
|
+
export declare function getUser(c: CtxLike): FunctionUser | undefined;
|
|
68
|
+
/** The caller's id, or `undefined` when nobody is signed in. */
|
|
69
|
+
export declare function getUserId(c: CtxLike): string | undefined;
|
|
70
|
+
/** The caller's roles. Empty for an anonymous request — never `undefined`. */
|
|
71
|
+
export declare function getRoles(c: CtxLike): string[];
|
|
72
|
+
/**
|
|
73
|
+
* Whether the caller holds **any** of the named roles.
|
|
74
|
+
*
|
|
75
|
+
* Any rather than all, because that is what a route guard means by a list of
|
|
76
|
+
* roles; require several by calling this more than once.
|
|
77
|
+
*/
|
|
78
|
+
export declare function hasRole(c: CtxLike, ...roles: string[]): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Whether the caller holds an administrative role.
|
|
81
|
+
*
|
|
82
|
+
* Delegates to the single definition in `auth/admin-roles.ts` — which is
|
|
83
|
+
* `admin` **or** `schema-admin` — rather than comparing against `"admin"`.
|
|
84
|
+
* Those two lists disagreed once, and the gap made every public registrant an
|
|
85
|
+
* administrator; see that file.
|
|
86
|
+
*/
|
|
87
|
+
export declare function isAdmin(c: CtxLike): boolean;
|
|
88
|
+
/** Whether the request carries an identity at all. */
|
|
89
|
+
export declare function isAuthenticated(c: CtxLike): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* The request-scoped data driver: reads and writes run as **the caller**, with
|
|
92
|
+
* your row-level security policies evaluated against their identity.
|
|
93
|
+
*
|
|
94
|
+
* This is the accessor to reach for when a function serves user-facing data.
|
|
95
|
+
* `rebase.dataAsAdmin` is the other one, and it is not the same thing — it runs
|
|
96
|
+
* as `{ uid: "service", roles: ["admin"] }` for every caller alike, which is
|
|
97
|
+
* correct for trusted background work and wrong for a request.
|
|
98
|
+
*
|
|
99
|
+
* `undefined` only when no Rebase auth middleware ran (see
|
|
100
|
+
* {@link identityResolved}); inside a function mounted by the framework it is
|
|
101
|
+
* always present, anonymous requests included — they get an anon-scoped driver
|
|
102
|
+
* so policies still have an identity to evaluate.
|
|
103
|
+
*/
|
|
104
|
+
export declare function getDriver(c: CtxLike): DataDriver | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* {@link getDriver}, but throws instead of handing back `undefined`.
|
|
107
|
+
*
|
|
108
|
+
* For the common case where a handler cannot proceed without it and would
|
|
109
|
+
* otherwise write `c.get("driver")!` — an assertion that turns a wiring problem
|
|
110
|
+
* into `Cannot read properties of undefined (reading 'fetchCollection')` twenty
|
|
111
|
+
* lines away from the cause.
|
|
112
|
+
*/
|
|
113
|
+
export declare function requireDriver(c: CtxLike): DataDriver;
|
|
114
|
+
/**
|
|
115
|
+
* The API key this request authenticated with, masked, or `undefined` when it
|
|
116
|
+
* did not use one.
|
|
117
|
+
*
|
|
118
|
+
* Useful for attribution and for per-key behaviour. The permission check itself
|
|
119
|
+
* has already happened — reaching a handler means the key was allowed to.
|
|
120
|
+
*/
|
|
121
|
+
export declare function getApiKey(c: CtxLike): ApiKeyMasked | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* The correlation id for this request — generated, or taken from an inbound
|
|
124
|
+
* `X-Request-ID`.
|
|
125
|
+
*
|
|
126
|
+
* Log it. It is the only thing that ties a line written inside a function to
|
|
127
|
+
* the framework's own lines for the same request.
|
|
128
|
+
*/
|
|
129
|
+
export declare function getRequestId(c: CtxLike): string | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* Whether a Rebase auth middleware has run on this request.
|
|
132
|
+
*
|
|
133
|
+
* Both middlewares populate `driver` for *every* outcome, anonymous included,
|
|
134
|
+
* and populate `user` whenever there is one. So "neither is set" does not mean
|
|
135
|
+
* "anonymous" — it means nothing resolved the identity, and treating that as
|
|
136
|
+
* anonymous is the dangerous reading. The guards use this to tell a genuinely
|
|
137
|
+
* anonymous caller (401) from a misconfigured mount (500), because answering
|
|
138
|
+
* 401 to the second sends whoever is debugging it to look at the token.
|
|
139
|
+
*/
|
|
140
|
+
export declare function identityResolved(c: CtxLike): boolean;
|
|
141
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import type { RebaseServerClient } from "@rebasepro/types";
|
|
3
|
-
import type { HonoEnv } from "../api/types";
|
|
3
|
+
import type { HonoEnv } from "../api/types.js";
|
|
4
4
|
/**
|
|
5
5
|
* Typed context injected into a function authored with {@link defineFunction}.
|
|
6
6
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import { HonoEnv } from "../api/types";
|
|
3
|
-
import { LoadedFunction } from "./function-loader";
|
|
2
|
+
import { HonoEnv } from "../api/types.js";
|
|
3
|
+
import { LoadedFunction } from "./function-loader.js";
|
|
4
4
|
/**
|
|
5
5
|
* Mount all loaded function routes under a single Hono router.
|
|
6
6
|
*
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route guards for custom functions.
|
|
3
|
+
*
|
|
4
|
+
* These decide access from the identity the platform already resolved. They do
|
|
5
|
+
* **not** verify tokens, and that division is the point rather than a
|
|
6
|
+
* limitation:
|
|
7
|
+
*
|
|
8
|
+
* - Verifying a token needs a signing key, constant-time comparison and a
|
|
9
|
+
* revocation lookup. That is host work, it belongs to the process that holds
|
|
10
|
+
* the secret, and it is the part of the stack that cannot be made
|
|
11
|
+
* runtime-neutral without rewriting it against WebCrypto.
|
|
12
|
+
* - Deciding whether *this* caller may call *this* route is application work.
|
|
13
|
+
* It needs nothing but the resolved identity, so it costs nothing to make it
|
|
14
|
+
* portable — and it is the half that lives in user code.
|
|
15
|
+
*
|
|
16
|
+
* Splitting there is what lets a function file compile and run unchanged on a
|
|
17
|
+
* host with no Node built-ins, and it is why these live in
|
|
18
|
+
* `@rebasepro/server/functions` while `verifyAccessToken` does not.
|
|
19
|
+
*
|
|
20
|
+
* **Inside the functions router these are equivalent to the guards exported
|
|
21
|
+
* from the package root.** Both auth middlewares resolve the identity before
|
|
22
|
+
* any handler runs: a valid credential populates `user`, an invalid one is
|
|
23
|
+
* rejected with 401 by the middleware itself, and a missing one leaves `user`
|
|
24
|
+
* unset. So the root `requireAuth`'s token-parsing branch is unreachable from a
|
|
25
|
+
* function, and removing it changes no outcome. The one difference is a handler
|
|
26
|
+
* mounted **outside** the framework's router, where no middleware ran: the root
|
|
27
|
+
* guard would parse the `Authorization` header itself, and these refuse the
|
|
28
|
+
* request with a 500 that names the wiring problem. Fail-closed, and legible.
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
32
|
+
import type { MiddlewareHandler } from "hono";
|
|
33
|
+
import type { HonoEnv } from "../api/types.js";
|
|
34
|
+
/**
|
|
35
|
+
* Reject anonymous callers with 401.
|
|
36
|
+
*
|
|
37
|
+
* Put it in the route's own middleware slot rather than `app.use("/*", …)`:
|
|
38
|
+
* `use()` covers only the routes declared *below* it, so a route appended later
|
|
39
|
+
* — by you, months from now, at the bottom of the file — is silently
|
|
40
|
+
* unprotected. The per-route form cannot drift that way.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* app.post("/", requireAuth, async (c) => {
|
|
45
|
+
* const user = getUser(c)!; // guaranteed by the guard
|
|
46
|
+
* return c.json({ uid: user.uid });
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare const requireAuth: MiddlewareHandler<HonoEnv>;
|
|
51
|
+
/**
|
|
52
|
+
* Reject callers without an administrative role with 403.
|
|
53
|
+
*
|
|
54
|
+
* Must come **after** {@link requireAuth}: on its own it answers 401 for an
|
|
55
|
+
* anonymous caller, which is right, but pairing them keeps the two failures
|
|
56
|
+
* distinguishable — 401 "who are you", 403 "not you".
|
|
57
|
+
*
|
|
58
|
+
* Administrative means `admin` or `schema-admin`, from the single list in
|
|
59
|
+
* `auth/admin-roles.ts`. Do not compare against `"admin"` by hand; that is the
|
|
60
|
+
* divergence that list exists to prevent.
|
|
61
|
+
*/
|
|
62
|
+
export declare const requireAdmin: MiddlewareHandler<HonoEnv>;
|
|
63
|
+
/**
|
|
64
|
+
* Reject callers holding none of the named roles with 403.
|
|
65
|
+
*
|
|
66
|
+
* Any of them, not all — require several by chaining the guard twice. Naming no
|
|
67
|
+
* role at all is a programming error and throws at module load rather than at
|
|
68
|
+
* request time, because `requireRole()` with an empty list would otherwise read
|
|
69
|
+
* as a guard while admitting everyone.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* app.post("/publish", requireAuth, requireRole("editor", "admin"), handler);
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function requireRole(...roles: string[]): MiddlewareHandler<HonoEnv>;
|
|
@@ -1,5 +1,96 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `@rebasepro/server/functions` — the portable authoring surface.
|
|
3
|
+
*
|
|
4
|
+
* Everything a custom function needs, and nothing that ties it to one runtime.
|
|
5
|
+
* Import from here rather than from `@rebasepro/server`:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { defineFunction, requireAuth, getUser, rebase } from "@rebasepro/server/functions";
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* ## Why this entry point exists
|
|
12
|
+
*
|
|
13
|
+
* `@rebasepro/server` is a single barrel over the whole framework: the boot
|
|
14
|
+
* sequence, the collection loader, the backup routes, the SPA server, the
|
|
15
|
+
* WebSocket layer. Importing one name from it pulls `@hono/node-server`, `ws`,
|
|
16
|
+
* `jsonwebtoken`, Drizzle and a dozen modules that open files. On Node that
|
|
17
|
+
* costs a little start-up time and nothing else, which is why it stood for as
|
|
18
|
+
* long as it did. On a host without Node built-ins it does not resolve at all —
|
|
19
|
+
* so with only that entry point, *no* custom function could ever run anywhere
|
|
20
|
+
* but Node, no matter how portable the function's own code was.
|
|
21
|
+
*
|
|
22
|
+
* That is not a limitation you can lift later. `import { defineFunction } from
|
|
23
|
+
* "@rebasepro/server"` is the line in every function file, every template and
|
|
24
|
+
* every documentation page; changing it afterwards is a breaking change for
|
|
25
|
+
* everyone who has written one. The entry point has to exist before the code
|
|
26
|
+
* that would depend on it does.
|
|
27
|
+
*
|
|
28
|
+
* ## What "portable" means here, precisely
|
|
29
|
+
*
|
|
30
|
+
* Every module reachable from this file:
|
|
31
|
+
*
|
|
32
|
+
* - imports no Node built-in, directly or transitively;
|
|
33
|
+
* - imports no package that needs one (`@hono/node-server`, `ws`,
|
|
34
|
+
* `jsonwebtoken`, `drizzle-orm`, `pg`, …);
|
|
35
|
+
* - touches no host global — `process`, `Buffer`, `__dirname` — at module
|
|
36
|
+
* scope, so the module *evaluates* on a runtime that has none.
|
|
37
|
+
*
|
|
38
|
+
* `portability.test.ts` walks this graph on every run and fails naming the
|
|
39
|
+
* import chain that broke it. The rule is not a convention; it is a test.
|
|
40
|
+
*
|
|
41
|
+
* ## What is deliberately not here
|
|
42
|
+
*
|
|
43
|
+
* - **`rebase.sql()`** — reachable through `rebase`, and Node-only in practice:
|
|
44
|
+
* it runs on the database owner connection over a TCP socket. It is left on
|
|
45
|
+
* the object rather than hidden because there is nothing wrong with using it
|
|
46
|
+
* on a Node deployment; see its docblock, and `runtimeKey()` if a function
|
|
47
|
+
* needs to degrade rather than fail.
|
|
48
|
+
* - **Token verification.** Deciding whether a caller is who they say needs the
|
|
49
|
+
* signing key and belongs to the host; deciding whether *this* caller may
|
|
50
|
+
* call *this* route needs only the resolved identity and belongs here. That
|
|
51
|
+
* is why `requireAuth` below carries no crypto — see `./guards.ts`.
|
|
52
|
+
* - **The loader, the router, the proxy, the timeout middleware.** Host
|
|
53
|
+
* machinery. It lives in `./internal.ts`.
|
|
54
|
+
*
|
|
55
|
+
* @module
|
|
56
|
+
*/
|
|
57
|
+
export { defineFunction } from "./define-function.js";
|
|
58
|
+
export type { RebaseFunctionContext } from "./define-function.js";
|
|
59
|
+
/**
|
|
60
|
+
* The app-scoped Rebase client: `dataAsAdmin`, `auth`, `storage`, `email`,
|
|
61
|
+
* `sql`.
|
|
62
|
+
*
|
|
63
|
+
* Re-exported here — the same object the package root exports, not a copy —
|
|
64
|
+
* because it is the one piece of the framework a function reaches for at
|
|
65
|
+
* runtime, and requiring a second import from the Node-only barrel to get it
|
|
66
|
+
* would defeat the entry point.
|
|
67
|
+
*
|
|
68
|
+
* It is safe to hold at module scope, unlike a configuration value, because it
|
|
69
|
+
* is a lazy Proxy: nothing is resolved until a property is read, which happens
|
|
70
|
+
* inside a request. That indirection is also the whole of what a future
|
|
71
|
+
* isolate-based host has to hook — see `_setRebaseResolver` in
|
|
72
|
+
* `../singleton.ts`.
|
|
73
|
+
*/
|
|
74
|
+
export { rebase } from "../singleton.js";
|
|
75
|
+
export { getUser, getUserId, getRoles, hasRole, isAdmin, isAuthenticated, getDriver, requireDriver, getApiKey, getRequestId, identityResolved } from "./context.js";
|
|
76
|
+
export type { FunctionUser } from "./context.js";
|
|
77
|
+
export { requireAuth, requireAdmin, requireRole } from "./guards.js";
|
|
78
|
+
export { getEnv, env, requireEnv, runtimeKey, isNodeRuntime, lazyResource } from "./runtime-env.js";
|
|
79
|
+
export { waitUntil } from "./wait-until.js";
|
|
80
|
+
/**
|
|
81
|
+
* The Hono environment a Rebase function runs in: `c.get("user")`,
|
|
82
|
+
* `c.get("driver")`, `c.get("apiKey")` and `c.get("requestId")` are typed
|
|
83
|
+
* through it.
|
|
84
|
+
*
|
|
85
|
+
* `defineFunction` applies it for you. Declare it explicitly only when building
|
|
86
|
+
* the Hono app by hand: `new Hono<HonoEnv>()`.
|
|
87
|
+
*/
|
|
88
|
+
export type { HonoEnv, ApiResponse } from "../api/types.js";
|
|
89
|
+
/**
|
|
90
|
+
* Throw this to answer with a specific status.
|
|
91
|
+
*
|
|
92
|
+
* The functions router installs the framework's error handler, so an `ApiError`
|
|
93
|
+
* thrown anywhere inside a handler becomes the status and body it names,
|
|
94
|
+
* whereas any other throw becomes a 500 with its detail withheld.
|
|
95
|
+
*/
|
|
96
|
+
export { ApiError } from "../api/errors.js";
|