@rebasepro/server 0.16.0 → 0.16.1-canary.g0d7af95
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/{GCSStorageController-BEmDYFKc.js → GCSStorageController-Bl7nmhdv.js} +7 -6
- package/dist/{GCSStorageController-BEmDYFKc.js.map → GCSStorageController-Bl7nmhdv.js.map} +1 -1
- package/dist/{S3StorageController-B2EDXXMH.js → S3StorageController-CWvvrRpF.js} +7 -6
- package/dist/{S3StorageController-B2EDXXMH.js.map → S3StorageController-CWvvrRpF.js.map} +1 -1
- package/dist/{admin_block-DLILvzle.js → admin_block-BeypnEfb.js} +6 -6
- package/dist/admin_block-BeypnEfb.js.map +1 -0
- package/dist/api/ast-schema-editor.d.ts +23 -0
- 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/live-schema-routes.d.ts +122 -0
- package/dist/api/logs-routes.d.ts +1 -1
- package/dist/api/mount.d.ts +41 -0
- 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 +12 -4
- package/dist/{schema-editor-routes-CV9k0w3G.js → ast-schema-editor-BrarYZCq.js} +37 -45
- package/dist/ast-schema-editor-BrarYZCq.js.map +1 -0
- 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 -6
- 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 +4 -4
- package/dist/auth/bitbucket-oauth.d.ts +2 -2
- package/dist/auth/builtin-auth-adapter.d.ts +8 -4
- package/dist/auth/capabilities.d.ts +51 -0
- 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 +58 -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 +6 -7
- package/dist/auth/otp-routes.d.ts +89 -0
- 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 +18 -10
- 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-DU-nUjPp.js} +604 -4376
- package/dist/auth-DU-nUjPp.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-CRdZkA6c.js} +7 -6
- package/dist/{backup-C6ljYVTp.js.map → backup-CRdZkA6c.js.map} +1 -1
- package/dist/boot/boot.d.ts +5 -5
- package/dist/boot/bundle.d.ts +10 -1
- package/dist/boot/driver.d.ts +1 -1
- package/dist/boot/env.d.ts +28 -1
- package/dist/boot/fetch-bundle.d.ts +144 -1
- package/dist/boot/options.d.ts +30 -6
- package/dist/boot/resource-adapters.d.ts +31 -0
- package/dist/boot/resource-loading.d.ts +10 -0
- package/dist/boot/role.d.ts +3 -2
- package/dist/boot/sources.d.ts +8 -2
- package/dist/boot/version-skew.d.ts +1 -1
- package/dist/collections/BackendCollectionRegistry.d.ts +1 -1
- package/dist/collections/loader.d.ts +1 -1
- package/dist/collections/validate-config.d.ts +13 -0
- package/dist/{contract-routes-DZ-LBpSL.js → contract-routes-D8TvxPLo.js} +8 -7
- package/dist/contract-routes-D8TvxPLo.js.map +1 -0
- package/dist/cron/cron-routes.d.ts +2 -2
- package/dist/cron/cron-scheduler.d.ts +3 -3
- package/dist/cron/index.d.ts +8 -8
- package/dist/{cron-loader-YhhQeVBM.js → cron-loader-d9WMFENB.js} +8 -7
- package/dist/{cron-loader-YhhQeVBM.js.map → cron-loader-d9WMFENB.js.map} +1 -1
- package/dist/{cron-routes-maM_RlUu.js → cron-routes-BsukhMGm.js} +9 -8
- package/dist/cron-routes-BsukhMGm.js.map +1 -0
- package/dist/{cron-scheduler-DIpYBmZP.js → cron-scheduler-BB82dWuU.js} +9 -9
- package/dist/cron-scheduler-BB82dWuU.js.map +1 -0
- package/dist/{cron-store-DfH_4Cd9.js → cron-store-CbFfQhbg.js} +11 -9
- package/dist/{cron-store-DfH_4Cd9.js.map → cron-store-CbFfQhbg.js.map} +1 -1
- package/dist/ddl-bootstrap-5YZCZ8qk.js +146 -0
- package/dist/ddl-bootstrap-5YZCZ8qk.js.map +1 -0
- package/dist/deploy/pod-contract.d.ts +139 -0
- package/dist/dev-secrets.d.ts +52 -0
- package/dist/{dynamic-import-Dvh-K5fl.js → dynamic-import-X40pTZUQ.js} +5 -4
- package/dist/{dynamic-import-Dvh-K5fl.js.map → dynamic-import-X40pTZUQ.js.map} +1 -1
- package/dist/email/dev-sink.d.ts +88 -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 +2 -2
- package/dist/email/templates.d.ts +12 -0
- package/dist/email/types.d.ts +18 -6
- package/dist/env.d.ts +1 -1
- package/dist/{errors-EBYiaJ2E.js → errors-DBwpj9N8.js} +8 -7
- package/dist/errors-DBwpj9N8.js.map +1 -0
- package/dist/{function-loader-DDS1v7YX.js → function-loader-LLdmBFoL.js} +9 -8
- package/dist/{function-loader-DDS1v7YX.js.map → function-loader-LLdmBFoL.js.map} +1 -1
- package/dist/{function-routes-Btcez1T-.js → function-routes-ClT6UQpD.js} +8 -7
- package/dist/function-routes-ClT6UQpD.js.map +1 -0
- package/dist/functions/context.d.ts +141 -0
- package/dist/functions/define-function.d.ts +1 -1
- package/dist/functions/function-routes.d.ts +9 -3
- 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/history-recorder-B67maiTi.js +76 -0
- package/dist/history-recorder-B67maiTi.js.map +1 -0
- package/dist/history-store-oiqhb3HU.js +210 -0
- package/dist/history-store-oiqhb3HU.js.map +1 -0
- package/dist/index.d.ts +65 -54
- package/dist/index.es.js +3667 -328
- 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 +179 -22
- package/dist/internal-tables-DpxfPaEB.js +97 -0
- package/dist/internal-tables-DpxfPaEB.js.map +1 -0
- package/dist/jobs/index.d.ts +5 -5
- package/dist/{jobs-CyOKXXlu.js → jobs-B2ELModo.js} +11 -9
- package/dist/{jobs-CyOKXXlu.js.map → jobs-B2ELModo.js.map} +1 -1
- package/dist/{jwt-DxH9fLPt.js → jwt-DoHkMMWF.js} +9 -8
- package/dist/jwt-DoHkMMWF.js.map +1 -0
- package/dist/{logger-DfvF_8r-.js → logger-DS03e908.js} +104 -10
- package/dist/logger-DS03e908.js.map +1 -0
- package/dist/{logs-routes-CWBLQj2l.js → logs-routes-DB72iQSr.js} +36 -9
- package/dist/logs-routes-DB72iQSr.js.map +1 -0
- package/dist/metrics/history-recorder.d.ts +18 -0
- package/dist/metrics/history-store.d.ts +123 -0
- package/dist/metrics/index.d.ts +10 -2
- package/dist/{openapi-generator-BCKJRUS4.js → openapi-generator-FFGT0H6O.js} +7 -11
- package/dist/{openapi-generator-BCKJRUS4.js.map → openapi-generator-FFGT0H6O.js.map} +1 -1
- package/dist/{proxy-Bj5DVllb.js → proxy-CMymhnwG.js} +9 -6
- package/dist/{proxy-Bj5DVllb.js.map → proxy-CMymhnwG.js.map} +1 -1
- package/dist/query-parser--nstjRCh.js +355 -0
- package/dist/query-parser--nstjRCh.js.map +1 -0
- package/dist/{request-timeout-BuFoEKwT.js → request-timeout-C8gkc-j7.js} +21 -6
- package/dist/request-timeout-C8gkc-j7.js.map +1 -0
- package/dist/rls-audit/index.d.ts +111 -0
- package/dist/{rolldown-runtime-DSJWtz9O.js → rolldown-runtime-dW7B1o5h.js} +4 -3
- package/dist/schema-edit/apply-schema-change.d.ts +141 -0
- package/dist/schema-edit/github-repository.d.ts +67 -0
- package/dist/schema-edit/local-git-repository.d.ts +28 -0
- package/dist/schema-edit/project-root.d.ts +43 -0
- package/dist/schema-edit/remote-source.d.ts +25 -0
- package/dist/schema-edit/schema-edit-permissions.d.ts +129 -0
- package/dist/schema-editor-routes-Bf5h5Emf.js +87 -0
- package/dist/schema-editor-routes-Bf5h5Emf.js.map +1 -0
- package/dist/schemas-DBxgjM9A.js +4153 -0
- package/dist/schemas-DBxgjM9A.js.map +1 -0
- package/dist/{selection-_z6TM1DB.js → selection-CRpqKUbt.js} +6 -5
- package/dist/{selection-_z6TM1DB.js.map → selection-CRpqKUbt.js.map} +1 -1
- package/dist/services/webhook-service.d.ts +1 -1
- package/dist/singleton.d.ts +7 -0
- package/dist/{src-BPfYOeN4.js → src-B-CmIFMr.js} +8 -6
- package/dist/src-B-CmIFMr.js.map +1 -0
- package/dist/{src-CrCxd8km.js → src-Cdsw7DqV.js} +126 -5
- package/dist/src-Cdsw7DqV.js.map +1 -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/path-pattern.d.ts +58 -0
- package/dist/storage/policies.d.ts +88 -0
- package/dist/storage/range.d.ts +63 -0
- package/dist/storage/rendition-cache.d.ts +45 -0
- package/dist/storage/routes.d.ts +17 -5
- package/dist/storage/storage-registry.d.ts +1 -1
- package/dist/storage/triggers.d.ts +66 -0
- package/dist/storage/tus-handler.d.ts +34 -3
- package/dist/topics/runtime.d.ts +68 -0
- package/dist/{types-DSnOC4mF.js → types-BfKcm9do.js} +5 -4
- package/dist/{types-DSnOC4mF.js.map → types-BfKcm9do.js.map} +1 -1
- 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/admin_block-DLILvzle.js.map +0 -1
- package/dist/auth-5Et5mnUA.js.map +0 -1
- package/dist/contract-routes-DZ-LBpSL.js.map +0 -1
- package/dist/cron-routes-maM_RlUu.js.map +0 -1
- package/dist/cron-scheduler-DIpYBmZP.js.map +0 -1
- package/dist/ddl-bootstrap-Cywoj8Ta.js +0 -221
- package/dist/ddl-bootstrap-Cywoj8Ta.js.map +0 -1
- package/dist/errors-EBYiaJ2E.js.map +0 -1
- package/dist/function-routes-Btcez1T-.js.map +0 -1
- package/dist/jwt-DxH9fLPt.js.map +0 -1
- package/dist/logger-DfvF_8r-.js.map +0 -1
- package/dist/logs-routes-CWBLQj2l.js.map +0 -1
- package/dist/request-timeout-BuFoEKwT.js.map +0 -1
- package/dist/schema-editor-routes-CV9k0w3G.js.map +0 -1
- package/dist/src-BPfYOeN4.js.map +0 -1
- package/dist/src-CrCxd8km.js.map +0 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarative access control for storage.
|
|
3
|
+
*
|
|
4
|
+
* Storage is not under row-level security, so `storageAuthorize` — a hook, a
|
|
5
|
+
* piece of imperative code — was the whole access-control model. That is the one
|
|
6
|
+
* place the claim "security lives in the database" does not hold, and it shows
|
|
7
|
+
* in the shape of the alternative: without a hook, **any authenticated caller
|
|
8
|
+
* may read, overwrite, delete or list any key they can name**, because storage
|
|
9
|
+
* keys share one flat namespace.
|
|
10
|
+
*
|
|
11
|
+
* A policy list says the same things declaratively, and can be read without
|
|
12
|
+
* running it:
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* storagePolicies: [
|
|
16
|
+
* { path: "public/**", operations: ["read"], allow: "public" },
|
|
17
|
+
* { path: "users/:uid/**", allow: ({ params, user }) => user?.uid === params.uid }
|
|
18
|
+
* ]
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* ## Deny by default, and why that is the whole design
|
|
22
|
+
*
|
|
23
|
+
* A key matched by no policy is refused. That makes every widening an explicit,
|
|
24
|
+
* reviewable line, and it makes a mistake in this module fail *closed* — a
|
|
25
|
+
* pattern that fails to match denies access rather than granting it. Authz code
|
|
26
|
+
* that fails open is worth more to an attacker than the feature is to anyone
|
|
27
|
+
* else, so the bias is deliberate and absolute.
|
|
28
|
+
*
|
|
29
|
+
* ## The hook remains, as an escape hatch and not as a fallback
|
|
30
|
+
*
|
|
31
|
+
* Ownership frequently lives in a row rather than in a key, which no pattern can
|
|
32
|
+
* express. So when policies match nothing, an explicit `storageAuthorize` is
|
|
33
|
+
* consulted before the request is refused. Present, it can widen; absent, the
|
|
34
|
+
* answer is no. Policies never *narrow* what the hook allowed and the hook never
|
|
35
|
+
* overrides a policy denial — each can only say yes, which keeps "who allowed
|
|
36
|
+
* this?" answerable by reading either one alone.
|
|
37
|
+
*/
|
|
38
|
+
import type { StorageAuthorize, StorageAuthorizeContext, StorageOperation } from "@rebasepro/types";
|
|
39
|
+
/** Everything a predicate is told, plus whatever the path captured. */
|
|
40
|
+
export interface StoragePolicyContext extends StorageAuthorizeContext {
|
|
41
|
+
/** Segments captured by `:name` placeholders in the matched path. */
|
|
42
|
+
params: Record<string, string>;
|
|
43
|
+
}
|
|
44
|
+
export type StoragePolicyPredicate = (ctx: StoragePolicyContext) => boolean | Promise<boolean>;
|
|
45
|
+
export interface StoragePolicy {
|
|
46
|
+
/**
|
|
47
|
+
* A key pattern, matched segment by segment against the sanitized key.
|
|
48
|
+
*
|
|
49
|
+
* - a literal segment matches itself
|
|
50
|
+
* - `*` matches exactly one segment
|
|
51
|
+
* - `:name` matches one segment and captures it
|
|
52
|
+
* - `**` matches the rest of the key, including nothing, and is only
|
|
53
|
+
* allowed as the final segment
|
|
54
|
+
*/
|
|
55
|
+
path: string;
|
|
56
|
+
/** Which operations this grants. Defaults to every one of them. */
|
|
57
|
+
operations?: StorageOperation[];
|
|
58
|
+
/**
|
|
59
|
+
* Who it grants to.
|
|
60
|
+
*
|
|
61
|
+
* - `"public"` — anyone, signed in or not
|
|
62
|
+
* - `"authenticated"` — any caller with a uid
|
|
63
|
+
* - a predicate — anything else, given the captured params and the user
|
|
64
|
+
*/
|
|
65
|
+
allow: "public" | "authenticated" | StoragePolicyPredicate;
|
|
66
|
+
}
|
|
67
|
+
export declare class StoragePolicyError extends Error {
|
|
68
|
+
constructor(message: string);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Compile a policy list into a {@link StorageAuthorize}.
|
|
72
|
+
*
|
|
73
|
+
* Compiled once, at boot, so a malformed pattern fails the start rather than the
|
|
74
|
+
* first upload. `fallback` is an explicit `storageAuthorize`, consulted only
|
|
75
|
+
* when no policy matched.
|
|
76
|
+
*/
|
|
77
|
+
export declare function compileStoragePolicies(policies: StoragePolicy[], fallback?: StorageAuthorize): StorageAuthorize;
|
|
78
|
+
/**
|
|
79
|
+
* The access-control function for a configuration, or `undefined` when it
|
|
80
|
+
* declares none.
|
|
81
|
+
*
|
|
82
|
+
* Kept separate from {@link compileStoragePolicies} so `init` has one call to
|
|
83
|
+
* make and one thing to reason about: policies, a hook, both, or neither.
|
|
84
|
+
*/
|
|
85
|
+
export declare function resolveStorageAccessControl(config: {
|
|
86
|
+
storagePolicies?: StoragePolicy[];
|
|
87
|
+
storageAuthorize?: StorageAuthorize;
|
|
88
|
+
}): StorageAuthorize | undefined;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte-range requests for served objects.
|
|
3
|
+
*
|
|
4
|
+
* Without `Accept-Ranges`, a browser will not offer to seek in an audio or
|
|
5
|
+
* video element served from here: it has no way to ask for the middle of a file,
|
|
6
|
+
* so scrubbing means fetching the whole thing from the start, and on a long
|
|
7
|
+
* recording it means fetching it again for every seek. Safari goes further and
|
|
8
|
+
* refuses to play a `<video>` at all unless the first response is a `206`.
|
|
9
|
+
*
|
|
10
|
+
* So this is not a performance nicety. For media it is the difference between a
|
|
11
|
+
* player that works and one that does not.
|
|
12
|
+
*
|
|
13
|
+
* ## What is implemented, and what is refused
|
|
14
|
+
*
|
|
15
|
+
* A single range — `bytes=0-499`, `bytes=500-`, `bytes=-500`. That is what every
|
|
16
|
+
* browser sends for media playback.
|
|
17
|
+
*
|
|
18
|
+
* Multiple ranges in one request (`bytes=0-99,200-299`) are **not** served.
|
|
19
|
+
* Answering them means composing a `multipart/byteranges` body, and nothing that
|
|
20
|
+
* matters sends them; a server may always answer a range request with the whole
|
|
21
|
+
* `200` instead, which is what happens here. Refusing to guess is better than a
|
|
22
|
+
* half-implemented multipart encoder.
|
|
23
|
+
*
|
|
24
|
+
* An unsatisfiable range — one starting past the end of the object — is a `416`
|
|
25
|
+
* with a `Content-Range: bytes /<size>`, as RFC 9110 requires. Answering `200`
|
|
26
|
+
* there would hand a player the whole file when it asked for a byte that does
|
|
27
|
+
* not exist, and it would never notice.
|
|
28
|
+
*/
|
|
29
|
+
/** A resolved, inclusive byte range within an object of known size. */
|
|
30
|
+
export interface ByteRange {
|
|
31
|
+
start: number;
|
|
32
|
+
/** Inclusive, as the header is. */
|
|
33
|
+
end: number;
|
|
34
|
+
/** `end - start + 1`. */
|
|
35
|
+
length: number;
|
|
36
|
+
}
|
|
37
|
+
export type RangeParse =
|
|
38
|
+
/** No `Range` header, or one this server declines to honour. Serve `200`. */
|
|
39
|
+
{
|
|
40
|
+
kind: "none";
|
|
41
|
+
}
|
|
42
|
+
/** Serve `206` with this range. */
|
|
43
|
+
| {
|
|
44
|
+
kind: "range";
|
|
45
|
+
range: ByteRange;
|
|
46
|
+
}
|
|
47
|
+
/** Serve `416`. The range cannot be satisfied for an object of this size. */
|
|
48
|
+
| {
|
|
49
|
+
kind: "unsatisfiable";
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Parse a `Range` header against an object of `size` bytes.
|
|
53
|
+
*
|
|
54
|
+
* Deliberately conservative: anything malformed, multi-range, or in a unit other
|
|
55
|
+
* than bytes resolves to `none`, which serves the whole object. A range request
|
|
56
|
+
* answered with `200` is always legal; a range answered wrongly is a corrupted
|
|
57
|
+
* download.
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseRange(header: string | undefined, size: number): RangeParse;
|
|
60
|
+
/** The `Content-Range` for a served range. */
|
|
61
|
+
export declare function contentRange(range: ByteRange, size: number): string;
|
|
62
|
+
/** The `Content-Range` for a `416`, which names the size and no range. */
|
|
63
|
+
export declare function unsatisfiableContentRange(size: number): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { StorageController } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Where renditions live inside the source bucket.
|
|
4
|
+
*
|
|
5
|
+
* Fixed rather than configurable: it is the target of a lifecycle rule and of
|
|
6
|
+
* the route-layer refusal below, and both of those are worth being able to
|
|
7
|
+
* write down once, in the documentation, for every deployment.
|
|
8
|
+
*/
|
|
9
|
+
export declare const RENDITION_PREFIX = "_rebase/renditions/";
|
|
10
|
+
/** True for a key that names the reserved rendition space. */
|
|
11
|
+
export declare function isRenditionKey(key: string): boolean;
|
|
12
|
+
export interface RenditionCacheConfig {
|
|
13
|
+
/** Off unless set. See the module comment for why. */
|
|
14
|
+
enabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface DurableRendition {
|
|
17
|
+
data: Buffer;
|
|
18
|
+
contentType: string;
|
|
19
|
+
}
|
|
20
|
+
export interface DurableRenditionCache {
|
|
21
|
+
/** The stored rendition for this cache key, or null. Never throws. */
|
|
22
|
+
get(controller: StorageController, cacheKey: string, bucket: string | undefined): Promise<DurableRendition | null>;
|
|
23
|
+
/** Store a rendition. Never throws: a failed write is a slower cache. */
|
|
24
|
+
put(controller: StorageController, cacheKey: string, bucket: string | undefined, rendition: DurableRendition): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The object key for a rendition.
|
|
28
|
+
*
|
|
29
|
+
* Hashed rather than derived from the source path: the source key can be up to
|
|
30
|
+
* 1024 characters and the transform options are a JSON object, so a readable
|
|
31
|
+
* composition would exceed key limits on exactly the paths people use — deep
|
|
32
|
+
* per-user prefixes. The source key is kept in the object's metadata, where it
|
|
33
|
+
* is available to anyone auditing the prefix and to nothing on the hot path.
|
|
34
|
+
*/
|
|
35
|
+
export declare function renditionKey(cacheKey: string, contentType: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* A rendition's key when reading, where the content type is not yet known.
|
|
38
|
+
*
|
|
39
|
+
* Reads try the known extensions rather than storing an index: four `getObject`
|
|
40
|
+
* calls at worst is still one round trip in the common case — the first
|
|
41
|
+
* candidate is the format the request asked for — and an index is a second
|
|
42
|
+
* thing to keep consistent with the objects it describes.
|
|
43
|
+
*/
|
|
44
|
+
export declare function renditionKeyCandidates(cacheKey: string, preferred?: string): string[];
|
|
45
|
+
export declare function createDurableRenditionCache(): DurableRenditionCache;
|
package/dist/storage/routes.d.ts
CHANGED
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
* is used.
|
|
8
8
|
*/
|
|
9
9
|
import { Hono } from "hono";
|
|
10
|
-
import { StorageController, type StorageAuthorize, type StorageAuthorizeData } from "./types";
|
|
11
|
-
import { type StorageRegistry } from "./storage-registry";
|
|
10
|
+
import { StorageController, type StorageAuthorize, type StorageAuthorizeData } from "./types.js";
|
|
11
|
+
import { type StorageRegistry } from "./storage-registry.js";
|
|
12
12
|
import { type StorageSourceDefinition, type AuthAdapter } from "@rebasepro/types";
|
|
13
|
-
import { HonoEnv } from "../api/types";
|
|
13
|
+
import { HonoEnv } from "../api/types.js";
|
|
14
|
+
import { type StorageTrigger } from "./triggers.js";
|
|
15
|
+
import { type RenditionCacheConfig } from "./rendition-cache.js";
|
|
14
16
|
/**
|
|
15
17
|
* Decide what to actually serve for a stored content type.
|
|
16
18
|
*
|
|
@@ -24,8 +26,8 @@ export declare function resolveServedContentType(storedContentType: string): {
|
|
|
24
26
|
};
|
|
25
27
|
export interface StorageRoutesConfig {
|
|
26
28
|
/**
|
|
27
|
-
*
|
|
28
|
-
* Used
|
|
29
|
+
* A single storage controller, for a backend with one storage source.
|
|
30
|
+
* Used when no `registry` is provided.
|
|
29
31
|
*/
|
|
30
32
|
controller?: StorageController;
|
|
31
33
|
/**
|
|
@@ -71,6 +73,16 @@ export interface StorageRoutesConfig {
|
|
|
71
73
|
* resolved.
|
|
72
74
|
*/
|
|
73
75
|
authorizeData?: () => StorageAuthorizeData | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Keep derived image renditions in the storage source instead of only in
|
|
78
|
+
* this process's memory. Off unless enabled — see `rendition-cache.ts` for
|
|
79
|
+
* why a read that writes to somebody's bucket is not a default.
|
|
80
|
+
*/
|
|
81
|
+
renditionCache?: RenditionCacheConfig;
|
|
82
|
+
/**
|
|
83
|
+
* Run something when an object lands, or when one goes. See `triggers.ts`.
|
|
84
|
+
*/
|
|
85
|
+
triggers?: StorageTrigger[];
|
|
74
86
|
}
|
|
75
87
|
/**
|
|
76
88
|
* Extract the wildcard portion of a route path from the full request path.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - String properties use `storageId` in their config to specify which storage to use
|
|
11
11
|
* - Properties without `storageId` fallback to "(default)"
|
|
12
12
|
*/
|
|
13
|
-
import { StorageController } from "./types";
|
|
13
|
+
import { StorageController } from "./types.js";
|
|
14
14
|
/**
|
|
15
15
|
* The default storage identifier used when:
|
|
16
16
|
* - A single storage controller is provided (not a map)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** What happened to the object. */
|
|
2
|
+
export type StorageTriggerEvent = "finalize" | "delete";
|
|
3
|
+
export interface StorageEventContext {
|
|
4
|
+
/** Which event this is. */
|
|
5
|
+
event: StorageTriggerEvent;
|
|
6
|
+
/** The canonical storage key, as written. */
|
|
7
|
+
key: string;
|
|
8
|
+
/** The bucket, when the request named one. */
|
|
9
|
+
bucket?: string;
|
|
10
|
+
/** The storage source the object lives in. */
|
|
11
|
+
storageId: string;
|
|
12
|
+
/** Size in bytes. Present on `finalize`, absent on `delete`. */
|
|
13
|
+
size?: number;
|
|
14
|
+
/** The uploader's declared content type, when there was one. */
|
|
15
|
+
contentType?: string;
|
|
16
|
+
/** Segments captured by `:name` placeholders in the matched path. */
|
|
17
|
+
params: Record<string, string>;
|
|
18
|
+
/** Who made the request, when it was authenticated. */
|
|
19
|
+
user?: {
|
|
20
|
+
uid: string;
|
|
21
|
+
email?: string;
|
|
22
|
+
roles?: string[];
|
|
23
|
+
} | null;
|
|
24
|
+
/** When the event was raised, ISO 8601. */
|
|
25
|
+
at: string;
|
|
26
|
+
}
|
|
27
|
+
export type StorageTriggerHandler = (ctx: StorageEventContext) => void | Promise<void>;
|
|
28
|
+
export interface StorageTrigger {
|
|
29
|
+
/**
|
|
30
|
+
* A key pattern, matched segment by segment against the canonical key.
|
|
31
|
+
*
|
|
32
|
+
* - a literal segment matches itself
|
|
33
|
+
* - `*` matches exactly one segment
|
|
34
|
+
* - `:name` matches one segment and captures it
|
|
35
|
+
* - `**` matches the rest of the key, including nothing, and is only
|
|
36
|
+
* allowed as the final segment
|
|
37
|
+
*/
|
|
38
|
+
path: string;
|
|
39
|
+
/** Which events fire it. Defaults to `["finalize"]`. */
|
|
40
|
+
events?: StorageTriggerEvent[];
|
|
41
|
+
/** A name for the logs. Defaults to the pattern. */
|
|
42
|
+
name?: string;
|
|
43
|
+
handler: StorageTriggerHandler;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A request's principal, in the shape a trigger is documented to receive.
|
|
47
|
+
*
|
|
48
|
+
* Hono's `user` variable is typed `AuthResult`, which admits `true` — some
|
|
49
|
+
* middleware sets a bare boolean to mean "authenticated, with no identity
|
|
50
|
+
* attached". A trigger asking "who did this?" is better told `null` than
|
|
51
|
+
* `true`, and better told `null` than a `{}` with no `uid`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function triggerUser(raw: unknown): StorageEventContext["user"];
|
|
54
|
+
export declare class StorageTriggerError extends Error {
|
|
55
|
+
constructor(message: string);
|
|
56
|
+
}
|
|
57
|
+
/** Fires the triggers a key and event match. Never throws. */
|
|
58
|
+
export type StorageTriggerDispatcher = (ctx: Omit<StorageEventContext, "params">) => Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Compile a trigger list into a dispatcher, or throw
|
|
61
|
+
* {@link StorageTriggerError}.
|
|
62
|
+
*
|
|
63
|
+
* Compiled at boot so a malformed pattern fails the start rather than the first
|
|
64
|
+
* upload — and, worse, rather than failing *silently* by matching nothing.
|
|
65
|
+
*/
|
|
66
|
+
export declare function compileStorageTriggers(triggers: StorageTrigger[]): StorageTriggerDispatcher;
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* @see https://tus.io/protocols/resumable-upload
|
|
9
9
|
*/
|
|
10
10
|
import type { Context } from "hono";
|
|
11
|
-
import type { StorageController } from "./types";
|
|
12
|
-
import { type StorageRegistry } from "./storage-registry";
|
|
11
|
+
import type { StorageController } from "./types.js";
|
|
12
|
+
import { type StorageRegistry } from "./storage-registry.js";
|
|
13
13
|
/**
|
|
14
14
|
* TUS resumable upload handler.
|
|
15
15
|
*
|
|
@@ -33,6 +33,16 @@ export declare class TusHandler {
|
|
|
33
33
|
* can only answer for the destination it is told about.
|
|
34
34
|
*/
|
|
35
35
|
private authorizeUpload?;
|
|
36
|
+
/**
|
|
37
|
+
* Called once the bytes are stored, so storage triggers fire for the
|
|
38
|
+
* resumable path too. A trigger wired only to `POST /upload` would miss
|
|
39
|
+
* exactly the uploads big enough to be worth reacting to.
|
|
40
|
+
*
|
|
41
|
+
* Never throws: the dispatcher swallows handler errors, because the
|
|
42
|
+
* object is already written and failing here would tell the client to
|
|
43
|
+
* repeat a write that succeeded.
|
|
44
|
+
*/
|
|
45
|
+
private onFinalized?;
|
|
36
46
|
private uploads;
|
|
37
47
|
private tusDir;
|
|
38
48
|
private cleanupTimer?;
|
|
@@ -49,7 +59,28 @@ export declare class TusHandler {
|
|
|
49
59
|
* Every routing value the write will use is passed in, because the hook
|
|
50
60
|
* can only answer for the destination it is told about.
|
|
51
61
|
*/
|
|
52
|
-
authorizeUpload?: ((c: Context, key: string, bucket: string, storageId?: string) => Promise<void>) | undefined
|
|
62
|
+
authorizeUpload?: ((c: Context, key: string, bucket: string, storageId?: string) => Promise<void>) | undefined,
|
|
63
|
+
/**
|
|
64
|
+
* Called once the bytes are stored, so storage triggers fire for the
|
|
65
|
+
* resumable path too. A trigger wired only to `POST /upload` would miss
|
|
66
|
+
* exactly the uploads big enough to be worth reacting to.
|
|
67
|
+
*
|
|
68
|
+
* Never throws: the dispatcher swallows handler errors, because the
|
|
69
|
+
* object is already written and failing here would tell the client to
|
|
70
|
+
* repeat a write that succeeded.
|
|
71
|
+
*/
|
|
72
|
+
onFinalized?: ((event: {
|
|
73
|
+
key: string;
|
|
74
|
+
bucket?: string;
|
|
75
|
+
storageId?: string;
|
|
76
|
+
size: number;
|
|
77
|
+
contentType?: string;
|
|
78
|
+
user?: {
|
|
79
|
+
uid: string;
|
|
80
|
+
email?: string;
|
|
81
|
+
roles?: string[];
|
|
82
|
+
} | null;
|
|
83
|
+
}) => Promise<void>) | undefined);
|
|
53
84
|
/** Ensure the temp directory exists. */
|
|
54
85
|
private ensureDir;
|
|
55
86
|
/** Start periodic cleanup of stale uploads. */
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Topics, on the durable job queue.
|
|
3
|
+
*
|
|
4
|
+
* ## Why fan out at publish time
|
|
5
|
+
*
|
|
6
|
+
* Publishing writes **one job row per subscription**, not one row for the
|
|
7
|
+
* event. That is the shape SNS→SQS has and the reason is the same: each
|
|
8
|
+
* subscriber then retries on its own schedule, and a subscription that is
|
|
9
|
+
* broken or slow neither blocks the others nor causes them to run again. A
|
|
10
|
+
* single row per event forces one retry policy across every consumer, so the
|
|
11
|
+
* fourth attempt of a failing audit log re-delivers a welcome email that
|
|
12
|
+
* already went out.
|
|
13
|
+
*
|
|
14
|
+
* It also makes "did this subscriber get it" a row somebody can look at, which
|
|
15
|
+
* is the property the job queue was built for: work that gives up is *kept*,
|
|
16
|
+
* because a queue that silently drops what it could not deliver is
|
|
17
|
+
* indistinguishable from one with nothing to do.
|
|
18
|
+
*
|
|
19
|
+
* ## What at-least-once means here
|
|
20
|
+
*
|
|
21
|
+
* A handler can see the same event twice — a worker that dies holding a job
|
|
22
|
+
* releases it after the visibility timeout, and the next worker starts the
|
|
23
|
+
* handler again from the top. Handlers must tolerate that. It is the honest
|
|
24
|
+
* name for what a retrying queue does, which is why `at-most-once` is refused
|
|
25
|
+
* at declaration rather than quietly given the other guarantee.
|
|
26
|
+
*
|
|
27
|
+
* ## Transactional publish
|
|
28
|
+
*
|
|
29
|
+
* `enqueue` is a row insert, so a publish inside a transaction that rolls back
|
|
30
|
+
* was never published — the difference between "email sent for an order that
|
|
31
|
+
* does not exist" and nothing having happened at all.
|
|
32
|
+
*/
|
|
33
|
+
import { type ResourceDeclaration, type TopicRuntime } from "@rebasepro/types";
|
|
34
|
+
import type { JobHandler, JobQueueClient } from "./../jobs/types.js";
|
|
35
|
+
/** The job task name a subscription's deliveries are recorded under. */
|
|
36
|
+
export declare function topicTaskName(topic: string, subscription: string): string;
|
|
37
|
+
/** Attempts a subscription gets before its delivery is left failed. */
|
|
38
|
+
export declare const DEFAULT_TOPIC_ATTEMPTS = 5;
|
|
39
|
+
/**
|
|
40
|
+
* Build the job handlers every declared subscription needs.
|
|
41
|
+
*
|
|
42
|
+
* Returned rather than registered, because the queue takes its whole task map
|
|
43
|
+
* at construction — and a task map assembled in one place is one somebody can
|
|
44
|
+
* print.
|
|
45
|
+
*/
|
|
46
|
+
export declare function topicJobHandlers(): Record<string, JobHandler<never>>;
|
|
47
|
+
export interface TopicRuntimeOptions {
|
|
48
|
+
queue: JobQueueClient;
|
|
49
|
+
/** Declared topics, so publishing to an undeclared one can be refused. */
|
|
50
|
+
topics: ResourceDeclaration[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build the runtime topics publish through.
|
|
54
|
+
*
|
|
55
|
+
* Publishing to a topic nothing declared throws. The handle API makes it hard
|
|
56
|
+
* to reach, but a string name from an ejected project or a dynamic caller can —
|
|
57
|
+
* and enqueueing under a task no worker handles would write rows nobody ever
|
|
58
|
+
* runs.
|
|
59
|
+
*/
|
|
60
|
+
export declare function createTopicRuntime(options: TopicRuntimeOptions): TopicRuntime;
|
|
61
|
+
/**
|
|
62
|
+
* Install the runtime, and hand back a teardown.
|
|
63
|
+
*
|
|
64
|
+
* Publishing without one throws rather than resolving — an event that
|
|
65
|
+
* disappears into a resolved promise is the failure a queue exists to
|
|
66
|
+
* prevent — so it is installed for exactly as long as a backend is up.
|
|
67
|
+
*/
|
|
68
|
+
export declare function installTopicRuntime(options: TopicRuntimeOptions): () => void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { createRequire as
|
|
2
|
-
import "process";
|
|
3
|
-
|
|
1
|
+
import { createRequire as __rebaseCreateRequire } from "module";
|
|
2
|
+
import __rebaseProcess from "process";
|
|
3
|
+
globalThis.process ??= __rebaseProcess;
|
|
4
|
+
__rebaseCreateRequire(import.meta.url);
|
|
4
5
|
//#region src/storage/types.ts
|
|
5
6
|
/**
|
|
6
7
|
* Default maximum file size (50MB)
|
|
@@ -35,4 +36,4 @@ var DOCUMENT_MIME_TYPES = [
|
|
|
35
36
|
//#endregion
|
|
36
37
|
export { DOCUMENT_MIME_TYPES as n, IMAGE_MIME_TYPES as r, DEFAULT_MAX_FILE_SIZE as t };
|
|
37
38
|
|
|
38
|
-
//# sourceMappingURL=types-
|
|
39
|
+
//# sourceMappingURL=types-BfKcm9do.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types-
|
|
1
|
+
{"version":3,"file":"types-BfKcm9do.js","names":[],"sources":["../src/storage/types.ts"],"sourcesContent":["/**\n * Storage configuration and types for Rebase backend\n */\n\nimport { StorageSource, UploadFileProps, UploadFileResult, DownloadConfig, StorageListResult, StorageReference } from \"@rebasepro/types\";\n\n/**\n * Local filesystem storage configuration\n */\nexport interface LocalStorageConfig {\n type: \"local\";\n /** Base directory for file storage (e.g., './uploads') */\n basePath: string;\n /** Maximum file size in bytes (default: 50MB) */\n maxFileSize?: number;\n /** Allowed MIME types (if not set, all types allowed) */\n allowedMimeTypes?: string[];\n /** Base URL for generating download URLs (default: auto-detected from request) */\n baseUrl?: string;\n}\n\n/**\n * S3-compatible storage configuration (works with AWS S3 and MinIO)\n */\nexport interface S3StorageConfig {\n type: \"s3\";\n /** S3 bucket name */\n bucket: string;\n /** AWS region (e.g., 'us-east-1') */\n region?: string;\n /** Custom endpoint URL (required for MinIO, Cloudflare R2, Hetzner Object Storage) */\n endpoint?: string;\n /** AWS access key ID */\n accessKeyId: string;\n /** AWS secret access key */\n secretAccessKey: string;\n /** Use path-style URLs (required for MinIO) */\n forcePathStyle?: boolean;\n /** Maximum file size in bytes (default: 50MB) */\n maxFileSize?: number;\n /** Allowed MIME types (if not set, all types allowed) */\n allowedMimeTypes?: string[];\n /** URL expiration time in seconds for signed URLs (default: 3600) */\n signedUrlExpiration?: number;\n}\n\n/**\n * Google Cloud Storage configuration (works with GCS and Firebase Storage)\n */\nexport interface GCSStorageConfig {\n type: \"gcs\";\n /** GCS bucket name (e.g. \"my-project.appspot.com\" for Firebase Storage) */\n bucket: string;\n /** GCP project ID (optional, auto-detected from credentials) */\n projectId?: string;\n /** Path to service account JSON key file */\n keyFilename?: string;\n /** Service account credentials object (alternative to keyFilename) */\n credentials?: { client_email: string; private_key: string; project_id?: string };\n /** Maximum file size in bytes (default: 50MB) */\n maxFileSize?: number;\n /** Allowed MIME types */\n allowedMimeTypes?: string[];\n /** Signed URL expiration in seconds (default: 3600) */\n signedUrlExpiration?: number;\n}\n\n/**\n * Storage configuration — local filesystem, S3-compatible, or Google Cloud Storage.\n *\n * **Built-in providers:**\n * - `local` — Zero-config filesystem storage. Great for dev and single-server deployments (Hetzner, bare metal).\n * - `s3` — Any S3-compatible provider. AWS S3, Cloudflare R2, MinIO, Hetzner Object Storage,\n * Backblaze B2, DigitalOcean Spaces, and even GCS (via its S3-compatible interoperability API).\n * - `gcs` — Native Google Cloud Storage / Firebase Storage via `@google-cloud/storage`.\n *\n * **Custom providers:**\n * For other cloud storage (Azure Blob, etc.), implement the `StorageController`\n * interface and pass the instance directly to the `storage` config.\n */\nexport type BackendStorageConfig = LocalStorageConfig | S3StorageConfig | GCSStorageConfig;\n\n/** What a storage request is trying to do to an object. */\nexport type {\n StorageOperation,\n StorageAuthorizeUser,\n StorageAuthorizeContext,\n StorageAuthorizeData,\n StorageAuthorize\n} from \"@rebasepro/types\";\n\n/**\n * Storage controller interface for backend implementations\n */\nexport interface StorageController {\n /**\n * Upload an object\n */\n putObject(props: UploadFileProps): Promise<UploadFileResult>;\n\n /**\n * Get a download URL (signed URL equivalent) for an object\n */\n getSignedUrl(key: string, bucket?: string): Promise<DownloadConfig>;\n\n /**\n * Get object as a File\n */\n getObject(key: string, bucket?: string): Promise<File | null>;\n\n /**\n * Delete an object\n */\n deleteObject(key: string, bucket?: string): Promise<void>;\n\n /**\n * List objects in a prefix\n */\n listObjects(prefix: string, options?: {\n bucket?: string;\n maxResults?: number;\n pageToken?: string;\n }): Promise<StorageListResult>;\n\n /**\n * Get the storage provider identifier.\n *\n * Built-in values are `'local'` and `'s3'`. Custom implementations\n * should return their own identifier (e.g. `'gcs'`, `'azure'`).\n */\n getType(): string;\n}\n\n/**\n * Default maximum file size (50MB)\n */\nexport const DEFAULT_MAX_FILE_SIZE = 50 * 1024 * 1024;\n\n/**\n * Common image MIME types\n */\nexport const IMAGE_MIME_TYPES = [\n \"image/jpeg\",\n \"image/png\",\n \"image/gif\",\n \"image/webp\",\n \"image/svg+xml\",\n \"image/bmp\",\n \"image/tiff\"\n];\n\n/**\n * Common document MIME types\n */\nexport const DOCUMENT_MIME_TYPES = [\n \"application/pdf\",\n \"application/msword\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \"application/vnd.ms-excel\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"application/vnd.ms-powerpoint\",\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n \"text/plain\",\n \"text/csv\"\n];\n"],"mappings":";;;;;;;;AAwIA,IAAa,wBAAwB,KAAK,OAAO;;;;AAKjD,IAAa,mBAAmB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;AACJ;;;;AAKA,IAAa,sBAAsB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACJ"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host globals this package reads, behind functions that do not assume Node.
|
|
3
|
+
*
|
|
4
|
+
* `process` is not defined on workerd, on Deno Deploy without the compat flag,
|
|
5
|
+
* or in a browser. That matters here for one specific reason: the portable
|
|
6
|
+
* authoring surface (`@rebasepro/server/functions`) reaches the logger and the
|
|
7
|
+
* error handler, and a bare `process.env.NODE_ENV` inside either of them turns
|
|
8
|
+
* the first log line of a request into a `ReferenceError` on a runtime that has
|
|
9
|
+
* no `process` — a failure that reads as "the framework crashed" rather than
|
|
10
|
+
* "this runtime has no process object".
|
|
11
|
+
*
|
|
12
|
+
* Nothing here throws and nothing here is async. A runtime that cannot answer
|
|
13
|
+
* gets the empty answer, because every caller in this file's blast radius is
|
|
14
|
+
* choosing a log level or a format, and the safe default for both is the
|
|
15
|
+
* development one.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* The process environment, or the closest thing this runtime has to one.
|
|
21
|
+
*
|
|
22
|
+
* Order: a bag published by {@link setHostEnv} first, because an adapter that
|
|
23
|
+
* set one knows more than the ambient globals do; then `process.env`; then
|
|
24
|
+
* nothing.
|
|
25
|
+
*/
|
|
26
|
+
export declare function hostEnv(): Record<string, string | undefined>;
|
|
27
|
+
/**
|
|
28
|
+
* Read one environment variable without touching `process` directly.
|
|
29
|
+
*
|
|
30
|
+
* Trimmed, and blank is treated as absent — a variable declared with no value
|
|
31
|
+
* is the ordinary way to write a compose file or a `.env` line, and every
|
|
32
|
+
* caller in this package means "unset" by it. See `resolveFunctionsTimeoutMs`,
|
|
33
|
+
* which learned that the hard way.
|
|
34
|
+
*/
|
|
35
|
+
export declare function hostEnvVar(name: string): string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Publish an environment bag for contextless readers.
|
|
38
|
+
*
|
|
39
|
+
* Called by an adapter for a runtime whose environment is not ambient. Merges
|
|
40
|
+
* rather than replaces, so two adapters (or an adapter plus a test) do not
|
|
41
|
+
* silently erase each other's variables.
|
|
42
|
+
*/
|
|
43
|
+
export declare function setHostEnv(env: Record<string, string | undefined>): void;
|
|
44
|
+
/** @internal Test seam — drops anything {@link setHostEnv} published. */
|
|
45
|
+
export declare function _clearHostEnv(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Write one already-formatted line to the process's output.
|
|
48
|
+
*
|
|
49
|
+
* `process.stdout.write` is preferred where it exists because it is the only
|
|
50
|
+
* one of the two that does not append its own formatting to a line that is
|
|
51
|
+
* already a complete JSON document — `console.log` on Node is
|
|
52
|
+
* `process.stdout.write` plus `util.format`, and `util.format` will happily
|
|
53
|
+
* reinterpret a `%s` that appeared inside a user's log message.
|
|
54
|
+
*
|
|
55
|
+
* Where it does not exist, `console` is the runtime's log sink and is what its
|
|
56
|
+
* platform collects.
|
|
57
|
+
*/
|
|
58
|
+
export declare function writeLine(stream: "out" | "err", line: string): void;
|
package/dist/utils/logger.d.ts
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Structured Logger for Rebase Backend
|
|
3
|
-
*
|
|
4
|
-
* Outputs JSON lines when `NODE_ENV=production`, human-readable prefixed
|
|
5
|
-
* lines otherwise. Designed to work with Google Cloud Logging severity levels.
|
|
6
|
-
*
|
|
7
|
-
* Every line — message and data, at any depth — passes through the redaction
|
|
8
|
-
* below, which strips Drizzle's `Failed query: … / params: …` wrapper and the
|
|
9
|
-
* values of secret-looking keys. See the block above `serialiseError`.
|
|
10
|
-
*
|
|
11
|
-
* Usage:
|
|
12
|
-
* import { logger } from "./utils/logger";
|
|
13
|
-
* logger.info("Server started", { port: 3001 });
|
|
14
|
-
* logger.error("Request failed", { path: "/api/test", error: err });
|
|
15
|
-
*/
|
|
16
1
|
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
17
2
|
export interface LogEntry {
|
|
18
3
|
severity: string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"//": [
|
|
3
|
+
"Not a package. A resolution redirect, so that `@rebasepro/server/functions`",
|
|
4
|
+
"works under TypeScript's legacy `moduleResolution: \"node\"` as well as under",
|
|
5
|
+
"`bundler` / `node16` / `nodenext`.",
|
|
6
|
+
"",
|
|
7
|
+
"The `exports` map in ../package.json is the real declaration, and it is what",
|
|
8
|
+
"Node uses at runtime — once a package has `exports`, Node ignores directory",
|
|
9
|
+
"redirects like this one entirely. TypeScript's node10 mode does the opposite:",
|
|
10
|
+
"it ignores `exports` and resolves subpaths as directories. A project scaffolded",
|
|
11
|
+
"by `rebase init` compiles with `moduleResolution: \"node\"`, so without this file",
|
|
12
|
+
"the very import the template ships — `@rebasepro/server/functions` — fails its",
|
|
13
|
+
"own `tsc` with TS2307, while running perfectly.",
|
|
14
|
+
"",
|
|
15
|
+
"Deleting this file breaks type-checking for every such project and nothing",
|
|
16
|
+
"else, which is the hardest kind of breakage to attribute. `files` in",
|
|
17
|
+
"../package.json ships it; assert-build-output.mjs verifies the targets exist."
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "../dist/functions/index.js",
|
|
21
|
+
"module": "../dist/functions/index.js",
|
|
22
|
+
"types": "../dist/functions/index.d.ts",
|
|
23
|
+
"sideEffects": false
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/server",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.16.
|
|
4
|
+
"version": "0.16.1-canary.g0d7af95",
|
|
5
5
|
"description": "Database-Agnostic Backend Core for Rebase",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/rebaseco"
|
|
@@ -36,6 +36,11 @@
|
|
|
36
36
|
"development": "./dist/index.es.js",
|
|
37
37
|
"import": "./dist/index.es.js"
|
|
38
38
|
},
|
|
39
|
+
"./functions": {
|
|
40
|
+
"types": "./dist/functions/index.d.ts",
|
|
41
|
+
"development": "./dist/functions/index.js",
|
|
42
|
+
"import": "./dist/functions/index.js"
|
|
43
|
+
},
|
|
39
44
|
"./package.json": "./package.json"
|
|
40
45
|
},
|
|
41
46
|
"dependencies": {
|
|
@@ -44,10 +49,10 @@
|
|
|
44
49
|
"jsonwebtoken": "^9.0.3",
|
|
45
50
|
"ws": "^8.21.1",
|
|
46
51
|
"zod": "^4.4.3",
|
|
47
|
-
"@rebasepro/client": "0.16.
|
|
48
|
-
"@rebasepro/
|
|
49
|
-
"@rebasepro/
|
|
50
|
-
"@rebasepro/utils": "0.16.
|
|
52
|
+
"@rebasepro/client": "0.16.1-canary.g0d7af95",
|
|
53
|
+
"@rebasepro/common": "0.16.1-canary.g0d7af95",
|
|
54
|
+
"@rebasepro/types": "0.16.1-canary.g0d7af95",
|
|
55
|
+
"@rebasepro/utils": "0.16.1-canary.g0d7af95"
|
|
51
56
|
},
|
|
52
57
|
"devDependencies": {
|
|
53
58
|
"@jest/globals": "^30.4.1",
|
|
@@ -103,14 +108,15 @@
|
|
|
103
108
|
},
|
|
104
109
|
"files": [
|
|
105
110
|
"bin",
|
|
106
|
-
"dist"
|
|
111
|
+
"dist",
|
|
112
|
+
"functions"
|
|
107
113
|
],
|
|
108
114
|
"bin": {
|
|
109
115
|
"rebase-server": "bin/rebase-server.js"
|
|
110
116
|
},
|
|
111
117
|
"scripts": {
|
|
112
118
|
"watch": "vite build --watch",
|
|
113
|
-
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json && node ../../scripts/assert-build-output.mjs",
|
|
119
|
+
"build": "vite build && vite build --config vite.config.functions.ts && tsc --emitDeclarationOnly -p tsconfig.prod.json && node ../../tooling/scripts/add-dts-extensions.mjs dist && node ../../tooling/scripts/assert-build-output.mjs && node --experimental-vm-modules --no-warnings ../../tooling/scripts/assert-portable-entry.mjs dist/functions/index.js",
|
|
114
120
|
"test:lint": "eslint \"src/**\" --quiet",
|
|
115
121
|
"test": "cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest --passWithNoTests --forceExit",
|
|
116
122
|
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
|