@rebasepro/server-core 0.1.0 → 0.2.1

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 (148) hide show
  1. package/LICENSE +22 -6
  2. package/dist/common/src/util/entities.d.ts +2 -2
  3. package/dist/common/src/util/relations.d.ts +1 -1
  4. package/dist/{index-DXVBFp5V.js → index-BZoAtuqi.js} +6 -2
  5. package/dist/index-BZoAtuqi.js.map +1 -0
  6. package/dist/index.es.js +15909 -16083
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/index.umd.js +15847 -16017
  9. package/dist/index.umd.js.map +1 -1
  10. package/dist/server-core/src/auth/adapter-middleware.d.ts +33 -0
  11. package/dist/server-core/src/auth/admin-routes.d.ts +6 -0
  12. package/dist/server-core/src/auth/auth-overrides.d.ts +139 -0
  13. package/dist/server-core/src/auth/builtin-auth-adapter.d.ts +49 -0
  14. package/dist/server-core/src/auth/crypto-utils.d.ts +16 -0
  15. package/dist/server-core/src/auth/custom-auth-adapter.d.ts +39 -0
  16. package/dist/server-core/src/auth/index.d.ts +7 -0
  17. package/dist/server-core/src/auth/interfaces.d.ts +2 -0
  18. package/dist/server-core/src/auth/middleware.d.ts +18 -0
  19. package/dist/server-core/src/auth/rls-scope.d.ts +31 -0
  20. package/dist/server-core/src/auth/routes.d.ts +7 -1
  21. package/dist/server-core/src/env.d.ts +131 -0
  22. package/dist/server-core/src/index.d.ts +2 -0
  23. package/dist/server-core/src/init.d.ts +62 -3
  24. package/dist/types/src/controllers/auth.d.ts +9 -8
  25. package/dist/types/src/controllers/client.d.ts +3 -0
  26. package/dist/types/src/types/auth_adapter.d.ts +356 -0
  27. package/dist/types/src/types/collections.d.ts +67 -2
  28. package/dist/types/src/types/database_adapter.d.ts +94 -0
  29. package/dist/types/src/types/entity_actions.d.ts +7 -1
  30. package/dist/types/src/types/entity_callbacks.d.ts +1 -1
  31. package/dist/types/src/types/entity_views.d.ts +36 -1
  32. package/dist/types/src/types/index.d.ts +2 -0
  33. package/dist/types/src/types/plugins.d.ts +1 -1
  34. package/dist/types/src/types/properties.d.ts +24 -5
  35. package/dist/types/src/types/property_config.d.ts +6 -2
  36. package/dist/types/src/types/relations.d.ts +1 -1
  37. package/dist/types/src/types/translations.d.ts +8 -0
  38. package/dist/types/src/users/user.d.ts +5 -0
  39. package/package.json +26 -26
  40. package/src/api/errors.ts +1 -1
  41. package/src/api/graphql/graphql-schema-generator.ts +7 -0
  42. package/src/api/openapi-generator.ts +13 -1
  43. package/src/api/rest/api-generator-count.test.ts +14 -12
  44. package/src/api/rest/query-parser.ts +2 -20
  45. package/src/auth/adapter-middleware.ts +83 -0
  46. package/src/auth/admin-routes.ts +36 -43
  47. package/src/auth/auth-overrides.ts +172 -0
  48. package/src/auth/builtin-auth-adapter.ts +384 -0
  49. package/src/auth/crypto-utils.ts +31 -0
  50. package/src/auth/custom-auth-adapter.ts +85 -0
  51. package/src/auth/index.ts +10 -0
  52. package/src/auth/interfaces.ts +2 -0
  53. package/src/auth/jwt.ts +3 -1
  54. package/src/auth/middleware.ts +2 -46
  55. package/src/auth/rls-scope.ts +58 -0
  56. package/src/auth/routes.ts +74 -32
  57. package/src/cron/cron-scheduler.test.ts +9 -9
  58. package/src/cron/cron-scheduler.ts +1 -1
  59. package/src/env.ts +224 -0
  60. package/src/index.ts +4 -0
  61. package/src/init.ts +355 -135
  62. package/src/storage/routes.ts +1 -19
  63. package/src/utils/logging.ts +3 -3
  64. package/test/admin-routes.test.ts +10 -4
  65. package/test/auth-routes.test.ts +2 -2
  66. package/test/backend-hooks-admin.test.ts +32 -12
  67. package/test/custom-auth-adapter.test.ts +177 -0
  68. package/test/env.test.ts +138 -0
  69. package/test/query-parser.test.ts +0 -29
  70. package/tsconfig.json +3 -0
  71. package/app/frontend/node_modules/esbuild/LICENSE.md +0 -21
  72. package/app/frontend/node_modules/esbuild/README.md +0 -3
  73. package/app/frontend/node_modules/esbuild/bin/esbuild +0 -220
  74. package/app/frontend/node_modules/esbuild/install.js +0 -285
  75. package/app/frontend/node_modules/esbuild/lib/main.d.ts +0 -705
  76. package/app/frontend/node_modules/esbuild/lib/main.js +0 -2239
  77. package/app/frontend/node_modules/esbuild/package.json +0 -46
  78. package/dist/index-DXVBFp5V.js.map +0 -1
  79. package/examples/firebase/node_modules/esbuild/LICENSE.md +0 -21
  80. package/examples/firebase/node_modules/esbuild/README.md +0 -3
  81. package/examples/firebase/node_modules/esbuild/bin/esbuild +0 -220
  82. package/examples/firebase/node_modules/esbuild/install.js +0 -285
  83. package/examples/firebase/node_modules/esbuild/lib/main.d.ts +0 -705
  84. package/examples/firebase/node_modules/esbuild/lib/main.js +0 -2239
  85. package/examples/firebase/node_modules/esbuild/package.json +0 -46
  86. package/examples/medmot-staging/frontend/node_modules/esbuild/LICENSE.md +0 -21
  87. package/examples/medmot-staging/frontend/node_modules/esbuild/README.md +0 -3
  88. package/examples/medmot-staging/frontend/node_modules/esbuild/bin/esbuild +0 -220
  89. package/examples/medmot-staging/frontend/node_modules/esbuild/install.js +0 -285
  90. package/examples/medmot-staging/frontend/node_modules/esbuild/lib/main.d.ts +0 -705
  91. package/examples/medmot-staging/frontend/node_modules/esbuild/lib/main.js +0 -2239
  92. package/examples/medmot-staging/frontend/node_modules/esbuild/package.json +0 -46
  93. package/examples/sdk-demo/node_modules/esbuild/LICENSE.md +0 -21
  94. package/examples/sdk-demo/node_modules/esbuild/README.md +0 -3
  95. package/examples/sdk-demo/node_modules/esbuild/bin/esbuild +0 -223
  96. package/examples/sdk-demo/node_modules/esbuild/install.js +0 -289
  97. package/examples/sdk-demo/node_modules/esbuild/lib/main.d.ts +0 -716
  98. package/examples/sdk-demo/node_modules/esbuild/lib/main.js +0 -2242
  99. package/examples/sdk-demo/node_modules/esbuild/package.json +0 -49
  100. package/packages/client/node_modules/esbuild/LICENSE.md +0 -21
  101. package/packages/client/node_modules/esbuild/README.md +0 -3
  102. package/packages/client/node_modules/esbuild/bin/esbuild +0 -220
  103. package/packages/client/node_modules/esbuild/install.js +0 -285
  104. package/packages/client/node_modules/esbuild/lib/main.d.ts +0 -705
  105. package/packages/client/node_modules/esbuild/lib/main.js +0 -2239
  106. package/packages/client/node_modules/esbuild/package.json +0 -46
  107. package/packages/client-postgresql/node_modules/esbuild/LICENSE.md +0 -21
  108. package/packages/client-postgresql/node_modules/esbuild/README.md +0 -3
  109. package/packages/client-postgresql/node_modules/esbuild/bin/esbuild +0 -220
  110. package/packages/client-postgresql/node_modules/esbuild/install.js +0 -285
  111. package/packages/client-postgresql/node_modules/esbuild/lib/main.d.ts +0 -705
  112. package/packages/client-postgresql/node_modules/esbuild/lib/main.js +0 -2239
  113. package/packages/client-postgresql/node_modules/esbuild/package.json +0 -46
  114. package/packages/common/node_modules/esbuild/LICENSE.md +0 -21
  115. package/packages/common/node_modules/esbuild/README.md +0 -3
  116. package/packages/common/node_modules/esbuild/bin/esbuild +0 -220
  117. package/packages/common/node_modules/esbuild/install.js +0 -285
  118. package/packages/common/node_modules/esbuild/lib/main.d.ts +0 -705
  119. package/packages/common/node_modules/esbuild/lib/main.js +0 -2239
  120. package/packages/common/node_modules/esbuild/package.json +0 -46
  121. package/packages/server-mongodb/node_modules/esbuild/LICENSE.md +0 -21
  122. package/packages/server-mongodb/node_modules/esbuild/README.md +0 -3
  123. package/packages/server-mongodb/node_modules/esbuild/bin/esbuild +0 -220
  124. package/packages/server-mongodb/node_modules/esbuild/install.js +0 -285
  125. package/packages/server-mongodb/node_modules/esbuild/lib/main.d.ts +0 -705
  126. package/packages/server-mongodb/node_modules/esbuild/lib/main.js +0 -2239
  127. package/packages/server-mongodb/node_modules/esbuild/package.json +0 -46
  128. package/packages/server-postgresql/node_modules/esbuild/LICENSE.md +0 -21
  129. package/packages/server-postgresql/node_modules/esbuild/README.md +0 -3
  130. package/packages/server-postgresql/node_modules/esbuild/bin/esbuild +0 -220
  131. package/packages/server-postgresql/node_modules/esbuild/install.js +0 -285
  132. package/packages/server-postgresql/node_modules/esbuild/lib/main.d.ts +0 -705
  133. package/packages/server-postgresql/node_modules/esbuild/lib/main.js +0 -2239
  134. package/packages/server-postgresql/node_modules/esbuild/package.json +0 -46
  135. package/packages/types/node_modules/esbuild/LICENSE.md +0 -21
  136. package/packages/types/node_modules/esbuild/README.md +0 -3
  137. package/packages/types/node_modules/esbuild/bin/esbuild +0 -220
  138. package/packages/types/node_modules/esbuild/install.js +0 -285
  139. package/packages/types/node_modules/esbuild/lib/main.d.ts +0 -705
  140. package/packages/types/node_modules/esbuild/lib/main.js +0 -2239
  141. package/packages/types/node_modules/esbuild/package.json +0 -46
  142. package/packages/utils/node_modules/esbuild/LICENSE.md +0 -21
  143. package/packages/utils/node_modules/esbuild/README.md +0 -3
  144. package/packages/utils/node_modules/esbuild/bin/esbuild +0 -220
  145. package/packages/utils/node_modules/esbuild/install.js +0 -285
  146. package/packages/utils/node_modules/esbuild/lib/main.d.ts +0 -705
  147. package/packages/utils/node_modules/esbuild/lib/main.js +0 -2239
  148. package/packages/utils/node_modules/esbuild/package.json +0 -46
