@vectry/js-core
Version:
Universal JavaScript SDK core for Vectry Analytics. Enables structured event capture, enrichment, validation, and transport across environments.
446 lines (431 loc) • 12.3 kB
JavaScript
// src/services/base/api.service.ts
var ApiService = class {
constructor(apiServiceParameters) {
this.apiServiceConfig = apiServiceParameters.config;
this.endpointUrl = apiServiceParameters.baseUrl;
this.endpoints = apiServiceParameters.endpoints;
}
objectToQueryString(obj) {
if (!obj || typeof obj !== "object") return "";
const build = (o, prefix = "") => Object.keys(o).flatMap((key) => {
const k = prefix ? `${prefix}[${key}]` : key;
const v = o[key];
if (v && typeof v === "object") return build(v, k);
return `${encodeURIComponent(k)}=${encodeURIComponent(v ?? "")}`;
});
const query = build(obj).join("&");
return query ? `?${query}` : "";
}
async getByParameters(data) {
if (!data?.queryselector) throw new Error("Missing queryselector");
const query = this.objectToQueryString(data);
const fullPath = `${this.apiServiceConfig.baseUrl}${this.endpointUrl}${this.endpoints.get ?? ""}${data.queryselector}${query}`;
return this.apiServiceConfig?.transport?.get(fullPath, {});
}
async create(payload) {
const fullPath = `${this.apiServiceConfig.baseUrl}${this.endpointUrl}${this.endpoints.create ?? ""}`;
return this.apiServiceConfig?.transport?.post(fullPath, payload);
}
async update(payload) {
const fullPath = `${this.apiServiceConfig.baseUrl}${this.endpointUrl}${this.endpoints.update ?? ""}`;
return this.apiServiceConfig?.transport?.patch(fullPath, payload);
}
async delete(payload) {
const fullPath = `${this.apiServiceConfig.baseUrl}${this.endpointUrl}${this.endpoints.delete ?? ""}`;
return this.apiServiceConfig?.transport?.delete(fullPath, payload);
}
async post(payload, endpoint) {
const fullPath = `${this.apiServiceConfig.baseUrl}${this.endpointUrl}${endpoint ?? this.endpoints.post ?? ""}`;
return this.apiServiceConfig?.transport?.post(fullPath, payload);
}
async put(payload, endpoint) {
const fullPath = `${this.apiServiceConfig.baseUrl}${this.endpointUrl}${endpoint ?? this.endpoints.put ?? ""}`;
return this.apiServiceConfig?.transport?.put(fullPath, payload);
}
async patch(payload, endpoint) {
const fullPath = `${this.apiServiceConfig.baseUrl}${this.endpointUrl}${endpoint ?? this.endpoints.patch ?? ""}`;
return this.apiServiceConfig?.transport?.patch(fullPath, payload);
}
};
// src/services/observation/event.service.ts
var EventService = class extends ApiService {
constructor(config) {
super({
config,
baseUrl: "/causal/observation/event",
endpoints: {
get: "/",
create: "",
update: "",
delete: ""
}
});
}
/**
* Fetches events based on custom filtering parameters.
* @param data An object containing the query selector and filters.
*/
async getByParameters(data) {
return super.getByParameters(data);
}
/**
* Sends a new event to the backend.
* @param payload Event data to be created.
*/
async create(payload) {
return super.create(payload);
}
/**
* Updates an existing event.
* @param payload Event data to be updated.
*/
async update(payload) {
return super.update(payload);
}
/**
* Deletes an event.
* @param payload Identifier or full object of the event to delete.
*/
async delete(payload) {
return super.delete(payload);
}
};
// src/config/environmentMap.ts
var EnvironmentBaseUrls = {
local: "http://localhost:3101",
development: "https://vectry-backend-svc-dev.azurewebsites.net",
production: "https://api.vectry.io"
};
// src/config/defaultConfig.ts
var defaultConfig = {
organizationId: "",
vectryEnvironment: "production",
baseUrl: EnvironmentBaseUrls["production"],
contextProvider: async () => ({ user: { id: "anonymous" } }),
autoFlush: true,
flushIntervalMs: 1e4,
enrichers: []
};
// src/config/runtimeConfig.ts
var currentConfig = { ...defaultConfig };
function getRuntimeConfig() {
return currentConfig;
}
function setRuntimeConfig(config) {
currentConfig = {
...defaultConfig,
...currentConfig,
...config
};
}
// src/utils/timestamp.ts
function getCurrentTimestamp() {
return (/* @__PURE__ */ new Date()).toISOString();
}
function normalizeTimestamp(input) {
if (input instanceof Date) return input.toISOString();
if (typeof input === "number") return new Date(input).toISOString();
return new Date(input).toISOString();
}
// src/utils/object.ts
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
function isEmptyObject(obj) {
return Object.keys(obj).length === 0 && obj.constructor === Object;
}
// src/utils/detect-mutation.ts
function detectMutation(input) {
const { original, updated, ignoreProperties = [] } = input;
const originalDiff = {};
const updatedDiff = {};
function compare(key, a, b) {
if (ignoreProperties.includes(key)) return false;
const bothObjects = typeof a === "object" && typeof b === "object" && a !== null && b !== null;
if (bothObjects && !Array.isArray(a) && !Array.isArray(b)) {
const nested = detectMutation({ original: a, updated: b, ignoreProperties });
if (nested) {
originalDiff[key] = nested.original;
updatedDiff[key] = nested.updated;
return true;
}
return false;
}
const isDifferent = JSON.stringify(a) !== JSON.stringify(b);
if (isDifferent) {
originalDiff[key] = a;
updatedDiff[key] = b;
}
return isDifferent;
}
const keys = /* @__PURE__ */ new Set([...Object.keys(original || {}), ...Object.keys(updated || {})]);
let hasDiff = false;
for (const key of keys) {
if (compare(key, original?.[key], updated?.[key])) {
hasDiff = true;
}
}
return hasDiff ? { original: originalDiff, updated: updatedDiff } : null;
}
// src/core/enrich.ts
function enrichEvent(event) {
return {
...event,
created: {
user: { id: "anonymous" },
// Can be replaced by context provider later
timestamp: getCurrentTimestamp()
},
status: {
id: 1,
name: "active",
title: "Active"
},
metadata: event.metadata ?? {},
context: event.context ?? {}
};
}
// src/core/validate.ts
function validateEvent(event) {
const requiredFields = [
"organization_id",
"namespace",
"actor_id",
"actor_type"
];
const missing = requiredFields.filter((field) => !event[field]);
if (missing.length > 0) {
throw new Error(`Missing required event fields: ${missing.join(", ")}`);
}
}
// src/core/capture.ts
async function capture(event) {
const config = getRuntimeConfig();
if (!config.transport) {
throw new Error("Transport not initialized in runtime config.");
}
const enriched = enrichEvent(event);
validateEvent(enriched);
const service = new EventService(config);
return await service.create(enriched);
}
// src/services/observation/event-explanation.service.ts
var EventExplanationService = class extends ApiService {
constructor(config) {
super({
config,
baseUrl: "/causal/observation/event",
endpoints: {
get: "/",
create: "",
update: "",
delete: ""
}
});
}
/**
* Fetches events based on custom filtering parameters.
* @param data An object containing the query selector and filters.
*/
async getByParameters(data) {
return super.getByParameters(data);
}
/**
* Sends a new event to the backend.
* @param payload EventExplanation data to be created.
*/
async create(payload) {
return super.create(payload);
}
/**
* Updates an existing event.
* @param payload EventExplanation data to be updated.
*/
async update(payload) {
return super.update(payload);
}
/**
* Deletes an event.
* @param payload Identifier or full object of the event to delete.
*/
async delete(payload) {
return super.delete(payload);
}
};
// src/services/execution/trace.service.ts
var TraceService = class extends ApiService {
constructor(config) {
super({
config,
baseUrl: "/causal/observation/event",
endpoints: {
get: "/",
create: "",
update: "",
delete: ""
}
});
}
/**
* Fetches events based on custom filtering parameters.
* @param data An object containing the query selector and filters.
*/
async getByParameters(data) {
return super.getByParameters(data);
}
/**
* Sends a new event to the backend.
* @param payload Trace data to be created.
*/
async create(payload) {
return super.create(payload);
}
/**
* Updates an existing event.
* @param payload Trace data to be updated.
*/
async update(payload) {
return super.update(payload);
}
/**
* Deletes an event.
* @param payload Identifier or full object of the event to delete.
*/
async delete(payload) {
return super.delete(payload);
}
};
// src/services/execution/causal-thread.service.ts
var CausalThreadService = class extends ApiService {
constructor(config) {
super({
config,
baseUrl: "/causal/observation/event",
endpoints: {
get: "/",
create: "",
update: "",
delete: ""
}
});
}
/**
* Fetches events based on custom filtering parameters.
* @param data An object containing the query selector and filters.
*/
async getByParameters(data) {
return super.getByParameters(data);
}
/**
* Sends a new event to the backend.
* @param payload CausalThread data to be created.
*/
async create(payload) {
return super.create(payload);
}
/**
* Updates an existing event.
* @param payload CausalThread data to be updated.
*/
async update(payload) {
return super.update(payload);
}
/**
* Deletes an event.
* @param payload Identifier or full object of the event to delete.
*/
async delete(payload) {
return super.delete(payload);
}
};
// src/services/analysis/anomaly.service.ts
var AnomalyService = class extends ApiService {
constructor(config) {
super({
config,
baseUrl: "/causal/observation/event",
endpoints: {
get: "/",
create: "",
update: "",
delete: ""
}
});
}
/**
* Fetches events based on custom filtering parameters.
* @param data An object containing the query selector and filters.
*/
async getByParameters(data) {
return super.getByParameters(data);
}
/**
* Sends a new event to the backend.
* @param payload Anomaly data to be created.
*/
async create(payload) {
return super.create(payload);
}
/**
* Updates an existing event.
* @param payload Anomaly data to be updated.
*/
async update(payload) {
return super.update(payload);
}
/**
* Deletes an event.
* @param payload Identifier or full object of the event to delete.
*/
async delete(payload) {
return super.delete(payload);
}
};
// src/sdk/VectryCore.ts
var VectryCore = class {
constructor(args) {
this.detectMutation = detectMutation;
this.transport = args.transport;
this.organizationId = args.organizationId;
setRuntimeConfig({
...defaultConfig,
...args
});
this.event = new EventService({ transport: this.transport });
this.trace = new TraceService({ transport: this.transport });
this.thread = new CausalThreadService({ transport: this.transport });
this.eventExplanation = new EventExplanationService({ transport: this.transport });
this.anomaly = new AnomalyService({ transport: this.transport });
}
/**
* Captures a raw event and sends it to Vectry using the core handler.
* Automatically enriches, validates, and dispatches the event.
*/
async capture(event) {
if (!event) {
throw new Error("Event cannot be null or undefined");
}
return capture(event);
}
};
export {
AnomalyService,
CausalThreadService,
EnvironmentBaseUrls,
EventExplanationService,
EventService,
TraceService,
VectryCore,
capture,
deepClone,
defaultConfig,
detectMutation,
enrichEvent,
getCurrentTimestamp,
getRuntimeConfig,
isEmptyObject,
normalizeTimestamp,
setRuntimeConfig,
validateEvent
};
//# sourceMappingURL=index.mjs.map