@friggframework/core 2.0.0-next.6 → 2.0.0-next.61
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/CLAUDE.md +694 -0
- package/README.md +959 -50
- package/application/commands/README.md +451 -0
- package/application/commands/credential-commands.js +245 -0
- package/application/commands/entity-commands.js +336 -0
- package/application/commands/integration-commands.js +210 -0
- package/application/commands/user-commands.js +283 -0
- package/application/index.js +69 -0
- package/core/CLAUDE.md +690 -0
- package/core/Worker.js +8 -21
- package/core/create-handler.js +14 -7
- package/credential/repositories/credential-repository-documentdb.js +304 -0
- package/credential/repositories/credential-repository-factory.js +54 -0
- package/credential/repositories/credential-repository-interface.js +98 -0
- package/credential/repositories/credential-repository-mongo.js +269 -0
- package/credential/repositories/credential-repository-postgres.js +291 -0
- package/credential/repositories/credential-repository.js +302 -0
- package/credential/use-cases/get-credential-for-user.js +25 -0
- package/credential/use-cases/update-authentication-status.js +15 -0
- package/database/MONGODB_TRANSACTION_FIX.md +198 -0
- package/database/adapters/lambda-invoker.js +97 -0
- package/database/config.js +154 -0
- package/database/documentdb-encryption-service.js +330 -0
- package/database/documentdb-utils.js +136 -0
- package/database/encryption/README.md +839 -0
- package/database/encryption/documentdb-encryption-service.md +3575 -0
- package/database/encryption/encryption-schema-registry.js +268 -0
- package/database/encryption/field-encryption-service.js +226 -0
- package/database/encryption/logger.js +79 -0
- package/database/encryption/prisma-encryption-extension.js +222 -0
- package/database/index.js +61 -21
- package/database/models/WebsocketConnection.js +16 -10
- package/database/models/readme.md +1 -0
- package/database/prisma.js +182 -0
- package/database/repositories/health-check-repository-documentdb.js +134 -0
- package/database/repositories/health-check-repository-factory.js +48 -0
- package/database/repositories/health-check-repository-interface.js +82 -0
- package/database/repositories/health-check-repository-mongodb.js +89 -0
- package/database/repositories/health-check-repository-postgres.js +82 -0
- package/database/repositories/health-check-repository.js +108 -0
- package/database/repositories/migration-status-repository-s3.js +137 -0
- package/database/use-cases/check-database-health-use-case.js +29 -0
- package/database/use-cases/check-database-state-use-case.js +81 -0
- package/database/use-cases/check-encryption-health-use-case.js +83 -0
- package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
- package/database/use-cases/get-migration-status-use-case.js +93 -0
- package/database/use-cases/run-database-migration-use-case.js +139 -0
- package/database/use-cases/test-encryption-use-case.js +253 -0
- package/database/use-cases/trigger-database-migration-use-case.js +157 -0
- package/database/utils/mongodb-collection-utils.js +91 -0
- package/database/utils/mongodb-schema-init.js +106 -0
- package/database/utils/prisma-runner.js +477 -0
- package/database/utils/prisma-schema-parser.js +182 -0
- package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
- package/encrypt/Cryptor.js +34 -168
- package/encrypt/index.js +1 -2
- package/encrypt/test-encrypt.js +0 -2
- package/errors/client-safe-error.js +26 -0
- package/errors/fetch-error.js +2 -1
- package/errors/index.js +2 -0
- package/generated/prisma-mongodb/client.d.ts +1 -0
- package/generated/prisma-mongodb/client.js +4 -0
- package/generated/prisma-mongodb/default.d.ts +1 -0
- package/generated/prisma-mongodb/default.js +4 -0
- package/generated/prisma-mongodb/edge.d.ts +1 -0
- package/generated/prisma-mongodb/edge.js +334 -0
- package/generated/prisma-mongodb/index-browser.js +316 -0
- package/generated/prisma-mongodb/index.d.ts +22903 -0
- package/generated/prisma-mongodb/index.js +359 -0
- package/generated/prisma-mongodb/package.json +183 -0
- package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
- package/generated/prisma-mongodb/runtime/binary.js +289 -0
- package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
- package/generated/prisma-mongodb/runtime/edge.js +34 -0
- package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
- package/generated/prisma-mongodb/runtime/library.d.ts +3977 -0
- package/generated/prisma-mongodb/runtime/react-native.js +83 -0
- package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-mongodb/schema.prisma +360 -0
- package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm.d.ts +1 -0
- package/generated/prisma-mongodb/wasm.js +341 -0
- package/generated/prisma-postgresql/client.d.ts +1 -0
- package/generated/prisma-postgresql/client.js +4 -0
- package/generated/prisma-postgresql/default.d.ts +1 -0
- package/generated/prisma-postgresql/default.js +4 -0
- package/generated/prisma-postgresql/edge.d.ts +1 -0
- package/generated/prisma-postgresql/edge.js +356 -0
- package/generated/prisma-postgresql/index-browser.js +338 -0
- package/generated/prisma-postgresql/index.d.ts +25077 -0
- package/generated/prisma-postgresql/index.js +381 -0
- package/generated/prisma-postgresql/package.json +183 -0
- package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query_engine_bg.js +2 -0
- package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
- package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
- package/generated/prisma-postgresql/runtime/binary.js +289 -0
- package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
- package/generated/prisma-postgresql/runtime/edge.js +34 -0
- package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
- package/generated/prisma-postgresql/runtime/library.d.ts +3977 -0
- package/generated/prisma-postgresql/runtime/react-native.js +83 -0
- package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-postgresql/schema.prisma +343 -0
- package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm.d.ts +1 -0
- package/generated/prisma-postgresql/wasm.js +363 -0
- package/handlers/WEBHOOKS.md +653 -0
- package/handlers/app-definition-loader.js +38 -0
- package/handlers/app-handler-helpers.js +56 -0
- package/handlers/backend-utils.js +186 -0
- package/handlers/database-migration-handler.js +227 -0
- package/handlers/integration-event-dispatcher.js +54 -0
- package/handlers/routers/HEALTHCHECK.md +342 -0
- package/handlers/routers/auth.js +15 -0
- package/handlers/routers/db-migration.handler.js +29 -0
- package/handlers/routers/db-migration.js +326 -0
- package/handlers/routers/health.js +516 -0
- package/handlers/routers/integration-defined-routers.js +45 -0
- package/handlers/routers/integration-webhook-routers.js +67 -0
- package/handlers/routers/user.js +63 -0
- package/handlers/routers/websocket.js +57 -0
- package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
- package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
- package/handlers/workers/db-migration.js +352 -0
- package/handlers/workers/integration-defined-workers.js +27 -0
- package/index.js +77 -22
- package/integrations/WEBHOOK-QUICKSTART.md +151 -0
- package/integrations/index.js +12 -10
- package/integrations/integration-base.js +326 -55
- package/integrations/integration-router.js +374 -179
- package/integrations/options.js +1 -1
- package/integrations/repositories/integration-mapping-repository-documentdb.js +280 -0
- package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
- package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
- package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
- package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
- package/integrations/repositories/integration-mapping-repository.js +156 -0
- package/integrations/repositories/integration-repository-documentdb.js +210 -0
- package/integrations/repositories/integration-repository-factory.js +51 -0
- package/integrations/repositories/integration-repository-interface.js +127 -0
- package/integrations/repositories/integration-repository-mongo.js +303 -0
- package/integrations/repositories/integration-repository-postgres.js +352 -0
- package/integrations/repositories/process-repository-documentdb.js +243 -0
- package/integrations/repositories/process-repository-factory.js +53 -0
- package/integrations/repositories/process-repository-interface.js +90 -0
- package/integrations/repositories/process-repository-mongo.js +190 -0
- package/integrations/repositories/process-repository-postgres.js +217 -0
- package/integrations/tests/doubles/config-capturing-integration.js +81 -0
- package/integrations/tests/doubles/dummy-integration-class.js +105 -0
- package/integrations/tests/doubles/test-integration-repository.js +99 -0
- package/integrations/use-cases/create-integration.js +83 -0
- package/integrations/use-cases/create-process.js +128 -0
- package/integrations/use-cases/delete-integration-for-user.js +101 -0
- package/integrations/use-cases/find-integration-context-by-external-entity-id.js +72 -0
- package/integrations/use-cases/get-integration-for-user.js +78 -0
- package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
- package/integrations/use-cases/get-integration-instance.js +83 -0
- package/integrations/use-cases/get-integrations-for-user.js +88 -0
- package/integrations/use-cases/get-possible-integrations.js +27 -0
- package/integrations/use-cases/get-process.js +87 -0
- package/integrations/use-cases/index.js +19 -0
- package/integrations/use-cases/load-integration-context.js +71 -0
- package/integrations/use-cases/update-integration-messages.js +44 -0
- package/integrations/use-cases/update-integration-status.js +32 -0
- package/integrations/use-cases/update-integration.js +92 -0
- package/integrations/use-cases/update-process-metrics.js +201 -0
- package/integrations/use-cases/update-process-state.js +119 -0
- package/integrations/utils/map-integration-dto.js +37 -0
- package/jest-global-setup-noop.js +3 -0
- package/jest-global-teardown-noop.js +3 -0
- package/logs/logger.js +0 -4
- package/{module-plugin → modules}/entity.js +1 -1
- package/{module-plugin → modules}/index.js +0 -8
- package/modules/module-factory.js +56 -0
- package/modules/module.js +221 -0
- package/modules/repositories/module-repository-documentdb.js +307 -0
- package/modules/repositories/module-repository-factory.js +40 -0
- package/modules/repositories/module-repository-interface.js +129 -0
- package/modules/repositories/module-repository-mongo.js +377 -0
- package/modules/repositories/module-repository-postgres.js +426 -0
- package/modules/repositories/module-repository.js +316 -0
- package/modules/requester/api-key.js +52 -0
- package/{module-plugin → modules}/requester/requester.js +1 -0
- package/{module-plugin → modules}/test/mock-api/api.js +8 -3
- package/{module-plugin → modules}/test/mock-api/definition.js +12 -8
- package/modules/tests/doubles/test-module-factory.js +16 -0
- package/modules/tests/doubles/test-module-repository.js +39 -0
- package/modules/use-cases/get-entities-for-user.js +32 -0
- package/modules/use-cases/get-entity-options-by-id.js +71 -0
- package/modules/use-cases/get-entity-options-by-type.js +34 -0
- package/modules/use-cases/get-module-instance-from-type.js +31 -0
- package/modules/use-cases/get-module.js +74 -0
- package/modules/use-cases/process-authorization-callback.js +133 -0
- package/modules/use-cases/refresh-entity-options.js +72 -0
- package/modules/use-cases/test-module-auth.js +72 -0
- package/modules/utils/map-module-dto.js +18 -0
- package/package.json +82 -50
- package/prisma-mongodb/schema.prisma +360 -0
- package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
- package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
- package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
- package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
- package/prisma-postgresql/migrations/migration_lock.toml +3 -0
- package/prisma-postgresql/schema.prisma +343 -0
- package/queues/queuer-util.js +27 -22
- package/syncs/manager.js +468 -443
- package/syncs/repositories/sync-repository-documentdb.js +240 -0
- package/syncs/repositories/sync-repository-factory.js +43 -0
- package/syncs/repositories/sync-repository-interface.js +109 -0
- package/syncs/repositories/sync-repository-mongo.js +239 -0
- package/syncs/repositories/sync-repository-postgres.js +319 -0
- package/syncs/sync.js +0 -1
- package/token/repositories/token-repository-documentdb.js +137 -0
- package/token/repositories/token-repository-factory.js +40 -0
- package/token/repositories/token-repository-interface.js +131 -0
- package/token/repositories/token-repository-mongo.js +219 -0
- package/token/repositories/token-repository-postgres.js +264 -0
- package/token/repositories/token-repository.js +219 -0
- package/types/core/index.d.ts +2 -2
- package/types/integrations/index.d.ts +2 -6
- package/types/module-plugin/index.d.ts +5 -59
- package/types/syncs/index.d.ts +0 -2
- package/user/repositories/user-repository-documentdb.js +441 -0
- package/user/repositories/user-repository-factory.js +52 -0
- package/user/repositories/user-repository-interface.js +201 -0
- package/user/repositories/user-repository-mongo.js +308 -0
- package/user/repositories/user-repository-postgres.js +360 -0
- package/user/tests/doubles/test-user-repository.js +72 -0
- package/user/use-cases/authenticate-user.js +127 -0
- package/user/use-cases/authenticate-with-shared-secret.js +48 -0
- package/user/use-cases/create-individual-user.js +61 -0
- package/user/use-cases/create-organization-user.js +47 -0
- package/user/use-cases/create-token-for-user-id.js +30 -0
- package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
- package/user/use-cases/get-user-from-bearer-token.js +77 -0
- package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user.js +125 -0
- package/utils/backend-path.js +38 -0
- package/utils/index.js +6 -0
- package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
- package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
- package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
- package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
- package/websocket/repositories/websocket-connection-repository.js +161 -0
- package/database/models/State.js +0 -9
- package/database/models/Token.js +0 -70
- package/database/mongo.js +0 -45
- package/encrypt/Cryptor.test.js +0 -32
- package/encrypt/encrypt.js +0 -132
- package/encrypt/encrypt.test.js +0 -1069
- package/errors/base-error.test.js +0 -32
- package/errors/fetch-error.test.js +0 -79
- package/errors/halt-error.test.js +0 -11
- package/errors/validation-errors.test.js +0 -120
- package/integrations/create-frigg-backend.js +0 -31
- package/integrations/integration-factory.js +0 -251
- package/integrations/integration-mapping.js +0 -43
- package/integrations/integration-model.js +0 -46
- package/integrations/integration-user.js +0 -144
- package/integrations/test/integration-base.test.js +0 -144
- package/lambda/TimeoutCatcher.test.js +0 -68
- package/logs/logger.test.js +0 -76
- package/module-plugin/auther.js +0 -393
- package/module-plugin/credential.js +0 -22
- package/module-plugin/entity-manager.js +0 -70
- package/module-plugin/manager.js +0 -169
- package/module-plugin/module-factory.js +0 -61
- package/module-plugin/requester/api-key.js +0 -36
- package/module-plugin/requester/requester.test.js +0 -28
- package/module-plugin/test/auther.test.js +0 -97
- /package/{module-plugin → modules}/ModuleConstants.js +0 -0
- /package/{module-plugin → modules}/requester/basic.js +0 -0
- /package/{module-plugin → modules}/requester/oauth-2.js +0 -0
- /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
const { prisma } = require('../../database/prisma');
|
|
2
|
+
const bcrypt = require('bcryptjs');
|
|
3
|
+
const { TokenRepositoryInterface } = require('./token-repository-interface');
|
|
4
|
+
const { ClientSafeError } = require('../../errors');
|
|
5
|
+
|
|
6
|
+
const BCRYPT_ROUNDS = 10;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* MongoDB Token Repository Adapter
|
|
10
|
+
* Handles persistence of authentication tokens with bcrypt hashing
|
|
11
|
+
*
|
|
12
|
+
* MongoDB-specific characteristics:
|
|
13
|
+
* - Uses String IDs (ObjectId)
|
|
14
|
+
* - No ID conversion needed (IDs are already strings)
|
|
15
|
+
* - Bcrypt hashing handled in repository layer
|
|
16
|
+
*/
|
|
17
|
+
class TokenRepositoryMongo extends TokenRepositoryInterface {
|
|
18
|
+
constructor() {
|
|
19
|
+
super();
|
|
20
|
+
this.prisma = prisma;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create a token with expiration
|
|
25
|
+
* Replaces: Token.createTokenWithExpire(userId, rawToken, minutes)
|
|
26
|
+
*
|
|
27
|
+
* @param {string} userId - The user ID
|
|
28
|
+
* @param {string} rawToken - The raw (unhashed) token string
|
|
29
|
+
* @param {number} minutes - Minutes until expiration
|
|
30
|
+
* @returns {Promise<Object>} The created token record with string IDs
|
|
31
|
+
*/
|
|
32
|
+
async createTokenWithExpire(userId, rawToken, minutes) {
|
|
33
|
+
// Hash the token with bcrypt
|
|
34
|
+
const tokenHash = await bcrypt.hash(rawToken, BCRYPT_ROUNDS);
|
|
35
|
+
|
|
36
|
+
// Calculate expiration time
|
|
37
|
+
const expires = new Date(Date.now() + minutes * 60000);
|
|
38
|
+
|
|
39
|
+
return await this.prisma.token.create({
|
|
40
|
+
data: {
|
|
41
|
+
token: tokenHash,
|
|
42
|
+
expires,
|
|
43
|
+
userId,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Validate and retrieve token from JSON token object
|
|
50
|
+
* Replaces: Token.validateAndGetTokenFromJSONToken(tokenObj)
|
|
51
|
+
*
|
|
52
|
+
* @param {Object} tokenObj - Object with id and token properties
|
|
53
|
+
* @returns {Promise<Object>} The validated token record with string IDs
|
|
54
|
+
* @throws {Error} If token is invalid, expired, or doesn't exist
|
|
55
|
+
*/
|
|
56
|
+
async validateAndGetToken(tokenObj) {
|
|
57
|
+
const sessionToken = await this.prisma.token.findUnique({
|
|
58
|
+
where: { id: tokenObj.id },
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!sessionToken) {
|
|
62
|
+
throw new ClientSafeError(
|
|
63
|
+
'Invalid Token: Token does not exist',
|
|
64
|
+
401
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Verify token hash matches
|
|
69
|
+
const isValid = await bcrypt.compare(
|
|
70
|
+
tokenObj.token,
|
|
71
|
+
sessionToken.token
|
|
72
|
+
);
|
|
73
|
+
if (!isValid) {
|
|
74
|
+
throw new ClientSafeError(
|
|
75
|
+
'Invalid Token: Token does not match',
|
|
76
|
+
401
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check if token is expired
|
|
81
|
+
if (
|
|
82
|
+
sessionToken.expires &&
|
|
83
|
+
new Date(sessionToken.expires) < new Date()
|
|
84
|
+
) {
|
|
85
|
+
throw new ClientSafeError('Invalid Token: Token is expired', 401);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return sessionToken;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Find a token by ID
|
|
93
|
+
* Replaces: Token.findById(tokenId)
|
|
94
|
+
*
|
|
95
|
+
* @param {string} tokenId - The token ID
|
|
96
|
+
* @returns {Promise<Object|null>} The token record with string IDs or null
|
|
97
|
+
*/
|
|
98
|
+
async findTokenById(tokenId) {
|
|
99
|
+
return await this.prisma.token.findUnique({
|
|
100
|
+
where: { id: tokenId },
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Find tokens by user ID
|
|
106
|
+
* Replaces: Token.find({ user: userId })
|
|
107
|
+
*
|
|
108
|
+
* @param {string} userId - The user ID
|
|
109
|
+
* @returns {Promise<Array>} Array of token records with string IDs
|
|
110
|
+
*/
|
|
111
|
+
async findTokensByUserId(userId) {
|
|
112
|
+
return await this.prisma.token.findMany({
|
|
113
|
+
where: { userId },
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Delete a token by ID
|
|
119
|
+
* Replaces: Token.deleteOne({ _id: tokenId })
|
|
120
|
+
*
|
|
121
|
+
* @param {string} tokenId - The token ID
|
|
122
|
+
* @returns {Promise<Object>} The deletion result
|
|
123
|
+
*/
|
|
124
|
+
async deleteToken(tokenId) {
|
|
125
|
+
try {
|
|
126
|
+
await this.prisma.token.delete({
|
|
127
|
+
where: { id: tokenId },
|
|
128
|
+
});
|
|
129
|
+
return { acknowledged: true, deletedCount: 1 };
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (error.code === 'P2025') {
|
|
132
|
+
// Record not found
|
|
133
|
+
return { acknowledged: true, deletedCount: 0 };
|
|
134
|
+
}
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Delete expired tokens
|
|
141
|
+
* Replaces: Token.deleteMany({ expires: { $lt: new Date() } })
|
|
142
|
+
*
|
|
143
|
+
* @returns {Promise<Object>} The deletion result with count
|
|
144
|
+
*/
|
|
145
|
+
async deleteExpiredTokens() {
|
|
146
|
+
const result = await this.prisma.token.deleteMany({
|
|
147
|
+
where: {
|
|
148
|
+
expires: {
|
|
149
|
+
lt: new Date(),
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
acknowledged: true,
|
|
156
|
+
deletedCount: result.count,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Delete all tokens for a user
|
|
162
|
+
* Replaces: Token.deleteMany({ user: userId })
|
|
163
|
+
*
|
|
164
|
+
* @param {string} userId - The user ID
|
|
165
|
+
* @returns {Promise<Object>} The deletion result
|
|
166
|
+
*/
|
|
167
|
+
async deleteTokensByUserId(userId) {
|
|
168
|
+
const result = await this.prisma.token.deleteMany({
|
|
169
|
+
where: { userId },
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
acknowledged: true,
|
|
174
|
+
deletedCount: result.count,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Create JSON token string from token object and raw token
|
|
180
|
+
* Replaces: Token.createJSONToken(token, rawToken)
|
|
181
|
+
*
|
|
182
|
+
* @param {Object} token - The token record
|
|
183
|
+
* @param {string} rawToken - The raw token string
|
|
184
|
+
* @returns {string} JSON string with id and token
|
|
185
|
+
*/
|
|
186
|
+
createJSONToken(token, rawToken) {
|
|
187
|
+
return JSON.stringify({
|
|
188
|
+
id: token.id,
|
|
189
|
+
token: rawToken,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Create base64 encoded buffer token
|
|
195
|
+
* Replaces: Token.createBase64BufferToken(token, rawToken)
|
|
196
|
+
*
|
|
197
|
+
* @param {Object} token - The token record
|
|
198
|
+
* @param {string} rawToken - The raw token string
|
|
199
|
+
* @returns {string} Base64 encoded token
|
|
200
|
+
*/
|
|
201
|
+
createBase64BufferToken(token, rawToken) {
|
|
202
|
+
const jsonVal = this.createJSONToken(token, rawToken);
|
|
203
|
+
return Buffer.from(jsonVal).toString('base64');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Parse JSON token from base64 buffer
|
|
208
|
+
* Replaces: Token.getJSONTokenFromBase64BufferToken(buffer)
|
|
209
|
+
*
|
|
210
|
+
* @param {string} buffer - Base64 encoded token string
|
|
211
|
+
* @returns {Object} Parsed token object with id and token
|
|
212
|
+
*/
|
|
213
|
+
getJSONTokenFromBase64BufferToken(buffer) {
|
|
214
|
+
const tokenStr = Buffer.from(buffer.trim(), 'base64').toString('ascii');
|
|
215
|
+
return JSON.parse(tokenStr);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
module.exports = { TokenRepositoryMongo };
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
const { prisma } = require('../../database/prisma');
|
|
2
|
+
const bcrypt = require('bcryptjs');
|
|
3
|
+
const { TokenRepositoryInterface } = require('./token-repository-interface');
|
|
4
|
+
const { ClientSafeError } = require('../../errors');
|
|
5
|
+
|
|
6
|
+
const BCRYPT_ROUNDS = 10;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* PostgreSQL Token Repository Adapter
|
|
10
|
+
* Handles persistence of authentication tokens with bcrypt hashing
|
|
11
|
+
*
|
|
12
|
+
* PostgreSQL-specific characteristics:
|
|
13
|
+
* - Uses Int IDs with autoincrement
|
|
14
|
+
* - Requires ID conversion: String (app layer) ↔ Int (database)
|
|
15
|
+
* - All returned IDs are converted to strings for application layer consistency
|
|
16
|
+
*/
|
|
17
|
+
class TokenRepositoryPostgres extends TokenRepositoryInterface {
|
|
18
|
+
constructor() {
|
|
19
|
+
super();
|
|
20
|
+
this.prisma = prisma;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Convert string ID to integer for PostgreSQL queries
|
|
25
|
+
* @private
|
|
26
|
+
* @param {string|number|null|undefined} id - ID to convert
|
|
27
|
+
* @returns {number|null|undefined} Integer ID or null/undefined
|
|
28
|
+
* @throws {Error} If ID cannot be converted to integer
|
|
29
|
+
*/
|
|
30
|
+
_convertId(id) {
|
|
31
|
+
if (id === null || id === undefined) return id;
|
|
32
|
+
const parsed = parseInt(id, 10);
|
|
33
|
+
if (isNaN(parsed)) {
|
|
34
|
+
throw new Error(`Invalid ID: ${id} cannot be converted to integer`);
|
|
35
|
+
}
|
|
36
|
+
return parsed;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Convert token object IDs to strings
|
|
41
|
+
* @private
|
|
42
|
+
* @param {Object|null} token - Token object from database
|
|
43
|
+
* @returns {Object|null} Token with string IDs
|
|
44
|
+
*/
|
|
45
|
+
_convertTokenIds(token) {
|
|
46
|
+
if (!token) return token;
|
|
47
|
+
return {
|
|
48
|
+
...token,
|
|
49
|
+
id: token.id?.toString(),
|
|
50
|
+
userId: token.userId?.toString(),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create a token with expiration
|
|
56
|
+
* Replaces: Token.createTokenWithExpire(userId, rawToken, minutes)
|
|
57
|
+
*
|
|
58
|
+
* @param {string} userId - The user ID (string from application layer)
|
|
59
|
+
* @param {string} rawToken - The raw (unhashed) token string
|
|
60
|
+
* @param {number} minutes - Minutes until expiration
|
|
61
|
+
* @returns {Promise<Object>} The created token record with string IDs
|
|
62
|
+
*/
|
|
63
|
+
async createTokenWithExpire(userId, rawToken, minutes) {
|
|
64
|
+
// Hash the token with bcrypt
|
|
65
|
+
const tokenHash = await bcrypt.hash(rawToken, BCRYPT_ROUNDS);
|
|
66
|
+
|
|
67
|
+
// Calculate expiration time
|
|
68
|
+
const expires = new Date(Date.now() + minutes * 60000);
|
|
69
|
+
|
|
70
|
+
const token = await this.prisma.token.create({
|
|
71
|
+
data: {
|
|
72
|
+
token: tokenHash,
|
|
73
|
+
expires,
|
|
74
|
+
userId: this._convertId(userId),
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return this._convertTokenIds(token);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Validate and retrieve token from JSON token object
|
|
83
|
+
* Replaces: Token.validateAndGetTokenFromJSONToken(tokenObj)
|
|
84
|
+
*
|
|
85
|
+
* @param {Object} tokenObj - Object with id and token properties (id as string from app layer)
|
|
86
|
+
* @returns {Promise<Object>} The validated token record with string IDs
|
|
87
|
+
* @throws {Error} If token is invalid, expired, or doesn't exist
|
|
88
|
+
*/
|
|
89
|
+
async validateAndGetToken(tokenObj) {
|
|
90
|
+
const intId = this._convertId(tokenObj.id);
|
|
91
|
+
const sessionToken = await this.prisma.token.findUnique({
|
|
92
|
+
where: { id: intId },
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (!sessionToken) {
|
|
96
|
+
throw new ClientSafeError(
|
|
97
|
+
'Invalid Token: Token does not exist',
|
|
98
|
+
401
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Verify token hash matches
|
|
103
|
+
const isValid = await bcrypt.compare(
|
|
104
|
+
tokenObj.token,
|
|
105
|
+
sessionToken.token
|
|
106
|
+
);
|
|
107
|
+
if (!isValid) {
|
|
108
|
+
throw new ClientSafeError(
|
|
109
|
+
'Invalid Token: Token does not match',
|
|
110
|
+
401
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Check if token is expired
|
|
115
|
+
if (
|
|
116
|
+
sessionToken.expires &&
|
|
117
|
+
new Date(sessionToken.expires) < new Date()
|
|
118
|
+
) {
|
|
119
|
+
throw new ClientSafeError('Invalid Token: Token is expired', 401);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return this._convertTokenIds(sessionToken);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Find a token by ID
|
|
127
|
+
* Replaces: Token.findById(tokenId)
|
|
128
|
+
*
|
|
129
|
+
* @param {string} tokenId - The token ID (string from application layer)
|
|
130
|
+
* @returns {Promise<Object|null>} The token record with string IDs or null
|
|
131
|
+
*/
|
|
132
|
+
async findTokenById(tokenId) {
|
|
133
|
+
const intId = this._convertId(tokenId);
|
|
134
|
+
const token = await this.prisma.token.findUnique({
|
|
135
|
+
where: { id: intId },
|
|
136
|
+
});
|
|
137
|
+
return this._convertTokenIds(token);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Find tokens by user ID
|
|
142
|
+
* Replaces: Token.find({ user: userId })
|
|
143
|
+
*
|
|
144
|
+
* @param {string} userId - The user ID (string from application layer)
|
|
145
|
+
* @returns {Promise<Array>} Array of token records with string IDs
|
|
146
|
+
*/
|
|
147
|
+
async findTokensByUserId(userId) {
|
|
148
|
+
const intUserId = this._convertId(userId);
|
|
149
|
+
const tokens = await this.prisma.token.findMany({
|
|
150
|
+
where: { userId: intUserId },
|
|
151
|
+
});
|
|
152
|
+
return tokens.map((token) => this._convertTokenIds(token));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Delete a token by ID
|
|
157
|
+
* Replaces: Token.deleteOne({ _id: tokenId })
|
|
158
|
+
*
|
|
159
|
+
* @param {string} tokenId - The token ID (string from application layer)
|
|
160
|
+
* @returns {Promise<Object>} The deletion result
|
|
161
|
+
*/
|
|
162
|
+
async deleteToken(tokenId) {
|
|
163
|
+
try {
|
|
164
|
+
const intId = this._convertId(tokenId);
|
|
165
|
+
await this.prisma.token.delete({
|
|
166
|
+
where: { id: intId },
|
|
167
|
+
});
|
|
168
|
+
return { acknowledged: true, deletedCount: 1 };
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (error.code === 'P2025') {
|
|
171
|
+
// Record not found
|
|
172
|
+
return { acknowledged: true, deletedCount: 0 };
|
|
173
|
+
}
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Delete expired tokens
|
|
180
|
+
* Replaces: Token.deleteMany({ expires: { $lt: new Date() } })
|
|
181
|
+
*
|
|
182
|
+
* @returns {Promise<Object>} The deletion result with count
|
|
183
|
+
*/
|
|
184
|
+
async deleteExpiredTokens() {
|
|
185
|
+
const result = await this.prisma.token.deleteMany({
|
|
186
|
+
where: {
|
|
187
|
+
expires: {
|
|
188
|
+
lt: new Date(),
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
acknowledged: true,
|
|
195
|
+
deletedCount: result.count,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Delete all tokens for a user
|
|
201
|
+
* Replaces: Token.deleteMany({ user: userId })
|
|
202
|
+
*
|
|
203
|
+
* @param {string} userId - The user ID (string from application layer)
|
|
204
|
+
* @returns {Promise<Object>} The deletion result
|
|
205
|
+
*/
|
|
206
|
+
async deleteTokensByUserId(userId) {
|
|
207
|
+
const intUserId = this._convertId(userId);
|
|
208
|
+
const result = await this.prisma.token.deleteMany({
|
|
209
|
+
where: { userId: intUserId },
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
acknowledged: true,
|
|
214
|
+
deletedCount: result.count,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Create JSON token string from token object and raw token
|
|
220
|
+
* Replaces: Token.createJSONToken(token, rawToken)
|
|
221
|
+
*
|
|
222
|
+
* Note: Token ID is already a string at this point (from _convertTokenIds),
|
|
223
|
+
* so no conversion needed here.
|
|
224
|
+
*
|
|
225
|
+
* @param {Object} token - The token record (with string IDs)
|
|
226
|
+
* @param {string} rawToken - The raw token string
|
|
227
|
+
* @returns {string} JSON string with id and token
|
|
228
|
+
*/
|
|
229
|
+
createJSONToken(token, rawToken) {
|
|
230
|
+
return JSON.stringify({
|
|
231
|
+
id: token.id,
|
|
232
|
+
token: rawToken,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Create base64 encoded buffer token
|
|
238
|
+
* Replaces: Token.createBase64BufferToken(token, rawToken)
|
|
239
|
+
*
|
|
240
|
+
* @param {Object} token - The token record (with string IDs)
|
|
241
|
+
* @param {string} rawToken - The raw token string
|
|
242
|
+
* @returns {string} Base64 encoded token
|
|
243
|
+
*/
|
|
244
|
+
createBase64BufferToken(token, rawToken) {
|
|
245
|
+
const jsonVal = this.createJSONToken(token, rawToken);
|
|
246
|
+
return Buffer.from(jsonVal).toString('base64');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Parse JSON token from base64 buffer
|
|
251
|
+
* Replaces: Token.getJSONTokenFromBase64BufferToken(buffer)
|
|
252
|
+
*
|
|
253
|
+
* Note: Parsed token ID will be a string, which is correct for application layer
|
|
254
|
+
*
|
|
255
|
+
* @param {string} buffer - Base64 encoded token string
|
|
256
|
+
* @returns {Object} Parsed token object with id and token (id as string)
|
|
257
|
+
*/
|
|
258
|
+
getJSONTokenFromBase64BufferToken(buffer) {
|
|
259
|
+
const tokenStr = Buffer.from(buffer.trim(), 'base64').toString('ascii');
|
|
260
|
+
return JSON.parse(tokenStr);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
module.exports = { TokenRepositoryPostgres };
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
const { prisma } = require('../../database/prisma');
|
|
2
|
+
const bcrypt = require('bcryptjs');
|
|
3
|
+
const { TokenRepositoryInterface } = require('./token-repository-interface');
|
|
4
|
+
|
|
5
|
+
const BCRYPT_ROUNDS = 10;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Prisma-based Token Repository
|
|
9
|
+
* Handles persistence of authentication tokens with bcrypt hashing
|
|
10
|
+
*
|
|
11
|
+
* Works identically for both MongoDB and PostgreSQL:
|
|
12
|
+
* - MongoDB: String IDs with @db.ObjectId
|
|
13
|
+
* - PostgreSQL: Integer IDs with auto-increment
|
|
14
|
+
* - Both use same query patterns (no many-to-many differences)
|
|
15
|
+
*
|
|
16
|
+
* Migration from Mongoose:
|
|
17
|
+
* - Constructor injection of Prisma client
|
|
18
|
+
* - Static methods → Instance methods
|
|
19
|
+
* - Token.createTokenWithExpire() → createTokenWithExpire()
|
|
20
|
+
* - Token.validateAndGetTokenFromJSONToken() → validateAndGetToken()
|
|
21
|
+
* - Bcrypt hashing handled in repository layer
|
|
22
|
+
*/
|
|
23
|
+
class TokenRepository extends TokenRepositoryInterface {
|
|
24
|
+
constructor(prismaClient = prisma) {
|
|
25
|
+
super();
|
|
26
|
+
this.prisma = prismaClient; // Allow injection for testing
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create a token with expiration
|
|
31
|
+
* Replaces: Token.createTokenWithExpire(userId, rawToken, minutes)
|
|
32
|
+
*
|
|
33
|
+
* @param {string} userId - The user ID
|
|
34
|
+
* @param {string} rawToken - The raw (unhashed) token string
|
|
35
|
+
* @param {number} minutes - Minutes until expiration
|
|
36
|
+
* @returns {Promise<Object>} The created token record
|
|
37
|
+
*/
|
|
38
|
+
async createTokenWithExpire(userId, rawToken, minutes) {
|
|
39
|
+
// Hash the token with bcrypt
|
|
40
|
+
const tokenHash = await bcrypt.hash(rawToken, BCRYPT_ROUNDS);
|
|
41
|
+
|
|
42
|
+
// Calculate expiration time
|
|
43
|
+
const expires = new Date(Date.now() + minutes * 60000);
|
|
44
|
+
|
|
45
|
+
return await this.prisma.token.create({
|
|
46
|
+
data: {
|
|
47
|
+
token: tokenHash,
|
|
48
|
+
expires,
|
|
49
|
+
userId,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Validate and retrieve token from JSON token object
|
|
56
|
+
* Replaces: Token.validateAndGetTokenFromJSONToken(tokenObj)
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} tokenObj - Object with id and token properties
|
|
59
|
+
* @returns {Promise<Object>} The validated token record
|
|
60
|
+
* @throws {Error} If token is invalid, expired, or doesn't exist
|
|
61
|
+
*/
|
|
62
|
+
async validateAndGetToken(tokenObj) {
|
|
63
|
+
const sessionToken = await this.prisma.token.findUnique({
|
|
64
|
+
where: { id: tokenObj.id },
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!sessionToken) {
|
|
68
|
+
throw new Error('Invalid Token: Token does not exist');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Verify token hash matches
|
|
72
|
+
const isValid = await bcrypt.compare(
|
|
73
|
+
tokenObj.token,
|
|
74
|
+
sessionToken.token
|
|
75
|
+
);
|
|
76
|
+
if (!isValid) {
|
|
77
|
+
throw new Error('Invalid Token: Token does not match');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check if token is expired
|
|
81
|
+
if (
|
|
82
|
+
sessionToken.expires &&
|
|
83
|
+
new Date(sessionToken.expires) < new Date()
|
|
84
|
+
) {
|
|
85
|
+
throw new Error('Invalid Token: Token is expired');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return sessionToken;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Find a token by ID
|
|
93
|
+
* Replaces: Token.findById(tokenId)
|
|
94
|
+
*
|
|
95
|
+
* @param {string} tokenId - The token ID
|
|
96
|
+
* @returns {Promise<Object|null>} The token record or null
|
|
97
|
+
*/
|
|
98
|
+
async findTokenById(tokenId) {
|
|
99
|
+
return await this.prisma.token.findUnique({
|
|
100
|
+
where: { id: tokenId },
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Find tokens by user ID
|
|
106
|
+
* Replaces: Token.find({ user: userId })
|
|
107
|
+
*
|
|
108
|
+
* @param {string} userId - The user ID
|
|
109
|
+
* @returns {Promise<Array>} Array of token records
|
|
110
|
+
*/
|
|
111
|
+
async findTokensByUserId(userId) {
|
|
112
|
+
return await this.prisma.token.findMany({
|
|
113
|
+
where: { userId },
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Delete a token by ID
|
|
119
|
+
* Replaces: Token.deleteOne({ _id: tokenId })
|
|
120
|
+
*
|
|
121
|
+
* @param {string} tokenId - The token ID
|
|
122
|
+
* @returns {Promise<Object>} The deletion result
|
|
123
|
+
*/
|
|
124
|
+
async deleteToken(tokenId) {
|
|
125
|
+
try {
|
|
126
|
+
await this.prisma.token.delete({
|
|
127
|
+
where: { id: tokenId },
|
|
128
|
+
});
|
|
129
|
+
return { acknowledged: true, deletedCount: 1 };
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (error.code === 'P2025') {
|
|
132
|
+
// Record not found
|
|
133
|
+
return { acknowledged: true, deletedCount: 0 };
|
|
134
|
+
}
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Delete expired tokens
|
|
141
|
+
* Replaces: Token.deleteMany({ expires: { $lt: new Date() } })
|
|
142
|
+
*
|
|
143
|
+
* @returns {Promise<Object>} The deletion result with count
|
|
144
|
+
*/
|
|
145
|
+
async deleteExpiredTokens() {
|
|
146
|
+
const result = await this.prisma.token.deleteMany({
|
|
147
|
+
where: {
|
|
148
|
+
expires: {
|
|
149
|
+
lt: new Date(),
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
acknowledged: true,
|
|
156
|
+
deletedCount: result.count,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Delete all tokens for a user
|
|
162
|
+
* Replaces: Token.deleteMany({ user: userId })
|
|
163
|
+
*
|
|
164
|
+
* @param {string} userId - The user ID
|
|
165
|
+
* @returns {Promise<Object>} The deletion result
|
|
166
|
+
*/
|
|
167
|
+
async deleteTokensByUserId(userId) {
|
|
168
|
+
const result = await this.prisma.token.deleteMany({
|
|
169
|
+
where: { userId },
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
acknowledged: true,
|
|
174
|
+
deletedCount: result.count,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Create JSON token string from token object and raw token
|
|
180
|
+
* Replaces: Token.createJSONToken(token, rawToken)
|
|
181
|
+
*
|
|
182
|
+
* @param {Object} token - The token record
|
|
183
|
+
* @param {string} rawToken - The raw token string
|
|
184
|
+
* @returns {string} JSON string with id and token
|
|
185
|
+
*/
|
|
186
|
+
createJSONToken(token, rawToken) {
|
|
187
|
+
return JSON.stringify({
|
|
188
|
+
id: token.id,
|
|
189
|
+
token: rawToken,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Create base64 encoded buffer token
|
|
195
|
+
* Replaces: Token.createBase64BufferToken(token, rawToken)
|
|
196
|
+
*
|
|
197
|
+
* @param {Object} token - The token record
|
|
198
|
+
* @param {string} rawToken - The raw token string
|
|
199
|
+
* @returns {string} Base64 encoded token
|
|
200
|
+
*/
|
|
201
|
+
createBase64BufferToken(token, rawToken) {
|
|
202
|
+
const jsonVal = this.createJSONToken(token, rawToken);
|
|
203
|
+
return Buffer.from(jsonVal).toString('base64');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Parse JSON token from base64 buffer
|
|
208
|
+
* Replaces: Token.getJSONTokenFromBase64BufferToken(buffer)
|
|
209
|
+
*
|
|
210
|
+
* @param {string} buffer - Base64 encoded token string
|
|
211
|
+
* @returns {Object} Parsed token object with id and token
|
|
212
|
+
*/
|
|
213
|
+
getJSONTokenFromBase64BufferToken(buffer) {
|
|
214
|
+
const tokenStr = Buffer.from(buffer.trim(), 'base64').toString('ascii');
|
|
215
|
+
return JSON.parse(tokenStr);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
module.exports = { TokenRepository };
|
package/types/core/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
declare module "@friggframework/core" {
|
|
2
|
-
import {
|
|
2
|
+
import type { SendMessageCommandInput } from "@aws-sdk/client-sqs";
|
|
3
3
|
|
|
4
4
|
export class Delegate implements IFriggDelegate {
|
|
5
5
|
delegate: any;
|
|
@@ -50,5 +50,5 @@ declare module "@friggframework/core" {
|
|
|
50
50
|
QueueOwnerAWSAccountId?: string;
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
type SendSQSMessageParams =
|
|
53
|
+
type SendSQSMessageParams = SendMessageCommandInput;
|
|
54
54
|
}
|