@rebasepro/server-core 0.0.1-canary.f81da60 → 0.1.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 (108) hide show
  1. package/app/frontend/node_modules/esbuild/LICENSE.md +21 -0
  2. package/app/frontend/node_modules/esbuild/README.md +3 -0
  3. package/app/frontend/node_modules/esbuild/bin/esbuild +220 -0
  4. package/app/frontend/node_modules/esbuild/install.js +285 -0
  5. package/app/frontend/node_modules/esbuild/lib/main.d.ts +705 -0
  6. package/app/frontend/node_modules/esbuild/lib/main.js +2239 -0
  7. package/app/frontend/node_modules/esbuild/package.json +46 -0
  8. package/dist/index.es.js +140 -28
  9. package/dist/index.es.js.map +1 -1
  10. package/dist/index.umd.js +140 -28
  11. package/dist/index.umd.js.map +1 -1
  12. package/dist/server-core/src/auth/google-oauth.d.ts +33 -3
  13. package/dist/server-core/src/auth/index.d.ts +1 -0
  14. package/dist/server-core/src/init.d.ts +1 -0
  15. package/dist/types/src/controllers/auth.d.ts +8 -2
  16. package/dist/types/src/controllers/client.d.ts +13 -0
  17. package/dist/types/src/controllers/navigation.d.ts +18 -6
  18. package/dist/types/src/controllers/registry.d.ts +9 -1
  19. package/dist/types/src/controllers/side_entity_controller.d.ts +7 -0
  20. package/dist/types/src/rebase_context.d.ts +17 -0
  21. package/dist/types/src/types/collections.d.ts +20 -1
  22. package/dist/types/src/types/component_ref.d.ts +47 -0
  23. package/dist/types/src/types/entity_views.d.ts +2 -1
  24. package/dist/types/src/types/index.d.ts +1 -0
  25. package/dist/types/src/types/properties.d.ts +15 -3
  26. package/dist/types/src/types/translations.d.ts +2 -0
  27. package/examples/firebase/node_modules/esbuild/LICENSE.md +21 -0
  28. package/examples/firebase/node_modules/esbuild/README.md +3 -0
  29. package/examples/firebase/node_modules/esbuild/bin/esbuild +220 -0
  30. package/examples/firebase/node_modules/esbuild/install.js +285 -0
  31. package/examples/firebase/node_modules/esbuild/lib/main.d.ts +705 -0
  32. package/examples/firebase/node_modules/esbuild/lib/main.js +2239 -0
  33. package/examples/firebase/node_modules/esbuild/package.json +46 -0
  34. package/examples/medmot-staging/frontend/node_modules/esbuild/LICENSE.md +21 -0
  35. package/examples/medmot-staging/frontend/node_modules/esbuild/README.md +3 -0
  36. package/examples/medmot-staging/frontend/node_modules/esbuild/bin/esbuild +220 -0
  37. package/examples/medmot-staging/frontend/node_modules/esbuild/install.js +285 -0
  38. package/examples/medmot-staging/frontend/node_modules/esbuild/lib/main.d.ts +705 -0
  39. package/examples/medmot-staging/frontend/node_modules/esbuild/lib/main.js +2239 -0
  40. package/examples/medmot-staging/frontend/node_modules/esbuild/package.json +46 -0
  41. package/examples/sdk-demo/node_modules/esbuild/LICENSE.md +21 -0
  42. package/examples/sdk-demo/node_modules/esbuild/README.md +3 -0
  43. package/examples/sdk-demo/node_modules/esbuild/bin/esbuild +223 -0
  44. package/examples/sdk-demo/node_modules/esbuild/install.js +289 -0
  45. package/examples/sdk-demo/node_modules/esbuild/lib/main.d.ts +716 -0
  46. package/examples/sdk-demo/node_modules/esbuild/lib/main.js +2242 -0
  47. package/examples/sdk-demo/node_modules/esbuild/package.json +49 -0
  48. package/package.json +7 -7
  49. package/packages/client/node_modules/esbuild/LICENSE.md +21 -0
  50. package/packages/client/node_modules/esbuild/README.md +3 -0
  51. package/packages/client/node_modules/esbuild/bin/esbuild +220 -0
  52. package/packages/client/node_modules/esbuild/install.js +285 -0
  53. package/packages/client/node_modules/esbuild/lib/main.d.ts +705 -0
  54. package/packages/client/node_modules/esbuild/lib/main.js +2239 -0
  55. package/packages/client/node_modules/esbuild/package.json +46 -0
  56. package/packages/client-postgresql/node_modules/esbuild/LICENSE.md +21 -0
  57. package/packages/client-postgresql/node_modules/esbuild/README.md +3 -0
  58. package/packages/client-postgresql/node_modules/esbuild/bin/esbuild +220 -0
  59. package/packages/client-postgresql/node_modules/esbuild/install.js +285 -0
  60. package/packages/client-postgresql/node_modules/esbuild/lib/main.d.ts +705 -0
  61. package/packages/client-postgresql/node_modules/esbuild/lib/main.js +2239 -0
  62. package/packages/client-postgresql/node_modules/esbuild/package.json +46 -0
  63. package/packages/common/node_modules/esbuild/LICENSE.md +21 -0
  64. package/packages/common/node_modules/esbuild/README.md +3 -0
  65. package/packages/common/node_modules/esbuild/bin/esbuild +220 -0
  66. package/packages/common/node_modules/esbuild/install.js +285 -0
  67. package/packages/common/node_modules/esbuild/lib/main.d.ts +705 -0
  68. package/packages/common/node_modules/esbuild/lib/main.js +2239 -0
  69. package/packages/common/node_modules/esbuild/package.json +46 -0
  70. package/packages/server-mongodb/node_modules/esbuild/LICENSE.md +21 -0
  71. package/packages/server-mongodb/node_modules/esbuild/README.md +3 -0
  72. package/packages/server-mongodb/node_modules/esbuild/bin/esbuild +220 -0
  73. package/packages/server-mongodb/node_modules/esbuild/install.js +285 -0
  74. package/packages/server-mongodb/node_modules/esbuild/lib/main.d.ts +705 -0
  75. package/packages/server-mongodb/node_modules/esbuild/lib/main.js +2239 -0
  76. package/packages/server-mongodb/node_modules/esbuild/package.json +46 -0
  77. package/packages/server-postgresql/node_modules/esbuild/LICENSE.md +21 -0
  78. package/packages/server-postgresql/node_modules/esbuild/README.md +3 -0
  79. package/packages/server-postgresql/node_modules/esbuild/bin/esbuild +220 -0
  80. package/packages/server-postgresql/node_modules/esbuild/install.js +285 -0
  81. package/packages/server-postgresql/node_modules/esbuild/lib/main.d.ts +705 -0
  82. package/packages/server-postgresql/node_modules/esbuild/lib/main.js +2239 -0
  83. package/packages/server-postgresql/node_modules/esbuild/package.json +46 -0
  84. package/packages/types/node_modules/esbuild/LICENSE.md +21 -0
  85. package/packages/types/node_modules/esbuild/README.md +3 -0
  86. package/packages/types/node_modules/esbuild/bin/esbuild +220 -0
  87. package/packages/types/node_modules/esbuild/install.js +285 -0
  88. package/packages/types/node_modules/esbuild/lib/main.d.ts +705 -0
  89. package/packages/types/node_modules/esbuild/lib/main.js +2239 -0
  90. package/packages/types/node_modules/esbuild/package.json +46 -0
  91. package/packages/utils/node_modules/esbuild/LICENSE.md +21 -0
  92. package/packages/utils/node_modules/esbuild/README.md +3 -0
  93. package/packages/utils/node_modules/esbuild/bin/esbuild +220 -0
  94. package/packages/utils/node_modules/esbuild/install.js +285 -0
  95. package/packages/utils/node_modules/esbuild/lib/main.d.ts +705 -0
  96. package/packages/utils/node_modules/esbuild/lib/main.js +2239 -0
  97. package/packages/utils/node_modules/esbuild/package.json +46 -0
  98. package/src/api/errors.ts +3 -2
  99. package/src/api/server.ts +5 -2
  100. package/src/auth/google-oauth.ts +148 -17
  101. package/src/auth/index.ts +1 -0
  102. package/src/auth/routes.ts +25 -5
  103. package/src/collections/loader.ts +3 -3
  104. package/src/init.ts +14 -2
  105. package/history_diff.log +0 -385
  106. package/scratch.ts +0 -9
  107. package/test-ast.ts +0 -28
  108. package/test_output.txt +0 -1133
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "esbuild",
3
+ "version": "0.21.5",
4
+ "description": "An extremely fast JavaScript and CSS bundler and minifier.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/evanw/esbuild.git"
8
+ },
9
+ "scripts": {
10
+ "postinstall": "node install.js"
11
+ },
12
+ "main": "lib/main.js",
13
+ "types": "lib/main.d.ts",
14
+ "engines": {
15
+ "node": ">=12"
16
+ },
17
+ "bin": {
18
+ "esbuild": "bin/esbuild"
19
+ },
20
+ "optionalDependencies": {
21
+ "@esbuild/aix-ppc64": "0.21.5",
22
+ "@esbuild/android-arm": "0.21.5",
23
+ "@esbuild/android-arm64": "0.21.5",
24
+ "@esbuild/android-x64": "0.21.5",
25
+ "@esbuild/darwin-arm64": "0.21.5",
26
+ "@esbuild/darwin-x64": "0.21.5",
27
+ "@esbuild/freebsd-arm64": "0.21.5",
28
+ "@esbuild/freebsd-x64": "0.21.5",
29
+ "@esbuild/linux-arm": "0.21.5",
30
+ "@esbuild/linux-arm64": "0.21.5",
31
+ "@esbuild/linux-ia32": "0.21.5",
32
+ "@esbuild/linux-loong64": "0.21.5",
33
+ "@esbuild/linux-mips64el": "0.21.5",
34
+ "@esbuild/linux-ppc64": "0.21.5",
35
+ "@esbuild/linux-riscv64": "0.21.5",
36
+ "@esbuild/linux-s390x": "0.21.5",
37
+ "@esbuild/linux-x64": "0.21.5",
38
+ "@esbuild/netbsd-x64": "0.21.5",
39
+ "@esbuild/openbsd-x64": "0.21.5",
40
+ "@esbuild/sunos-x64": "0.21.5",
41
+ "@esbuild/win32-arm64": "0.21.5",
42
+ "@esbuild/win32-ia32": "0.21.5",
43
+ "@esbuild/win32-x64": "0.21.5"
44
+ },
45
+ "license": "MIT"
46
+ }
package/src/api/errors.ts CHANGED
@@ -120,10 +120,11 @@ export const errorHandler: ErrorHandler = (err, c) => {
120
120
  `❌ [API] ${c.req.method} ${c.req.path} → ${statusCode} ${code}: ${logMessage}`
121
121
  );
