UNPKG

@accounter/server

Version:
97 lines 4.22 kB
import { __decorate, __metadata, __param } from "tslib"; import { GraphQLError } from 'graphql'; import { Inject, Injectable, Scope } from 'graphql-modules'; import { sql } from '@pgtyped/runtime'; import { ENVIRONMENT } from '../../../shared/tokens.js'; import { TenantAwareDBClient } from '../../app-providers/tenant-db-client.js'; import { decryptCredential, encryptCredential } from '../helpers/encryption.js'; import { DeelPayloadSchema, GreenInvoicePayloadSchema, } from '../helpers/payload-schemas.js'; const PROVIDER_SCHEMAS = { green_invoice: GreenInvoicePayloadSchema, deel: DeelPayloadSchema, }; const upsertProviderCredentials = sql ` INSERT INTO accounter_schema.provider_credentials (owner_id, provider, payload) VALUES (accounter_schema.get_current_business_id(), $provider, $encrypted) ON CONFLICT (owner_id, provider) DO UPDATE SET payload = EXCLUDED.payload, updated_at = now() RETURNING updated_at;`; const deleteProviderCredentials = sql ` DELETE FROM accounter_schema.provider_credentials WHERE owner_id = accounter_schema.get_current_business_id() AND provider = $provider;`; const getProviderStatuses = sql ` SELECT provider, updated_at FROM accounter_schema.provider_credentials WHERE owner_id = accounter_schema.get_current_business_id();`; const getProviderCredentialPayload = sql ` SELECT payload FROM accounter_schema.provider_credentials WHERE owner_id = accounter_schema.get_current_business_id() AND provider = $provider;`; let ProviderCredentialsProvider = class ProviderCredentialsProvider { db; env; constructor(db, env) { this.db = db; this.env = env; } get encryptionKey() { const key = this.env.credentialsEncryptionKey; if (!key) { throw new GraphQLError('Credentials encryption key is not configured', { extensions: { code: 'INTERNAL_SERVER_ERROR' }, }); } return key; } async setCredentials(provider, payload) { const schema = PROVIDER_SCHEMAS[provider]; const result = schema.safeParse(payload); if (!result.success) { throw new GraphQLError(`Invalid credentials for provider "${provider}"`, { extensions: { code: 'BAD_USER_INPUT', details: result.error.flatten() }, }); } const encrypted = encryptCredential(JSON.stringify(result.data), this.encryptionKey); const credentials = await upsertProviderCredentials.run({ provider, encrypted }, this.db); return credentials[0]?.updated_at; } async deleteCredentials(provider) { await deleteProviderCredentials.run({ provider }, this.db); } async getProviderStatuses() { const rows = await getProviderStatuses.run(undefined, this.db); return rows.map(row => ({ provider: row.provider, configuredAt: row.updated_at.toISOString(), })); } async getGreenInvoiceCredentials() { return this._getDecrypted('green_invoice', GreenInvoicePayloadSchema); } async getDeelCredentials() { return this._getDecrypted('deel', DeelPayloadSchema); } async _getDecrypted(provider, schema) { const rows = await getProviderCredentialPayload.run({ provider }, this.db); if (rows.length === 0) return null; try { const plaintext = decryptCredential(rows[0].payload, this.encryptionKey); return schema.parse(JSON.parse(plaintext)); } catch (err) { console.error(`[ProviderCredentialsProvider] Failed to decrypt/parse "${provider}" credentials: ${err instanceof Error ? err.message : String(err)}`); throw new GraphQLError('Failed to retrieve provider credentials', { extensions: { code: 'INTERNAL_SERVER_ERROR' }, }); } } }; ProviderCredentialsProvider = __decorate([ Injectable({ scope: Scope.Operation, global: true }), __param(1, Inject(ENVIRONMENT)), __metadata("design:paramtypes", [TenantAwareDBClient, Object]) ], ProviderCredentialsProvider); export { ProviderCredentialsProvider }; //# sourceMappingURL=provider-credentials.provider.js.map