@accounter/server
Version:
Accounter GraphQL server
97 lines • 4.22 kB
JavaScript
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