@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.
Files changed (219) hide show
  1. package/dist/{GCSStorageController-BEmDYFKc.js → GCSStorageController-Bl7nmhdv.js} +7 -6
  2. package/dist/{GCSStorageController-BEmDYFKc.js.map → GCSStorageController-Bl7nmhdv.js.map} +1 -1
  3. package/dist/{S3StorageController-B2EDXXMH.js → S3StorageController-CWvvrRpF.js} +7 -6
  4. package/dist/{S3StorageController-B2EDXXMH.js.map → S3StorageController-CWvvrRpF.js.map} +1 -1
  5. package/dist/{admin_block-DLILvzle.js → admin_block-BeypnEfb.js} +6 -6
  6. package/dist/admin_block-BeypnEfb.js.map +1 -0
  7. package/dist/api/ast-schema-editor.d.ts +23 -0
  8. package/dist/api/contract-routes.d.ts +1 -1
  9. package/dist/api/errors.d.ts +1 -1
  10. package/dist/api/index.d.ts +3 -3
  11. package/dist/api/live-schema-routes.d.ts +122 -0
  12. package/dist/api/logs-routes.d.ts +1 -1
  13. package/dist/api/mount.d.ts +41 -0
  14. package/dist/api/rest/api-generator.d.ts +2 -2
  15. package/dist/api/rest/index.d.ts +1 -1
  16. package/dist/api/rest/query-parser.d.ts +1 -1
  17. package/dist/api/schema-editor-routes.d.ts +1 -1
  18. package/dist/api/types.d.ts +12 -4
  19. package/dist/{schema-editor-routes-CV9k0w3G.js → ast-schema-editor-BrarYZCq.js} +37 -45
  20. package/dist/ast-schema-editor-BrarYZCq.js.map +1 -0
  21. package/dist/auth/adapter-middleware.d.ts +2 -2
  22. package/dist/auth/admin-roles-route.d.ts +2 -2
  23. package/dist/auth/admin-user-ops.d.ts +3 -3
  24. package/dist/auth/admin-users-route.d.ts +4 -6
  25. package/dist/auth/api-keys/api-key-middleware.d.ts +2 -2
  26. package/dist/auth/api-keys/api-key-permission-guard.d.ts +1 -1
  27. package/dist/auth/api-keys/api-key-routes.d.ts +2 -2
  28. package/dist/auth/api-keys/api-key-store.d.ts +1 -1
  29. package/dist/auth/api-keys/index.d.ts +9 -9
  30. package/dist/auth/apple-oauth.d.ts +2 -2
  31. package/dist/auth/auth-hooks.d.ts +4 -4
  32. package/dist/auth/bitbucket-oauth.d.ts +2 -2
  33. package/dist/auth/builtin-auth-adapter.d.ts +8 -4
  34. package/dist/auth/capabilities.d.ts +51 -0
  35. package/dist/auth/captcha.d.ts +86 -0
  36. package/dist/auth/cookie-utils.d.ts +2 -2
  37. package/dist/auth/discord-oauth.d.ts +2 -2
  38. package/dist/auth/facebook-oauth.d.ts +2 -2
  39. package/dist/auth/github-oauth.d.ts +2 -2
  40. package/dist/auth/gitlab-oauth.d.ts +2 -2
  41. package/dist/auth/google-oauth.d.ts +1 -1
  42. package/dist/auth/index.d.ts +58 -54
  43. package/dist/auth/jwks-routes.d.ts +1 -1
  44. package/dist/auth/jwt.d.ts +1 -1
  45. package/dist/auth/linkedin-oauth.d.ts +2 -2
  46. package/dist/auth/magic-link-routes.d.ts +10 -3
  47. package/dist/auth/mfa-gate.d.ts +1 -1
  48. package/dist/auth/mfa-routes.d.ts +3 -3
  49. package/dist/auth/microsoft-oauth.d.ts +2 -2
  50. package/dist/auth/middleware.d.ts +6 -7
  51. package/dist/auth/otp-routes.d.ts +89 -0
  52. package/dist/auth/rate-limiter.d.ts +2 -2
  53. package/dist/auth/require-auth.d.ts +1 -1
  54. package/dist/auth/reset-password-admin.d.ts +4 -4
  55. package/dist/auth/routes.d.ts +18 -10
  56. package/dist/auth/session-routes.d.ts +3 -3
  57. package/dist/auth/slack-oauth.d.ts +2 -2
  58. package/dist/auth/spotify-oauth.d.ts +2 -2
  59. package/dist/auth/token-revocation.d.ts +2 -2
  60. package/dist/auth/twitter-oauth.d.ts +2 -2
  61. package/dist/{auth-5Et5mnUA.js → auth-DU-nUjPp.js} +604 -4376
  62. package/dist/auth-DU-nUjPp.js.map +1 -0
  63. package/dist/backup/backup-common.d.ts +1 -1
  64. package/dist/backup/backup-routes.d.ts +3 -3
  65. package/dist/backup/index.d.ts +3 -3
  66. package/dist/{backup-C6ljYVTp.js → backup-CRdZkA6c.js} +7 -6
  67. package/dist/{backup-C6ljYVTp.js.map → backup-CRdZkA6c.js.map} +1 -1
  68. package/dist/boot/boot.d.ts +5 -5
  69. package/dist/boot/bundle.d.ts +10 -1
  70. package/dist/boot/driver.d.ts +1 -1
  71. package/dist/boot/env.d.ts +28 -1
  72. package/dist/boot/fetch-bundle.d.ts +144 -1
  73. package/dist/boot/options.d.ts +30 -6
  74. package/dist/boot/resource-adapters.d.ts +31 -0
  75. package/dist/boot/resource-loading.d.ts +10 -0
  76. package/dist/boot/role.d.ts +3 -2
  77. package/dist/boot/sources.d.ts +8 -2
  78. package/dist/boot/version-skew.d.ts +1 -1
  79. package/dist/collections/BackendCollectionRegistry.d.ts +1 -1
  80. package/dist/collections/loader.d.ts +1 -1
  81. package/dist/collections/validate-config.d.ts +13 -0
  82. package/dist/{contract-routes-DZ-LBpSL.js → contract-routes-D8TvxPLo.js} +8 -7
  83. package/dist/contract-routes-D8TvxPLo.js.map +1 -0
  84. package/dist/cron/cron-routes.d.ts +2 -2
  85. package/dist/cron/cron-scheduler.d.ts +3 -3
  86. package/dist/cron/index.d.ts +8 -8
  87. package/dist/{cron-loader-YhhQeVBM.js → cron-loader-d9WMFENB.js} +8 -7
  88. package/dist/{cron-loader-YhhQeVBM.js.map → cron-loader-d9WMFENB.js.map} +1 -1
  89. package/dist/{cron-routes-maM_RlUu.js → cron-routes-BsukhMGm.js} +9 -8
  90. package/dist/cron-routes-BsukhMGm.js.map +1 -0
  91. package/dist/{cron-scheduler-DIpYBmZP.js → cron-scheduler-BB82dWuU.js} +9 -9
  92. package/dist/cron-scheduler-BB82dWuU.js.map +1 -0
  93. package/dist/{cron-store-DfH_4Cd9.js → cron-store-CbFfQhbg.js} +11 -9
  94. package/dist/{cron-store-DfH_4Cd9.js.map → cron-store-CbFfQhbg.js.map} +1 -1
  95. package/dist/ddl-bootstrap-5YZCZ8qk.js +146 -0
  96. package/dist/ddl-bootstrap-5YZCZ8qk.js.map +1 -0
  97. package/dist/deploy/pod-contract.d.ts +139 -0
  98. package/dist/dev-secrets.d.ts +52 -0
  99. package/dist/{dynamic-import-Dvh-K5fl.js → dynamic-import-X40pTZUQ.js} +5 -4
  100. package/dist/{dynamic-import-Dvh-K5fl.js.map → dynamic-import-X40pTZUQ.js.map} +1 -1
  101. package/dist/email/dev-sink.d.ts +88 -0
  102. package/dist/email/index.d.ts +9 -7
  103. package/dist/email/link-base.d.ts +1 -1
  104. package/dist/email/smtp-email-service.d.ts +2 -2
  105. package/dist/email/templates.d.ts +12 -0
  106. package/dist/email/types.d.ts +18 -6
  107. package/dist/env.d.ts +1 -1
  108. package/dist/{errors-EBYiaJ2E.js → errors-DBwpj9N8.js} +8 -7
  109. package/dist/errors-DBwpj9N8.js.map +1 -0
  110. package/dist/{function-loader-DDS1v7YX.js → function-loader-LLdmBFoL.js} +9 -8
  111. package/dist/{function-loader-DDS1v7YX.js.map → function-loader-LLdmBFoL.js.map} +1 -1
  112. package/dist/{function-routes-Btcez1T-.js → function-routes-ClT6UQpD.js} +8 -7
  113. package/dist/function-routes-ClT6UQpD.js.map +1 -0
  114. package/dist/functions/context.d.ts +141 -0
  115. package/dist/functions/define-function.d.ts +1 -1
  116. package/dist/functions/function-routes.d.ts +9 -3
  117. package/dist/functions/guards.d.ts +76 -0
  118. package/dist/functions/index.d.ts +96 -5
  119. package/dist/functions/index.js +919 -0
  120. package/dist/functions/index.js.map +1 -0
  121. package/dist/functions/internal.d.ts +26 -0
  122. package/dist/functions/proxy.d.ts +1 -1
  123. package/dist/functions/request-timeout.d.ts +9 -1
  124. package/dist/functions/runtime-env.d.ts +92 -0
  125. package/dist/functions/wait-until.d.ts +74 -0
  126. package/dist/history/history-routes.d.ts +2 -2
  127. package/dist/history/index.d.ts +1 -1
  128. package/dist/history-recorder-B67maiTi.js +76 -0
  129. package/dist/history-recorder-B67maiTi.js.map +1 -0
  130. package/dist/history-store-oiqhb3HU.js +210 -0
  131. package/dist/history-store-oiqhb3HU.js.map +1 -0
  132. package/dist/index.d.ts +65 -54
  133. package/dist/index.es.js +3667 -328
  134. package/dist/index.es.js.map +1 -1
  135. package/dist/init/docs.d.ts +1 -1
  136. package/dist/init/middlewares.d.ts +1 -1
  137. package/dist/init/shutdown.d.ts +4 -0
  138. package/dist/init/storage.d.ts +1 -1
  139. package/dist/init/surfaces.d.ts +10 -0
  140. package/dist/init.d.ts +179 -22
  141. package/dist/internal-tables-DpxfPaEB.js +97 -0
  142. package/dist/internal-tables-DpxfPaEB.js.map +1 -0
  143. package/dist/jobs/index.d.ts +5 -5
  144. package/dist/{jobs-CyOKXXlu.js → jobs-B2ELModo.js} +11 -9
  145. package/dist/{jobs-CyOKXXlu.js.map → jobs-B2ELModo.js.map} +1 -1
  146. package/dist/{jwt-DxH9fLPt.js → jwt-DoHkMMWF.js} +9 -8
  147. package/dist/jwt-DoHkMMWF.js.map +1 -0
  148. package/dist/{logger-DfvF_8r-.js → logger-DS03e908.js} +104 -10
  149. package/dist/logger-DS03e908.js.map +1 -0
  150. package/dist/{logs-routes-CWBLQj2l.js → logs-routes-DB72iQSr.js} +36 -9
  151. package/dist/logs-routes-DB72iQSr.js.map +1 -0
  152. package/dist/metrics/history-recorder.d.ts +18 -0
  153. package/dist/metrics/history-store.d.ts +123 -0
  154. package/dist/metrics/index.d.ts +10 -2
  155. package/dist/{openapi-generator-BCKJRUS4.js → openapi-generator-FFGT0H6O.js} +7 -11
  156. package/dist/{openapi-generator-BCKJRUS4.js.map → openapi-generator-FFGT0H6O.js.map} +1 -1
  157. package/dist/{proxy-Bj5DVllb.js → proxy-CMymhnwG.js} +9 -6
  158. package/dist/{proxy-Bj5DVllb.js.map → proxy-CMymhnwG.js.map} +1 -1
  159. package/dist/query-parser--nstjRCh.js +355 -0
  160. package/dist/query-parser--nstjRCh.js.map +1 -0
  161. package/dist/{request-timeout-BuFoEKwT.js → request-timeout-C8gkc-j7.js} +21 -6
  162. package/dist/request-timeout-C8gkc-j7.js.map +1 -0
  163. package/dist/rls-audit/index.d.ts +111 -0
  164. package/dist/{rolldown-runtime-DSJWtz9O.js → rolldown-runtime-dW7B1o5h.js} +4 -3
  165. package/dist/schema-edit/apply-schema-change.d.ts +141 -0
  166. package/dist/schema-edit/github-repository.d.ts +67 -0
  167. package/dist/schema-edit/local-git-repository.d.ts +28 -0
  168. package/dist/schema-edit/project-root.d.ts +43 -0
  169. package/dist/schema-edit/remote-source.d.ts +25 -0
  170. package/dist/schema-edit/schema-edit-permissions.d.ts +129 -0
  171. package/dist/schema-editor-routes-Bf5h5Emf.js +87 -0
  172. package/dist/schema-editor-routes-Bf5h5Emf.js.map +1 -0
  173. package/dist/schemas-DBxgjM9A.js +4153 -0
  174. package/dist/schemas-DBxgjM9A.js.map +1 -0
  175. package/dist/{selection-_z6TM1DB.js → selection-CRpqKUbt.js} +6 -5
  176. package/dist/{selection-_z6TM1DB.js.map → selection-CRpqKUbt.js.map} +1 -1
  177. package/dist/services/webhook-service.d.ts +1 -1
  178. package/dist/singleton.d.ts +7 -0
  179. package/dist/{src-BPfYOeN4.js → src-B-CmIFMr.js} +8 -6
  180. package/dist/src-B-CmIFMr.js.map +1 -0
  181. package/dist/{src-CrCxd8km.js → src-Cdsw7DqV.js} +126 -5
  182. package/dist/src-Cdsw7DqV.js.map +1 -0
  183. package/dist/storage/GCSStorageController.d.ts +1 -1
  184. package/dist/storage/LocalStorageController.d.ts +1 -1
  185. package/dist/storage/S3StorageController.d.ts +1 -1
  186. package/dist/storage/cache-headers.d.ts +87 -0
  187. package/dist/storage/index.d.ts +11 -11
  188. package/dist/storage/path-pattern.d.ts +58 -0
  189. package/dist/storage/policies.d.ts +88 -0
  190. package/dist/storage/range.d.ts +63 -0
  191. package/dist/storage/rendition-cache.d.ts +45 -0
  192. package/dist/storage/routes.d.ts +17 -5
  193. package/dist/storage/storage-registry.d.ts +1 -1
  194. package/dist/storage/triggers.d.ts +66 -0
  195. package/dist/storage/tus-handler.d.ts +34 -3
  196. package/dist/topics/runtime.d.ts +68 -0
  197. package/dist/{types-DSnOC4mF.js → types-BfKcm9do.js} +5 -4
  198. package/dist/{types-DSnOC4mF.js.map → types-BfKcm9do.js.map} +1 -1
  199. package/dist/utils/host.d.ts +58 -0
  200. package/dist/utils/logger.d.ts +0 -15
  201. package/dist/utils/request-id.d.ts +1 -1
  202. package/functions/package.json +24 -0
  203. package/package.json +13 -7
  204. package/dist/admin_block-DLILvzle.js.map +0 -1
  205. package/dist/auth-5Et5mnUA.js.map +0 -1
  206. package/dist/contract-routes-DZ-LBpSL.js.map +0 -1
  207. package/dist/cron-routes-maM_RlUu.js.map +0 -1
  208. package/dist/cron-scheduler-DIpYBmZP.js.map +0 -1
  209. package/dist/ddl-bootstrap-Cywoj8Ta.js +0 -221
  210. package/dist/ddl-bootstrap-Cywoj8Ta.js.map +0 -1
  211. package/dist/errors-EBYiaJ2E.js.map +0 -1
  212. package/dist/function-routes-Btcez1T-.js.map +0 -1
  213. package/dist/jwt-DxH9fLPt.js.map +0 -1
  214. package/dist/logger-DfvF_8r-.js.map +0 -1
  215. package/dist/logs-routes-CWBLQj2l.js.map +0 -1
  216. package/dist/request-timeout-BuFoEKwT.js.map +0 -1
  217. package/dist/schema-editor-routes-CV9k0w3G.js.map +0 -1
  218. package/dist/src-BPfYOeN4.js.map +0 -1
  219. 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;
@@ -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
- * Single storage controller (backward-compatible).
28
- * Used as fallback when no `registry` is provided.
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 __createRequire } from "module";
2
- import "process";
3
- __createRequire(import.meta.url);
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-DSnOC4mF.js.map
39
+ //# sourceMappingURL=types-BfKcm9do.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types-DSnOC4mF.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"}
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;
@@ -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;
@@ -1,4 +1,4 @@
1
1
  import type { MiddlewareHandler } from "hono";
2
- import type { HonoEnv } from "../api/types";
2
+ import type { HonoEnv } from "../api/types.js";
3
3
  export declare const REQUEST_ID_HEADER = "X-Request-ID";
4
4
  export declare function requestId(): MiddlewareHandler<HonoEnv>;
@@ -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.0",
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.0",
48
- "@rebasepro/types": "0.16.0",
49
- "@rebasepro/common": "0.16.0",
50
- "@rebasepro/utils": "0.16.0"
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"