@axiom-lattice/client-sdk 3.0.6 → 4.0.0
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/__tests__/a2a-keys.test.d.ts +8 -0
- package/dist/__tests__/a2a-keys.test.d.ts.map +1 -0
- package/dist/__tests__/a2a-keys.test.js +110 -0
- package/dist/__tests__/a2a-keys.test.js.map +1 -0
- package/dist/__tests__/export-import.test.d.ts +2 -0
- package/dist/__tests__/export-import.test.d.ts.map +1 -0
- package/dist/__tests__/export-import.test.js +245 -0
- package/dist/__tests__/export-import.test.js.map +1 -0
- package/dist/__tests__/tasks.test.d.ts +2 -0
- package/dist/__tests__/tasks.test.d.ts.map +1 -0
- package/dist/__tests__/tasks.test.js +67 -0
- package/dist/__tests__/tasks.test.js.map +1 -0
- package/dist/__tests__/workspace-client.test.d.ts +10 -0
- package/dist/__tests__/workspace-client.test.d.ts.map +1 -0
- package/dist/__tests__/workspace-client.test.js +56 -0
- package/dist/__tests__/workspace-client.test.js.map +1 -0
- package/dist/abstract-client.d.ts +59 -2
- package/dist/abstract-client.d.ts.map +1 -1
- package/dist/abstract-client.js +74 -3
- package/dist/abstract-client.js.map +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -0
- package/dist/client.js.map +1 -1
- package/dist/export-import.d.ts +136 -24
- package/dist/export-import.d.ts.map +1 -1
- package/dist/export-import.js +142 -48
- package/dist/export-import.js.map +1 -1
- package/dist/index.d.ts +263 -33
- package/dist/index.js +258 -96
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +258 -96
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/workspace-client.d.ts +2 -2
- package/dist/workspace-client.d.ts.map +1 -1
- package/dist/workspace-client.js +7 -2
- package/dist/workspace-client.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2153,6 +2153,77 @@ var AbstractClient = class {
|
|
|
2153
2153
|
}
|
|
2154
2154
|
}
|
|
2155
2155
|
};
|
|
2156
|
+
/**
|
|
2157
|
+
* A2A API keys namespace for managing A2A API keys
|
|
2158
|
+
*/
|
|
2159
|
+
this.a2aKeys = {
|
|
2160
|
+
/**
|
|
2161
|
+
* Lists A2A API keys, optionally filtered by tenant
|
|
2162
|
+
* Key values are masked in list responses
|
|
2163
|
+
* @param params - Optional tenant filter and pagination
|
|
2164
|
+
* @returns A promise that resolves to the list of key records and total
|
|
2165
|
+
*/
|
|
2166
|
+
list: async (params) => {
|
|
2167
|
+
const searchParams = new URLSearchParams();
|
|
2168
|
+
if (params?.tenantId)
|
|
2169
|
+
searchParams.set("tenantId", params.tenantId);
|
|
2170
|
+
if (params?.limit !== void 0)
|
|
2171
|
+
searchParams.set("limit", String(params.limit));
|
|
2172
|
+
if (params?.offset !== void 0)
|
|
2173
|
+
searchParams.set("offset", String(params.offset));
|
|
2174
|
+
const qs = searchParams.toString();
|
|
2175
|
+
const response = await this.makeRequest(`/api/a2a/keys${qs ? `?${qs}` : ""}`);
|
|
2176
|
+
return response.data;
|
|
2177
|
+
},
|
|
2178
|
+
/**
|
|
2179
|
+
* Creates a new A2A API key
|
|
2180
|
+
* The full key value is returned only from this call
|
|
2181
|
+
* @param input - Key creation input (tenant, project, optional assistant whitelist and label)
|
|
2182
|
+
* @returns A promise that resolves to the created key record (full key value)
|
|
2183
|
+
*/
|
|
2184
|
+
create: async (input) => {
|
|
2185
|
+
const response = await this.makeRequest("/api/a2a/keys", { method: "POST", body: input });
|
|
2186
|
+
return response.data;
|
|
2187
|
+
},
|
|
2188
|
+
/**
|
|
2189
|
+
* Permanently deletes an A2A API key
|
|
2190
|
+
* @param id - Key identifier
|
|
2191
|
+
* @returns A promise that resolves when the key is deleted
|
|
2192
|
+
*/
|
|
2193
|
+
delete: async (id) => {
|
|
2194
|
+
await this.makeRequest(`/api/a2a/keys/${id}`, {
|
|
2195
|
+
method: "DELETE"
|
|
2196
|
+
});
|
|
2197
|
+
},
|
|
2198
|
+
/**
|
|
2199
|
+
* Disables an A2A API key
|
|
2200
|
+
* @param id - Key identifier
|
|
2201
|
+
* @returns A promise that resolves to the updated key record
|
|
2202
|
+
*/
|
|
2203
|
+
disable: async (id) => {
|
|
2204
|
+
const response = await this.makeRequest(`/api/a2a/keys/${id}/disable`, { method: "POST" });
|
|
2205
|
+
return response.data;
|
|
2206
|
+
},
|
|
2207
|
+
/**
|
|
2208
|
+
* Enables a previously disabled A2A API key
|
|
2209
|
+
* @param id - Key identifier
|
|
2210
|
+
* @returns A promise that resolves to the updated key record
|
|
2211
|
+
*/
|
|
2212
|
+
enable: async (id) => {
|
|
2213
|
+
const response = await this.makeRequest(`/api/a2a/keys/${id}/enable`, { method: "POST" });
|
|
2214
|
+
return response.data;
|
|
2215
|
+
},
|
|
2216
|
+
/**
|
|
2217
|
+
* Rotates an A2A API key, generating a new key value
|
|
2218
|
+
* The full new key value is returned only from this call
|
|
2219
|
+
* @param id - Key identifier
|
|
2220
|
+
* @returns A promise that resolves to the updated key record (full new key value)
|
|
2221
|
+
*/
|
|
2222
|
+
rotate: async (id) => {
|
|
2223
|
+
const response = await this.makeRequest(`/api/a2a/keys/${id}/rotate`, { method: "POST" });
|
|
2224
|
+
return response.data;
|
|
2225
|
+
}
|
|
2226
|
+
};
|
|
2156
2227
|
/**
|
|
2157
2228
|
* Skills namespace for managing skills
|
|
2158
2229
|
*/
|
|
@@ -2673,11 +2744,11 @@ var AbstractClient = class {
|
|
|
2673
2744
|
delete: async (id) => {
|
|
2674
2745
|
await this.makeRequest(`/api/tasks/${id}`, { method: "DELETE" });
|
|
2675
2746
|
},
|
|
2676
|
-
complete: async (id) => {
|
|
2677
|
-
const response = await this.makeRequest(`/api/tasks/${id}/complete`, { method: "PATCH" });
|
|
2747
|
+
complete: async (id, data) => {
|
|
2748
|
+
const response = await this.makeRequest(`/api/tasks/${id}/complete`, { method: "PATCH", body: data });
|
|
2678
2749
|
if (!response.data)
|
|
2679
2750
|
throw new ApiError("Failed to complete task", 500);
|
|
2680
|
-
return response
|
|
2751
|
+
return response;
|
|
2681
2752
|
},
|
|
2682
2753
|
workItems: {
|
|
2683
2754
|
list: async (taskId, params) => {
|
|
@@ -2984,6 +3055,182 @@ var ResourcesClient = class {
|
|
|
2984
3055
|
}
|
|
2985
3056
|
};
|
|
2986
3057
|
|
|
3058
|
+
// src/export-import.ts
|
|
3059
|
+
function base64ToBytes(base64) {
|
|
3060
|
+
if (typeof globalThis.atob === "function") {
|
|
3061
|
+
const binary = globalThis.atob(base64);
|
|
3062
|
+
const bytes = new Uint8Array(binary.length);
|
|
3063
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
3064
|
+
bytes[index] = binary.charCodeAt(index);
|
|
3065
|
+
}
|
|
3066
|
+
return bytes;
|
|
3067
|
+
}
|
|
3068
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
3069
|
+
}
|
|
3070
|
+
function bytesToArrayBuffer(bytes) {
|
|
3071
|
+
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
3072
|
+
}
|
|
3073
|
+
async function archiveToBlob(archive) {
|
|
3074
|
+
if (typeof archive === "string") {
|
|
3075
|
+
return {
|
|
3076
|
+
blob: new Blob([bytesToArrayBuffer(base64ToBytes(archive))], { type: "application/gzip" }),
|
|
3077
|
+
filename: "tenant-import.tar.gz"
|
|
3078
|
+
};
|
|
3079
|
+
}
|
|
3080
|
+
if (archive instanceof Blob) {
|
|
3081
|
+
const filename = "name" in archive && typeof archive.name === "string" ? archive.name : "tenant-import.tar.gz";
|
|
3082
|
+
return { blob: archive, filename };
|
|
3083
|
+
}
|
|
3084
|
+
const bytes = archive instanceof Uint8Array ? archive : archive instanceof ArrayBuffer ? new Uint8Array(archive) : new Uint8Array(await archive.arrayBuffer());
|
|
3085
|
+
return {
|
|
3086
|
+
blob: new Blob([bytesToArrayBuffer(bytes)], { type: "application/gzip" }),
|
|
3087
|
+
filename: "tenant-import.tar.gz"
|
|
3088
|
+
};
|
|
3089
|
+
}
|
|
3090
|
+
function attachmentFilename(contentDisposition) {
|
|
3091
|
+
if (!contentDisposition)
|
|
3092
|
+
return "tenant-export.tar.gz";
|
|
3093
|
+
const encoded = contentDisposition.match(/filename\*=UTF-8''([^;]+)/i)?.[1];
|
|
3094
|
+
if (encoded) {
|
|
3095
|
+
try {
|
|
3096
|
+
return decodeURIComponent(encoded);
|
|
3097
|
+
} catch {
|
|
3098
|
+
return encoded;
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
return contentDisposition.match(/filename="([^"]+)"/i)?.[1] ?? contentDisposition.match(/filename=([^;\s]+)/i)?.[1] ?? "tenant-export.tar.gz";
|
|
3102
|
+
}
|
|
3103
|
+
var ExportImportClient = class {
|
|
3104
|
+
/**
|
|
3105
|
+
* Creates an export/import client.
|
|
3106
|
+
*
|
|
3107
|
+
* @param config - Base client configuration.
|
|
3108
|
+
* @param headerProvider - Optional provider for headers that change after construction.
|
|
3109
|
+
*/
|
|
3110
|
+
constructor(config, headerProvider) {
|
|
3111
|
+
this.baseURL = config.baseURL;
|
|
3112
|
+
this.headers = {
|
|
3113
|
+
"Content-Type": "application/json",
|
|
3114
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
3115
|
+
...config.headers
|
|
3116
|
+
};
|
|
3117
|
+
this.headerProvider = headerProvider;
|
|
3118
|
+
}
|
|
3119
|
+
async request(url, options = {}) {
|
|
3120
|
+
const headers = {
|
|
3121
|
+
...this.headers,
|
|
3122
|
+
...this.headerProvider?.(),
|
|
3123
|
+
...options.headers
|
|
3124
|
+
};
|
|
3125
|
+
if (options.body instanceof FormData) {
|
|
3126
|
+
for (const name of Object.keys(headers)) {
|
|
3127
|
+
if (name.toLowerCase() === "content-type")
|
|
3128
|
+
delete headers[name];
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
const response = await fetch(`${this.baseURL}${url}`, {
|
|
3132
|
+
method: options.method ?? "GET",
|
|
3133
|
+
...options,
|
|
3134
|
+
headers
|
|
3135
|
+
});
|
|
3136
|
+
const envelope = await response.json().catch(() => ({}));
|
|
3137
|
+
if (!response.ok || envelope.success === false) {
|
|
3138
|
+
throw new Error(
|
|
3139
|
+
envelope.message || envelope.error || `HTTP error! Status: ${response.status}`
|
|
3140
|
+
);
|
|
3141
|
+
}
|
|
3142
|
+
if (envelope.data === void 0) {
|
|
3143
|
+
throw new Error(envelope.message || envelope.error || "API response contained no data");
|
|
3144
|
+
}
|
|
3145
|
+
return envelope.data;
|
|
3146
|
+
}
|
|
3147
|
+
/** Returns all entity types registered for export. */
|
|
3148
|
+
getExportableTypes() {
|
|
3149
|
+
return this.request("/api/tenants/exportable-types");
|
|
3150
|
+
}
|
|
3151
|
+
/** Starts an export or returns dependencies requiring confirmation. */
|
|
3152
|
+
exportConfig(tenantId, entityTypes, entityIds) {
|
|
3153
|
+
return this.request(`/api/tenants/${tenantId}/export`, {
|
|
3154
|
+
method: "POST",
|
|
3155
|
+
body: JSON.stringify({ entityTypes, ...entityIds ? { entityIds } : {} })
|
|
3156
|
+
});
|
|
3157
|
+
}
|
|
3158
|
+
/** Starts an export after confirming dependency additions. */
|
|
3159
|
+
exportConfigConfirm(tenantId, entityTypes, entityIds) {
|
|
3160
|
+
return this.request(`/api/tenants/${tenantId}/export/confirm`, {
|
|
3161
|
+
method: "POST",
|
|
3162
|
+
body: JSON.stringify({ entityTypes, ...entityIds ? { entityIds } : {} })
|
|
3163
|
+
});
|
|
3164
|
+
}
|
|
3165
|
+
/** Lists selectable entities for the requested export types. */
|
|
3166
|
+
previewEntities(tenantId, entityTypes) {
|
|
3167
|
+
return this.request(
|
|
3168
|
+
`/api/tenants/${tenantId}/export/entities`,
|
|
3169
|
+
{ method: "POST", body: JSON.stringify({ entityTypes }) }
|
|
3170
|
+
);
|
|
3171
|
+
}
|
|
3172
|
+
/** Returns the gateway URL for an export download job. */
|
|
3173
|
+
getExportDownloadUrl(tenantId, jobId) {
|
|
3174
|
+
return `${this.baseURL}/api/tenants/${tenantId}/export/${jobId}/download`;
|
|
3175
|
+
}
|
|
3176
|
+
/** Downloads an export archive as raw bytes. */
|
|
3177
|
+
async downloadExport(tenantId, jobId) {
|
|
3178
|
+
const response = await fetch(
|
|
3179
|
+
`${this.baseURL}/api/tenants/${tenantId}/export/${jobId}/download`,
|
|
3180
|
+
{
|
|
3181
|
+
method: "GET",
|
|
3182
|
+
headers: {
|
|
3183
|
+
...this.headers,
|
|
3184
|
+
...this.headerProvider?.()
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
);
|
|
3188
|
+
if (!response.ok) {
|
|
3189
|
+
const envelope = await response.json().catch(() => ({}));
|
|
3190
|
+
throw new Error(
|
|
3191
|
+
envelope.message || envelope.error || `HTTP error! Status: ${response.status}`
|
|
3192
|
+
);
|
|
3193
|
+
}
|
|
3194
|
+
return {
|
|
3195
|
+
filename: attachmentFilename(response.headers.get("Content-Disposition")),
|
|
3196
|
+
data: new Uint8Array(await response.arrayBuffer())
|
|
3197
|
+
};
|
|
3198
|
+
}
|
|
3199
|
+
/** Previews an archive or plain JSON bundle import. */
|
|
3200
|
+
async importPreview(tenantId, source) {
|
|
3201
|
+
if (source.archive !== void 0) {
|
|
3202
|
+
const form = new FormData();
|
|
3203
|
+
const { blob, filename } = await archiveToBlob(source.archive);
|
|
3204
|
+
form.append("file", blob, filename);
|
|
3205
|
+
return this.request(`/api/tenants/${tenantId}/import/preview`, {
|
|
3206
|
+
method: "POST",
|
|
3207
|
+
body: form
|
|
3208
|
+
});
|
|
3209
|
+
}
|
|
3210
|
+
return this.request(`/api/tenants/${tenantId}/import/preview`, {
|
|
3211
|
+
method: "POST",
|
|
3212
|
+
body: JSON.stringify({ bundle: source.bundle })
|
|
3213
|
+
});
|
|
3214
|
+
}
|
|
3215
|
+
/** Applies an archive or plain JSON bundle import with conflict resolutions. */
|
|
3216
|
+
async importApply(tenantId, source, resolutions) {
|
|
3217
|
+
if (source.archive !== void 0) {
|
|
3218
|
+
const form = new FormData();
|
|
3219
|
+
const { blob, filename } = await archiveToBlob(source.archive);
|
|
3220
|
+
form.append("file", blob, filename);
|
|
3221
|
+
form.append("resolutions", JSON.stringify(resolutions));
|
|
3222
|
+
return this.request(`/api/tenants/${tenantId}/import/apply`, {
|
|
3223
|
+
method: "POST",
|
|
3224
|
+
body: form
|
|
3225
|
+
});
|
|
3226
|
+
}
|
|
3227
|
+
return this.request(`/api/tenants/${tenantId}/import/apply`, {
|
|
3228
|
+
method: "POST",
|
|
3229
|
+
body: JSON.stringify({ bundle: source.bundle, resolutions })
|
|
3230
|
+
});
|
|
3231
|
+
}
|
|
3232
|
+
};
|
|
3233
|
+
|
|
2987
3234
|
// src/client.ts
|
|
2988
3235
|
var _Client = class extends AbstractClient {
|
|
2989
3236
|
/**
|
|
@@ -2998,6 +3245,7 @@ var _Client = class extends AbstractClient {
|
|
|
2998
3245
|
...this.config.headers
|
|
2999
3246
|
};
|
|
3000
3247
|
this.resources = new ResourcesClient(this.config.baseURL, () => this.getAllHeaders());
|
|
3248
|
+
this.exportImport = new ExportImportClient(this.config, () => this.getAllHeaders());
|
|
3001
3249
|
}
|
|
3002
3250
|
/**
|
|
3003
3251
|
* Helper method to handle fetch responses and errors
|
|
@@ -3758,9 +4006,14 @@ var WorkspaceClient = class {
|
|
|
3758
4006
|
});
|
|
3759
4007
|
}
|
|
3760
4008
|
// ==================== Project CRUD ====================
|
|
3761
|
-
async listProjects(workspaceId) {
|
|
4009
|
+
async listProjects(workspaceId, kind) {
|
|
4010
|
+
const params = new URLSearchParams();
|
|
4011
|
+
if (kind) {
|
|
4012
|
+
params.set("kind", kind);
|
|
4013
|
+
}
|
|
4014
|
+
const qs = params.toString();
|
|
3762
4015
|
const response = await this.request(
|
|
3763
|
-
`/api/workspaces/${workspaceId}/projects`
|
|
4016
|
+
`/api/workspaces/${workspaceId}/projects${qs ? `?${qs}` : ""}`
|
|
3764
4017
|
);
|
|
3765
4018
|
return response.data || [];
|
|
3766
4019
|
}
|
|
@@ -3899,97 +4152,6 @@ var WorkspaceClient = class {
|
|
|
3899
4152
|
}
|
|
3900
4153
|
};
|
|
3901
4154
|
|
|
3902
|
-
// src/export-import.ts
|
|
3903
|
-
var ExportImportClient = class {
|
|
3904
|
-
constructor(config) {
|
|
3905
|
-
this.baseURL = config.baseURL;
|
|
3906
|
-
this.headers = {
|
|
3907
|
-
"Content-Type": "application/json",
|
|
3908
|
-
Authorization: `Bearer ${config.apiKey}`,
|
|
3909
|
-
...config.headers
|
|
3910
|
-
};
|
|
3911
|
-
}
|
|
3912
|
-
async request(url, options = {}) {
|
|
3913
|
-
const fullUrl = `${this.baseURL}${url}`;
|
|
3914
|
-
const response = await fetch(fullUrl, {
|
|
3915
|
-
...options,
|
|
3916
|
-
headers: {
|
|
3917
|
-
...this.headers,
|
|
3918
|
-
...options.headers
|
|
3919
|
-
}
|
|
3920
|
-
});
|
|
3921
|
-
if (!response.ok) {
|
|
3922
|
-
const err = await response.json().catch(() => ({}));
|
|
3923
|
-
throw new Error(
|
|
3924
|
-
err.message || `HTTP error! Status: ${response.status}`
|
|
3925
|
-
);
|
|
3926
|
-
}
|
|
3927
|
-
return response.json();
|
|
3928
|
-
}
|
|
3929
|
-
async getExportableTypes() {
|
|
3930
|
-
const response = await this.request(
|
|
3931
|
-
"/api/tenants/exportable-types"
|
|
3932
|
-
);
|
|
3933
|
-
return response.data || [];
|
|
3934
|
-
}
|
|
3935
|
-
async exportConfig(tenantId, entityTypes) {
|
|
3936
|
-
const response = await this.request(
|
|
3937
|
-
`/api/tenants/${tenantId}/export`,
|
|
3938
|
-
{
|
|
3939
|
-
method: "POST",
|
|
3940
|
-
body: JSON.stringify({ entityTypes })
|
|
3941
|
-
}
|
|
3942
|
-
);
|
|
3943
|
-
return response.data;
|
|
3944
|
-
}
|
|
3945
|
-
async exportConfigConfirm(tenantId, entityTypes) {
|
|
3946
|
-
const response = await this.request(
|
|
3947
|
-
`/api/tenants/${tenantId}/export/confirm`,
|
|
3948
|
-
{
|
|
3949
|
-
method: "POST",
|
|
3950
|
-
body: JSON.stringify({ entityTypes })
|
|
3951
|
-
}
|
|
3952
|
-
);
|
|
3953
|
-
return response.data;
|
|
3954
|
-
}
|
|
3955
|
-
getExportDownloadUrl(tenantId, jobId) {
|
|
3956
|
-
return `${this.baseURL}/api/tenants/${tenantId}/export/${jobId}/download`;
|
|
3957
|
-
}
|
|
3958
|
-
async importPreview(tenantId, file) {
|
|
3959
|
-
const formData = new FormData();
|
|
3960
|
-
formData.append("file", file);
|
|
3961
|
-
const fullUrl = `${this.baseURL}/api/tenants/${tenantId}/import/preview`;
|
|
3962
|
-
const headers = { ...this.headers };
|
|
3963
|
-
delete headers["Content-Type"];
|
|
3964
|
-
const response = await fetch(fullUrl, {
|
|
3965
|
-
method: "POST",
|
|
3966
|
-
headers,
|
|
3967
|
-
body: formData
|
|
3968
|
-
});
|
|
3969
|
-
if (!response.ok) {
|
|
3970
|
-
const err = await response.json().catch(() => ({}));
|
|
3971
|
-
throw new Error(
|
|
3972
|
-
err.message || `HTTP error! Status: ${response.status}`
|
|
3973
|
-
);
|
|
3974
|
-
}
|
|
3975
|
-
const json = await response.json();
|
|
3976
|
-
if (!json.success || !json.data) {
|
|
3977
|
-
throw new Error(json.error || "Import preview failed");
|
|
3978
|
-
}
|
|
3979
|
-
return json.data;
|
|
3980
|
-
}
|
|
3981
|
-
async importApply(tenantId, bundle, resolutions) {
|
|
3982
|
-
const response = await this.request(
|
|
3983
|
-
`/api/tenants/${tenantId}/import/apply`,
|
|
3984
|
-
{
|
|
3985
|
-
method: "POST",
|
|
3986
|
-
body: JSON.stringify({ bundle, resolutions })
|
|
3987
|
-
}
|
|
3988
|
-
);
|
|
3989
|
-
return response.data;
|
|
3990
|
-
}
|
|
3991
|
-
};
|
|
3992
|
-
|
|
3993
4155
|
// src/ChunkMessageMerger.ts
|
|
3994
4156
|
var import_best_effort_json_parser = require("best-effort-json-parser");
|
|
3995
4157
|
function createSimpleMessageMerger() {
|