@ultipa-graph/ultipa-driver
Version:
NodeJS SDK for Ultipa GQL
230 lines • 32.4 kB
JavaScript
;
/**
* Data service handles node and edge insert/delete/export operations.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataService = void 0;
exports.parseVersion = parseVersion;
const types_1 = require("../types");
const services_1 = require("../services");
const converters_1 = require("./converters");
const errors_1 = require("../errors");
/**
* Minimum server version that supports `InsertMode.UPSERT` on the bulk-import
* RPCs. Older servers ignore the unknown enum value and silently downgrade
* to Normal, surfacing as a confusing "duplicate _id" error.
*
* See `GQLDB-6.1.149-DRIVER-AND-TEST-HANDOFF-2026-05-05.md` (Test plan section D).
*/
const UPSERT_MIN_VERSION = [6, 1, 149];
/**
* Parse leading major.minor.patch from a server version string.
* Returns [0,0,0] on parse failure (treated as "unknown / pre-6.1.149").
*/
function parseVersion(s) {
if (!s)
return [0, 0, 0];
const m = s.match(/(\d+)\.(\d+)\.(\d+)/);
if (!m)
return [0, 0, 0];
return [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10)];
}
function versionGTE(actual, required) {
for (let i = 0; i < 3; i++) {
if (actual[i] !== required[i])
return actual[i] > required[i];
}
return true;
}
/**
* Data service for inserting, deleting, and exporting graph data.
*/
class DataService {
ctx;
constructor(ctx) {
this.ctx = ctx;
}
/**
* Throw GqldbError if `mode` is UPSERT and the connected server is
* older than 6.1.149.
*
* Server >= 6.1.154 reports the real version in
* `LoginResponse.server_version`. Older servers either return a
* placeholder "1.0.0" or leave the field empty — both are now treated
* as "definitely older than 6.1.149" and rejected. (Earlier versions
* of this gate let those cases pass through; that workaround was
* removed once 6.1.154+ started populating the field correctly.)
*/
requireUpsertSupport(mode) {
if (mode !== types_1.InsertType.Upsert)
return;
const session = this.ctx.sessions.getSession();
const serverVer = session?.serverVersion || '';
if (!versionGTE(parseVersion(serverVer), UPSERT_MIN_VERSION)) {
throw new errors_1.GqldbError(`InsertType.Upsert requires server >= ${UPSERT_MIN_VERSION.join('.')}, ` +
`connected server reports ${serverVer || 'unknown'}`);
}
}
/**
* Insert multiple nodes into a graph.
*/
async insertNodes(graphName, nodes, config) {
this.requireUpsertSupport(config?.options?.mode);
const request = {
graph_name: graphName,
nodes: nodes.map((n) => (0, converters_1.nodeDataToProto)(n)),
};
// ALWAYS set options (even when undefined) to avoid deprecated bulk operations error.
// `mode` is a numeric enum aligned with proto InsertMode values; pass through directly.
request.options = { mode: (config?.options?.mode ?? 0) };
if (config?.bulkImportSessionId) {
request.bulk_import_session_id = config.bulkImportSessionId;
}
const metadata = this.ctx.getSessionMetadata();
const response = await (0, services_1.promisifyCall)(this.ctx.clients.dataService, 'InsertNodes', request, metadata);
return {
success: response.success || false,
nodeIds: response.node_ids || [],
nodeCount: parseInt(response.node_count || '0', 10),
message: response.message || '',
};
}
/**
* Insert multiple edges into a graph.
*/
async insertEdges(graphName, edges, config) {
this.requireUpsertSupport(config?.options?.mode);
const request = {
graph_name: graphName,
edges: edges.map((e) => (0, converters_1.edgeDataToProto)(e)),
};
// ALWAYS set options (even when undefined) to avoid deprecated bulk operations error.
request.options = {
skip_invalid_nodes: config?.options?.skipInvalidNodes || false,
mode: (config?.options?.mode ?? 0),
};
if (config?.bulkImportSessionId) {
request.bulk_import_session_id = config.bulkImportSessionId;
}
const metadata = this.ctx.getSessionMetadata();
const response = await (0, services_1.promisifyCall)(this.ctx.clients.dataService, 'InsertEdges', request, metadata);
return {
success: response.success || false,
edgeIds: response.edge_ids || [],
edgeCount: parseInt(response.edge_count || '0', 10),
message: response.message || '',
skippedCount: parseInt(response.skipped_count || '0', 10),
};
}
// deleteNodes / deleteEdges no longer go through the gRPC DataService
// DeleteNodes / DeleteEdges RPCs (those proto methods are being removed
// server-side). The public delete API lives on GqldbClient as
// deleteNodesByIds / deleteNodesByCondition / deleteEdgesByIds /
// deleteEdgesByCondition, which emit GQL and return a full Response.
/**
* Export graph data in JSON Lines format (streaming).
*/
async export(config, callback) {
const request = {
graph_name: config.graphName,
batch_size: config.batchSize || 0,
export_nodes: config.exportNodes !== false,
export_edges: config.exportEdges !== false,
node_labels: config.nodeLabels || [],
edge_labels: config.edgeLabels || [],
include_metadata: config.includeMetadata || false,
};
const metadata = this.ctx.getSessionMetadata();
return new Promise((resolve, reject) => {
const stream = this.ctx.clients.dataService.Export(request, metadata);
stream.on('data', (response) => {
if (callback) {
let stats;
if (response.stats) {
stats = {
nodesExported: parseInt(response.stats.nodes_exported || '0', 10),
edgesExported: parseInt(response.stats.edges_exported || '0', 10),
bytesWritten: parseInt(response.stats.bytes_written || '0', 10),
durationMs: parseInt(response.stats.duration_ms || '0', 10),
};
}
const chunk = {
data: Buffer.from(response.data || []),
isFinal: response.is_final || false,
stats,
};
callback(chunk);
}
if (response.is_final) {
stream.cancel();
}
});
stream.on('end', () => resolve());
stream.on('error', (error) => reject(error));
});
}
/**
* Stream nodes from a graph.
* @deprecated Use export() with ExportConfig instead
*/
async exportNodes(graphName, labels, limit = 0, callback) {
console.warn('exportNodes is deprecated, use export() with ExportConfig instead');
const request = {
graph_name: graphName,
labels: labels || [],
limit: limit.toString(),
};
const metadata = this.ctx.getSessionMetadata();
return new Promise((resolve, reject) => {
const stream = this.ctx.clients.dataService.ExportNodes(request, metadata);
stream.on('data', (response) => {
if (callback) {
callback({
nodes: (response.nodes || []).map((n) => ({
id: n.id || '',
labels: n.labels || [],
properties: (0, converters_1.convertProtoProperties)(n.properties || {}),
})),
hasMore: response.has_more || false,
});
}
});
stream.on('end', () => resolve());
stream.on('error', (error) => reject(error));
});
}
/**
* Stream edges from a graph.
* @deprecated Use export() with ExportConfig instead
*/
async exportEdges(graphName, labels, limit = 0, callback) {
console.warn('exportEdges is deprecated, use export() with ExportConfig instead');
const request = {
graph_name: graphName,
labels: labels || [],
limit: limit.toString(),
};
const metadata = this.ctx.getSessionMetadata();
return new Promise((resolve, reject) => {
const stream = this.ctx.clients.dataService.ExportEdges(request, metadata);
stream.on('data', (response) => {
if (callback) {
callback({
edges: (response.edges || []).map((e) => ({
id: e.id || '',
label: e.label || '',
fromNodeId: e.from_node_id || '',
toNodeId: e.to_node_id || '',
properties: (0, converters_1.convertProtoProperties)(e.properties || {}),
})),
hasMore: response.has_more || false,
});
}
});
stream.on('end', () => resolve());
stream.on('error', (error) => reject(error));
});
}
}
exports.DataService = DataService;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS1zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZpY2VzL2RhdGEtc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7OztBQStCSCxvQ0FLQztBQXhCRCxvQ0FBMEQ7QUFDMUQsMENBQTRDO0FBQzVDLDZDQUF3RjtBQUV4RixzQ0FBdUM7QUFFdkM7Ozs7OztHQU1HO0FBQ0gsTUFBTSxrQkFBa0IsR0FBNkIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBRWpFOzs7R0FHRztBQUNILFNBQWdCLFlBQVksQ0FBQyxDQUE0QjtJQUN2RCxJQUFJLENBQUMsQ0FBQztRQUFFLE9BQU8sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3pCLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUN6QyxJQUFJLENBQUMsQ0FBQztRQUFFLE9BQU8sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3pCLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ3RFLENBQUM7QUFFRCxTQUFTLFVBQVUsQ0FBQyxNQUFnQyxFQUFFLFFBQWtDO0lBQ3RGLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUMzQixJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDO1lBQUUsT0FBTyxNQUFNLENBQUMsQ0FBQyxD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QUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUNwRCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQXpQRCxrQ0F5UEMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIERhdGEgc2VydmljZSBoYW5kbGVzIG5vZGUgYW5kIGVkZ2UgaW5zZXJ0L2RlbGV0ZS9leHBvcnQgb3BlcmF0aW9ucy5cbiAqL1xuXG5pbXBvcnQgeyBTZXJ2aWNlQ29udGV4dCB9IGZyb20gJy4vc2VydmljZS1jb250ZXh0JztcbmltcG9ydCB7XG4gIEluc2VydE5vZGVzUmVzdWx0LFxuICBJbnNlcnRFZGdlc1Jlc3VsdCxcbiAgRXhwb3J0Tm9kZXNSZXN1bHQsXG4gIEV4cG9ydEVkZ2VzUmVzdWx0LFxuICBFeHBvcnRDb25maWcsXG4gIEV4cG9ydENodW5rLFxuICBFeHBvcnRTdGF0cyxcbn0gZnJvbSAnLi4vcmVzcG9uc2UnO1xuaW1wb3J0IHsgTm9kZURhdGEsIEVkZ2VEYXRhLCBJbnNlcnRUeXBlIH0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IHsgcHJvbWlzaWZ5Q2FsbCB9IGZyb20gJy4uL3NlcnZpY2VzJztcbmltcG9ydCB7IG5vZGVEYXRhVG9Qcm90bywgZWRnZURhdGFUb1Byb3RvLCBjb252ZXJ0UHJvdG9Qcm9wZXJ0aWVzIH0gZnJvbSAnLi9jb252ZXJ0ZXJzJztcbmltcG9ydCB7IEluc2VydE5vZGVzQ29uZmlnLCBJbnNlcnRFZGdlc0NvbmZpZyB9IGZyb20gJy4uL2NsaWVudCc7XG5pbXBvcnQgeyBHcWxkYkVycm9yIH0gZnJvbSAnLi4vZXJyb3JzJztcblxuLyoqXG4gKiBNaW5pbXVtIHNlcnZlciB2ZXJzaW9uIHRoYXQgc3VwcG9ydHMgYEluc2VydE1vZGUuVVBTRVJUYCBvbiB0aGUgYnVsay1pbXBvcnRcbiAqIFJQQ3MuIE9sZGVyIHNlcnZlcnMgaWdub3JlIHRoZSB1bmtub3duIGVudW0gdmFsdWUgYW5kIHNpbGVudGx5IGRvd25ncmFkZVxuICogdG8gTm9ybWFsLCBzdXJmYWNpbmcgYXMgYSBjb25mdXNpbmcgXCJkdXBsaWNhdGUgX2lkXCIgZXJyb3IuXG4gKlxuICogU2VlIGBHUUxEQi02LjEuMTQ5LURSSVZFUi1BTkQtVEVTVC1IQU5ET0ZGLTIwMjYtMDUtMDUubWRgIChUZXN0IHBsYW4gc2VjdGlvbiBEKS5cbiAqL1xuY29uc3QgVVBTRVJUX01JTl9WRVJTSU9OOiBbbnVtYmVyLCBudW1iZXIsIG51bWJlcl0gPSBbNiwgMSwgMTQ5XTtcblxuLyoqXG4gKiBQYXJzZSBsZWFkaW5nIG1ham9yLm1pbm9yLnBhdGNoIGZyb20gYSBzZXJ2ZXIgdmVyc2lvbiBzdHJpbmcuXG4gKiBSZXR1cm5zIFswLDAsMF0gb24gcGFyc2UgZmFpbHVyZSAodHJlYXRlZCBhcyBcInVua25vd24gLyBwcmUtNi4xLjE0OVwiKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlVmVyc2lvbihzOiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKTogW251bWJlciwgbnVtYmVyLCBudW1iZXJdIHtcbiAgaWYgKCFzKSByZXR1cm4gWzAsIDAsIDBdO1xuICBjb25zdCBtID0gcy5tYXRjaCgvKFxcZCspXFwuKFxcZCspXFwuKFxcZCspLyk7XG4gIGlmICghbSkgcmV0dXJuIFswLCAwLCAwXTtcbiAgcmV0dXJuIFtwYXJzZUludChtWzFdLCAxMCksIHBhcnNlSW50KG1bMl0sIDEwKSwgcGFyc2VJbnQobVszXSwgMTApXTtcbn1cblxuZnVuY3Rpb24gdmVyc2lvbkdURShhY3R1YWw6IFtudW1iZXIsIG51bWJlciwgbnVtYmVyXSwgcmVxdWlyZWQ6IFtudW1iZXIsIG51bWJlciwgbnVtYmVyXSk6IGJvb2xlYW4ge1xuICBmb3IgKGxldCBpID0gMDsgaSA8IDM7IGkrKykge1xuICAgIGlmIChhY3R1YWxbaV0gIT09IHJlcXVpcmVkW2ldKSByZXR1cm4gYWN0dWFsW2ldID4gcmVxdWlyZWRbaV07XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59XG5cbi8qKlxuICogRGF0YSBzZXJ2aWNlIGZvciBpbnNlcnRpbmcsIGRlbGV0aW5nLCBhbmQgZXhwb3J0aW5nIGdyYXBoIGRhdGEuXG4gKi9cbmV4cG9ydCBjbGFzcyBEYXRhU2VydmljZSB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgY3R4OiBTZXJ2aWNlQ29udGV4dCkge31cblxuICAvKipcbiAgICogVGhyb3cgR3FsZGJFcnJvciBpZiBgbW9kZWAgaXMgVVBTRVJUIGFuZCB0aGUgY29ubmVjdGVkIHNlcnZlciBpc1xuICAgKiBvbGRlciB0aGFuIDYuMS4xNDkuXG4gICAqXG4gICAqIFNlcnZlciA+PSA2LjEuMTU0IHJlcG9ydHMgdGhlIHJlYWwgdmVyc2lvbiBpblxuICAgKiBgTG9naW5SZXNwb25zZS5zZXJ2ZXJfdmVyc2lvbmAuIE9sZGVyIHNlcnZlcnMgZWl0aGVyIHJldHVybiBhXG4gICAqIHBsYWNlaG9sZGVyIFwiMS4wLjBcIiBvciBsZWF2ZSB0aGUgZmllbGQgZW1wdHkg4oCUIGJvdGggYXJlIG5vdyB0cmVhdGVkXG4gICAqIGFzIFwiZGVmaW5pdGVseSBvbGRlciB0aGFuIDYuMS4xNDlcIiBhbmQgcmVqZWN0ZWQuIChFYXJsaWVyIHZlcnNpb25zXG4gICAqIG9mIHRoaXMgZ2F0ZSBsZXQgdGhvc2UgY2FzZXMgcGFzcyB0aHJvdWdoOyB0aGF0IHdvcmthcm91bmQgd2FzXG4gICAqIHJlbW92ZWQgb25jZSA2LjEuMTU0KyBzdGFydGVkIHBvcHVsYXRpbmcgdGhlIGZpZWxkIGNvcnJlY3RseS4pXG4gICAqL1xuICBwcml2YXRlIHJlcXVpcmVVcHNlcnRTdXBwb3J0KG1vZGU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIGlmIChtb2RlICE9PSBJbnNlcnRUeXBlLlVwc2VydCkgcmV0dXJuO1xuICAgIGNvbnN0IHNlc3Npb24gPSB0aGlzLmN0eC5zZXNzaW9ucy5nZXRTZXNzaW9uKCk7XG4gICAgY29uc3Qgc2VydmVyVmVyID0gc2Vzc2lvbj8uc2VydmVyVmVyc2lvbiB8fCAnJztcbiAgICBpZiAoIXZlcnNpb25HVEUocGFyc2VWZXJzaW9uKHNlcnZlclZlciksIFVQU0VSVF9NSU5fVkVSU0lPTikpIHtcbiAgICAgIHRocm93IG5ldyBHcWxkYkVycm9yKFxuICAgICAgICBgSW5zZXJ0VHlwZS5VcHNlcnQgcmVxdWlyZXMgc2VydmVyID49ICR7VVBTRVJUX01JTl9WRVJTSU9OLmpvaW4oJy4nKX0sIGAgK1xuICAgICAgICBgY29ubmVjdGVkIHNlcnZlciByZXBvcnRzICR7c2VydmVyVmVyIHx8ICd1bmtub3duJ31gXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnQgbXVsdGlwbGUgbm9kZXMgaW50byBhIGdyYXBoLlxuICAgKi9cbiAgYXN5bmMgaW5zZXJ0Tm9kZXMoXG4gICAgZ3JhcGhOYW1lOiBzdHJpbmcsXG4gICAgbm9kZXM6IE5vZGVEYXRhW10sXG4gICAgY29uZmlnPzogSW5zZXJ0Tm9kZXNDb25maWdcbiAgKTogUHJvbWlzZTxJbnNlcnROb2Rlc1Jlc3VsdD4ge1xuICAgIHRoaXMucmVxdWlyZVVwc2VydFN1cHBvcnQoY29uZmlnPy5vcHRpb25zPy5tb2RlIGFzIG51bWJlciB8IHVuZGVmaW5lZCk7XG5cbiAgICBjb25zdCByZXF1ZXN0OiBhbnkgPSB7XG4gICAgICBncmFwaF9uYW1lOiBncmFwaE5hbWUsXG4gICAgICBub2Rlczogbm9kZXMubWFwKChuKSA9PiBub2RlRGF0YVRvUHJvdG8obikpLFxuICAgIH07XG5cbiAgICAvLyBBTFdBWVMgc2V0IG9wdGlvbnMgKGV2ZW4gd2hlbiB1bmRlZmluZWQpIHRvIGF2b2lkIGRlcHJlY2F0ZWQgYnVsayBvcGVyYXRpb25zIGVycm9yLlxuICAgIC8vIGBtb2RlYCBpcyBhIG51bWVyaWMgZW51bSBhbGlnbmVkIHdpdGggcHJvdG8gSW5zZXJ0TW9kZSB2YWx1ZXM7IHBhc3MgdGhyb3VnaCBkaXJlY3RseS5cbiAgICByZXF1ZXN0Lm9wdGlvbnMgPSB7IG1vZGU6IChjb25maWc/Lm9wdGlvbnM/Lm1vZGUgPz8gMCkgYXMgbnVtYmVyIH07XG5cbiAgICBpZiAoY29uZmlnPy5idWxrSW1wb3J0U2Vzc2lvbklkKSB7XG4gICAgICByZXF1ZXN0LmJ1bGtfaW1wb3J0X3Nlc3Npb25faWQgPSBjb25maWcuYnVsa0ltcG9ydFNlc3Npb25JZDtcbiAgICB9XG5cbiAgICBjb25zdCBtZXRhZGF0YSA9IHRoaXMuY3R4LmdldFNlc3Npb25NZXRhZGF0YSgpO1xuICAgIGNvbnN0IHJlc3BvbnNlOiBhbnkgPSBhd2FpdCBwcm9taXNpZnlDYWxsKFxuICAgICAgdGhpcy5jdHguY2xpZW50cy5kYXRhU2VydmljZSxcbiAgICAgICdJbnNlcnROb2RlcycsXG4gICAgICByZXF1ZXN0LFxuICAgICAgbWV0YWRhdGFcbiAgICApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IHJlc3BvbnNlLnN1Y2Nlc3MgfHwgZmFsc2UsXG4gICAgICBub2RlSWRzOiByZXNwb25zZS5ub2RlX2lkcyB8fCBbXSxcbiAgICAgIG5vZGVDb3VudDogcGFyc2VJbnQocmVzcG9uc2Uubm9kZV9jb3VudCB8fCAnMCcsIDEwKSxcbiAgICAgIG1lc3NhZ2U6IHJlc3BvbnNlLm1lc3NhZ2UgfHwgJycsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnQgbXVsdGlwbGUgZWRnZXMgaW50byBhIGdyYXBoLlxuICAgKi9cbiAgYXN5bmMgaW5zZXJ0RWRnZXMoXG4gICAgZ3JhcGhOYW1lOiBzdHJpbmcsXG4gICAgZWRnZXM6IEVkZ2VEYXRhW10sXG4gICAgY29uZmlnPzogSW5zZXJ0RWRnZXNDb25maWdcbiAgKTogUHJvbWlzZTxJbnNlcnRFZGdlc1Jlc3VsdD4ge1xuICAgIHRoaXMucmVxdWlyZVVwc2VydFN1cHBvcnQoY29uZmlnPy5vcHRpb25zPy5tb2RlIGFzIG51bWJlciB8IHVuZGVmaW5lZCk7XG5cbiAgICBjb25zdCByZXF1ZXN0OiBhbnkgPSB7XG4gICAgICBncmFwaF9uYW1lOiBncmFwaE5hbWUsXG4gICAgICBlZGdlczogZWRnZXMubWFwKChlKSA9PiBlZGdlRGF0YVRvUHJvdG8oZSkpLFxuICAgIH07XG5cbiAgICAvLyBBTFdBWVMgc2V0IG9wdGlvbnMgKGV2ZW4gd2hlbiB1bmRlZmluZWQpIHRvIGF2b2lkIGRlcHJlY2F0ZWQgYnVsayBvcGVyYXRpb25zIGVycm9yLlxuICAgIHJlcXVlc3Qub3B0aW9ucyA9IHtcbiAgICAgIHNraXBfaW52YWxpZF9ub2RlczogY29uZmlnPy5vcHRpb25zPy5za2lwSW52YWxpZE5vZGVzIHx8IGZhbHNlLFxuICAgICAgbW9kZTogKGNvbmZpZz8ub3B0aW9ucz8ubW9kZSA/PyAwKSBhcyBudW1iZXIsXG4gICAgfTtcblxuICAgIGlmIChjb25maWc/LmJ1bGtJbXBvcnRTZXNzaW9uSWQpIHtcbiAgICAgIHJlcXVlc3QuYnVsa19pbXBvcnRfc2Vzc2lvbl9pZCA9IGNvbmZpZy5idWxrSW1wb3J0U2Vzc2lvbklkO1xuICAgIH1cblxuICAgIGNvbnN0IG1ldGFkYXRhID0gdGhpcy5jdHguZ2V0U2Vzc2lvbk1ldGFkYXRhKCk7XG4gICAgY29uc3QgcmVzcG9uc2U6IGFueSA9IGF3YWl0IHByb21pc2lmeUNhbGwoXG4gICAgICB0aGlzLmN0eC5jbGllbnRzLmRhdGFTZXJ2aWNlLFxuICAgICAgJ0luc2VydEVkZ2VzJyxcbiAgICAgIHJlcXVlc3QsXG4gICAgICBtZXRhZGF0YVxuICAgICk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogcmVzcG9uc2Uuc3VjY2VzcyB8fCBmYWxzZSxcbiAgICAgIGVkZ2VJZHM6IHJlc3BvbnNlLmVkZ2VfaWRzIHx8IFtdLFxuICAgICAgZWRnZUNvdW50OiBwYXJzZUludChyZXNwb25zZS5lZGdlX2NvdW50IHx8ICcwJywgMTApLFxuICAgICAgbWVzc2FnZTogcmVzcG9uc2UubWVzc2FnZSB8fCAnJyxcbiAgICAgIHNraXBwZWRDb3VudDogcGFyc2VJbnQocmVzcG9uc2Uuc2tpcHBlZF9jb3VudCB8fCAnMCcsIDEwKSxcbiAgICB9O1xuICB9XG5cbiAgLy8gZGVsZXRlTm9kZXMgLyBkZWxldGVFZGdlcyBubyBsb25nZXIgZ28gdGhyb3VnaCB0aGUgZ1JQQyBEYXRhU2VydmljZVxuICAvLyBEZWxldGVOb2RlcyAvIERlbGV0ZUVkZ2VzIFJQQ3MgKHRob3NlIHByb3RvIG1ldGhvZHMgYXJlIGJlaW5nIHJlbW92ZWRcbiAgLy8gc2VydmVyLXNpZGUpLiBUaGUgcHVibGljIGRlbGV0ZSBBUEkgbGl2ZXMgb24gR3FsZGJDbGllbnQgYXNcbiAgLy8gZGVsZXRlTm9kZXNCeUlkcyAvIGRlbGV0ZU5vZGVzQnlDb25kaXRpb24gLyBkZWxldGVFZGdlc0J5SWRzIC9cbiAgLy8gZGVsZXRlRWRnZXNCeUNvbmRpdGlvbiwgd2hpY2ggZW1pdCBHUUwgYW5kIHJldHVybiBhIGZ1bGwgUmVzcG9uc2UuXG5cbiAgLyoqXG4gICAqIEV4cG9ydCBncmFwaCBkYXRhIGluIEpTT04gTGluZXMgZm9ybWF0IChzdHJlYW1pbmcpLlxuICAgKi9cbiAgYXN5bmMgZXhwb3J0KFxuICAgIGNvbmZpZzogRXhwb3J0Q29uZmlnLFxuICAgIGNhbGxiYWNrPzogKGNodW5rOiBFeHBvcnRDaHVuaykgPT4gdm9pZFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCByZXF1ZXN0ID0ge1xuICAgICAgZ3JhcGhfbmFtZTogY29uZmlnLmdyYXBoTmFtZSxcbiAgICAgIGJhdGNoX3NpemU6IGNvbmZpZy5iYXRjaFNpemUgfHwgMCxcbiAgICAgIGV4cG9ydF9ub2RlczogY29uZmlnLmV4cG9ydE5vZGVzICE9PSBmYWxzZSxcbiAgICAgIGV4cG9ydF9lZGdlczogY29uZmlnLmV4cG9ydEVkZ2VzICE9PSBmYWxzZSxcbiAgICAgIG5vZGVfbGFiZWxzOiBjb25maWcubm9kZUxhYmVscyB8fCBbXSxcbiAgICAgIGVkZ2VfbGFiZWxzOiBjb25maWcuZWRnZUxhYmVscyB8fCBbXSxcbiAgICAgIGluY2x1ZGVfbWV0YWRhdGE6IGNvbmZpZy5pbmNsdWRlTWV0YWRhdGEgfHwgZmFsc2UsXG4gICAgfTtcblxuICAgIGNvbnN0IG1ldGFkYXRhID0gdGhpcy5jdHguZ2V0U2Vzc2lvbk1ldGFkYXRhKCk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3Qgc3RyZWFtID0gKHRoaXMuY3R4LmNsaWVudHMuZGF0YVNlcnZpY2UgYXMgYW55KS5FeHBvcnQocmVxdWVzdCwgbWV0YWRhdGEpO1xuXG4gICAgICBzdHJlYW0ub24oJ2RhdGEnLCAocmVzcG9uc2U6IGFueSkgPT4ge1xuICAgICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgICBsZXQgc3RhdHM6IEV4cG9ydFN0YXRzIHwgdW5kZWZpbmVkO1xuICAgICAgICAgIGlmIChyZXNwb25zZS5zdGF0cykge1xuICAgICAgICAgICAgc3RhdHMgPSB7XG4gICAgICAgICAgICAgIG5vZGVzRXhwb3J0ZWQ6IHBhcnNlSW50KHJlc3BvbnNlLnN0YXRzLm5vZGVzX2V4cG9ydGVkIHx8ICcwJywgMTApLFxuICAgICAgICAgICAgICBlZGdlc0V4cG9ydGVkOiBwYXJzZUludChyZXNwb25zZS5zdGF0cy5lZGdlc19leHBvcnRlZCB8fCAnMCcsIDEwKSxcbiAgICAgICAgICAgICAgYnl0ZXNXcml0dGVuOiBwYXJzZUludChyZXNwb25zZS5zdGF0cy5ieXRlc193cml0dGVuIHx8ICcwJywgMTApLFxuICAgICAgICAgICAgICBkdXJhdGlvbk1zOiBwYXJzZUludChyZXNwb25zZS5zdGF0cy5kdXJhdGlvbl9tcyB8fCAnMCcsIDEwKSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgY2h1bms6IEV4cG9ydENodW5rID0ge1xuICAgICAgICAgICAgZGF0YTogQnVmZmVyLmZyb20ocmVzcG9uc2UuZGF0YSB8fCBbXSksXG4gICAgICAgICAgICBpc0ZpbmFsOiByZXNwb25zZS5pc19maW5hbCB8fCBmYWxzZSxcbiAgICAgICAgICAgIHN0YXRzLFxuICAgICAgICAgIH07XG5cbiAgICAgICAgICBjYWxsYmFjayhjaHVuayk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocmVzcG9uc2UuaXNfZmluYWwpIHtcbiAgICAgICAgICBzdHJlYW0uY2FuY2VsKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBzdHJlYW0ub24oJ2VuZCcsICgpID0+IHJlc29sdmUoKSk7XG4gICAgICBzdHJlYW0ub24oJ2Vycm9yJywgKGVycm9yOiBhbnkpID0+IHJlamVjdChlcnJvcikpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0cmVhbSBub2RlcyBmcm9tIGEgZ3JhcGguXG4gICAqIEBkZXByZWNhdGVkIFVzZSBleHBvcnQoKSB3aXRoIEV4cG9ydENvbmZpZyBpbnN0ZWFkXG4gICAqL1xuICBhc3luYyBleHBvcnROb2RlcyhcbiAgICBncmFwaE5hbWU6IHN0cmluZyxcbiAgICBsYWJlbHM/OiBzdHJpbmdbXSxcbiAgICBsaW1pdDogbnVtYmVyID0gMCxcbiAgICBjYWxsYmFjaz86IChyZXN1bHQ6IEV4cG9ydE5vZGVzUmVzdWx0KSA9PiB2b2lkXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnNvbGUud2FybignZXhwb3J0Tm9kZXMgaXMgZGVwcmVjYXRlZCwgdXNlIGV4cG9ydCgpIHdpdGggRXhwb3J0Q29uZmlnIGluc3RlYWQnKTtcblxuICAgIGNvbnN0IHJlcXVlc3QgPSB7XG4gICAgICBncmFwaF9uYW1lOiBncmFwaE5hbWUsXG4gICAgICBsYWJlbHM6IGxhYmVscyB8fCBbXSxcbiAgICAgIGxpbWl0OiBsaW1pdC50b1N0cmluZygpLFxuICAgIH07XG5cbiAgICBjb25zdCBtZXRhZGF0YSA9IHRoaXMuY3R4LmdldFNlc3Npb25NZXRhZGF0YSgpO1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IHN0cmVhbSA9ICh0aGlzLmN0eC5jbGllbnRzLmRhdGFTZXJ2aWNlIGFzIGFueSkuRXhwb3J0Tm9kZXMocmVxdWVzdCwgbWV0YWRhdGEpO1xuXG4gICAgICBzdHJlYW0ub24oJ2RhdGEnLCAocmVzcG9uc2U6IGFueSkgPT4ge1xuICAgICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgICBjYWxsYmFjayh7XG4gICAgICAgICAgICBub2RlczogKHJlc3BvbnNlLm5vZGVzIHx8IFtdKS5tYXAoKG46IGFueSkgPT4gKHtcbiAgICAgICAgICAgICAgaWQ6IG4uaWQgfHwgJycsXG4gICAgICAgICAgICAgIGxhYmVsczogbi5sYWJlbHMgfHwgW10sXG4gICAgICAgICAgICAgIHByb3BlcnRpZXM6IGNvbnZlcnRQcm90b1Byb3BlcnRpZXMobi5wcm9wZXJ0aWVzIHx8IHt9KSxcbiAgICAgICAgICAgIH0pKSxcbiAgICAgICAgICAgIGhhc01vcmU6IHJlc3BvbnNlLmhhc19tb3JlIHx8IGZhbHNlLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgc3RyZWFtLm9uKCdlbmQnLCAoKSA9PiByZXNvbHZlKCkpO1xuICAgICAgc3RyZWFtLm9uKCdlcnJvcicsIChlcnJvcjogYW55KSA9PiByZWplY3QoZXJyb3IpKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdHJlYW0gZWRnZXMgZnJvbSBhIGdyYXBoLlxuICAgKiBAZGVwcmVjYXRlZCBVc2UgZXhwb3J0KCkgd2l0aCBFeHBvcnRDb25maWcgaW5zdGVhZFxuICAgKi9cbiAgYXN5bmMgZXhwb3J0RWRnZXMoXG4gICAgZ3JhcGhOYW1lOiBzdHJpbmcsXG4gICAgbGFiZWxzPzogc3RyaW5nW10sXG4gICAgbGltaXQ6IG51bWJlciA9IDAsXG4gICAgY2FsbGJhY2s/OiAocmVzdWx0OiBFeHBvcnRFZGdlc1Jlc3VsdCkgPT4gdm9pZFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zb2xlLndhcm4oJ2V4cG9ydEVkZ2VzIGlzIGRlcHJlY2F0ZWQsIHVzZSBleHBvcnQoKSB3aXRoIEV4cG9ydENvbmZpZyBpbnN0ZWFkJyk7XG5cbiAgICBjb25zdCByZXF1ZXN0ID0ge1xuICAgICAgZ3JhcGhfbmFtZTogZ3JhcGhOYW1lLFxuICAgICAgbGFiZWxzOiBsYWJlbHMgfHwgW10sXG4gICAgICBsaW1pdDogbGltaXQudG9TdHJpbmcoKSxcbiAgICB9O1xuXG4gICAgY29uc3QgbWV0YWRhdGEgPSB0aGlzLmN0eC5nZXRTZXNzaW9uTWV0YWRhdGEoKTtcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBzdHJlYW0gPSAodGhpcy5jdHguY2xpZW50cy5kYXRhU2VydmljZSBhcyBhbnkpLkV4cG9ydEVkZ2VzKHJlcXVlc3QsIG1ldGFkYXRhKTtcblxuICAgICAgc3RyZWFtLm9uKCdkYXRhJywgKHJlc3BvbnNlOiBhbnkpID0+IHtcbiAgICAgICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgICAgY2FsbGJhY2soe1xuICAgICAgICAgICAgZWRnZXM6IChyZXNwb25zZS5lZGdlcyB8fCBbXSkubWFwKChlOiBhbnkpID0+ICh7XG4gICAgICAgICAgICAgIGlkOiBlLmlkIHx8ICcnLFxuICAgICAgICAgICAgICBsYWJlbDogZS5sYWJlbCB8fCAnJyxcbiAgICAgICAgICAgICAgZnJvbU5vZGVJZDogZS5mcm9tX25vZGVfaWQgfHwgJycsXG4gICAgICAgICAgICAgIHRvTm9kZUlkOiBlLnRvX25vZGVfaWQgfHwgJycsXG4gICAgICAgICAgICAgIHByb3BlcnRpZXM6IGNvbnZlcnRQcm90b1Byb3BlcnRpZXMoZS5wcm9wZXJ0aWVzIHx8IHt9KSxcbiAgICAgICAgICAgIH0pKSxcbiAgICAgICAgICAgIGhhc01vcmU6IHJlc3BvbnNlLmhhc19tb3JlIHx8IGZhbHNlLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgc3RyZWFtLm9uKCdlbmQnLCAoKSA9PiByZXNvbHZlKCkpO1xuICAgICAgc3RyZWFtLm9uKCdlcnJvcicsIChlcnJvcjogYW55KSA9PiByZWplY3QoZXJyb3IpKTtcbiAgICB9KTtcbiAgfVxufVxuIl19