@rebasepro/server 0.13.1-canary.gef9608c → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/dist/{admin_block-EmIHae6X.js → admin_block-H86dCPsj.js} +61 -2
  2. package/dist/admin_block-H86dCPsj.js.map +1 -0
  3. package/dist/api/ast-schema-editor.d.ts +74 -6
  4. package/dist/api/errors.d.ts +12 -0
  5. package/dist/api/rest/api-generator.d.ts +26 -1
  6. package/dist/api/rest/idempotency.d.ts +25 -4
  7. package/dist/api/rest/query-parser.d.ts +15 -1
  8. package/dist/api/rest/write-validation.d.ts +40 -4
  9. package/dist/auth/adapter-middleware.d.ts +3 -1
  10. package/dist/auth/admin-roles.d.ts +24 -0
  11. package/dist/auth/apple-oauth.d.ts +16 -11
  12. package/dist/auth/bitbucket-oauth.d.ts +2 -4
  13. package/dist/auth/builtin-auth-adapter.d.ts +11 -0
  14. package/dist/auth/discord-oauth.d.ts +5 -6
  15. package/dist/auth/facebook-oauth.d.ts +2 -4
  16. package/dist/auth/github-oauth.d.ts +2 -4
  17. package/dist/auth/gitlab-oauth.d.ts +6 -4
  18. package/dist/auth/google-oauth.d.ts +1 -0
  19. package/dist/auth/index.d.ts +7 -0
  20. package/dist/auth/interfaces.d.ts +81 -1
  21. package/dist/auth/jwt.d.ts +40 -0
  22. package/dist/auth/linkedin-oauth.d.ts +2 -4
  23. package/dist/auth/mfa-crypto.d.ts +54 -3
  24. package/dist/auth/mfa-gate.d.ts +42 -0
  25. package/dist/auth/mfa-routes.d.ts +26 -1
  26. package/dist/auth/mfa.d.ts +16 -0
  27. package/dist/auth/microsoft-oauth.d.ts +19 -4
  28. package/dist/auth/middleware.d.ts +26 -0
  29. package/dist/auth/oauth-code-flow.d.ts +66 -0
  30. package/dist/auth/oauth-signin-policy.d.ts +61 -0
  31. package/dist/auth/oidc-id-token.d.ts +61 -0
  32. package/dist/auth/rate-limiter.d.ts +62 -5
  33. package/dist/auth/registration-policy.d.ts +31 -0
  34. package/dist/auth/rls-scope.d.ts +25 -0
  35. package/dist/auth/routes.d.ts +15 -0
  36. package/dist/auth/slack-oauth.d.ts +2 -4
  37. package/dist/auth/spotify-oauth.d.ts +2 -4
  38. package/dist/auth/token-revocation.d.ts +38 -0
  39. package/dist/auth/twitter-oauth.d.ts +2 -5
  40. package/dist/{auth-DU4ShERo.js → auth-CYoPVf-E.js} +1985 -395
  41. package/dist/auth-CYoPVf-E.js.map +1 -0
  42. package/dist/{backup-BJiY_mM-.js → backup-C6ljYVTp.js} +2 -2
  43. package/dist/{backup-BJiY_mM-.js.map → backup-C6ljYVTp.js.map} +1 -1
  44. package/dist/boot/ddl-bootstrap.d.ts +70 -0
  45. package/dist/{contract-routes-Dj8i5AiM.js → contract-routes-Bet-eCNJ.js} +3 -3
  46. package/dist/{contract-routes-Dj8i5AiM.js.map → contract-routes-Bet-eCNJ.js.map} +1 -1
  47. package/dist/cron/cron-loader.d.ts +26 -1
  48. package/dist/cron/cron-routes.d.ts +1 -1
  49. package/dist/cron/cron-scheduler.d.ts +13 -3
  50. package/dist/cron/define-cron.d.ts +17 -3
  51. package/dist/cron/index.d.ts +2 -2
  52. package/dist/{cron-loader-B1S2MCSl.js → cron-loader-YhhQeVBM.js} +43 -8
  53. package/dist/cron-loader-YhhQeVBM.js.map +1 -0
  54. package/dist/{cron-routes-D5a9v1HY.js → cron-routes-maM_RlUu.js} +10 -4
  55. package/dist/cron-routes-maM_RlUu.js.map +1 -0
  56. package/dist/{cron-scheduler-BhFZWR0T.js → cron-scheduler-DIpYBmZP.js} +20 -8
  57. package/dist/cron-scheduler-DIpYBmZP.js.map +1 -0
  58. package/dist/{cron-store-Cu4sOseb.js → cron-store-Dvr4Y1sZ.js} +60 -51
  59. package/dist/cron-store-Dvr4Y1sZ.js.map +1 -0
  60. package/dist/ddl-bootstrap-BhXbTnBl.js +183 -0
  61. package/dist/ddl-bootstrap-BhXbTnBl.js.map +1 -0
  62. package/dist/email/html.d.ts +54 -0
  63. package/dist/email/index.d.ts +3 -0
  64. package/dist/email/link-base.d.ts +39 -0
  65. package/dist/email/smtp-email-service.d.ts +7 -1
  66. package/dist/email/templates.d.ts +9 -1
  67. package/dist/email/types.d.ts +11 -1
  68. package/dist/env.d.ts +5 -0
  69. package/dist/{errors-BpudWAVU.js → errors-EBYiaJ2E.js} +14 -2
  70. package/dist/errors-EBYiaJ2E.js.map +1 -0
  71. package/dist/function-loader-DDS1v7YX.js +139 -0
  72. package/dist/function-loader-DDS1v7YX.js.map +1 -0
  73. package/dist/{function-routes-C0cLIy3N.js → function-routes-Btcez1T-.js} +18 -6
  74. package/dist/function-routes-Btcez1T-.js.map +1 -0
  75. package/dist/functions/define-function.d.ts +25 -6
  76. package/dist/functions/function-loader.d.ts +23 -0
  77. package/dist/functions/function-routes.d.ts +7 -1
  78. package/dist/functions/request-timeout.d.ts +34 -0
  79. package/dist/history/history-routes.d.ts +6 -0
  80. package/dist/index.d.ts +3 -2
  81. package/dist/index.es.js +1893 -714
  82. package/dist/index.es.js.map +1 -1
  83. package/dist/init/docs.d.ts +10 -1
  84. package/dist/init/process-safety.d.ts +25 -0
  85. package/dist/init.d.ts +38 -0
  86. package/dist/{jwt-CzeviDcB.js → jwt-_IFqfTOg.js} +57 -9
  87. package/dist/jwt-_IFqfTOg.js.map +1 -0
  88. package/dist/logger-DfvF_8r-.js +190 -0
  89. package/dist/logger-DfvF_8r-.js.map +1 -0
  90. package/dist/{openapi-generator-D5xsfVJY.js → openapi-generator-DPKtUC9X.js} +326 -55
  91. package/dist/openapi-generator-DPKtUC9X.js.map +1 -0
  92. package/dist/request-timeout-RivJsME0.js +65 -0
  93. package/dist/request-timeout-RivJsME0.js.map +1 -0
  94. package/dist/schema-editor-routes-CRcS3ArS.js +437 -0
  95. package/dist/schema-editor-routes-CRcS3ArS.js.map +1 -0
  96. package/dist/serve-spa.d.ts +5 -4
  97. package/dist/services/outbound-url-guard.d.ts +53 -0
  98. package/dist/services/routed-realtime-service.d.ts +10 -2
  99. package/dist/services/webhook-service.d.ts +76 -1
  100. package/dist/singleton.d.ts +25 -8
  101. package/dist/{src-CKOZBpeJ.js → src-C7rkDGxA.js} +619 -70
  102. package/dist/src-C7rkDGxA.js.map +1 -0
  103. package/dist/{src-_qQ3RNCK.js → src-Cz9nMgUR.js} +93 -3
  104. package/dist/src-Cz9nMgUR.js.map +1 -0
  105. package/dist/storage/LocalStorageController.d.ts +12 -1
  106. package/dist/storage/image-transform.d.ts +57 -0
  107. package/dist/storage/keys.d.ts +98 -0
  108. package/dist/storage/routes.d.ts +11 -0
  109. package/dist/storage/tus-handler.d.ts +22 -2
  110. package/dist/utils/logger.d.ts +18 -0
  111. package/dist/utils/sql.d.ts +11 -6
  112. package/package.json +6 -5
  113. package/dist/admin_block-EmIHae6X.js.map +0 -1
  114. package/dist/auth-DU4ShERo.js.map +0 -1
  115. package/dist/backend-CIxN4FVm.js +0 -15
  116. package/dist/backend-CIxN4FVm.js.map +0 -1
  117. package/dist/cron-loader-B1S2MCSl.js.map +0 -1
  118. package/dist/cron-routes-D5a9v1HY.js.map +0 -1
  119. package/dist/cron-scheduler-BhFZWR0T.js.map +0 -1
  120. package/dist/cron-store-Cu4sOseb.js.map +0 -1
  121. package/dist/errors-BpudWAVU.js.map +0 -1
  122. package/dist/function-loader-B_1fYfUY.js +0 -86
  123. package/dist/function-loader-B_1fYfUY.js.map +0 -1
  124. package/dist/function-routes-C0cLIy3N.js.map +0 -1
  125. package/dist/jwt-CzeviDcB.js.map +0 -1
  126. package/dist/logger-BYU66ENZ.js +0 -94
  127. package/dist/logger-BYU66ENZ.js.map +0 -1
  128. package/dist/openapi-generator-D5xsfVJY.js.map +0 -1
  129. package/dist/schema-editor-routes-C1DxDnDR.js +0 -248
  130. package/dist/schema-editor-routes-C1DxDnDR.js.map +0 -1
  131. package/dist/src-CKOZBpeJ.js.map +0 -1
  132. package/dist/src-_qQ3RNCK.js.map +0 -1
