@granular-software/sdk 0.4.7 → 0.4.9
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/cli/index.js +1269 -371
- package/dist/index.d.mts +137 -1
- package/dist/index.d.ts +137 -1
- package/dist/index.js +331 -113
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +331 -113
- 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);
|
|
@@ -4474,6 +4477,18 @@ var Session = class {
|
|
|
4474
4477
|
this.setupEventHandlers();
|
|
4475
4478
|
this.setupToolInvokeHandler();
|
|
4476
4479
|
}
|
|
4480
|
+
extractDomainRevisionFromDoc(doc) {
|
|
4481
|
+
const domain = doc?.domain;
|
|
4482
|
+
const active = domain?.active;
|
|
4483
|
+
if (typeof active === "string" && active.trim()) {
|
|
4484
|
+
return active;
|
|
4485
|
+
}
|
|
4486
|
+
const nestedRevision = active?.domainRevision;
|
|
4487
|
+
if (typeof nestedRevision === "string" && nestedRevision.trim()) {
|
|
4488
|
+
return nestedRevision;
|
|
4489
|
+
}
|
|
4490
|
+
return null;
|
|
4491
|
+
}
|
|
4477
4492
|
buildLegacyEffectContext() {
|
|
4478
4493
|
return {
|
|
4479
4494
|
effectClientId: this.clientId,
|
|
@@ -4491,6 +4506,9 @@ var Session = class {
|
|
|
4491
4506
|
get document() {
|
|
4492
4507
|
return this.client.doc;
|
|
4493
4508
|
}
|
|
4509
|
+
get sessionId() {
|
|
4510
|
+
return this.client.currentSessionId;
|
|
4511
|
+
}
|
|
4494
4512
|
get domainRevision() {
|
|
4495
4513
|
return this.currentDomainRevision;
|
|
4496
4514
|
}
|
|
@@ -4568,7 +4586,14 @@ var Session = class {
|
|
|
4568
4586
|
* execute locally and return the result to the sandbox.
|
|
4569
4587
|
*/
|
|
4570
4588
|
async submitJob(code, domainRevision) {
|
|
4571
|
-
|
|
4589
|
+
let revision = domainRevision || this.currentDomainRevision || this.extractDomainRevisionFromDoc(this.client.doc) || void 0;
|
|
4590
|
+
if (!revision) {
|
|
4591
|
+
try {
|
|
4592
|
+
const summary = await this.getDomain();
|
|
4593
|
+
revision = summary.activeDomainRevision || this.extractDomainRevisionFromDoc(this.client.doc) || void 0;
|
|
4594
|
+
} catch {
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4572
4597
|
if (!revision) {
|
|
4573
4598
|
throw new Error("No domain revision available. Register live effects or ensure the build schema is activated.");
|
|
4574
4599
|
}
|
|
@@ -4579,7 +4604,11 @@ var Session = class {
|
|
|
4579
4604
|
if (!result.jobId) {
|
|
4580
4605
|
throw new Error("Failed to submit job: no jobId returned");
|
|
4581
4606
|
}
|
|
4582
|
-
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
|
+
});
|
|
4583
4612
|
this.jobsMap.set(result.jobId, job);
|
|
4584
4613
|
return job;
|
|
4585
4614
|
}
|
|
@@ -4693,7 +4722,13 @@ var Session = class {
|
|
|
4693
4722
|
* Get the current domain state and available tools
|
|
4694
4723
|
*/
|
|
4695
4724
|
async getDomain() {
|
|
4696
|
-
|
|
4725
|
+
const summary = await this.client.call("domain.getSummary", {});
|
|
4726
|
+
if (summary.activeDomainRevision) {
|
|
4727
|
+
this.currentDomainRevision = summary.activeDomainRevision;
|
|
4728
|
+
} else {
|
|
4729
|
+
this.currentDomainRevision = this.extractDomainRevisionFromDoc(this.client.doc);
|
|
4730
|
+
}
|
|
4731
|
+
return summary;
|
|
4697
4732
|
}
|
|
4698
4733
|
/**
|
|
4699
4734
|
* Fetch a domain package part from the backend (no fallback).
|
|
@@ -4911,6 +4946,7 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
4911
4946
|
}
|
|
4912
4947
|
setupEventHandlers() {
|
|
4913
4948
|
this.client.on("sync", (doc) => {
|
|
4949
|
+
this.currentDomainRevision = this.extractDomainRevisionFromDoc(doc);
|
|
4914
4950
|
this.emit("sync", doc);
|
|
4915
4951
|
this.checkForToolChanges();
|
|
4916
4952
|
});
|
|
@@ -4966,6 +5002,78 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
4966
5002
|
}
|
|
4967
5003
|
}
|
|
4968
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
|
+
}
|
|
4969
5077
|
var JobImplementation = class {
|
|
4970
5078
|
id;
|
|
4971
5079
|
client;
|
|
@@ -4974,9 +5082,20 @@ var JobImplementation = class {
|
|
|
4974
5082
|
_resolveResult;
|
|
4975
5083
|
_rejectResult;
|
|
4976
5084
|
eventListeners = /* @__PURE__ */ new Map();
|
|
4977
|
-
|
|
5085
|
+
metadata;
|
|
5086
|
+
constructor(id, client, initialState) {
|
|
4978
5087
|
this.id = id;
|
|
4979
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
|
+
};
|
|
4980
5099
|
this._resultPromise = new Promise((resolve, reject) => {
|
|
4981
5100
|
this._resolveResult = resolve;
|
|
4982
5101
|
this._rejectResult = reject;
|
|
@@ -4984,69 +5103,98 @@ var JobImplementation = class {
|
|
|
4984
5103
|
this.client.on("exec.completed", (data) => {
|
|
4985
5104
|
const execData = data;
|
|
4986
5105
|
if (execData.execId === id || execData.jobId === id) {
|
|
4987
|
-
this.status = "succeeded";
|
|
4988
|
-
this.emit("status", this.status);
|
|
4989
5106
|
if (execData.error) {
|
|
4990
|
-
this.
|
|
5107
|
+
this.finalize("failed", void 0, execData.error);
|
|
4991
5108
|
} else {
|
|
4992
|
-
this.
|
|
5109
|
+
this.finalize("succeeded", execData.result);
|
|
4993
5110
|
}
|
|
5111
|
+
this.emit("status", this.status);
|
|
4994
5112
|
}
|
|
4995
5113
|
});
|
|
4996
5114
|
this.client.on("exec.progress", (data) => {
|
|
4997
5115
|
const progressData = data;
|
|
4998
5116
|
if (progressData.execId === id || progressData.jobId === id) {
|
|
4999
5117
|
if (progressData.stdout) {
|
|
5118
|
+
this.markStarted();
|
|
5119
|
+
this.metadata.stdout = [...this.metadata.stdout, truncateFeedbackString(progressData.stdout)].slice(-100);
|
|
5000
5120
|
this.emit("stdout", progressData.stdout);
|
|
5001
5121
|
}
|
|
5002
5122
|
if (progressData.stderr) {
|
|
5123
|
+
this.markStarted();
|
|
5124
|
+
this.metadata.stderr = [...this.metadata.stderr, truncateFeedbackString(progressData.stderr)].slice(-100);
|
|
5003
5125
|
this.emit("stderr", progressData.stderr);
|
|
5004
5126
|
}
|
|
5005
5127
|
}
|
|
5006
5128
|
});
|
|
5007
5129
|
this.client.on(`job.${id}.status`, (status) => {
|
|
5008
|
-
|
|
5009
|
-
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);
|
|
5010
5143
|
});
|
|
5011
5144
|
this.client.on(`job.${id}.stdout`, (line) => {
|
|
5145
|
+
this.markStarted();
|
|
5146
|
+
this.metadata.stdout = [...this.metadata.stdout, truncateFeedbackString(String(line))].slice(-100);
|
|
5012
5147
|
this.emit("stdout", line);
|
|
5013
5148
|
});
|
|
5014
5149
|
this.client.on(`job.${id}.stderr`, (line) => {
|
|
5150
|
+
this.markStarted();
|
|
5151
|
+
this.metadata.stderr = [...this.metadata.stderr, truncateFeedbackString(String(line))].slice(-100);
|
|
5015
5152
|
this.emit("stderr", line);
|
|
5016
5153
|
});
|
|
5017
5154
|
this.client.on(`job.${id}.result`, (result) => {
|
|
5018
|
-
this.
|
|
5019
|
-
this._resolveResult(result);
|
|
5155
|
+
this.finalize("succeeded", result);
|
|
5020
5156
|
});
|
|
5021
5157
|
this.client.on(`job.${id}.error`, (error) => {
|
|
5022
|
-
this.
|
|
5023
|
-
this._rejectResult(error);
|
|
5158
|
+
this.finalize("failed", void 0, error);
|
|
5024
5159
|
});
|
|
5025
5160
|
this.client.on("job.completed", (data) => {
|
|
5026
5161
|
const jobData = data;
|
|
5027
5162
|
if (jobData.jobId === id) {
|
|
5028
|
-
this.
|
|
5163
|
+
this.finalize("succeeded", jobData.result);
|
|
5029
5164
|
this.emit("status", this.status);
|
|
5030
|
-
this._resolveResult(jobData.result);
|
|
5031
5165
|
}
|
|
5032
5166
|
});
|
|
5033
5167
|
this.client.on("job.failed", (data) => {
|
|
5034
5168
|
const jobData = data;
|
|
5035
5169
|
if (jobData.jobId === id) {
|
|
5036
|
-
this.
|
|
5170
|
+
this.finalize("failed", void 0, jobData.error || new Error("Job failed"));
|
|
5037
5171
|
this.emit("status", this.status);
|
|
5038
|
-
this._rejectResult(jobData.error || new Error("Job failed"));
|
|
5039
5172
|
}
|
|
5040
5173
|
});
|
|
5041
5174
|
this.client.on("tool.call.start", (data) => {
|
|
5042
5175
|
const d = data;
|
|
5043
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
|
+
});
|
|
5044
5183
|
this.emit("toolCallStart", { callId: d.callId, toolName: d.toolName, input: d.input, timestamp: d.timestamp });
|
|
5045
5184
|
}
|
|
5046
5185
|
});
|
|
5047
5186
|
this.client.on("tool.call.end", (data) => {
|
|
5048
5187
|
const d = data;
|
|
5049
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
|
+
});
|
|
5050
5198
|
this.emit("toolCallEnd", { callId: d.callId, toolName: d.toolName, result: d.result, error: d.error, durationMs: d.durationMs, timestamp: d.timestamp });
|
|
5051
5199
|
}
|
|
5052
5200
|
});
|
|
@@ -5054,12 +5202,87 @@ var JobImplementation = class {
|
|
|
5054
5202
|
get result() {
|
|
5055
5203
|
return this._resultPromise;
|
|
5056
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
|
+
}
|
|
5057
5220
|
on(event, handler) {
|
|
5058
5221
|
if (!this.eventListeners.has(event)) {
|
|
5059
5222
|
this.eventListeners.set(event, []);
|
|
5060
5223
|
}
|
|
5061
5224
|
this.eventListeners.get(event).push(handler);
|
|
5062
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
|
+
}
|
|
5063
5286
|
emit(event, data) {
|
|
5064
5287
|
const handlers = this.eventListeners.get(event);
|
|
5065
5288
|
if (handlers) {
|
|
@@ -5200,7 +5423,7 @@ function normalizeUser(user) {
|
|
|
5200
5423
|
permissions: Array.isArray(user.permissions) ? user.permissions : []
|
|
5201
5424
|
};
|
|
5202
5425
|
}
|
|
5203
|
-
var Environment = class
|
|
5426
|
+
var Environment = class extends Session {
|
|
5204
5427
|
envData;
|
|
5205
5428
|
_apiKey;
|
|
5206
5429
|
_apiEndpoint;
|
|
@@ -5260,6 +5483,22 @@ var Environment = class _Environment extends Session {
|
|
|
5260
5483
|
return this._apiEndpoint.replace(/\/orchestrator\/graphql$/, "").replace(/\/$/, "");
|
|
5261
5484
|
}
|
|
5262
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
|
+
}
|
|
5263
5502
|
/**
|
|
5264
5503
|
* Close the session and disconnect from the sandbox.
|
|
5265
5504
|
*
|
|
@@ -5856,105 +6095,84 @@ var Environment = class _Environment extends Session {
|
|
|
5856
6095
|
* ```
|
|
5857
6096
|
*/
|
|
5858
6097
|
async recordObject(options) {
|
|
5859
|
-
const
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
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
|
+
}
|
|
5863
6117
|
);
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
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
|
+
}
|
|
5873
6133
|
);
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
model { path }
|
|
5883
|
-
}
|
|
5884
|
-
}
|
|
5885
|
-
}`
|
|
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}`
|
|
5886
6142
|
);
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
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`
|
|
5895
6151
|
);
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
} else if (typeof value === "number") {
|
|
5919
|
-
await this.graphql(
|
|
5920
|
-
`mutation {
|
|
5921
|
-
at(path: "${instancePath}") {
|
|
5922
|
-
at(submodel: "${fieldName}") {
|
|
5923
|
-
set_number_value(value: ${value}) { done }
|
|
5924
|
-
}
|
|
5925
|
-
}
|
|
5926
|
-
}`
|
|
5927
|
-
);
|
|
5928
|
-
} else if (typeof value === "boolean") {
|
|
5929
|
-
await this.graphql(
|
|
5930
|
-
`mutation {
|
|
5931
|
-
at(path: "${instancePath}") {
|
|
5932
|
-
at(submodel: "${fieldName}") {
|
|
5933
|
-
set_boolean_value(value: ${value}) { done }
|
|
5934
|
-
}
|
|
5935
|
-
}
|
|
5936
|
-
}`
|
|
5937
|
-
);
|
|
5938
|
-
}
|
|
5939
|
-
}
|
|
5940
|
-
}
|
|
5941
|
-
if (relationships) {
|
|
5942
|
-
const rels = await this.getRelationships(className);
|
|
5943
|
-
const relMap = {};
|
|
5944
|
-
for (const rel of rels) {
|
|
5945
|
-
const submodelLeaf = rel.local_submodel.path.includes(":") ? rel.local_submodel.path.split(":").pop() : rel.local_submodel.path;
|
|
5946
|
-
relMap[submodelLeaf] = rel.foreign_model.path;
|
|
5947
|
-
}
|
|
5948
|
-
for (const [submodelName, targets] of Object.entries(relationships)) {
|
|
5949
|
-
const foreignClass = relMap[submodelName];
|
|
5950
|
-
const targetList = Array.isArray(targets) ? targets : [targets];
|
|
5951
|
-
for (const target of targetList) {
|
|
5952
|
-
const targetGraphPath = foreignClass ? _Environment.toGraphPath(foreignClass, target) : target;
|
|
5953
|
-
await this.attach(instancePath, submodelName, targetGraphPath);
|
|
5954
|
-
}
|
|
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"
|
|
5955
6174
|
}
|
|
5956
|
-
|
|
5957
|
-
return { path: instancePath, id, created: !alreadyExists };
|
|
6175
|
+
);
|
|
5958
6176
|
}
|
|
5959
6177
|
// ==================== PUBLISH TOOLS ====================
|
|
5960
6178
|
/**
|