package/src/env.ts ADDED
@@ -0,0 +1,224 @@
1
+ import { z } from "zod";
2
+ import * as crypto from "crypto";
3
+
4
+ /**
5
+ * Generate a cryptographically secure random secret (hex-encoded).
6
+ * Used as a fallback when secrets are not explicitly configured —
7
+ * avoids the need for hardcoded dev secrets.
8
+ */
9
+ function generateSecret(bytes = 48): string {
10
+ return crypto.randomBytes(bytes).toString("hex");
11
+ }
12
+
13
+ /**
14
+ * Zod coercion helper: transforms `"true"` → `true`, everything else → `false`.
15
+ */
16
+ const boolString = z.enum(["true", "false", ""]).default("false").transform(v => v === "true");
17
+
18
+ /**
19
+ * Zod coercion helper for optional boolean strings.
20
+ */
21
+ const optionalBoolString = z.enum(["true", "false", ""]).optional().transform(v => v === "true");
22
+
23
+ /**
24
+ * Helper to determine if a string is a localhost or loopback address/URL.
25
+ */
26
+ function isLocalhostOrLoopback(value: string): boolean {
27
+ const trimmed = value.trim();
28
+ if (!trimmed) return false;
29
+
30
+ // 1. Try parsing as URL
31
+ try {
32
+ const parsed = new URL(trimmed);
33
+ const host = parsed.hostname.toLowerCase();
34
+ if (
35
+ host === "localhost" ||
36
+ host === "127.0.0.1" ||
37
+ host === "::1" ||
38
+ host.startsWith("127.")
39
+ ) {
40
+ return true;
41
+ }
42
+ } catch {
43
+ // Not a standard URL, or custom protocol that URL class fails to parse
44
+ }
45
+
46
+ // 2. Custom protocol parser fallback (e.g. postgres://, mongodb://, etc.)
47
+ const protocolMatch = trimmed.match(/^[a-zA-Z0-9+-.]+:\/\/(?:[^@/]+@)?(?:\[([^\]]+)\]|([^:/]+))/);
48
+ if (protocolMatch) {
49
+ const host = (protocolMatch[1] || protocolMatch[2] || "").toLowerCase();
50
+ if (
51
+ host === "localhost" ||
52
+ host === "127.0.0.1" ||
53
+ host === "::1" ||
54
+ host.startsWith("127.")
55
+ ) {
56
+ return true;
57
+ }
58
+ }
59
+
60
+ // 3. Plain hostname / host:port checker (e.g. "localhost", "127.0.0.1:5432", "[::1]:6379")
61
+ let plainHost = trimmed.toLowerCase();
62
+ if (plainHost.startsWith("[") && plainHost.includes("]")) {
63
+ const endBracket = plainHost.indexOf("]");
64
+ plainHost = plainHost.slice(1, endBracket);
65
+ } else {
66
+ const colonIndex = plainHost.lastIndexOf(":");
67
+ if (colonIndex !== -1 && plainHost.indexOf(":") === colonIndex) {
68
+ plainHost = plainHost.substring(0, colonIndex);
69
+ }
70
+ }
71
+
72
+ if (
73
+ plainHost === "localhost" ||
74
+ plainHost === "127.0.0.1" ||
75
+ plainHost === "::1" ||
76
+ plainHost.startsWith("127.")
77
+ ) {
78
+ return true;
79
+ }
80
+
81
+ return false;
82
+ }
83
+
84
+ /**
85
+ * The full set of environment variables recognized by a Rebase backend.
86
+ */
87
+ const rebaseEnvSchema = z.object({
88
+ NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
89
+ PORT: z.string().default("3001").transform(Number),
90
+ DATABASE_URL: z.string().url("DATABASE_URL must be a valid URL"),
91
+ ADMIN_CONNECTION_STRING: z.string().url().optional(),
92
+ JWT_SECRET: z.string().min(32, "JWT_SECRET must be at least 32 characters long"),
93
+ JWT_ACCESS_EXPIRES_IN: z.string().default("1h"),
94
+ JWT_REFRESH_EXPIRES_IN: z.string().default("30d"),
95
+ GOOGLE_CLIENT_ID: z.string().optional(),
96
+ GOOGLE_CLIENT_SECRET: z.string().optional(),
97
+ REBASE_SERVICE_KEY: z.string().optional(),
98
+ ALLOW_REGISTRATION: boolString,
99
+ ALLOW_LOCALHOST_IN_PRODUCTION: optionalBoolString,
100
+ CORS_ORIGINS: z.string().optional(),
101
+ FRONTEND_URL: z.string().optional(),
102
+ DB_POOL_MAX: z.string().default("20").transform(Number),
103
+ DB_POOL_IDLE_TIMEOUT: z.string().default("30000").transform(Number),
104
+ DB_POOL_CONNECT_TIMEOUT: z.string().default("10000").transform(Number),
105
+ FORCE_LOCAL_STORAGE: optionalBoolString,
106
+ STORAGE_TYPE: z.enum(["local", "s3"]).default("local"),
107
+ STORAGE_PATH: z.string().optional(),
108
+ S3_BUCKET: z.string().optional(),
109
+ S3_REGION: z.string().optional(),
110
+ S3_ACCESS_KEY_ID: z.string().optional(),
111
+ S3_SECRET_ACCESS_KEY: z.string().optional(),
112
+ S3_ENDPOINT: z.string().url().optional(),
113
+ S3_FORCE_PATH_STYLE: optionalBoolString,
114
+ });
115
+
116
+ /** Inferred type of the validated environment. */
117
+ export type RebaseEnv = z.infer<typeof rebaseEnvSchema>;
118
+
119
+ /**
120
+ * Load and validate the Rebase environment configuration from `process.env`.
121
+ *
122
+ * Call this **after** your `.env` file has been loaded (via `dotenv`, `--env-file`,
123
+ * container injection, etc.). This function does not load `.env` files itself —
124
+ * that is a deployment concern, not a framework concern.
125
+ *
126
+ * Behavior:
127
+ * - Auto-generates ephemeral `JWT_SECRET` and `REBASE_SERVICE_KEY` in
128
+ * non-production mode so developers can start without manual setup.
129
+ * - Blocks auto-generated secrets in production.
130
+ * - Returns a fully typed, validated env object.
131
+ *
132
+ * Use `extend` to add your own typed env variables on top of the base Rebase schema:
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * import dotenv from "dotenv";
137
+ * import { z } from "zod";
138
+ * import { loadEnv } from "@rebasepro/server-core";
139
+ *
140
+ * dotenv.config({ path: "../../.env" });
141
+ *
142
+ * // Basic — just Rebase env vars:
143
+ * export const env = loadEnv();
144
+ *
145
+ * // Extended — add your own typed vars:
146
+ * export const env = loadEnv({
147
+ * extend: z.object({
148
+ * SMTP_HOST: z.string().optional(),
149
+ * SMTP_PORT: z.string().default("587").transform(Number),
150
+ * STRIPE_SECRET_KEY: z.string(),
151
+ * })
152
+ * });
153
+ * // env.SMTP_HOST → string | undefined (fully typed)
154
+ * // env.STRIPE_SECRET_KEY → string (validated, required)
155
+ * ```
156
+ */
157
+ export function loadEnv(): RebaseEnv;
158
+ export function loadEnv<E extends z.AnyZodObject>(options: { extend: E }): RebaseEnv & z.infer<E>;
159
+ export function loadEnv(options?: { extend?: z.AnyZodObject }): Record<string, unknown> {
160
+ // Auto-generate dev secrets before validation so the Zod schema sees valid values.
161
+ const isProduction = process.env.NODE_ENV === "production";
162
+ const autoGeneratedSecrets: string[] = [];
163
+
164
+ if (!isProduction) {
165
+ if (!process.env.JWT_SECRET) {
166
+ process.env.JWT_SECRET = generateSecret();
167
+ autoGeneratedSecrets.push("JWT_SECRET");
168
+ }
169
+ if (!process.env.REBASE_SERVICE_KEY) {
170
+ process.env.REBASE_SERVICE_KEY = generateSecret();
171
+ autoGeneratedSecrets.push("REBASE_SERVICE_KEY");
172
+ }
173
+ }
174
+
175
+ // Merge base schema with user extensions (if provided).
176
+ const combinedSchema = options?.extend
177
+ ? rebaseEnvSchema.merge(options.extend)
178
+ : rebaseEnvSchema;
179
+
180
+ // Validate with production-specific refinements.
181
+ const schema = combinedSchema.superRefine((data, ctx) => {
182
+ const d = data as RebaseEnv & Record<string, unknown>;
183
+ if (d.NODE_ENV === "production" && !d.CORS_ORIGINS && !d.FRONTEND_URL) {
184
+ ctx.addIssue({
185
+ code: z.ZodIssueCode.custom,
186
+ message: "CORS_ORIGINS or FRONTEND_URL must be set in production to secure the API.",
187
+ path: ["CORS_ORIGINS"],
188
+ });
189
+ }
190
+ if (d.NODE_ENV === "production" && autoGeneratedSecrets.length > 0) {
191
+ ctx.addIssue({
192
+ code: z.ZodIssueCode.custom,
193
+ message: `${autoGeneratedSecrets.join(", ")} must be explicitly set in production. ` +
194
+ `Do not rely on auto-generated secrets outside development.`,
195
+ path: [autoGeneratedSecrets[0]],
196
+ });
197
+ }
198
+ if (d.NODE_ENV === "production" && !d.ALLOW_LOCALHOST_IN_PRODUCTION) {
199
+ for (const [key, value] of Object.entries(data)) {
200
+ if (key === "CORS_ORIGINS") continue;
201
+ if (typeof value === "string" && isLocalhostOrLoopback(value)) {
202
+ ctx.addIssue({
203
+ code: z.ZodIssueCode.custom,
204
+ message: `Environment variable ${key} contains a local/loopback URL or host "${value}". Deployed instances must not connect to localhost.`,
205
+ path: [key],
206
+ });
207
+ }
208
+ }
209
+ }
210
+ });
211
+
212
+ const env = schema.parse(process.env);
213
+
214
+ // Warn after successful parse so the server still starts in dev.
215
+ if (autoGeneratedSecrets.length > 0) {
216
+ console.warn(
217
+ `⚠️ Auto-generated secrets for: ${autoGeneratedSecrets.join(", ")}. ` +
218
+ `These are ephemeral — existing tokens will be invalidated on restart. ` +
219
+ `Set them explicitly in .env for persistent sessions.`,
220
+ );
221
+ }
222
+
223
+ return env as Record<string, unknown>;
224
+ }
package/src/index.ts CHANGED
@@ -62,5 +62,9 @@ export * from "./serve-spa";
62
62
  // Dev-mode port resolution (retry on EADDRINUSE)
63
63
  export * from "./utils/dev-port";
64
64
 
65
+ // Environment validation
66
+ export { loadEnv } from "./env";
67
+ export type { RebaseEnv } from "./env";
68
+
65
69
  // Backend bootstrappers (pluggable driver initialization)
66
70