@@ -0,0 +1,139 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ import "process";
3
+ __createRequire(import.meta.url);
4
+ import { n as __exportAll } from "./rolldown-runtime-DSJWtz9O.js";
5
+ import { t as logger } from "./logger-DfvF_8r-.js";
6
+ import { t as nativeDynamicImport } from "./dynamic-import-Dvh-K5fl.js";
7
+ import * as fs$1 from "fs";
8
+ import * as path$1 from "path";
9
+ import { pathToFileURL } from "url";
10
+ //#region src/functions/function-loader.ts
11
+ var function_loader_exports = /* @__PURE__ */ __exportAll({
12
+ loadFunctionsFromDirectory: () => loadFunctionsFromDirectory,
13
+ loadFunctionsWithDiagnostics: () => loadFunctionsWithDiagnostics
14
+ });
15
+ /**
16
+ * Extensions the bundler compiles (or a developer might reasonably write) that
17
+ * this loader cannot import. `rebase build` globs `functions/**\/*.ts`, so the
18
+ * build's idea of "a function file" is strictly wider than the runtime's — the
19
+ * worst direction for a mismatch to go. Anything listed here is reported as a
20
+ * problem instead of vanishing; non-code files (`.md`, `.json`, `.txt`) stay
21
+ * silent, because a README next to your functions is not a mistake.
22
+ */
23
+ var UNSUPPORTED_CODE_EXTENSIONS = [
24
+ ".mts",
25
+ ".cts",
26
+ ".tsx",
27
+ ".jsx",
28
+ ".mjs",
29
+ ".cjs"
30
+ ];
31
+ /**
32
+ * Auto-discover Hono route files from a directory.
33
+ *
34
+ * Each file should default-export a Hono app (or router).
35
+ * The filename (without extension) becomes the mount path:
36
+ * `functions/send-invoice.ts` → mounted at `/send-invoice`
37
+ *
38
+ * This mirrors how `loadCollectionsFromDirectory` works for collections.
39
+ *
40
+ * Returns only what loaded. Use {@link loadFunctionsWithDiagnostics} when the
41
+ * caller also needs to report what did not.
42
+ */
43
+ async function loadFunctionsFromDirectory(directory, importModule = nativeDynamicImport) {
44
+ return (await loadFunctionsWithDiagnostics(directory, importModule)).functions;
45
+ }
46
+ /**
47
+ * {@link loadFunctionsFromDirectory}, plus the list of files that were skipped.
48
+ *
49
+ * Never throws: a single malformed function must not crash server boot. The
50
+ * caller decides what to do with `problems` — `init.ts` mounts the router
51
+ * regardless and surfaces the count on the listing endpoint.
52
+ */
53
+ async function loadFunctionsWithDiagnostics(directory, importModule = nativeDynamicImport) {
54
+ const functions = [];
55
+ const problems = [];
56
+ if (!fs$1.existsSync(directory)) return {
57
+ functions,
58
+ problems
59
+ };
60
+ const entries = fs$1.readdirSync(directory, { withFileTypes: true });
61
+ for (const entry of entries) {
62
+ const file = entry.name;
63
+ if (entry.isDirectory()) {
64
+ if (file.startsWith(".") || file === "node_modules") continue;
65
+ logger.warn(`[functions] ${file}/: subdirectory ignored. Functions are loaded from the top level of ${directory} only, so nothing under ${file}/ is served. Move the file up (or flatten the name: \`admin/users.ts\` → \`admin-users.ts\`).`);
66
+ problems.push(`${file}/ (subdirectory — functions are not loaded recursively)`);
67
+ continue;
68
+ }
69
+ const extension = path$1.extname(file);
70
+ if (!file.startsWith(".") && !file.includes(".test.") && UNSUPPORTED_CODE_EXTENSIONS.includes(extension)) {
71
+ logger.warn(`[functions] ${file}: ${extension} files are not loaded. Rename it to .ts (or .js) to serve it.`);
72
+ problems.push(`${file} (unsupported extension ${extension})`);
73
+ continue;
74
+ }
75
+ if ((file.endsWith(".ts") || file.endsWith(".js")) && !file.startsWith(".") && !file.includes(".test.") && !file.endsWith(".d.ts") && file !== "index.ts" && file !== "index.js") {
76
+ const filePath = path$1.join(directory, file);
77
+ try {
78
+ const fileUrl = pathToFileURL(filePath).href;
79
+ const exported = (await importModule(fileUrl)).default;
80
+ if (!exported) {
81
+ logger.warn(`[functions] ${file}: no default export. Skipping.`);
82
+ problems.push(`${file} (no default export)`);
83
+ continue;
84
+ }
85
+ if (isHonoLike(exported)) {
86
+ const name = path$1.basename(file, path$1.extname(file));
87
+ functions.push({
88
+ name,
89
+ app: exported
90
+ });
91
+ logger.debug(`⚡ Loaded function route: ${name}`);
92
+ continue;
93
+ }
94
+ if (typeof exported === "function") {
95
+ const result = exported();
96
+ if (isHonoLike(result)) {
97
+ const name = path$1.basename(file, path$1.extname(file));
98
+ functions.push({
99
+ name,
100
+ app: result
101
+ });
102
+ logger.debug(`⚡ Loaded function route: ${name}`);
103
+ continue;
104
+ }
105
+ }
106
+ const exportType = typeof exported;
107
+ const keys = exported && typeof exported === "object" ? Object.getOwnPropertyNames(Object.getPrototypeOf(exported)).slice(0, 10).join(", ") : "N/A";
108
+ logger.warn(`[functions] ${file}: default export is not a Hono app or factory. Skipping.\n export type: ${exportType}${exported?.constructor?.name ? ` (${exported.constructor.name})` : ""}\n prototype methods: ${keys}\n Hint: ensure the function exports a Hono app created with the same hono version as the server.
109
+ Author with \`defineFunction(...)\` from @rebasepro/server for a typed, checked contract.
110
+ The loader checks for .fetch() and .routes — any Hono-compatible app will work.`);
111
+ problems.push(`${file} (not a Hono app or factory)`);
112
+ } catch (err) {
113
+ const message = err instanceof Error ? err.message : String(err);
114
+ logger.error(`[functions] Failed to load ${file}: ${message}`);
115
+ problems.push(`${file} (threw: ${message})`);
116
+ }
117
+ }
118
+ }
119
+ if (problems.length > 0) logger.warn(`[functions] ${problems.length} function file(s) were skipped and will NOT be served:\n` + problems.map((p) => ` - ${p}`).join("\n") + "\n Fix these or author them with `defineFunction(...)` for a typed, compile-checked contract.");
120
+ return {
121
+ functions,
122
+ problems
123
+ };
124
+ }
125
+ /**
126
+ * Duck-type check for Hono apps.
127
+ * We avoid `instanceof Hono` because different Hono versions
128
+ * installed in the user's project vs. our dependencies will
129
+ * not share the same prototype, causing false negatives.
130
+ */
131
+ function isHonoLike(obj) {
132
+ if (!obj || typeof obj !== "object") return false;
133
+ const record = obj;
134
+ return typeof record.fetch === "function" && Array.isArray(record.routes);
135
+ }
136
+ //#endregion
137
+ export { loadFunctionsFromDirectory as n, function_loader_exports as t };
138
+
139
+ //# sourceMappingURL=function-loader-DDS1v7YX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function-loader-DDS1v7YX.js","names":[],"sources":["../src/functions/function-loader.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as path from \"path\";\nimport { pathToFileURL } from \"url\";\nimport { Hono } from \"hono\";\nimport { logger } from \"../utils/logger.js\";\nimport { nativeDynamicImport, type ModuleImporter } from \"../utils/dynamic-import.js\";\n\nexport interface LoadedFunction {\n /** Endpoint name derived from filename (e.g., \"send-invoice\") */\n name: string;\n /** The Hono sub-app to mount */\n app: Hono<import(\"hono\").Env>;\n}\n\n/** What a directory of function files produced: what mounted, and what did not. */\nexport interface LoadedFunctions {\n /** The functions that will be served. */\n functions: LoadedFunction[];\n /**\n * One entry per file the loader saw and did **not** mount, each already\n * phrased as `<name> (<reason>)`. Returned rather than only logged so the\n * running server can say what is missing — a boot log line is not reachable\n * from `GET /api/functions`.\n */\n problems: string[];\n}\n\n/**\n * Extensions the bundler compiles (or a developer might reasonably write) that\n * this loader cannot import. `rebase build` globs `functions/**\\/*.ts`, so the\n * build's idea of \"a function file\" is strictly wider than the runtime's — the\n * worst direction for a mismatch to go. Anything listed here is reported as a\n * problem instead of vanishing; non-code files (`.md`, `.json`, `.txt`) stay\n * silent, because a README next to your functions is not a mistake.\n */\nconst UNSUPPORTED_CODE_EXTENSIONS = [\".mts\", \".cts\", \".tsx\", \".jsx\", \".mjs\", \".cjs\"];\n\n/**\n * Auto-discover Hono route files from a directory.\n *\n * Each file should default-export a Hono app (or router).\n * The filename (without extension) becomes the mount path:\n * `functions/send-invoice.ts` → mounted at `/send-invoice`\n *\n * This mirrors how `loadCollectionsFromDirectory` works for collections.\n *\n * Returns only what loaded. Use {@link loadFunctionsWithDiagnostics} when the\n * caller also needs to report what did not.\n */\nexport async function loadFunctionsFromDirectory(\n directory: string,\n importModule: ModuleImporter = nativeDynamicImport\n): Promise<LoadedFunction[]> {\n return (await loadFunctionsWithDiagnostics(directory, importModule)).functions;\n}\n\n/**\n * {@link loadFunctionsFromDirectory}, plus the list of files that were skipped.\n *\n * Never throws: a single malformed function must not crash server boot. The\n * caller decides what to do with `problems` — `init.ts` mounts the router\n * regardless and surfaces the count on the listing endpoint.\n */\nexport async function loadFunctionsWithDiagnostics(\n directory: string,\n importModule: ModuleImporter = nativeDynamicImport\n): Promise<LoadedFunctions> {\n const functions: LoadedFunction[] = [];\n // Aggregate problem files so a broken function surfaces as one loud\n // summary line, not just a warning buried per-file. We still don't throw:\n // a single malformed function must not crash server boot.\n const problems: string[] = [];\n\n if (!fs.existsSync(directory)) {\n return { functions, problems };\n }\n\n // `withFileTypes` so a directory entry is a *reported* skip rather than a\n // filter miss. `readdirSync(dir)` returned bare names, and a subdirectory\n // simply failed the `.ts`/`.js` test — so `functions/admin/users.ts` was\n // compiled by `rebase build`, shipped in the bundle, and then dropped at\n // boot without a single log line.\n const entries = fs.readdirSync(directory, { withFileTypes: true });\n for (const entry of entries) {\n const file = entry.name;\n\n if (entry.isDirectory()) {\n // Dot-directories are tooling (`.git`, `.turbo`), not intent.\n if (file.startsWith(\".\") || file === \"node_modules\") continue;\n logger.warn(\n `[functions] ${file}/: subdirectory ignored. Functions are loaded from the top level of ` +\n `${directory} only, so nothing under ${file}/ is served. Move the file up (or flatten the ` +\n \"name: `admin/users.ts` → `admin-users.ts`).\"\n );\n problems.push(`${file}/ (subdirectory — functions are not loaded recursively)`);\n continue;\n }\n\n const extension = path.extname(file);\n if (\n !file.startsWith(\".\") &&\n !file.includes(\".test.\") &&\n UNSUPPORTED_CODE_EXTENSIONS.includes(extension)\n ) {\n logger.warn(\n `[functions] ${file}: ${extension} files are not loaded. Rename it to .ts (or .js) to serve it.`\n );\n problems.push(`${file} (unsupported extension ${extension})`);\n continue;\n }\n\n if (\n (file.endsWith(\".ts\") || file.endsWith(\".js\")) &&\n // Dotfiles: notably macOS bsdtar AppleDouble sidecars (`._foo.ts`),\n // binary blobs that cannot be imported.\n !file.startsWith(\".\") &&\n !file.includes(\".test.\") &&\n !file.endsWith(\".d.ts\") &&\n file !== \"index.ts\" &&\n file !== \"index.js\"\n ) {\n const filePath = path.join(directory, file);\n try {\n const fileUrl = pathToFileURL(filePath).href;\n\n const mod = await importModule(fileUrl);\n\n const exported = mod.default;\n\n if (!exported) {\n logger.warn(`[functions] ${file}: no default export. Skipping.`);\n problems.push(`${file} (no default export)`);\n continue;\n }\n\n // Accept a Hono instance — use duck-typing to handle different\n // Hono versions which may not share the same prototype.\n if (isHonoLike(exported)) {\n const name = path.basename(file, path.extname(file));\n functions.push({ name,\napp: exported as Hono });\n logger.debug(`⚡ Loaded function route: ${name}`);\n continue;\n }\n\n // Also accept a factory function that returns a Hono instance\n if (typeof exported === \"function\") {\n const result = exported();\n if (isHonoLike(result)) {\n const name = path.basename(file, path.extname(file));\n functions.push({ name,\napp: result as Hono });\n logger.debug(`⚡ Loaded function route: ${name}`);\n continue;\n }\n }\n\n // Provide actionable diagnostics\n const exportType = typeof exported;\n const keys = exported && typeof exported === \"object\"\n ? Object.getOwnPropertyNames(Object.getPrototypeOf(exported)).slice(0, 10).join(\", \")\n : \"N/A\";\n logger.warn(\n `[functions] ${file}: default export is not a Hono app or factory. Skipping.\\n` +\n ` export type: ${exportType}${exported?.constructor?.name ? ` (${exported.constructor.name})` : \"\"}\\n` +\n ` prototype methods: ${keys}\\n` +\n \" Hint: ensure the function exports a Hono app created with the same hono version as the server.\\n\" +\n \" Author with `defineFunction(...)` from @rebasepro/server for a typed, checked contract.\\n\" +\n \" The loader checks for .fetch() and .routes — any Hono-compatible app will work.\"\n );\n problems.push(`${file} (not a Hono app or factory)`);\n } catch (err: unknown) {\n const message =\n err instanceof Error ? err.message : String(err);\n logger.error(`[functions] Failed to load ${file}: ${message}`);\n problems.push(`${file} (threw: ${message})`);\n }\n }\n }\n\n if (problems.length > 0) {\n logger.warn(\n `[functions] ${problems.length} function file(s) were skipped and will NOT be served:\\n` +\n problems.map((p) => ` - ${p}`).join(\"\\n\") + \"\\n\" +\n \" Fix these or author them with `defineFunction(...)` for a typed, compile-checked contract.\"\n );\n }\n\n return { functions, problems };\n}\n\n/**\n * Duck-type check for Hono apps.\n * We avoid `instanceof Hono` because different Hono versions\n * installed in the user's project vs. our dependencies will\n * not share the same prototype, causing false negatives.\n */\nfunction isHonoLike(obj: unknown): boolean {\n if (!obj || typeof obj !== \"object\") return false;\n // Hono instances always have .fetch() and .routes\n const record = obj as Record<string, unknown>;\n return (\n typeof record.fetch === \"function\" &&\n Array.isArray(record.routes)\n );\n}\n"],"mappings":"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"}
@@ -10,14 +10,26 @@ var function_routes_exports = /* @__PURE__ */ __exportAll({ createFunctionRoutes
10
10
  *
11
11
  * Each function is mounted at `/<function-name>`, preserving
12
12
  * whatever HTTP methods and middleware the Hono sub-app defines.
13
+ *
14
+ * @param functions What loaded. May be empty — the router still mounts, so
15
+ * "no functions are served" answers 200 with an empty list instead of 404.
16
+ * @param skipped How many files the loader saw and could not serve. Reported
17
+ * as a count and a pointer to the log, not as filenames: the listing is
18
+ * reachable anonymously, and the per-file reasons carry import errors.
13
19
  */
14
- function createFunctionRoutes(functions) {
20
+ function createFunctionRoutes(functions, skipped = 0) {
15
21
  const router = new Hono();
16
22
  router.get("/", (c) => {
17
- return c.json({ functions: functions.map((fn) => ({
18
- name: fn.name,
19
- endpoint: `/functions/${fn.name}`
20
- })) });
23
+ return c.json({
24
+ functions: functions.map((fn) => ({
25
+ name: fn.name,
26
+ endpoint: `/functions/${fn.name}`
27
+ })),
28
+ ...skipped > 0 && {
29
+ skipped,
30
+ note: `${skipped} function file(s) failed to load and are NOT served — see the server log for the reason.`
31
+ }
32
+ });
21
33
  });
22
34
  for (const fn of functions) router.route(`/${fn.name}`, fn.app);
23
35
  return router;
@@ -25,4 +37,4 @@ function createFunctionRoutes(functions) {
25
37
  //#endregion
26
38
  export { function_routes_exports as n, createFunctionRoutes as t };
27
39
 
28
- //# sourceMappingURL=function-routes-C0cLIy3N.js.map
40
+ //# sourceMappingURL=function-routes-Btcez1T-.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function-routes-Btcez1T-.js","names":[],"sources":["../src/functions/function-routes.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport { HonoEnv } from \"../api/types\";\nimport { LoadedFunction } from \"./function-loader\";\n\n/**\n * Mount all loaded function routes under a single Hono router.\n *\n * Each function is mounted at `/<function-name>`, preserving\n * whatever HTTP methods and middleware the Hono sub-app defines.\n *\n * @param functions What loaded. May be empty — the router still mounts, so\n * \"no functions are served\" answers 200 with an empty list instead of 404.\n * @param skipped How many files the loader saw and could not serve. Reported\n * as a count and a pointer to the log, not as filenames: the listing is\n * reachable anonymously, and the per-file reasons carry import errors.\n */\nexport function createFunctionRoutes(\n functions: LoadedFunction[],\n skipped = 0\n): Hono<HonoEnv> {\n const router = new Hono<HonoEnv>();\n\n // Listing endpoint: GET / → list available functions\n router.get(\"/\", (c) => {\n return c.json({\n functions: functions.map((fn) => ({\n name: fn.name,\n endpoint: `/functions/${fn.name}`\n })),\n ...(skipped > 0 && {\n skipped,\n note: `${skipped} function file(s) failed to load and are NOT served — see the server log for the reason.`\n })\n });\n });\n\n for (const fn of functions) {\n router.route(`/${fn.name}`, fn.app);\n }\n\n return router;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgBA,SAAgB,qBACZ,WACA,UAAU,GACG;CACb,MAAM,SAAS,IAAI,KAAc;CAGjC,OAAO,IAAI,MAAM,MAAM;EACnB,OAAO,EAAE,KAAK;GACV,WAAW,UAAU,KAAK,QAAQ;IAC9B,MAAM,GAAG;IACT,UAAU,cAAc,GAAG;GAC/B,EAAE;GACF,GAAI,UAAU,KAAK;IACf;IACA,MAAM,GAAG,QAAQ;GACrB;EACJ,CAAC;CACL,CAAC;CAED,KAAK,MAAM,MAAM,WACb,OAAO,MAAM,IAAI,GAAG,QAAQ,GAAG,GAAG;CAGtC,OAAO;AACX"}
@@ -15,11 +15,27 @@ export interface RebaseFunctionContext {
15
15
  * The server-side Rebase singleton (`dataAsAdmin`, `auth`, `storage`,
16
16
  * `email`, `sql`).
17
17
  *
18
- * `rebase.dataAsAdmin` runs with **admin privileges and bypasses RLS** — use
19
- * it only for trusted admin work. For user-scoped queries inside a handler,
20
- * use the request `driver` (`c.var.driver`), which carries the caller's
21
- * identity so RLS applies. (`rebase.data` no longer exists on this type —
22
- * `dataAsAdmin` is the only name for the admin-scoped accessor.)
18
+ * `rebase.dataAsAdmin` runs as the service identity
19
+ * `{ uid: "service", roles: ["admin"] }` — **admin-scoped, not an RLS
20
+ * bypass**. Policies are still evaluated; it passes the default ones
21
+ * through their `rolesOverlap(['admin'])` arm, the same arm an application
22
+ * user holding the `admin` role passes. Two things follow:
23
+ *
24
+ * - `policy.serverContext()` (`auth.uid() IS NULL`) is **false** here. A
25
+ * collection with `disableDefaultPolicies: true` whose write rule is
26
+ * `serverContext()` will refuse these writes with `42501`, and reads
27
+ * against a hand-written admin policy that does not name the `admin` role
28
+ * return zero rows with a 200.
29
+ * - Do not read it as "nobody else can reach these rows". Whatever an
30
+ * `admin`-roled user can reach, this can, and vice versa.
31
+ *
32
+ * `rebase.sql()` is the true bypass: it runs on the owner connection and
33
+ * never goes through `withAuth`.
34
+ *
35
+ * For user-scoped queries inside a handler, use the request `driver`
36
+ * (`c.var.driver`), which carries the caller's identity. (`rebase.data` no
37
+ * longer exists on this type — `dataAsAdmin` is the only name for the
38
+ * admin-scoped accessor.)
23
39
  */
24
40
  rebase: RebaseServerClient;
25
41
  }
@@ -41,7 +57,10 @@ export interface RebaseFunctionContext {
41
57
  * export default defineFunction((app, { rebase }) => {
42
58
  * app.use("/*", requireAuth);
43
59
  * app.get("/home", async (c) => {
44
- * const [stats] = await rebase.sql!(`SELECT count(*) AS n FROM orders`);
60
+ * // `rebase.sql` runs on the owner connection: no RLS, no policies,
61
+ * // every row. It is the most privileged thing in this context —
62
+ * // more so than `dataAsAdmin`, which is merely admin-scoped.
63
+ * const [stats] = await rebase.sql(`SELECT count(*) AS n FROM orders`);
45
64
  * return c.json({ orders: Number(stats.n) });
46
65
  * });
47
66
  * });
@@ -6,6 +6,18 @@ export interface LoadedFunction {
6
6
  /** The Hono sub-app to mount */
7
7
  app: Hono<import("hono").Env>;
8
8
  }
9
+ /** What a directory of function files produced: what mounted, and what did not. */
10
+ export interface LoadedFunctions {
11
+ /** The functions that will be served. */
12
+ functions: LoadedFunction[];
13
+ /**
14
+ * One entry per file the loader saw and did **not** mount, each already
15
+ * phrased as `<name> (<reason>)`. Returned rather than only logged so the
16
+ * running server can say what is missing — a boot log line is not reachable
17
+ * from `GET /api/functions`.
18
+ */
19
+ problems: string[];
20
+ }
9
21
  /**
10
22
  * Auto-discover Hono route files from a directory.
11
23
  *
@@ -14,5 +26,16 @@ export interface LoadedFunction {
14
26
  * `functions/send-invoice.ts` → mounted at `/send-invoice`
15
27
  *
16
28
  * This mirrors how `loadCollectionsFromDirectory` works for collections.
29
+ *
30
+ * Returns only what loaded. Use {@link loadFunctionsWithDiagnostics} when the
31
+ * caller also needs to report what did not.
17
32
  */
18
33
  export declare function loadFunctionsFromDirectory(directory: string, importModule?: ModuleImporter): Promise<LoadedFunction[]>;
34
+ /**
35
+ * {@link loadFunctionsFromDirectory}, plus the list of files that were skipped.
36
+ *
37
+ * Never throws: a single malformed function must not crash server boot. The
38
+ * caller decides what to do with `problems` — `init.ts` mounts the router
39
+ * regardless and surfaces the count on the listing endpoint.
40
+ */
41
+ export declare function loadFunctionsWithDiagnostics(directory: string, importModule?: ModuleImporter): Promise<LoadedFunctions>;
@@ -6,5 +6,11 @@ import { LoadedFunction } from "./function-loader";
6
6
  *
7
7
  * Each function is mounted at `/<function-name>`, preserving
8
8
  * whatever HTTP methods and middleware the Hono sub-app defines.
9
+ *
10
+ * @param functions What loaded. May be empty — the router still mounts, so
11
+ * "no functions are served" answers 200 with an empty list instead of 404.
12
+ * @param skipped How many files the loader saw and could not serve. Reported
13
+ * as a count and a pointer to the log, not as filenames: the listing is
14
+ * reachable anonymously, and the per-file reasons carry import errors.
9
15
  */
10
- export declare function createFunctionRoutes(functions: LoadedFunction[]): Hono<HonoEnv>;
16
+ export declare function createFunctionRoutes(functions: LoadedFunction[], skipped?: number): Hono<HonoEnv>;
@@ -0,0 +1,34 @@
1
+ import type { MiddlewareHandler } from "hono";
2
+ import type { HonoEnv } from "../api/types";
3
+ /** Default ceiling for a custom function request, in milliseconds. */
4
+ export declare const DEFAULT_FUNCTIONS_TIMEOUT_MS = 30000;
5
+ /**
6
+ * Resolve the functions request timeout from config, then env, then the default.
7
+ *
8
+ * `0` (or any non-positive number) disables the ceiling — for a deployment
9
+ * whose proxy already imposes one, or a function that legitimately streams for
10
+ * minutes.
11
+ */
12
+ export declare function resolveFunctionsTimeoutMs(configured?: number): number;
13
+ /**
14
+ * A per-request ceiling for the custom functions router.
15
+ *
16
+ * Custom functions are the one router that runs code the framework did not
17
+ * write, and nothing else in the stack bounds how long that code takes: the
18
+ * Node server is constructed without `requestTimeout`/`headersTimeout`, so a
19
+ * handler awaiting a promise that never settles — a `fetch` to an unreachable
20
+ * third party with no `AbortSignal`, a query on a wedged connection — holds its
21
+ * socket and its request object until the client gives up. On the managed
22
+ * runtime the process is shared between tenants, so that is not only the slow
23
+ * caller's problem.
24
+ *
25
+ * The handler is **not** cancelled — it cannot be, there is no cancellation
26
+ * token to hand user code. What is bounded is the client-visible request: after
27
+ * `ms` the caller gets a 504 and the socket is released, and the handler's
28
+ * eventual result is dropped. It is a ceiling, not a kill switch, and the exact
29
+ * number matters far less than its existence.
30
+ *
31
+ * Mounted in front of the auth middleware rather than behind it, so a wedged
32
+ * driver — the failure that also hangs `withAuth()` — is covered too.
33
+ */
34
+ export declare function createFunctionsRequestTimeout(ms: number): MiddlewareHandler<HonoEnv>;
@@ -19,5 +19,11 @@ export interface HistoryService {
19
19
  export declare function createHistoryRoutes(params: {
20
20
  historyService: HistoryService;
21
21
  registry: BackendCollectionRegistry;
22
+ /**
23
+ * The unscoped driver, still accepted so the call in `init.ts` and any
24
+ * embedder's keeps compiling — and deliberately not read. Every read and
25
+ * write on these routes goes through the request-scoped driver instead;
26
+ * see {@link authorizeEntityRead}.
27
+ */
22
28
  driver: DataDriver;
23
29
  }): Hono<HonoEnv>;
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ export { loadCollectionsFromDirectory, applyCollectionDefaults, type CollectionD
14
14
  export { assertCollectionConfigs, findCollectionConfigProblems, unknownKeyPolicyFromEnv, type ConfigProblem, type UnknownKeyPolicy, type ValidateCollectionConfigOptions } from "./collections/validate-config";
15
15
  export * from "./db/interfaces";
16
16
  export * from "./auth/interfaces";
17
- export { requireAuth, requireAdmin, optionalAuth, queryTokenAuth, fileTokenAuth, extractUserFromToken, hashPassword, verifyPassword, validatePasswordStrength, generateSecurePassword, resolveAuthHooks, createBuiltinAuthAdapter, createCustomAuthAdapter, createGoogleProvider, createLinkedinProvider, createGitHubProvider, createMicrosoftProvider, createAppleProvider, createFacebookProvider, createTwitterProvider, createDiscordProvider, createGitLabProvider, createBitbucketProvider, createSlackProvider, createSpotifyProvider, isApiKeyToken, validateApiKey, httpMethodToOperation, isOperationAllowed, safeCompare } from "./auth";
17
+ export { requireAuth, requireAdmin, optionalAuth, queryTokenAuth, fileTokenAuth, extractUserFromToken, hashPassword, verifyPassword, validatePasswordStrength, generateSecurePassword, resolveAuthHooks, createBuiltinAuthAdapter, createCustomAuthAdapter, createGoogleProvider, createLinkedinProvider, createGitHubProvider, createMicrosoftProvider, createAppleProvider, createFacebookProvider, createTwitterProvider, createDiscordProvider, createGitLabProvider, createBitbucketProvider, createSlackProvider, createSpotifyProvider, oauthCodeFlowSchema, pkceTokenParams, providerVerifiedEmail, verifyOidcIdToken, tryVerifyOidcIdToken, isApiKeyToken, validateApiKey, httpMethodToOperation, isOperationAllowed, safeCompare } from "./auth";
18
18
  export type { AccessTokenPayload, PasswordValidationResult, AuthHooks, AuthMethod, ResolvedAuthHooks, BuiltinAuthAdapterConfig, GoogleProviderConfig, AuthMiddlewareOptions, AuthResult, ApiKey, ApiKeyMasked, ApiKeyPermission, ApiKeyWithSecret, CreateApiKeyRequest, UpdateApiKeyRequest, ApiKeyStore, ApiKeyOperation } from "./auth";
19
19
  export * from "./api/types";
20
20
  export * from "./api/errors";
@@ -23,7 +23,7 @@ export * from "./storage";
23
23
  export { createHistoryRoutes } from "./history";
24
24
  export { loadFunctionsFromDirectory, createFunctionRoutes, defineFunction } from "./functions";
25
25
  export type { LoadedFunction, RebaseFunctionContext } from "./functions";
26
- export { loadCronJobsFromDirectory, CronScheduler, validateCronExpression, createCronRoutes, createCronStore, defineCron } from "./cron";
26
+ export { loadCronJobsFromDirectory, loadCronJobsWithDiagnostics, CronScheduler, validateCronExpression, createCronRoutes, createCronStore, defineCron } from "./cron";
27
27
  export type { LoadedCronJob, CronStore } from "./cron";
28
28
  export { createBackupRoutes, parseBackupDestination, parseBackupTimestamp, listBackupObjects, readBackupBytes } from "./backup";
29
29
  export type { BackupRoutesConfig, BackupDestination } from "./backup";
@@ -35,6 +35,7 @@ export type { RebaseEnv } from "./env";
35
35
  export * from "./types";
36
36
  export * from "./services/driver-registry";
37
37
  export * from "./services/webhook-service";
38
+ export * from "./services/outbound-url-guard";
38
39
  export { cleanupDevPortFile, listenWithPortRetry } from "./utils/dev-port";
39
40
  export { serveSPA } from "./serve-spa";
40
41
  export { installShutdownHandlers } from "./init/shutdown";