@granular-software/sdk 0.4.8 → 0.4.10
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/README.md +8 -0
- package/dist/cli/index.js +896 -245
- package/dist/index.d.mts +136 -1
- package/dist/index.d.ts +136 -1
- package/dist/index.js +303 -111
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +303 -111
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3950,6 +3950,9 @@ var WSClient = class {
|
|
|
3950
3950
|
this.sessionId = options.sessionId;
|
|
3951
3951
|
this.token = options.token;
|
|
3952
3952
|
}
|
|
3953
|
+
get currentSessionId() {
|
|
3954
|
+
return this.sessionId;
|
|
3955
|
+
}
|
|
3953
3956
|
clearTokenRefreshTimer() {
|
|
3954
3957
|
if (this.tokenRefreshTimer) {
|
|
3955
3958
|
clearTimeout(this.tokenRefreshTimer);
|
|
@@ -4503,6 +4506,9 @@ var Session = class {
|
|
|
4503
4506
|
get document() {
|
|
4504
4507
|
return this.client.doc;
|
|
4505
4508
|
}
|
|
4509
|
+
get sessionId() {
|
|
4510
|
+
return this.client.currentSessionId;
|
|
4511
|
+
}
|
|
4506
4512
|
get domainRevision() {
|
|
4507
4513
|
return this.currentDomainRevision;
|
|
4508
4514
|
}
|
|
@@ -4598,7 +4604,11 @@ var Session = class {
|
|
|
4598
4604
|
if (!result.jobId) {
|
|
4599
4605
|
throw new Error("Failed to submit job: no jobId returned");
|
|
4600
4606
|
}
|
|
4601
|
-
const job = new JobImplementation(result.jobId, this.client
|
|
4607
|
+
const job = new JobImplementation(result.jobId, this.client, {
|
|
4608
|
+
code,
|
|
4609
|
+
domainRevision: revision,
|
|
4610
|
+
createdAt: Date.now()
|
|
4611
|
+
});
|
|
4602
4612
|
this.jobsMap.set(result.jobId, job);
|
|
4603
4613
|
return job;
|
|
4604
4614
|
}
|
|
@@ -4992,6 +5002,78 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
4992
5002
|
}
|
|
4993
5003
|
}
|
|
4994
5004
|
};
|
|
5005
|
+
var MAX_FEEDBACK_STRING_LENGTH = 16e3;
|
|
5006
|
+
var MAX_FEEDBACK_TOOL_CALLS = 50;
|
|
5007
|
+
var MAX_FEEDBACK_ARRAY_ITEMS = 50;
|
|
5008
|
+
var MAX_FEEDBACK_OBJECT_KEYS = 50;
|
|
5009
|
+
var MAX_FEEDBACK_DEPTH = 6;
|
|
5010
|
+
function truncateFeedbackString(value, maxLength = MAX_FEEDBACK_STRING_LENGTH) {
|
|
5011
|
+
if (value.length <= maxLength) {
|
|
5012
|
+
return value;
|
|
5013
|
+
}
|
|
5014
|
+
return `${value.slice(0, maxLength)}...[truncated ${value.length - maxLength} chars]`;
|
|
5015
|
+
}
|
|
5016
|
+
function normalizeJobStatus(status) {
|
|
5017
|
+
if (typeof status !== "string") {
|
|
5018
|
+
return "queued";
|
|
5019
|
+
}
|
|
5020
|
+
switch (status) {
|
|
5021
|
+
case "completed":
|
|
5022
|
+
return "succeeded";
|
|
5023
|
+
case "failed":
|
|
5024
|
+
case "running":
|
|
5025
|
+
case "queued":
|
|
5026
|
+
case "succeeded":
|
|
5027
|
+
case "timeout":
|
|
5028
|
+
case "canceled":
|
|
5029
|
+
return status;
|
|
5030
|
+
default:
|
|
5031
|
+
return "queued";
|
|
5032
|
+
}
|
|
5033
|
+
}
|
|
5034
|
+
function sanitizeFeedbackValue(value, depth = 0, seen = /* @__PURE__ */ new WeakSet()) {
|
|
5035
|
+
if (depth >= MAX_FEEDBACK_DEPTH) {
|
|
5036
|
+
return "[Max depth reached]";
|
|
5037
|
+
}
|
|
5038
|
+
if (value === null || value === void 0) {
|
|
5039
|
+
return null;
|
|
5040
|
+
}
|
|
5041
|
+
if (typeof value === "string") {
|
|
5042
|
+
return truncateFeedbackString(value);
|
|
5043
|
+
}
|
|
5044
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
5045
|
+
return value;
|
|
5046
|
+
}
|
|
5047
|
+
if (typeof value === "bigint") {
|
|
5048
|
+
return truncateFeedbackString(value.toString());
|
|
5049
|
+
}
|
|
5050
|
+
if (value instanceof Error) {
|
|
5051
|
+
return {
|
|
5052
|
+
name: truncateFeedbackString(value.name),
|
|
5053
|
+
message: truncateFeedbackString(value.message),
|
|
5054
|
+
stack: truncateFeedbackString(value.stack || "")
|
|
5055
|
+
};
|
|
5056
|
+
}
|
|
5057
|
+
if (value instanceof Date) {
|
|
5058
|
+
return value.toISOString();
|
|
5059
|
+
}
|
|
5060
|
+
if (Array.isArray(value)) {
|
|
5061
|
+
return value.slice(0, MAX_FEEDBACK_ARRAY_ITEMS).map((entry) => sanitizeFeedbackValue(entry, depth + 1, seen));
|
|
5062
|
+
}
|
|
5063
|
+
if (typeof value === "object") {
|
|
5064
|
+
if (seen.has(value)) {
|
|
5065
|
+
return "[Circular]";
|
|
5066
|
+
}
|
|
5067
|
+
seen.add(value);
|
|
5068
|
+
const entries = Object.entries(value).slice(0, MAX_FEEDBACK_OBJECT_KEYS);
|
|
5069
|
+
const sanitized = {};
|
|
5070
|
+
for (const [key, entryValue] of entries) {
|
|
5071
|
+
sanitized[key] = sanitizeFeedbackValue(entryValue, depth + 1, seen);
|
|
5072
|
+
}
|
|
5073
|
+
return sanitized;
|
|
5074
|
+
}
|
|
5075
|
+
return truncateFeedbackString(String(value));
|
|
5076
|
+
}
|
|
4995
5077
|
var JobImplementation = class {
|
|
4996
5078
|
id;
|
|
4997
5079
|
client;
|
|
@@ -5000,9 +5082,20 @@ var JobImplementation = class {
|
|
|
5000
5082
|
_resolveResult;
|
|
5001
5083
|
_rejectResult;
|
|
5002
5084
|
eventListeners = /* @__PURE__ */ new Map();
|
|
5003
|
-
|
|
5085
|
+
metadata;
|
|
5086
|
+
constructor(id, client, initialState) {
|
|
5004
5087
|
this.id = id;
|
|
5005
5088
|
this.client = client;
|
|
5089
|
+
this.metadata = {
|
|
5090
|
+
source: "sdk",
|
|
5091
|
+
status: "queued",
|
|
5092
|
+
code: truncateFeedbackString(initialState.code),
|
|
5093
|
+
domainRevision: initialState.domainRevision,
|
|
5094
|
+
createdAt: initialState.createdAt,
|
|
5095
|
+
stdout: [],
|
|
5096
|
+
stderr: [],
|
|
5097
|
+
toolCalls: []
|
|
5098
|
+
};
|
|
5006
5099
|
this._resultPromise = new Promise((resolve, reject) => {
|
|
5007
5100
|
this._resolveResult = resolve;
|
|
5008
5101
|
this._rejectResult = reject;
|
|
@@ -5010,69 +5103,98 @@ var JobImplementation = class {
|
|
|
5010
5103
|
this.client.on("exec.completed", (data) => {
|
|
5011
5104
|
const execData = data;
|
|
5012
5105
|
if (execData.execId === id || execData.jobId === id) {
|
|
5013
|
-
this.status = "succeeded";
|
|
5014
|
-
this.emit("status", this.status);
|
|
5015
5106
|
if (execData.error) {
|
|
5016
|
-
this.
|
|
5107
|
+
this.finalize("failed", void 0, execData.error);
|
|
5017
5108
|
} else {
|
|
5018
|
-
this.
|
|
5109
|
+
this.finalize("succeeded", execData.result);
|
|
5019
5110
|
}
|
|
5111
|
+
this.emit("status", this.status);
|
|
5020
5112
|
}
|
|
5021
5113
|
});
|
|
5022
5114
|
this.client.on("exec.progress", (data) => {
|
|
5023
5115
|
const progressData = data;
|
|
5024
5116
|
if (progressData.execId === id || progressData.jobId === id) {
|
|
5025
5117
|
if (progressData.stdout) {
|
|
5118
|
+
this.markStarted();
|
|
5119
|
+
this.metadata.stdout = [...this.metadata.stdout, truncateFeedbackString(progressData.stdout)].slice(-100);
|
|
5026
5120
|
this.emit("stdout", progressData.stdout);
|
|
5027
5121
|
}
|
|
5028
5122
|
if (progressData.stderr) {
|
|
5123
|
+
this.markStarted();
|
|
5124
|
+
this.metadata.stderr = [...this.metadata.stderr, truncateFeedbackString(progressData.stderr)].slice(-100);
|
|
5029
5125
|
this.emit("stderr", progressData.stderr);
|
|
5030
5126
|
}
|
|
5031
5127
|
}
|
|
5032
5128
|
});
|
|
5033
5129
|
this.client.on(`job.${id}.status`, (status) => {
|
|
5034
|
-
|
|
5035
|
-
this.
|
|
5130
|
+
const normalizedStatus = normalizeJobStatus(status);
|
|
5131
|
+
this.status = normalizedStatus;
|
|
5132
|
+
this.metadata.status = normalizedStatus;
|
|
5133
|
+
if (normalizedStatus === "running") {
|
|
5134
|
+
this.markStarted();
|
|
5135
|
+
}
|
|
5136
|
+
if (normalizedStatus === "failed" || normalizedStatus === "timeout" || normalizedStatus === "canceled") {
|
|
5137
|
+
this.finalize(normalizedStatus);
|
|
5138
|
+
}
|
|
5139
|
+
if (normalizedStatus === "succeeded") {
|
|
5140
|
+
this.finalize("succeeded");
|
|
5141
|
+
}
|
|
5142
|
+
this.emit("status", normalizedStatus);
|
|
5036
5143
|
});
|
|
5037
5144
|
this.client.on(`job.${id}.stdout`, (line) => {
|
|
5145
|
+
this.markStarted();
|
|
5146
|
+
this.metadata.stdout = [...this.metadata.stdout, truncateFeedbackString(String(line))].slice(-100);
|
|
5038
5147
|
this.emit("stdout", line);
|
|
5039
5148
|
});
|
|
5040
5149
|
this.client.on(`job.${id}.stderr`, (line) => {
|
|
5150
|
+
this.markStarted();
|
|
5151
|
+
this.metadata.stderr = [...this.metadata.stderr, truncateFeedbackString(String(line))].slice(-100);
|
|
5041
5152
|
this.emit("stderr", line);
|
|
5042
5153
|
});
|
|
5043
5154
|
this.client.on(`job.${id}.result`, (result) => {
|
|
5044
|
-
this.
|
|
5045
|
-
this._resolveResult(result);
|
|
5155
|
+
this.finalize("succeeded", result);
|
|
5046
5156
|
});
|
|
5047
5157
|
this.client.on(`job.${id}.error`, (error) => {
|
|
5048
|
-
this.
|
|
5049
|
-
this._rejectResult(error);
|
|
5158
|
+
this.finalize("failed", void 0, error);
|
|
5050
5159
|
});
|
|
5051
5160
|
this.client.on("job.completed", (data) => {
|
|
5052
5161
|
const jobData = data;
|
|
5053
5162
|
if (jobData.jobId === id) {
|
|
5054
|
-
this.
|
|
5163
|
+
this.finalize("succeeded", jobData.result);
|
|
5055
5164
|
this.emit("status", this.status);
|
|
5056
|
-
this._resolveResult(jobData.result);
|
|
5057
5165
|
}
|
|
5058
5166
|
});
|
|
5059
5167
|
this.client.on("job.failed", (data) => {
|
|
5060
5168
|
const jobData = data;
|
|
5061
5169
|
if (jobData.jobId === id) {
|
|
5062
|
-
this.
|
|
5170
|
+
this.finalize("failed", void 0, jobData.error || new Error("Job failed"));
|
|
5063
5171
|
this.emit("status", this.status);
|
|
5064
|
-
this._rejectResult(jobData.error || new Error("Job failed"));
|
|
5065
5172
|
}
|
|
5066
5173
|
});
|
|
5067
5174
|
this.client.on("tool.call.start", (data) => {
|
|
5068
5175
|
const d = data;
|
|
5069
5176
|
if (d.jobId === id) {
|
|
5177
|
+
this.metadata.toolCalls = this.upsertToolCall({
|
|
5178
|
+
callId: d.callId,
|
|
5179
|
+
toolName: d.toolName,
|
|
5180
|
+
input: sanitizeFeedbackValue(d.input),
|
|
5181
|
+
startedAt: d.timestamp || Date.now()
|
|
5182
|
+
});
|
|
5070
5183
|
this.emit("toolCallStart", { callId: d.callId, toolName: d.toolName, input: d.input, timestamp: d.timestamp });
|
|
5071
5184
|
}
|
|
5072
5185
|
});
|
|
5073
5186
|
this.client.on("tool.call.end", (data) => {
|
|
5074
5187
|
const d = data;
|
|
5075
5188
|
if (d.jobId === id) {
|
|
5189
|
+
const completedAt = d.timestamp || Date.now();
|
|
5190
|
+
this.metadata.toolCalls = this.upsertToolCall({
|
|
5191
|
+
callId: d.callId,
|
|
5192
|
+
toolName: d.toolName,
|
|
5193
|
+
output: sanitizeFeedbackValue(d.result),
|
|
5194
|
+
error: d.error ? truncateFeedbackString(d.error) : void 0,
|
|
5195
|
+
completedAt,
|
|
5196
|
+
durationMs: typeof d.durationMs === "number" ? d.durationMs : void 0
|
|
5197
|
+
});
|
|
5076
5198
|
this.emit("toolCallEnd", { callId: d.callId, toolName: d.toolName, result: d.result, error: d.error, durationMs: d.durationMs, timestamp: d.timestamp });
|
|
5077
5199
|
}
|
|
5078
5200
|
});
|
|
@@ -5080,12 +5202,87 @@ var JobImplementation = class {
|
|
|
5080
5202
|
get result() {
|
|
5081
5203
|
return this._resultPromise;
|
|
5082
5204
|
}
|
|
5205
|
+
async leaveFeedback(input) {
|
|
5206
|
+
const sentiment = input.sentiment;
|
|
5207
|
+
if (sentiment !== "good" && sentiment !== "bad") {
|
|
5208
|
+
throw new Error('Job feedback sentiment must be "good" or "bad".');
|
|
5209
|
+
}
|
|
5210
|
+
const comment = typeof input.comment === "string" ? input.comment.trim() : "";
|
|
5211
|
+
const response = await this.client.call("job.feedback", {
|
|
5212
|
+
jobId: this.id,
|
|
5213
|
+
sentiment,
|
|
5214
|
+
comment: comment || void 0,
|
|
5215
|
+
metadata: this.buildFeedbackMetadata()
|
|
5216
|
+
});
|
|
5217
|
+
this.emit("feedback", response);
|
|
5218
|
+
return response;
|
|
5219
|
+
}
|
|
5083
5220
|
on(event, handler) {
|
|
5084
5221
|
if (!this.eventListeners.has(event)) {
|
|
5085
5222
|
this.eventListeners.set(event, []);
|
|
5086
5223
|
}
|
|
5087
5224
|
this.eventListeners.get(event).push(handler);
|
|
5088
5225
|
}
|
|
5226
|
+
buildFeedbackMetadata() {
|
|
5227
|
+
const startedAt = this.metadata.startedAt;
|
|
5228
|
+
const completedAt = this.metadata.completedAt;
|
|
5229
|
+
return {
|
|
5230
|
+
...this.metadata,
|
|
5231
|
+
durationMs: typeof startedAt === "number" && typeof completedAt === "number" ? completedAt - startedAt : this.metadata.durationMs ?? null,
|
|
5232
|
+
stdout: [...this.metadata.stdout],
|
|
5233
|
+
stderr: [...this.metadata.stderr],
|
|
5234
|
+
toolCalls: this.metadata.toolCalls.slice(0, MAX_FEEDBACK_TOOL_CALLS).map((call) => ({ ...call }))
|
|
5235
|
+
};
|
|
5236
|
+
}
|
|
5237
|
+
markStarted(timestamp = Date.now()) {
|
|
5238
|
+
if (!this.metadata.startedAt) {
|
|
5239
|
+
this.metadata.startedAt = timestamp;
|
|
5240
|
+
}
|
|
5241
|
+
if (this.status === "queued") {
|
|
5242
|
+
this.status = "running";
|
|
5243
|
+
}
|
|
5244
|
+
if (this.metadata.status === "queued") {
|
|
5245
|
+
this.metadata.status = "running";
|
|
5246
|
+
}
|
|
5247
|
+
}
|
|
5248
|
+
finalize(status, result, error) {
|
|
5249
|
+
if (!this.metadata.startedAt) {
|
|
5250
|
+
this.metadata.startedAt = Date.now();
|
|
5251
|
+
}
|
|
5252
|
+
this.status = status;
|
|
5253
|
+
this.metadata.status = status;
|
|
5254
|
+
this.metadata.completedAt = this.metadata.completedAt || Date.now();
|
|
5255
|
+
this.metadata.durationMs = this.metadata.completedAt - this.metadata.startedAt;
|
|
5256
|
+
if (result !== void 0) {
|
|
5257
|
+
this.metadata.result = sanitizeFeedbackValue(result);
|
|
5258
|
+
this._resolveResult(result);
|
|
5259
|
+
}
|
|
5260
|
+
if (error !== void 0) {
|
|
5261
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5262
|
+
this.metadata.error = truncateFeedbackString(message);
|
|
5263
|
+
this._rejectResult(error);
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5266
|
+
upsertToolCall(next) {
|
|
5267
|
+
const callId = next.callId || `tool-call-${Date.now()}`;
|
|
5268
|
+
const existingIndex = this.metadata.toolCalls.findIndex((entry) => entry.callId === callId);
|
|
5269
|
+
const existing = existingIndex >= 0 ? this.metadata.toolCalls[existingIndex] : void 0;
|
|
5270
|
+
const merged = {
|
|
5271
|
+
...existing,
|
|
5272
|
+
...next,
|
|
5273
|
+
callId,
|
|
5274
|
+
toolName: next.toolName || existing?.toolName
|
|
5275
|
+
};
|
|
5276
|
+
if (merged.durationMs === void 0 && typeof merged.startedAt === "number" && typeof merged.completedAt === "number") {
|
|
5277
|
+
merged.durationMs = merged.completedAt - merged.startedAt;
|
|
5278
|
+
}
|
|
5279
|
+
if (existingIndex >= 0) {
|
|
5280
|
+
const updated = [...this.metadata.toolCalls];
|
|
5281
|
+
updated[existingIndex] = merged;
|
|
5282
|
+
return updated.slice(-MAX_FEEDBACK_TOOL_CALLS);
|
|
5283
|
+
}
|
|
5284
|
+
return [...this.metadata.toolCalls, merged].slice(-MAX_FEEDBACK_TOOL_CALLS);
|
|
5285
|
+
}
|
|
5089
5286
|
emit(event, data) {
|
|
5090
5287
|
const handlers = this.eventListeners.get(event);
|
|
5091
5288
|
if (handlers) {
|
|
@@ -5226,7 +5423,7 @@ function normalizeUser(user) {
|
|
|
5226
5423
|
permissions: Array.isArray(user.permissions) ? user.permissions : []
|
|
5227
5424
|
};
|
|
5228
5425
|
}
|
|
5229
|
-
var Environment = class
|
|
5426
|
+
var Environment = class extends Session {
|
|
5230
5427
|
envData;
|
|
5231
5428
|
_apiKey;
|
|
5232
5429
|
_apiEndpoint;
|
|
@@ -5286,6 +5483,22 @@ var Environment = class _Environment extends Session {
|
|
|
5286
5483
|
return this._apiEndpoint.replace(/\/orchestrator\/graphql$/, "").replace(/\/$/, "");
|
|
5287
5484
|
}
|
|
5288
5485
|
}
|
|
5486
|
+
async controlPlaneRequest(path, options = {}) {
|
|
5487
|
+
const runtimeBase = this.getRuntimeBaseUrl();
|
|
5488
|
+
const url = `${runtimeBase}${path}`;
|
|
5489
|
+
const response = await fetch(url, {
|
|
5490
|
+
...options,
|
|
5491
|
+
headers: {
|
|
5492
|
+
"Authorization": `Bearer ${this._apiKey}`,
|
|
5493
|
+
"Content-Type": "application/json",
|
|
5494
|
+
...options.headers
|
|
5495
|
+
}
|
|
5496
|
+
});
|
|
5497
|
+
if (!response.ok) {
|
|
5498
|
+
throw new Error(`Control Plane API Error (${response.status}): ${await response.text()}`);
|
|
5499
|
+
}
|
|
5500
|
+
return response.json();
|
|
5501
|
+
}
|
|
5289
5502
|
/**
|
|
5290
5503
|
* Close the session and disconnect from the sandbox.
|
|
5291
5504
|
*
|
|
@@ -5882,105 +6095,84 @@ var Environment = class _Environment extends Session {
|
|
|
5882
6095
|
* ```
|
|
5883
6096
|
*/
|
|
5884
6097
|
async recordObject(options) {
|
|
5885
|
-
const
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
6098
|
+
const results = await this.recordObjects([options]);
|
|
6099
|
+
return results[0];
|
|
6100
|
+
}
|
|
6101
|
+
/**
|
|
6102
|
+
* Batch version of `recordObject()`.
|
|
6103
|
+
*
|
|
6104
|
+
* Sends several upserts through the control-plane batch endpoint so the
|
|
6105
|
+
* server can collapse the graph mutations into far fewer round trips.
|
|
6106
|
+
*/
|
|
6107
|
+
async recordObjects(records) {
|
|
6108
|
+
if (!Array.isArray(records) || records.length === 0) {
|
|
6109
|
+
return [];
|
|
6110
|
+
}
|
|
6111
|
+
const response = await this.controlPlaneRequest(
|
|
6112
|
+
`/control/environments/${this.environmentId}/records/batch`,
|
|
6113
|
+
{
|
|
6114
|
+
method: "POST",
|
|
6115
|
+
body: JSON.stringify({ records })
|
|
6116
|
+
}
|
|
5889
6117
|
);
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
6118
|
+
return Array.isArray(response.items) ? response.items : [];
|
|
6119
|
+
}
|
|
6120
|
+
/**
|
|
6121
|
+
* Queue a background record import for this environment.
|
|
6122
|
+
*/
|
|
6123
|
+
async enqueueRecordImport(records, options = {}) {
|
|
6124
|
+
return this.controlPlaneRequest(
|
|
6125
|
+
`/control/environments/${this.environmentId}/record-imports`,
|
|
6126
|
+
{
|
|
6127
|
+
method: "POST",
|
|
6128
|
+
body: JSON.stringify({
|
|
6129
|
+
records,
|
|
6130
|
+
batchSize: options.batchSize
|
|
6131
|
+
})
|
|
6132
|
+
}
|
|
5899
6133
|
);
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
model { path }
|
|
5909
|
-
}
|
|
5910
|
-
}
|
|
5911
|
-
}`
|
|
6134
|
+
}
|
|
6135
|
+
/**
|
|
6136
|
+
* List queued or completed record imports for this environment.
|
|
6137
|
+
*/
|
|
6138
|
+
async listRecordImports(status) {
|
|
6139
|
+
const suffix = status ? `?status=${encodeURIComponent(status)}` : "";
|
|
6140
|
+
const response = await this.controlPlaneRequest(
|
|
6141
|
+
`/control/environments/${this.environmentId}/record-imports${suffix}`
|
|
5912
6142
|
);
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
6143
|
+
return Array.isArray(response.items) ? response.items : [];
|
|
6144
|
+
}
|
|
6145
|
+
/**
|
|
6146
|
+
* Fetch the latest aggregate import counters for this environment.
|
|
6147
|
+
*/
|
|
6148
|
+
async getRecordImportSummary() {
|
|
6149
|
+
return this.controlPlaneRequest(
|
|
6150
|
+
`/control/environments/${this.environmentId}/record-imports/summary`
|
|
5921
6151
|
);
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
} else if (typeof value === "number") {
|
|
5945
|
-
await this.graphql(
|
|
5946
|
-
`mutation {
|
|
5947
|
-
at(path: "${instancePath}") {
|
|
5948
|
-
at(submodel: "${fieldName}") {
|
|
5949
|
-
set_number_value(value: ${value}) { done }
|
|
5950
|
-
}
|
|
5951
|
-
}
|
|
5952
|
-
}`
|
|
5953
|
-
);
|
|
5954
|
-
} else if (typeof value === "boolean") {
|
|
5955
|
-
await this.graphql(
|
|
5956
|
-
`mutation {
|
|
5957
|
-
at(path: "${instancePath}") {
|
|
5958
|
-
at(submodel: "${fieldName}") {
|
|
5959
|
-
set_boolean_value(value: ${value}) { done }
|
|
5960
|
-
}
|
|
5961
|
-
}
|
|
5962
|
-
}`
|
|
5963
|
-
);
|
|
5964
|
-
}
|
|
5965
|
-
}
|
|
5966
|
-
}
|
|
5967
|
-
if (relationships) {
|
|
5968
|
-
const rels = await this.getRelationships(className);
|
|
5969
|
-
const relMap = {};
|
|
5970
|
-
for (const rel of rels) {
|
|
5971
|
-
const submodelLeaf = rel.local_submodel.path.includes(":") ? rel.local_submodel.path.split(":").pop() : rel.local_submodel.path;
|
|
5972
|
-
relMap[submodelLeaf] = rel.foreign_model.path;
|
|
5973
|
-
}
|
|
5974
|
-
for (const [submodelName, targets] of Object.entries(relationships)) {
|
|
5975
|
-
const foreignClass = relMap[submodelName];
|
|
5976
|
-
const targetList = Array.isArray(targets) ? targets : [targets];
|
|
5977
|
-
for (const target of targetList) {
|
|
5978
|
-
const targetGraphPath = foreignClass ? _Environment.toGraphPath(foreignClass, target) : target;
|
|
5979
|
-
await this.attach(instancePath, submodelName, targetGraphPath);
|
|
5980
|
-
}
|
|
6152
|
+
}
|
|
6153
|
+
/**
|
|
6154
|
+
* Convenience helper returning queued + processing records for this environment.
|
|
6155
|
+
*/
|
|
6156
|
+
async getAwaitingRecordCount() {
|
|
6157
|
+
const summary = await this.getRecordImportSummary();
|
|
6158
|
+
return summary.awaitingRecords;
|
|
6159
|
+
}
|
|
6160
|
+
/**
|
|
6161
|
+
* Fetch a single record import by id.
|
|
6162
|
+
*/
|
|
6163
|
+
async getRecordImport(importId) {
|
|
6164
|
+
return this.controlPlaneRequest(`/control/record-imports/${importId}`);
|
|
6165
|
+
}
|
|
6166
|
+
/**
|
|
6167
|
+
* Cancel a queued/background record import.
|
|
6168
|
+
*/
|
|
6169
|
+
async cancelRecordImport(importId) {
|
|
6170
|
+
return this.controlPlaneRequest(
|
|
6171
|
+
`/control/record-imports/${importId}/cancel`,
|
|
6172
|
+
{
|
|
6173
|
+
method: "POST"
|
|
5981
6174
|
}
|
|
5982
|
-
|
|
5983
|
-
return { path: instancePath, id, created: !alreadyExists };
|
|
6175
|
+
);
|
|
5984
6176
|
}
|
|
5985
6177
|
// ==================== PUBLISH TOOLS ====================
|
|
5986
6178
|
/**
|