@ductape/sdk 0.1.124 → 0.1.128
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/dist/index.d.ts +28 -1
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -1
- package/dist/processor/services/processor.service.d.ts +4 -0
- package/dist/processor/services/processor.service.js +86 -3
- package/dist/processor/services/processor.service.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productHealthcheck.validator.js +25 -10
- package/dist/products/validators/joi-validators/create.productHealthcheck.validator.js.map +1 -1
- package/dist/resilience/healthcheck.service.d.ts +22 -0
- package/dist/resilience/healthcheck.service.js +171 -2
- package/dist/resilience/healthcheck.service.js.map +1 -1
- package/dist/resilience/index.d.ts +1 -0
- package/dist/resilience/index.js +1 -0
- package/dist/resilience/index.js.map +1 -1
- package/dist/resilience/rate-limit.service.d.ts +37 -0
- package/dist/resilience/rate-limit.service.js +55 -0
- package/dist/resilience/rate-limit.service.js.map +1 -0
- package/dist/resilience/resilience.service.js +42 -0
- package/dist/resilience/resilience.service.js.map +1 -1
- package/dist/resilience/types/index.d.ts +46 -2
- package/dist/resilience/types/index.js +3 -0
- package/dist/resilience/types/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/productsBuilder.types.d.ts +8 -1
- package/dist/types/productsBuilder.types.js +3 -0
- package/dist/types/productsBuilder.types.js.map +1 -1
- package/dist/vector/adapters/opensearch.adapter.js +1 -1
- package/dist/vector/adapters/opensearch.adapter.js.map +1 -1
- package/package.json +1 -1
|
@@ -157,6 +157,10 @@ export default class ProcessorService implements IProcessorService {
|
|
|
157
157
|
messageBroker?: string;
|
|
158
158
|
message_broker?: string;
|
|
159
159
|
storage?: string;
|
|
160
|
+
cache?: string;
|
|
161
|
+
vector?: string;
|
|
162
|
+
notification?: string;
|
|
163
|
+
channels?: string[];
|
|
160
164
|
event?: string;
|
|
161
165
|
input?: any;
|
|
162
166
|
};
|
|
@@ -57,6 +57,7 @@ const processor_utils_1 = require("../utils/processor.utils");
|
|
|
57
57
|
const axios_1 = __importDefault(require("axios"));
|
|
58
58
|
const processorApi_service_1 = require("../../api/services/processorApi.service");
|
|
59
59
|
const cache_service_1 = require("../../cache/cache.service");
|
|
60
|
+
const vector_1 = require("../../vector");
|
|
60
61
|
const expo_client_1 = __importDefault(require("../../clients/expo.client"));
|
|
61
62
|
const handlebars_1 = require("handlebars");
|
|
62
63
|
const string_utils_1 = require("../../products/utils/string.utils");
|
|
@@ -582,7 +583,7 @@ class ProcessorService {
|
|
|
582
583
|
* Public so the SDK monitor worker can call it with full healthcheck (including probe).
|
|
583
584
|
*/
|
|
584
585
|
async runOneHealthcheck(healthcheck, envSlug, decryptedInput, productTag) {
|
|
585
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
586
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
586
587
|
const probe = healthcheck.probe;
|
|
587
588
|
const retries = (_a = healthcheck.retries) !== null && _a !== void 0 ? _a : 0;
|
|
588
589
|
const inferType = () => {
|
|
@@ -598,6 +599,12 @@ class ProcessorService {
|
|
|
598
599
|
return 'graph';
|
|
599
600
|
if (probe === null || probe === void 0 ? void 0 : probe.storage)
|
|
600
601
|
return 'storage';
|
|
602
|
+
if (probe === null || probe === void 0 ? void 0 : probe.cache)
|
|
603
|
+
return 'cache';
|
|
604
|
+
if (probe === null || probe === void 0 ? void 0 : probe.vector)
|
|
605
|
+
return 'vector';
|
|
606
|
+
if (probe === null || probe === void 0 ? void 0 : probe.notification)
|
|
607
|
+
return 'notification';
|
|
601
608
|
if ((probe === null || probe === void 0 ? void 0 : probe.events) || (probe === null || probe === void 0 ? void 0 : probe.messageBroker) || (probe === null || probe === void 0 ? void 0 : probe.message_broker))
|
|
602
609
|
return 'events';
|
|
603
610
|
return 'app';
|
|
@@ -664,12 +671,88 @@ class ProcessorService {
|
|
|
664
671
|
input: { message: typeof decryptedInput === 'object' && decryptedInput != null ? decryptedInput : {} },
|
|
665
672
|
});
|
|
666
673
|
}
|
|
674
|
+
case 'cache': {
|
|
675
|
+
if (!this.redisClient) {
|
|
676
|
+
throw Object.assign(new Error('Healthcheck cache probes require Redis'), { code: 'HEALTHCHECK_REDIS_REQUIRED', retryable: false });
|
|
677
|
+
}
|
|
678
|
+
const started = Date.now();
|
|
679
|
+
const pong = await this.redisClient.ping();
|
|
680
|
+
return { status: pong === 'PONG' ? 'healthy' : 'unhealthy', latencyMs: Date.now() - started, cache: probe.cache };
|
|
681
|
+
}
|
|
682
|
+
case 'vector': {
|
|
683
|
+
const svc = new vector_1.VectorDatabaseService({
|
|
684
|
+
workspace_id: this.workspace_id, public_key: this.public_key, user_id: this.user_id,
|
|
685
|
+
token: this.token, env_type: this.environment, redis_client: this.redisClient,
|
|
686
|
+
private_key: this._privateKey, access_key: this.accessKey,
|
|
687
|
+
});
|
|
688
|
+
const started = Date.now();
|
|
689
|
+
const connection = await svc.connect({ product: productTag, env: envSlug, vector: probe.vector });
|
|
690
|
+
try {
|
|
691
|
+
const healthy = await connection.testConnection();
|
|
692
|
+
return { status: healthy ? 'healthy' : 'unhealthy', latencyMs: Date.now() - started, vector: probe.vector };
|
|
693
|
+
}
|
|
694
|
+
finally {
|
|
695
|
+
await svc.disconnect({ product: productTag, env: envSlug, vector: probe.vector });
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
case 'notification': {
|
|
699
|
+
// Non-delivering check: validate configuration and use provider identity/account
|
|
700
|
+
// endpoints where the provider supports one. Never sends a notification.
|
|
701
|
+
const started = Date.now();
|
|
702
|
+
const notification = await this.productBuilderService.fetchNotification(probe.notification);
|
|
703
|
+
if (!notification)
|
|
704
|
+
throw Object.assign(new Error(`Notification "${probe.notification}" not found`), { code: 'HEALTHCHECK_NOTIFICATION_NOT_FOUND' });
|
|
705
|
+
const requested = (_k = probe.channels) !== null && _k !== void 0 ? _k : [];
|
|
706
|
+
const envConfig = ((_l = notification.envs) !== null && _l !== void 0 ? _l : []).find((item) => item.slug === envSlug);
|
|
707
|
+
if (!envConfig)
|
|
708
|
+
throw Object.assign(new Error(`Notification has no environment "${envSlug}"`), { code: 'HEALTHCHECK_NOTIFICATION_ENV_MISSING' });
|
|
709
|
+
const configured = { sms: envConfig.sms, email: envConfig.emails, push: envConfig.push_notifications };
|
|
710
|
+
const missing = requested.filter((channel) => !configured[channel]);
|
|
711
|
+
if (missing.length)
|
|
712
|
+
throw Object.assign(new Error(`Notification channels are not configured: ${missing.join(', ')}`), { code: 'HEALTHCHECK_NOTIFICATION_CHANNEL_MISSING' });
|
|
713
|
+
const verifiedChannels = [];
|
|
714
|
+
for (const channel of requested) {
|
|
715
|
+
const config = configured[channel];
|
|
716
|
+
try {
|
|
717
|
+
if (channel === 'email' && String(config.provider).toLowerCase() === 'sendgrid') {
|
|
718
|
+
await axios_1.default.get('https://api.sendgrid.com/v3/user/profile', { headers: { Authorization: `Bearer ${(_m = config.sendgrid) === null || _m === void 0 ? void 0 : _m.apiKey}` }, timeout: 10000 });
|
|
719
|
+
verifiedChannels.push(channel);
|
|
720
|
+
}
|
|
721
|
+
else if (channel === 'sms' && ['nexmo', 'vonage'].includes(String(config.provider).toLowerCase())) {
|
|
722
|
+
await axios_1.default.get('https://rest.nexmo.com/account/get-balance', { params: { api_key: config.apiKey, api_secret: config.apiSecret }, timeout: 10000 });
|
|
723
|
+
verifiedChannels.push(channel);
|
|
724
|
+
}
|
|
725
|
+
else if (channel === 'push' && String(config.type).toLowerCase() === 'firebase') {
|
|
726
|
+
const app = await this.getFirebaseApp(config.credentials, { workspaceId: this.workspace_id, product: productTag });
|
|
727
|
+
await app.options.credential.getAccessToken();
|
|
728
|
+
verifiedChannels.push(channel);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
catch (_r) {
|
|
732
|
+
// Do not leak provider credentials through an Axios error/config object.
|
|
733
|
+
throw Object.assign(new Error(`Notification ${channel} provider credential check failed`), {
|
|
734
|
+
code: 'HEALTHCHECK_NOTIFICATION_CREDENTIALS_INVALID',
|
|
735
|
+
retryable: false,
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
const allVerified = verifiedChannels.length === requested.length;
|
|
740
|
+
return {
|
|
741
|
+
status: allVerified ? 'healthy' : 'degraded',
|
|
742
|
+
latencyMs: Date.now() - started,
|
|
743
|
+
notification: probe.notification,
|
|
744
|
+
channels: requested,
|
|
745
|
+
verifiedChannels,
|
|
746
|
+
deliveryAttempted: false,
|
|
747
|
+
credentialsVerified: allVerified,
|
|
748
|
+
};
|
|
749
|
+
}
|
|
667
750
|
default:
|
|
668
751
|
return this.processAction({
|
|
669
752
|
env: envSlug,
|
|
670
753
|
product: productTag,
|
|
671
|
-
app: (
|
|
672
|
-
action: (
|
|
754
|
+
app: (_o = healthcheck.app) !== null && _o !== void 0 ? _o : '',
|
|
755
|
+
action: (_q = (_p = healthcheck.event) !== null && _p !== void 0 ? _p : event) !== null && _q !== void 0 ? _q : '',
|
|
673
756
|
input: decryptedInput !== null && decryptedInput !== void 0 ? decryptedInput : {},
|
|
674
757
|
retries,
|
|
675
758
|
});
|