122
122
 
123
- // Suppress the huge stack trace for known missing schema errors (it's noisy and not a code bug)
123
+ // Suppress the huge stack trace for known DB errors (it's noisy and leaks SQL)
124
124
  const causePg = (error.cause && typeof error.cause === "object") ? (error.cause as PgLikeError) : undefined;
125
125
  const pgErrorCode = causePg?.code || error.code;
126
- if (pgErrorCode !== "42703" && pgErrorCode !== "42P01") {
126
+ const suppressStack = pgErrorCode === "42703" || pgErrorCode === "42P01" || (statusCode < 500 && code === "BAD_REQUEST");
127
+ if (!suppressStack) {
127
128
  console.error(error.stack || error);
128
129
  }
129
130
 
package/src/api/server.ts CHANGED
@@ -69,8 +69,11 @@ export class RebaseApiServer {
69
69
  * Setup Hono middleware
70
70
  */
71
71
  private setupMiddleware(): void {
72
- // Security headers
73
- this.router.use("/*", secureHeaders());
72
+ // Security headers — use same-origin-allow-popups for COOP so that
73
+ // OAuth popup flows (Google, etc.) can postMessage back to the opener.
74
+ this.router.use("/*", secureHeaders({
75
+ crossOriginOpenerPolicy: "same-origin-allow-popups"
76
+ }));
74
77
 
75
78
  // CORS — only applied if explicitly configured via `cors` option.
76
79
  // If omitted, the user is expected to configure CORS on their own
@@ -10,26 +10,69 @@ export interface GoogleUserInfo {
10
10
  emailVerified: boolean;
11
11
  }
12
12
 
13
+ export interface GoogleProviderConfig {
14
+ clientId: string;
15
+ /**
16
+ * The OAuth 2.0 client secret from Google Cloud Console.
17
+ *
18
+ * Required for the **authorization code flow** (Path 3), where the
19
+ * frontend sends an authorization `code` and the backend exchanges it
20
+ * server-side for tokens. This is the most secure flow because tokens
21
+ * never touch the browser.
22
+ *
23
+ * When omitted, only ID-token and access-token verification are available
24
+ * (Paths 1 & 2), which rely on the frontend obtaining tokens directly.
25
+ */
26
+ clientSecret?: string;
27
+ }
28
+
13
29
  /**
14
30
  * Creates a Google OAuth Provider integration.
15
- * Supports both ID-token verification (One Tap / renderButton) and
16
- * access-token verification (popup via initTokenClient).
31
+ *
32
+ * Supports three verification paths:
33
+ *
34
+ * **Path 1 – ID Token** (One Tap / Sign In With Google button):
35
+ * Frontend sends `idToken`. Backend verifies cryptographically using
36
+ * Google's public keys. No secret required.
37
+ *
38
+ * **Path 2 – Access Token** (popup via `initTokenClient`):
39
+ * Frontend sends `accessToken`. Backend validates by calling Google's
40
+ * userinfo endpoint. No secret required.
41
+ *
42
+ * **Path 3 – Authorization Code** (most secure, requires `clientSecret`):
43
+ * Frontend sends `code` + `redirectUri`. Backend exchanges the code
44
+ * server-side for an ID token using `clientId` + `clientSecret`, then
45
+ * verifies the ID token. Tokens never touch the browser.
17
46
  */
18
- export function createGoogleProvider(clientId: string): OAuthProvider<{ idToken?: string; accessToken?: string }> {
19
- const googleClient = new OAuth2Client(clientId);
47
+ export function createGoogleProvider(config: GoogleProviderConfig | string): OAuthProvider<{
48
+ idToken?: string;
49
+ accessToken?: string;
50
+ code?: string;
51
+ redirectUri?: string;
52
+ }> {
53
+ const clientId = typeof config === "string" ? config : config.clientId;
54
+ const clientSecret = typeof config === "string" ? undefined : config.clientSecret;
55
+ const googleClient = new OAuth2Client(clientId, clientSecret);
20
56
 
21
57
  return {
22
58
  id: "google",
23
59
  schema: z.object({
24
60
  idToken: z.string().min(1).optional(),
25
- accessToken: z.string().min(1).optional()
61
+ accessToken: z.string().min(1).optional(),
62
+ code: z.string().min(1).optional(),
63
+ redirectUri: z.string().min(1).optional()
26
64
  }).refine(
27
- (data) => data.idToken || data.accessToken,
28
- { message: "Either idToken or accessToken is required" }
65
+ (data) => data.idToken || data.accessToken || (data.code && data.redirectUri),
66
+ { message: "One of idToken, accessToken, or code+redirectUri is required" }
29
67
  ),
30
- verify: async (payload: { idToken?: string; accessToken?: string }): Promise<OAuthProviderProfile | null> => {
68
+ verify: async (payload: {
69
+ idToken?: string;
70
+ accessToken?: string;
71
+ code?: string;
72
+ redirectUri?: string;
73
+ }): Promise<OAuthProviderProfile | null> => {
31
74
  try {
32
- // Path 1: verify an ID token (legacy / One Tap)
75
+ // Path 1: verify an ID token (One Tap / renderButton)
33
76
  if (payload.idToken) {
34
77
  const ticket = await googleClient.verifyIdToken({
35
78
  idToken: payload.idToken,
@@ -38,7 +81,7 @@ export function createGoogleProvider(clientId: string): OAuthProvider<{ idToken?
38
81
 
39
82
  const content = ticket.getPayload();
40
83
  if (!content) {
41
- return null;
84
+ throw new Error("Google ID token payload was empty");
42
85
  }
43
86
 
44
87
  return {
@@ -56,8 +99,7 @@ export function createGoogleProvider(clientId: string): OAuthProvider<{ idToken?
56
99
  { headers: { Authorization: `Bearer ${payload.accessToken}` } }
57
100
  );
58
101
  if (!res.ok) {
59
- console.error("Google userinfo request failed:", res.status);
60
- return null;
102
+ throw new Error(`Google userinfo request failed with status ${res.status}`);
61
103
  }
62
104
  const info = await res.json() as {
63
105
  sub: string;
@@ -66,7 +108,7 @@ export function createGoogleProvider(clientId: string): OAuthProvider<{ idToken?
66
108
  picture?: string;
67
109
  };
68
110
  if (!info.sub || !info.email) {
69
- return null;
111
+ throw new Error("Google userinfo response missing sub or email");
70
112
  }
71
113
  return {
72
114
  providerId: info.sub,
@@ -76,12 +118,101 @@ export function createGoogleProvider(clientId: string): OAuthProvider<{ idToken?
76
118
  };
77
119
  }
78
120
 
79
- return null;
121
+ // Path 3: authorization code exchange (most secure)
122
+ // The frontend obtained a one-time authorization code via the
123
+ // Google OAuth consent screen. We exchange it server-side for
124
+ // tokens, so the access/id tokens never touch the browser.
125
+ if (payload.code && payload.redirectUri) {
126
+ if (!clientSecret) {
127
+ throw new Error(
128
+ "Google authorization code flow requires clientSecret. " +
129
+ "Configure GOOGLE_CLIENT_SECRET in your environment."
130
+ );
131
+ }
132
+
133
+ // Exchange the authorization code for tokens
134
+ const tokenResponse = await fetch("https://oauth2.googleapis.com/token", {
135
+ method: "POST",
136
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
137
+ body: new URLSearchParams({
138
+ code: payload.code,
139
+ client_id: clientId,
140
+ client_secret: clientSecret,
141
+ redirect_uri: payload.redirectUri,
142
+ grant_type: "authorization_code"
143
+ })
144
+ });
145
+
146
+ if (!tokenResponse.ok) {
147
+ const errorBody = await tokenResponse.text();
148
+ throw new Error(`Google token exchange failed (${tokenResponse.status}): ${errorBody}`);
149
+ }
150
+
151
+ const tokenData = await tokenResponse.json() as {
152
+ id_token?: string;
153
+ access_token?: string;
154
+ error?: string;
155
+ error_description?: string;
156
+ };
157
+
158
+ if (tokenData.error) {
159
+ throw new Error(`Google token exchange error: ${tokenData.error} – ${tokenData.error_description || "no details"}`);
160
+ }
161
+
162
+ // Prefer verifying the ID token (cryptographic verification)
163
+ if (tokenData.id_token) {
164
+ const ticket = await googleClient.verifyIdToken({
165
+ idToken: tokenData.id_token,
166
+ audience: clientId
167
+ });
168
+
169
+ const content = ticket.getPayload();
170
+ if (!content) {
171
+ throw new Error("Google ID token payload was empty after code exchange");
172
+ }
173
+
174
+ return {
175
+ providerId: content.sub,
176
+ email: content.email || "",
177
+ displayName: content.name || null,
178
+ photoUrl: content.picture || null
179
+ };
180
+ }
181
+
182
+ // Fallback: use the access token to fetch userinfo
183
+ if (tokenData.access_token) {
184
+ const userInfoRes = await fetch(
185
+ "https://www.googleapis.com/oauth2/v3/userinfo",
186
+ { headers: { Authorization: `Bearer ${tokenData.access_token}` } }
187
+ );
188
+ if (!userInfoRes.ok) {
189
+ throw new Error(`Google userinfo request failed after code exchange (${userInfoRes.status})`);
190
+ }
191
+ const info = await userInfoRes.json() as {
192
+ sub: string;
193
+ email?: string;
194
+ name?: string;
195
+ picture?: string;
196
+ };
197
+ if (!info.sub || !info.email) {
198
+ return null;
199
+ }
200
+ return {
201
+ providerId: info.sub,
202
+ email: info.email,
203
+ displayName: info.name || null,
204
+ photoUrl: info.picture || null
205
+ };
206
+ }
207
+
208
+ throw new Error("Google token exchange returned neither id_token nor access_token");
209
+ }
210
+
211
+ throw new Error("No valid Google credential provided (expected idToken, accessToken, or code+redirectUri)");
80
212
  } catch (error) {
81
- console.error("Failed to verify Google token:", error);
82
- return null;
213
+ console.error("Google OAuth verification failed:", error);
214
+ throw error;
83
215
  }
84
216
  }
85
217
  };
86
218
  }
87
-
package/src/auth/index.ts CHANGED
@@ -9,6 +9,7 @@ export type { PasswordValidationResult } from "./password";
9
9
 
10
10
  // OAuth Providers
11
11
  export { createGoogleProvider } from "./google-oauth";
12
+ export type { GoogleProviderConfig } from "./google-oauth";
12
13
  export { createLinkedinProvider } from "./linkedin-oauth";
13
14
  export { createGitHubProvider } from "./github-oauth";
14
15
  export { createMicrosoftProvider } from "./microsoft-oauth";
@@ -233,8 +233,16 @@ export function createAuthRoutes(config: AuthModuleConfig): Hono<HonoEnv> {
233
233
  displayName: displayName || undefined
234
234
  });
235
235
 
236
- // Assign configured default role (never auto-assign admin via registration)
237
- if (config.defaultRole) {
236
+ // Auto-bootstrap: if this is the very first user in the system, promote to admin.
237
+ // This avoids the chicken-and-egg problem where the first user has no permissions
238
+ // and no way to access the bootstrap endpoint from the UI.
239
+ const existingUsers = await authRepo.listUsers();
240
+ const isFirstUser = existingUsers.length === 1 && existingUsers[0].id === user.id;
241
+
242
+ if (isFirstUser) {
243
+ await authRepo.setUserRoles(user.id, ["admin"]);
244
+ } else if (config.defaultRole) {
245
+ // Assign configured default role (never auto-assign admin via registration)
238
246
  await authRepo.assignDefaultRole(user.id, config.defaultRole);
239
247
  }
240
248
 
@@ -289,7 +297,13 @@ displayName: user.displayName });
289
297
  router.post(`/${provider.id}`, defaultAuthLimiter, async (c) => {
290
298
  const payload = parseBody(provider.schema, await c.req.json());
291
299
 
292
- const externalUser = await provider.verify(payload);
300
+ let externalUser;
301
+ try {
302
+ externalUser = await provider.verify(payload);
303
+ } catch (err: unknown) {
304
+ const msg = err instanceof Error ? err.message : String(err);
305
+ throw ApiError.unauthorized(`${provider.id} login failed: ${msg}`, "OAUTH_ERROR");
306
+ }
293
307
  if (!externalUser) {
294
308
  throw ApiError.unauthorized(`Invalid ${provider.id} credentials`, "INVALID_TOKEN");
295
309
  }
@@ -320,8 +334,14 @@ displayName: user.displayName });
320
334
 
321
335
  await authRepo.linkUserIdentity(user.id, provider.id, externalUser.providerId, { email: externalUser.email });
322
336
 
323
- // Assign configured default role (never auto-assign admin via registration)
324
- if (config.defaultRole) {
337
+ // Auto-bootstrap: first user in the system gets admin
338
+ const allUsers = await authRepo.listUsers();
339
+ const isFirstUser = allUsers.length === 1 && allUsers[0].id === user.id;
340
+
341
+ if (isFirstUser) {
342
+ await authRepo.setUserRoles(user.id, ["admin"]);
343
+ } else if (config.defaultRole) {
344
+ // Assign configured default role (never auto-assign admin via registration)
325
345
  await authRepo.assignDefaultRole(user.id, config.defaultRole);
326
346
  }
327
347
 
@@ -26,9 +26,9 @@ export async function loadCollectionsFromDirectory(directory: string): Promise<E
26
26
  try {
27
27
  const fileUrl = pathToFileURL(filePath).href;
28
28
 
29
- // Use new Function to compile dynamic import natively and bypass tsc converting import() to require()
30
- const dynamicImport = new Function("url", "return import(url)");
31
- const module = await dynamicImport(fileUrl);
29
+ // Use standard import() so that tsx/loader hooks can
30
+ // resolve .ts files and workspace bare-specifiers.
31
+ const module = await import(fileUrl);
32
32
 
33
33
  // Expect the collection to be the default export
34
34
  if (module && module.default) {
package/src/init.ts CHANGED
@@ -43,7 +43,7 @@ export interface RebaseAuthConfig {
43
43
  */
44
44
  serviceKey?: string;
45
45
  email?: EmailConfig;
46
- google?: { clientId: string };
46
+ google?: { clientId: string; clientSecret?: string };
47
47
  linkedin?: { clientId: string; clientSecret: string };
48
48
  github?: { clientId: string; clientSecret: string };
49
49
  microsoft?: { clientId: string; clientSecret: string; tenantId?: string };
@@ -355,7 +355,7 @@ collectionRegistry });
355
355
 
356
356
  if (config.auth.google?.clientId) {
357
357
  const { createGoogleProvider } = await import("./auth");
358
- oauthProviders.push(createGoogleProvider(config.auth.google.clientId));
358
+ oauthProviders.push(createGoogleProvider(config.auth.google));
359
359
  }
360
360
 
361
361
  if (config.auth.linkedin?.clientId && config.auth.linkedin?.clientSecret) {
@@ -582,6 +582,18 @@ collectionRegistry });
582
582
  _initRebase(serverClient);
583
583
  logger.info("Rebase singleton initialized");
584
584
 
585
+ // Retroactively inject the server client into the driver so that
586
+ // entity callbacks receive `context.client` at runtime.
587
+ // The driver is created before the client (which depends on the mounted
588
+ // Hono app), so we set it here, mirroring the historyService injection above.
589
+ if (defaultDriverResult.internals) {
590
+ const internals = defaultDriverResult.internals as Record<string, unknown>;
591
+ const driver = internals.driver as Record<string, unknown> | undefined;
592
+ if (driver && "client" in driver) {
593
+ driver.client = serverClient;
594
+ }
595
+ }
596
+
585
597
  // 5. Mount Custom Functions
586
598
  if (config.functionsDir) {
587
599
  const { loadFunctionsFromDirectory } = await import("./functions/function-loader");