@rebasepro/server-core 0.0.1-canary.09e5ec5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +6 -0
- package/README.md +40 -0
- package/build-errors.txt +52 -0
- package/coverage/clover.xml +3739 -0
- package/coverage/coverage-final.json +31 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +266 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/api/ast-schema-editor.ts.html +952 -0
- package/coverage/lcov-report/src/api/errors.ts.html +472 -0
- package/coverage/lcov-report/src/api/graphql/graphql-schema-generator.ts.html +1069 -0
- package/coverage/lcov-report/src/api/graphql/index.html +116 -0
- package/coverage/lcov-report/src/api/index.html +176 -0
- package/coverage/lcov-report/src/api/openapi-generator.ts.html +565 -0
- package/coverage/lcov-report/src/api/rest/api-generator.ts.html +994 -0
- package/coverage/lcov-report/src/api/rest/index.html +131 -0
- package/coverage/lcov-report/src/api/rest/query-parser.ts.html +550 -0
- package/coverage/lcov-report/src/api/schema-editor-routes.ts.html +202 -0
- package/coverage/lcov-report/src/api/server.ts.html +823 -0
- package/coverage/lcov-report/src/auth/admin-routes.ts.html +973 -0
- package/coverage/lcov-report/src/auth/index.html +176 -0
- package/coverage/lcov-report/src/auth/jwt.ts.html +574 -0
- package/coverage/lcov-report/src/auth/middleware.ts.html +745 -0
- package/coverage/lcov-report/src/auth/password.ts.html +310 -0
- package/coverage/lcov-report/src/auth/services.ts.html +2074 -0
- package/coverage/lcov-report/src/collections/index.html +116 -0
- package/coverage/lcov-report/src/collections/loader.ts.html +232 -0
- package/coverage/lcov-report/src/db/auth-schema.ts.html +523 -0
- package/coverage/lcov-report/src/db/data-transformer.ts.html +1753 -0
- package/coverage/lcov-report/src/db/entityService.ts.html +700 -0
- package/coverage/lcov-report/src/db/index.html +146 -0
- package/coverage/lcov-report/src/db/services/EntityFetchService.ts.html +4048 -0
- package/coverage/lcov-report/src/db/services/EntityPersistService.ts.html +883 -0
- package/coverage/lcov-report/src/db/services/RelationService.ts.html +3121 -0
- package/coverage/lcov-report/src/db/services/entity-helpers.ts.html +442 -0
- package/coverage/lcov-report/src/db/services/index.html +176 -0
- package/coverage/lcov-report/src/db/services/index.ts.html +124 -0
- package/coverage/lcov-report/src/generate-drizzle-schema-logic.ts.html +1960 -0
- package/coverage/lcov-report/src/index.html +116 -0
- package/coverage/lcov-report/src/services/driver-registry.ts.html +631 -0
- package/coverage/lcov-report/src/services/index.html +131 -0
- package/coverage/lcov-report/src/services/postgresDataDriver.ts.html +3025 -0
- package/coverage/lcov-report/src/storage/LocalStorageController.ts.html +1189 -0
- package/coverage/lcov-report/src/storage/S3StorageController.ts.html +970 -0
- package/coverage/lcov-report/src/storage/index.html +161 -0
- package/coverage/lcov-report/src/storage/storage-registry.ts.html +646 -0
- package/coverage/lcov-report/src/storage/types.ts.html +451 -0
- package/coverage/lcov-report/src/utils/drizzle-conditions.ts.html +3082 -0
- package/coverage/lcov-report/src/utils/index.html +116 -0
- package/coverage/lcov.info +7179 -0
- package/dist/common/src/collections/CollectionRegistry.d.ts +56 -0
- package/dist/common/src/collections/index.d.ts +1 -0
- package/dist/common/src/data/buildRebaseData.d.ts +14 -0
- package/dist/common/src/index.d.ts +3 -0
- package/dist/common/src/util/builders.d.ts +57 -0
- package/dist/common/src/util/callbacks.d.ts +6 -0
- package/dist/common/src/util/collections.d.ts +11 -0
- package/dist/common/src/util/common.d.ts +2 -0
- package/dist/common/src/util/conditions.d.ts +26 -0
- package/dist/common/src/util/entities.d.ts +58 -0
- package/dist/common/src/util/enums.d.ts +3 -0
- package/dist/common/src/util/index.d.ts +16 -0
- package/dist/common/src/util/navigation_from_path.d.ts +34 -0
- package/dist/common/src/util/navigation_utils.d.ts +20 -0
- package/dist/common/src/util/parent_references_from_path.d.ts +6 -0
- package/dist/common/src/util/paths.d.ts +14 -0
- package/dist/common/src/util/permissions.d.ts +5 -0
- package/dist/common/src/util/references.d.ts +2 -0
- package/dist/common/src/util/relations.d.ts +22 -0
- package/dist/common/src/util/resolutions.d.ts +72 -0
- package/dist/common/src/util/storage.d.ts +24 -0
- package/dist/index-DXVBFp5V.js +37 -0
- package/dist/index-DXVBFp5V.js.map +1 -0
- package/dist/index.es.js +49934 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +49968 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/server-core/src/api/ast-schema-editor.d.ts +21 -0
- package/dist/server-core/src/api/collections_for_test/callbacks_test_collection.d.ts +2 -0
- package/dist/server-core/src/api/errors.d.ts +35 -0
- package/dist/server-core/src/api/graphql/graphql-schema-generator.d.ts +35 -0
- package/dist/server-core/src/api/graphql/index.d.ts +1 -0
- package/dist/server-core/src/api/index.d.ts +9 -0
- package/dist/server-core/src/api/openapi-generator.d.ts +16 -0
- package/dist/server-core/src/api/rest/api-generator.d.ts +64 -0
- package/dist/server-core/src/api/rest/index.d.ts +1 -0
- package/dist/server-core/src/api/rest/query-parser.d.ts +9 -0
- package/dist/server-core/src/api/schema-editor-routes.d.ts +3 -0
- package/dist/server-core/src/api/server.d.ts +40 -0
- package/dist/server-core/src/api/types.d.ts +90 -0
- package/dist/server-core/src/auth/admin-routes.d.ts +16 -0
- package/dist/server-core/src/auth/apple-oauth.d.ts +30 -0
- package/dist/server-core/src/auth/bitbucket-oauth.d.ts +11 -0
- package/dist/server-core/src/auth/discord-oauth.d.ts +14 -0
- package/dist/server-core/src/auth/facebook-oauth.d.ts +14 -0
- package/dist/server-core/src/auth/github-oauth.d.ts +15 -0
- package/dist/server-core/src/auth/gitlab-oauth.d.ts +13 -0
- package/dist/server-core/src/auth/google-oauth.d.ts +14 -0
- package/dist/server-core/src/auth/index.d.ts +23 -0
- package/dist/server-core/src/auth/interfaces.d.ts +309 -0
- package/dist/server-core/src/auth/jwt.d.ts +43 -0
- package/dist/server-core/src/auth/linkedin-oauth.d.ts +18 -0
- package/dist/server-core/src/auth/microsoft-oauth.d.ts +16 -0
- package/dist/server-core/src/auth/middleware.d.ts +81 -0
- package/dist/server-core/src/auth/password.d.ts +22 -0
- package/dist/server-core/src/auth/rate-limiter.d.ts +31 -0
- package/dist/server-core/src/auth/routes.d.ts +27 -0
- package/dist/server-core/src/auth/slack-oauth.d.ts +12 -0
- package/dist/server-core/src/auth/spotify-oauth.d.ts +12 -0
- package/dist/server-core/src/auth/twitter-oauth.d.ts +18 -0
- package/dist/server-core/src/bootstrappers/index.d.ts +0 -0
- package/dist/server-core/src/collections/BackendCollectionRegistry.d.ts +13 -0
- package/dist/server-core/src/collections/loader.d.ts +5 -0
- package/dist/server-core/src/cron/cron-loader.d.ts +17 -0
- package/dist/server-core/src/cron/cron-routes.d.ts +14 -0
- package/dist/server-core/src/cron/cron-scheduler.d.ts +61 -0
- package/dist/server-core/src/cron/cron-store.d.ts +32 -0
- package/dist/server-core/src/cron/index.d.ts +6 -0
- package/dist/server-core/src/db/interfaces.d.ts +18 -0
- package/dist/server-core/src/email/index.d.ts +6 -0
- package/dist/server-core/src/email/smtp-email-service.d.ts +25 -0
- package/dist/server-core/src/email/templates.d.ts +42 -0
- package/dist/server-core/src/email/types.d.ts +107 -0
- package/dist/server-core/src/functions/function-loader.d.ts +17 -0
- package/dist/server-core/src/functions/function-routes.d.ts +10 -0
- package/dist/server-core/src/functions/index.d.ts +3 -0
- package/dist/server-core/src/history/history-routes.d.ts +23 -0
- package/dist/server-core/src/history/index.d.ts +1 -0
- package/dist/server-core/src/index.d.ts +29 -0
- package/dist/server-core/src/init.d.ts +159 -0
- package/dist/server-core/src/serve-spa.d.ts +30 -0
- package/dist/server-core/src/services/driver-registry.d.ts +78 -0
- package/dist/server-core/src/singleton.d.ts +35 -0
- package/dist/server-core/src/storage/LocalStorageController.d.ts +46 -0
- package/dist/server-core/src/storage/S3StorageController.d.ts +36 -0
- package/dist/server-core/src/storage/index.d.ts +25 -0
- package/dist/server-core/src/storage/routes.d.ts +38 -0
- package/dist/server-core/src/storage/storage-registry.d.ts +78 -0
- package/dist/server-core/src/storage/types.d.ts +103 -0
- package/dist/server-core/src/types/index.d.ts +11 -0
- package/dist/server-core/src/utils/dev-port.d.ts +35 -0
- package/dist/server-core/src/utils/logger.d.ts +31 -0
- package/dist/server-core/src/utils/logging.d.ts +9 -0
- package/dist/server-core/src/utils/request-logger.d.ts +19 -0
- package/dist/server-core/src/utils/sql.d.ts +27 -0
- package/dist/types/src/controllers/analytics_controller.d.ts +7 -0
- package/dist/types/src/controllers/auth.d.ts +119 -0
- package/dist/types/src/controllers/client.d.ts +170 -0
- package/dist/types/src/controllers/collection_registry.d.ts +45 -0
- package/dist/types/src/controllers/customization_controller.d.ts +60 -0
- package/dist/types/src/controllers/data.d.ts +168 -0
- package/dist/types/src/controllers/data_driver.d.ts +160 -0
- package/dist/types/src/controllers/database_admin.d.ts +11 -0
- package/dist/types/src/controllers/dialogs_controller.d.ts +36 -0
- package/dist/types/src/controllers/effective_role.d.ts +4 -0
- package/dist/types/src/controllers/email.d.ts +34 -0
- package/dist/types/src/controllers/index.d.ts +18 -0
- package/dist/types/src/controllers/local_config_persistence.d.ts +20 -0
- package/dist/types/src/controllers/navigation.d.ts +213 -0
- package/dist/types/src/controllers/registry.d.ts +54 -0
- package/dist/types/src/controllers/side_dialogs_controller.d.ts +67 -0
- package/dist/types/src/controllers/side_entity_controller.d.ts +90 -0
- package/dist/types/src/controllers/snackbar.d.ts +24 -0
- package/dist/types/src/controllers/storage.d.ts +171 -0
- package/dist/types/src/index.d.ts +4 -0
- package/dist/types/src/rebase_context.d.ts +105 -0
- package/dist/types/src/types/backend.d.ts +536 -0
- package/dist/types/src/types/builders.d.ts +15 -0
- package/dist/types/src/types/chips.d.ts +5 -0
- package/dist/types/src/types/collections.d.ts +856 -0
- package/dist/types/src/types/cron.d.ts +102 -0
- package/dist/types/src/types/data_source.d.ts +64 -0
- package/dist/types/src/types/entities.d.ts +145 -0
- package/dist/types/src/types/entity_actions.d.ts +98 -0
- package/dist/types/src/types/entity_callbacks.d.ts +173 -0
- package/dist/types/src/types/entity_link_builder.d.ts +7 -0
- package/dist/types/src/types/entity_overrides.d.ts +10 -0
- package/dist/types/src/types/entity_views.d.ts +61 -0
- package/dist/types/src/types/export_import.d.ts +21 -0
- package/dist/types/src/types/index.d.ts +23 -0
- package/dist/types/src/types/locales.d.ts +4 -0
- package/dist/types/src/types/modify_collections.d.ts +5 -0
- package/dist/types/src/types/plugins.d.ts +279 -0
- package/dist/types/src/types/properties.d.ts +1176 -0
- package/dist/types/src/types/property_config.d.ts +70 -0
- package/dist/types/src/types/relations.d.ts +336 -0
- package/dist/types/src/types/slots.d.ts +252 -0
- package/dist/types/src/types/translations.d.ts +870 -0
- package/dist/types/src/types/user_management_delegate.d.ts +121 -0
- package/dist/types/src/types/websockets.d.ts +78 -0
- package/dist/types/src/users/index.d.ts +2 -0
- package/dist/types/src/users/roles.d.ts +22 -0
- package/dist/types/src/users/user.d.ts +46 -0
- package/history_diff.log +385 -0
- package/jest.config.cjs +16 -0
- package/package.json +86 -0
- package/scratch.ts +9 -0
- package/src/api/ast-schema-editor.ts +289 -0
- package/src/api/collections_for_test/callbacks_test_collection.ts +60 -0
- package/src/api/errors.ts +179 -0
- package/src/api/graphql/graphql-schema-generator.ts +336 -0
- package/src/api/graphql/index.ts +2 -0
- package/src/api/index.ts +11 -0
- package/src/api/openapi-generator.ts +715 -0
- package/src/api/rest/api-generator.ts +472 -0
- package/src/api/rest/index.ts +2 -0
- package/src/api/rest/query-parser.ts +155 -0
- package/src/api/schema-editor-routes.ts +41 -0
- package/src/api/server.ts +248 -0
- package/src/api/types.ts +90 -0
- package/src/auth/admin-routes.ts +529 -0
- package/src/auth/apple-oauth.ts +130 -0
- package/src/auth/bitbucket-oauth.ts +82 -0
- package/src/auth/discord-oauth.ts +83 -0
- package/src/auth/facebook-oauth.ts +72 -0
- package/src/auth/github-oauth.ts +110 -0
- package/src/auth/gitlab-oauth.ts +70 -0
- package/src/auth/google-oauth.ts +48 -0
- package/src/auth/index.ts +34 -0
- package/src/auth/interfaces.ts +363 -0
- package/src/auth/jwt.ts +181 -0
- package/src/auth/linkedin-oauth.ts +81 -0
- package/src/auth/microsoft-oauth.ts +88 -0
- package/src/auth/middleware.ts +384 -0
- package/src/auth/password.ts +77 -0
- package/src/auth/rate-limiter.ts +129 -0
- package/src/auth/routes.ts +788 -0
- package/src/auth/slack-oauth.ts +71 -0
- package/src/auth/spotify-oauth.ts +67 -0
- package/src/auth/twitter-oauth.ts +120 -0
- package/src/bootstrappers/index.ts +1 -0
- package/src/collections/BackendCollectionRegistry.ts +20 -0
- package/src/collections/loader.ts +49 -0
- package/src/cron/cron-loader.ts +89 -0
- package/src/cron/cron-routes.test.ts +265 -0
- package/src/cron/cron-routes.ts +85 -0
- package/src/cron/cron-scheduler.test.ts +421 -0
- package/src/cron/cron-scheduler.ts +413 -0
- package/src/cron/cron-store.ts +163 -0
- package/src/cron/index.ts +6 -0
- package/src/db/interfaces.ts +60 -0
- package/src/email/index.ts +18 -0
- package/src/email/smtp-email-service.ts +91 -0
- package/src/email/templates.ts +388 -0
- package/src/email/types.ts +105 -0
- package/src/functions/function-loader.ts +119 -0
- package/src/functions/function-routes.ts +31 -0
- package/src/functions/index.ts +3 -0
- package/src/history/history-routes.ts +129 -0
- package/src/history/index.ts +2 -0
- package/src/index.ts +66 -0
- package/src/init.ts +727 -0
- package/src/serve-spa.ts +81 -0
- package/src/services/driver-registry.ts +182 -0
- package/src/singleton.test.ts +28 -0
- package/src/singleton.ts +70 -0
- package/src/storage/LocalStorageController.ts +365 -0
- package/src/storage/S3StorageController.ts +298 -0
- package/src/storage/index.ts +43 -0
- package/src/storage/routes.ts +264 -0
- package/src/storage/storage-registry.ts +187 -0
- package/src/storage/types.ts +134 -0
- package/src/types/index.ts +27 -0
- package/src/utils/dev-port.ts +176 -0
- package/src/utils/logger.ts +143 -0
- package/src/utils/logging.ts +38 -0
- package/src/utils/request-logger.ts +66 -0
- package/src/utils/sql.ts +38 -0
- package/test/admin-routes.test.ts +640 -0
- package/test/api-generator.test.ts +501 -0
- package/test/ast-schema-editor.test.ts +63 -0
- package/test/auth-middleware-hono.test.ts +556 -0
- package/test/auth-routes.test.ts +1047 -0
- package/test/driver-registry.test.ts +282 -0
- package/test/error-propagation.test.ts +226 -0
- package/test/errors-hono.test.ts +133 -0
- package/test/errors.test.ts +155 -0
- package/test/jwt-security.test.ts +182 -0
- package/test/jwt.test.ts +324 -0
- package/test/middleware.test.ts +300 -0
- package/test/password.test.ts +165 -0
- package/test/query-parser.test.ts +263 -0
- package/test/rate-limiter.test.ts +102 -0
- package/test/safe-compare.test.ts +66 -0
- package/test/singleton.test.ts +59 -0
- package/test/storage-local.test.ts +271 -0
- package/test/storage-registry.test.ts +282 -0
- package/test/storage-routes.test.ts +222 -0
- package/test/storage-s3.test.ts +304 -0
- package/test-ast.ts +28 -0
- package/test.ts +6 -0
- package/test_output.txt +1133 -0
- package/tsconfig.json +49 -0
- package/tsconfig.prod.json +20 -0
- package/vite.config.ts +80 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { OAuthProvider, OAuthProviderProfile } from "./interfaces";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a Bitbucket OAuth Provider integration (OAuth 2.0 consumer).
|
|
6
|
+
*/
|
|
7
|
+
export function createBitbucketProvider(config: { clientId: string; clientSecret: string }): OAuthProvider<{ code: string; redirectUri: string }> {
|
|
8
|
+
return {
|
|
9
|
+
id: "bitbucket",
|
|
10
|
+
schema: z.object({
|
|
11
|
+
code: z.string().min(1, "Auth code is required"),
|
|
12
|
+
redirectUri: z.string().url("Valid redirect URI is required")
|
|
13
|
+
}),
|
|
14
|
+
verify: async (payload: { code: string; redirectUri: string }): Promise<OAuthProviderProfile | null> => {
|
|
15
|
+
try {
|
|
16
|
+
const basicAuth = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64");
|
|
17
|
+
|
|
18
|
+
const tokenResponse = await fetch("https://bitbucket.org/site/oauth2/access_token", {
|
|
19
|
+
method: "POST",
|
|
20
|
+
headers: {
|
|
21
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
22
|
+
"Authorization": `Basic ${basicAuth}`
|
|
23
|
+
},
|
|
24
|
+
body: new URLSearchParams({
|
|
25
|
+
grant_type: "authorization_code",
|
|
26
|
+
code: payload.code,
|
|
27
|
+
redirect_uri: payload.redirectUri
|
|
28
|
+
})
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (!tokenResponse.ok) {
|
|
32
|
+
console.error("Failed to get Bitbucket access token:", await tokenResponse.text());
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const tokenData = await tokenResponse.json() as { access_token: string };
|
|
37
|
+
const accessToken = tokenData.access_token;
|
|
38
|
+
|
|
39
|
+
const profileResponse = await fetch("https://api.bitbucket.org/2.0/user", {
|
|
40
|
+
headers: { "Authorization": `Bearer ${accessToken}` }
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (!profileResponse.ok) {
|
|
44
|
+
console.error("Failed to get Bitbucket user info:", await profileResponse.text());
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const p = await profileResponse.json() as {
|
|
49
|
+
uuid: string; display_name?: string; username?: string;
|
|
50
|
+
links?: { avatar?: { href?: string } };
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Bitbucket doesn't return email in user profile — fetch from /emails endpoint
|
|
54
|
+
const emailsResponse = await fetch("https://api.bitbucket.org/2.0/user/emails", {
|
|
55
|
+
headers: { "Authorization": `Bearer ${accessToken}` }
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
let email: string | null = null;
|
|
59
|
+
if (emailsResponse.ok) {
|
|
60
|
+
const emailData = await emailsResponse.json() as {
|
|
61
|
+
values: Array<{ email: string; is_primary: boolean; is_confirmed: boolean }>;
|
|
62
|
+
};
|
|
63
|
+
const primary = emailData.values.find(e => e.is_primary && e.is_confirmed)
|
|
64
|
+
|| emailData.values.find(e => e.is_confirmed);
|
|
65
|
+
email = primary?.email || null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!email) { console.error("Bitbucket user has no verified email"); return null; }
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
providerId: p.uuid,
|
|
72
|
+
email,
|
|
73
|
+
displayName: p.display_name || p.username || null,
|
|
74
|
+
photoUrl: p.links?.avatar?.href || null
|
|
75
|
+
};
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error("Bitbucket OAuth error:", error);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { OAuthProvider, OAuthProviderProfile } from "./interfaces";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a Discord OAuth2 Provider integration.
|
|
6
|
+
*
|
|
7
|
+
* Uses the authorization code flow. Requires the "identify" and "email"
|
|
8
|
+
* scopes to retrieve the user's email and profile information.
|
|
9
|
+
*/
|
|
10
|
+
export function createDiscordProvider(config: { clientId: string; clientSecret: string }): OAuthProvider<{ code: string; redirectUri: string }> {
|
|
11
|
+
return {
|
|
12
|
+
id: "discord",
|
|
13
|
+
schema: z.object({
|
|
14
|
+
code: z.string().min(1, "Auth code is required"),
|
|
15
|
+
redirectUri: z.string().url("Valid redirect URI is required")
|
|
16
|
+
}),
|
|
17
|
+
verify: async (payload: { code: string; redirectUri: string }): Promise<OAuthProviderProfile | null> => {
|
|
18
|
+
try {
|
|
19
|
+
// Exchange code for access token
|
|
20
|
+
const tokenResponse = await fetch("https://discord.com/api/v10/oauth2/token", {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
23
|
+
body: new URLSearchParams({
|
|
24
|
+
client_id: config.clientId,
|
|
25
|
+
client_secret: config.clientSecret,
|
|
26
|
+
grant_type: "authorization_code",
|
|
27
|
+
code: payload.code,
|
|
28
|
+
redirect_uri: payload.redirectUri
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (!tokenResponse.ok) {
|
|
33
|
+
console.error("Failed to get Discord access token:", await tokenResponse.text());
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const tokenData = await tokenResponse.json() as { access_token: string };
|
|
38
|
+
const accessToken = tokenData.access_token;
|
|
39
|
+
|
|
40
|
+
// Fetch user profile
|
|
41
|
+
const profileResponse = await fetch("https://discord.com/api/v10/users/@me", {
|
|
42
|
+
headers: { "Authorization": `Bearer ${accessToken}` }
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (!profileResponse.ok) {
|
|
46
|
+
console.error("Failed to get Discord user info:", await profileResponse.text());
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const profileData = await profileResponse.json() as {
|
|
51
|
+
id: string;
|
|
52
|
+
username: string;
|
|
53
|
+
global_name?: string | null;
|
|
54
|
+
avatar?: string | null;
|
|
55
|
+
email?: string | null;
|
|
56
|
+
verified?: boolean;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if (!profileData.email) {
|
|
60
|
+
console.error("Discord user has no email (email scope may not have been granted)");
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Build avatar URL
|
|
65
|
+
let photoUrl: string | null = null;
|
|
66
|
+
if (profileData.avatar) {
|
|
67
|
+
const ext = profileData.avatar.startsWith("a_") ? "gif" : "png";
|
|
68
|
+
photoUrl = `https://cdn.discordapp.com/avatars/${profileData.id}/${profileData.avatar}.${ext}?size=256`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
providerId: profileData.id,
|
|
73
|
+
email: profileData.email,
|
|
74
|
+
displayName: profileData.global_name || profileData.username || null,
|
|
75
|
+
photoUrl
|
|
76
|
+
};
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error("Discord OAuth error:", error);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { OAuthProvider, OAuthProviderProfile } from "./interfaces";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a Facebook / Meta OAuth Provider integration.
|
|
6
|
+
*
|
|
7
|
+
* Uses the authorization code flow to exchange a code for an access token,
|
|
8
|
+
* then fetches user profile from the Facebook Graph API.
|
|
9
|
+
*/
|
|
10
|
+
export function createFacebookProvider(config: { clientId: string; clientSecret: string }): OAuthProvider<{ code: string; redirectUri: string }> {
|
|
11
|
+
return {
|
|
12
|
+
id: "facebook",
|
|
13
|
+
schema: z.object({
|
|
14
|
+
code: z.string().min(1, "Auth code is required"),
|
|
15
|
+
redirectUri: z.string().url("Valid redirect URI is required")
|
|
16
|
+
}),
|
|
17
|
+
verify: async (payload: { code: string; redirectUri: string }): Promise<OAuthProviderProfile | null> => {
|
|
18
|
+
try {
|
|
19
|
+
// Exchange code for access token
|
|
20
|
+
const tokenUrl = new URL("https://graph.facebook.com/v19.0/oauth/access_token");
|
|
21
|
+
tokenUrl.searchParams.set("client_id", config.clientId);
|
|
22
|
+
tokenUrl.searchParams.set("client_secret", config.clientSecret);
|
|
23
|
+
tokenUrl.searchParams.set("redirect_uri", payload.redirectUri);
|
|
24
|
+
tokenUrl.searchParams.set("code", payload.code);
|
|
25
|
+
|
|
26
|
+
const tokenResponse = await fetch(tokenUrl.toString());
|
|
27
|
+
|
|
28
|
+
if (!tokenResponse.ok) {
|
|
29
|
+
console.error("Failed to get Facebook access token:", await tokenResponse.text());
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const tokenData = await tokenResponse.json() as { access_token: string };
|
|
34
|
+
const accessToken = tokenData.access_token;
|
|
35
|
+
|
|
36
|
+
// Fetch user profile with email and profile picture
|
|
37
|
+
const profileUrl = new URL("https://graph.facebook.com/v19.0/me");
|
|
38
|
+
profileUrl.searchParams.set("fields", "id,name,email,picture.type(large)");
|
|
39
|
+
profileUrl.searchParams.set("access_token", accessToken);
|
|
40
|
+
|
|
41
|
+
const profileResponse = await fetch(profileUrl.toString());
|
|
42
|
+
|
|
43
|
+
if (!profileResponse.ok) {
|
|
44
|
+
console.error("Failed to get Facebook user info:", await profileResponse.text());
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const profileData = await profileResponse.json() as {
|
|
49
|
+
id: string;
|
|
50
|
+
name?: string;
|
|
51
|
+
email?: string;
|
|
52
|
+
picture?: { data?: { url?: string } };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
if (!profileData.email) {
|
|
56
|
+
console.error("Facebook user has no email (email permission may not have been granted)");
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
providerId: profileData.id,
|
|
62
|
+
email: profileData.email,
|
|
63
|
+
displayName: profileData.name || null,
|
|
64
|
+
photoUrl: profileData.picture?.data?.url || null
|
|
65
|
+
};
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error("Facebook OAuth error:", error);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { OAuthProvider, OAuthProviderProfile } from "./interfaces";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a GitHub OAuth Provider integration.
|
|
6
|
+
*
|
|
7
|
+
* Flow: Frontend receives an authorization `code` via the GitHub OAuth redirect.
|
|
8
|
+
* This provider exchanges the code for an access token, then fetches the user's
|
|
9
|
+
* profile and primary email from the GitHub API.
|
|
10
|
+
*/
|
|
11
|
+
export function createGitHubProvider(config: { clientId: string; clientSecret: string }): OAuthProvider<{ code: string; redirectUri: string }> {
|
|
12
|
+
return {
|
|
13
|
+
id: "github",
|
|
14
|
+
schema: z.object({
|
|
15
|
+
code: z.string().min(1, "Auth code is required"),
|
|
16
|
+
redirectUri: z.string().url("Valid redirect URI is required")
|
|
17
|
+
}),
|
|
18
|
+
verify: async (payload: { code: string; redirectUri: string }): Promise<OAuthProviderProfile | null> => {
|
|
19
|
+
try {
|
|
20
|
+
// Exchange code for access token
|
|
21
|
+
const tokenResponse = await fetch("https://github.com/login/oauth/access_token", {
|
|
22
|
+
method: "POST",
|
|
23
|
+
headers: {
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
"Accept": "application/json"
|
|
26
|
+
},
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
client_id: config.clientId,
|
|
29
|
+
client_secret: config.clientSecret,
|
|
30
|
+
code: payload.code,
|
|
31
|
+
redirect_uri: payload.redirectUri
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (!tokenResponse.ok) {
|
|
36
|
+
console.error("Failed to get GitHub access token:", await tokenResponse.text());
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const tokenData = await tokenResponse.json() as { access_token?: string; error?: string };
|
|
41
|
+
if (tokenData.error || !tokenData.access_token) {
|
|
42
|
+
console.error("GitHub token exchange error:", tokenData.error);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const accessToken = tokenData.access_token;
|
|
47
|
+
|
|
48
|
+
// Fetch user profile
|
|
49
|
+
const profileResponse = await fetch("https://api.github.com/user", {
|
|
50
|
+
headers: {
|
|
51
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
52
|
+
"Accept": "application/vnd.github+json",
|
|
53
|
+
"User-Agent": "Rebase-Auth"
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (!profileResponse.ok) {
|
|
58
|
+
console.error("Failed to get GitHub user info:", await profileResponse.text());
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const profileData = await profileResponse.json() as {
|
|
63
|
+
id: number;
|
|
64
|
+
login: string;
|
|
65
|
+
name?: string | null;
|
|
66
|
+
avatar_url?: string | null;
|
|
67
|
+
email?: string | null;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// GitHub may not return email in profile if it's private.
|
|
71
|
+
// Fetch from /user/emails endpoint instead.
|
|
72
|
+
let email = profileData.email;
|
|
73
|
+
if (!email) {
|
|
74
|
+
const emailsResponse = await fetch("https://api.github.com/user/emails", {
|
|
75
|
+
headers: {
|
|
76
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
77
|
+
"Accept": "application/vnd.github+json",
|
|
78
|
+
"User-Agent": "Rebase-Auth"
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (emailsResponse.ok) {
|
|
83
|
+
const emails = await emailsResponse.json() as Array<{
|
|
84
|
+
email: string;
|
|
85
|
+
primary: boolean;
|
|
86
|
+
verified: boolean;
|
|
87
|
+
}>;
|
|
88
|
+
const primary = emails.find(e => e.primary && e.verified) || emails.find(e => e.verified);
|
|
89
|
+
email = primary?.email || null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!email) {
|
|
94
|
+
console.error("GitHub user has no verified email");
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
providerId: String(profileData.id),
|
|
100
|
+
email,
|
|
101
|
+
displayName: profileData.name || profileData.login || null,
|
|
102
|
+
photoUrl: profileData.avatar_url || null
|
|
103
|
+
};
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error("GitHub OAuth error:", error);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { OAuthProvider, OAuthProviderProfile } from "./interfaces";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a GitLab OAuth Provider integration.
|
|
6
|
+
* Works with both GitLab.com and self-hosted instances.
|
|
7
|
+
*/
|
|
8
|
+
export function createGitLabProvider(config: {
|
|
9
|
+
clientId: string;
|
|
10
|
+
clientSecret: string;
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
}): OAuthProvider<{ code: string; redirectUri: string }> {
|
|
13
|
+
const gitlabUrl = (config.baseUrl || "https://gitlab.com").replace(/\/$/, "");
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
id: "gitlab",
|
|
17
|
+
schema: z.object({
|
|
18
|
+
code: z.string().min(1, "Auth code is required"),
|
|
19
|
+
redirectUri: z.string().url("Valid redirect URI is required")
|
|
20
|
+
}),
|
|
21
|
+
verify: async (payload: { code: string; redirectUri: string }): Promise<OAuthProviderProfile | null> => {
|
|
22
|
+
try {
|
|
23
|
+
const tokenResponse = await fetch(`${gitlabUrl}/oauth/token`, {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: { "Content-Type": "application/json" },
|
|
26
|
+
body: JSON.stringify({
|
|
27
|
+
client_id: config.clientId,
|
|
28
|
+
client_secret: config.clientSecret,
|
|
29
|
+
code: payload.code,
|
|
30
|
+
grant_type: "authorization_code",
|
|
31
|
+
redirect_uri: payload.redirectUri
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (!tokenResponse.ok) {
|
|
36
|
+
console.error("Failed to get GitLab access token:", await tokenResponse.text());
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const tokenData = await tokenResponse.json() as { access_token: string };
|
|
41
|
+
|
|
42
|
+
const profileResponse = await fetch(`${gitlabUrl}/api/v4/user`, {
|
|
43
|
+
headers: { "Authorization": `Bearer ${tokenData.access_token}` }
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (!profileResponse.ok) {
|
|
47
|
+
console.error("Failed to get GitLab user info:", await profileResponse.text());
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const p = await profileResponse.json() as {
|
|
52
|
+
id: number; username: string; name?: string;
|
|
53
|
+
email: string; avatar_url?: string | null;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
if (!p.email) { console.error("GitLab user has no email"); return null; }
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
providerId: String(p.id),
|
|
60
|
+
email: p.email,
|
|
61
|
+
displayName: p.name || p.username || null,
|
|
62
|
+
photoUrl: p.avatar_url || null
|
|
63
|
+
};
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("GitLab OAuth error:", error);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { OAuth2Client } from "google-auth-library/build/src/index.js";
|
|
2
|
+
import type { OAuthProvider, OAuthProviderProfile } from "./interfaces";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
export interface GoogleUserInfo {
|
|
6
|
+
googleId: string;
|
|
7
|
+
email: string;
|
|
8
|
+
displayName: string | null;
|
|
9
|
+
photoUrl: string | null;
|
|
10
|
+
emailVerified: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a Google OAuth Provider integration
|
|
15
|
+
*/
|
|
16
|
+
export function createGoogleProvider(clientId: string): OAuthProvider<{ idToken: string }> {
|
|
17
|
+
const googleClient = new OAuth2Client(clientId);
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
id: "google",
|
|
21
|
+
schema: z.object({
|
|
22
|
+
idToken: z.string().min(1, "ID token is required")
|
|
23
|
+
}),
|
|
24
|
+
verify: async (payload: { idToken: string }): Promise<OAuthProviderProfile | null> => {
|
|
25
|
+
try {
|
|
26
|
+
const ticket = await googleClient.verifyIdToken({
|
|
27
|
+
idToken: payload.idToken,
|
|
28
|
+
audience: clientId
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const content = ticket.getPayload();
|
|
32
|
+
if (!content) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
providerId: content.sub,
|
|
38
|
+
email: content.email || "",
|
|
39
|
+
displayName: content.name || null,
|
|
40
|
+
photoUrl: content.picture || null
|
|
41
|
+
};
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error("Failed to verify Google ID token:", error);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Auth module exports
|
|
2
|
+
export * from "./interfaces";
|
|
3
|
+
|
|
4
|
+
export { configureJwt, generateAccessToken, verifyAccessToken, generateRefreshToken, hashRefreshToken, getRefreshTokenExpiry, getAccessTokenExpiry } from "./jwt";
|
|
5
|
+
export type { JwtConfig, AccessTokenPayload } from "./jwt";
|
|
6
|
+
|
|
7
|
+
export { hashPassword, verifyPassword, validatePasswordStrength } from "./password";
|
|
8
|
+
export type { PasswordValidationResult } from "./password";
|
|
9
|
+
|
|
10
|
+
// OAuth Providers
|
|
11
|
+
export { createGoogleProvider } from "./google-oauth";
|
|
12
|
+
export { createLinkedinProvider } from "./linkedin-oauth";
|
|
13
|
+
export { createGitHubProvider } from "./github-oauth";
|
|
14
|
+
export { createMicrosoftProvider } from "./microsoft-oauth";
|
|
15
|
+
export { createAppleProvider } from "./apple-oauth";
|
|
16
|
+
export { createFacebookProvider } from "./facebook-oauth";
|
|
17
|
+
export { createTwitterProvider } from "./twitter-oauth";
|
|
18
|
+
export { createDiscordProvider } from "./discord-oauth";
|
|
19
|
+
export { createGitLabProvider } from "./gitlab-oauth";
|
|
20
|
+
export { createBitbucketProvider } from "./bitbucket-oauth";
|
|
21
|
+
export { createSlackProvider } from "./slack-oauth";
|
|
22
|
+
export { createSpotifyProvider } from "./spotify-oauth";
|
|
23
|
+
|
|
24
|
+
export { requireAuth, requireAdmin, optionalAuth, extractUserFromToken, createAuthMiddleware } from "./middleware";
|
|
25
|
+
export type { AuthMiddlewareOptions, AuthResult } from "./middleware";
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
export { createAuthRoutes } from "./routes";
|
|
29
|
+
export type { AuthModuleConfig } from "./routes";
|
|
30
|
+
|
|
31
|
+
export { createAdminRoutes } from "./admin-routes";
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
export { createRateLimiter, defaultAuthLimiter, strictAuthLimiter } from "./rate-limiter";
|