@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.js
CHANGED
|
@@ -3972,6 +3972,9 @@ var WSClient = class {
|
|
|
3972
3972
|
this.sessionId = options.sessionId;
|
|
3973
3973
|
this.token = options.token;
|
|
3974
3974
|
}
|
|
3975
|
+
get currentSessionId() {
|
|
3976
|
+
return this.sessionId;
|
|
3977
|
+
}
|
|
3975
3978
|
clearTokenRefreshTimer() {
|
|
3976
3979
|
if (this.tokenRefreshTimer) {
|
|
3977
3980
|
clearTimeout(this.tokenRefreshTimer);
|
|
@@ -4496,6 +4499,18 @@ var Session = class {
|
|
|
4496
4499
|
this.setupEventHandlers();
|
|
4497
4500
|
this.setupToolInvokeHandler();
|
|
4498
4501
|
}
|
|
4502
|
+
extractDomainRevisionFromDoc(doc) {
|
|
4503
|
+
const domain = doc?.domain;
|
|
4504
|
+
const active = domain?.active;
|
|
4505
|
+
if (typeof active === "string" && active.trim()) {
|
|
4506
|
+
return active;
|
|
4507
|
+
}
|
|
4508
|
+
const nestedRevision = active?.domainRevision;
|
|
4509
|
+
if (typeof nestedRevision === "string" && nestedRevision.trim()) {
|
|
4510
|
+
return nestedRevision;
|
|
4511
|
+
}
|
|
4512
|
+
return null;
|
|
4513
|
+
}
|
|
4499
4514
|
buildLegacyEffectContext() {
|
|
4500
4515
|
return {
|
|
4501
4516
|
effectClientId: this.clientId,
|
|
@@ -4513,6 +4528,9 @@ var Session = class {
|
|
|
4513
4528
|
get document() {
|
|
4514
4529
|
return this.client.doc;
|
|
4515
4530
|
}
|
|
4531
|
+
get sessionId() {
|
|
4532
|
+
return this.client.currentSessionId;
|
|
4533
|
+
}
|
|
4516
4534
|
get domainRevision() {
|
|
4517
4535
|
return this.currentDomainRevision;
|
|
4518
4536
|
}
|
|
@@ -4590,7 +4608,14 @@ var Session = class {
|
|
|
4590
4608
|
* execute locally and return the result to the sandbox.
|
|
4591
4609
|
*/
|
|
4592
4610
|
async submitJob(code, domainRevision) {
|
|
4593
|
-
|
|
4611
|
+
let revision = domainRevision || this.currentDomainRevision || this.extractDomainRevisionFromDoc(this.client.doc) || void 0;
|
|
4612
|
+
if (!revision) {
|
|
4613
|
+
try {
|
|
4614
|
+
const summary = await this.getDomain();
|
|
4615
|
+
revision = summary.activeDomainRevision || this.extractDomainRevisionFromDoc(this.client.doc) || void 0;
|
|
4616
|
+
} catch {
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4594
4619
|
if (!revision) {
|
|
4595
4620
|
throw new Error("No domain revision available. Register live effects or ensure the build schema is activated.");
|
|
4596
4621
|
}
|
|
@@ -4601,7 +4626,11 @@ var Session = class {
|
|
|
4601
4626
|
if (!result.jobId) {
|
|
4602
4627
|
throw new Error("Failed to submit job: no jobId returned");
|
|
4603
4628
|
}
|
|
4604
|
-
const job = new JobImplementation(result.jobId, this.client
|
|
4629
|
+
const job = new JobImplementation(result.jobId, this.client, {
|
|
4630
|
+
code,
|
|
4631
|
+
domainRevision: revision,
|
|
4632
|
+
createdAt: Date.now()
|
|
4633
|
+
});
|
|
4605
4634
|
this.jobsMap.set(result.jobId, job);
|
|
4606
4635
|
return job;
|
|
4607
4636
|
}
|
|
@@ -4715,7 +4744,13 @@ var Session = class {
|
|
|
4715
4744
|
* Get the current domain state and available tools
|
|
4716
4745
|
*/
|
|
4717
4746
|
async getDomain() {
|
|
4718
|
-
|
|
4747
|
+
const summary = await this.client.call("domain.getSummary", {});
|
|
4748
|
+
if (summary.activeDomainRevision) {
|
|
4749
|
+
this.currentDomainRevision = summary.activeDomainRevision;
|
|
4750
|
+
} else {
|
|
4751
|
+
this.currentDomainRevision = this.extractDomainRevisionFromDoc(this.client.doc);
|
|
4752
|
+
}
|
|
4753
|
+
return summary;
|
|
4719
4754
|
}
|
|
4720
4755
|
/**
|
|
4721
4756
|
* Fetch a domain package part from the backend (no fallback).
|
|
@@ -4933,6 +4968,7 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
4933
4968
|
}
|
|
4934
4969
|
setupEventHandlers() {
|
|
4935
4970
|
this.client.on("sync", (doc) => {
|
|
4971
|
+
this.currentDomainRevision = this.extractDomainRevisionFromDoc(doc);
|
|
4936
4972
|
this.emit("sync", doc);
|
|
4937
4973
|
this.checkForToolChanges();
|
|
4938
4974
|
});
|
|
@@ -4988,6 +5024,78 @@ import { ${allImports} } from "./sandbox-tools";
|
|
|
4988
5024
|
}
|
|
4989
5025
|
}
|
|
4990
5026
|
};
|
|
5027
|
+
var MAX_FEEDBACK_STRING_LENGTH = 16e3;
|
|
5028
|
+
var MAX_FEEDBACK_TOOL_CALLS = 50;
|
|
5029
|
+
var MAX_FEEDBACK_ARRAY_ITEMS = 50;
|
|
5030
|
+
var MAX_FEEDBACK_OBJECT_KEYS = 50;
|
|
5031
|
+
var MAX_FEEDBACK_DEPTH = 6;
|
|
5032
|
+
function truncateFeedbackString(value, maxLength = MAX_FEEDBACK_STRING_LENGTH) {
|
|
5033
|
+
if (value.length <= maxLength) {
|
|
5034
|
+
return value;
|
|
5035
|
+
}
|
|
5036
|
+
return `${value.slice(0, maxLength)}...[truncated ${value.length - maxLength} chars]`;
|
|
5037
|
+
}
|
|
5038
|
+
function normalizeJobStatus(status) {
|
|
5039
|
+
if (typeof status !== "string") {
|
|
5040
|
+
return "queued";
|
|
5041
|
+
}
|
|
5042
|
+
switch (status) {
|
|
5043
|
+
case "completed":
|
|
5044
|
+
return "succeeded";
|
|
5045
|
+
case "failed":
|
|
5046
|
+
case "running":
|
|
5047
|
+
case "queued":
|
|
5048
|
+
case "succeeded":
|
|
5049
|
+
case "timeout":
|
|
5050
|
+
case "canceled":
|
|
5051
|
+
return status;
|
|
5052
|
+
default:
|
|
5053
|
+
return "queued";
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5056
|
+
function sanitizeFeedbackValue(value, depth = 0, seen = /* @__PURE__ */ new WeakSet()) {
|
|
5057
|
+
if (depth >= MAX_FEEDBACK_DEPTH) {
|
|
5058
|
+
return "[Max depth reached]";
|
|
5059
|
+
}
|
|
5060
|
+
if (value === null || value === void 0) {
|
|
5061
|
+
return null;
|
|
5062
|
+
}
|
|
5063
|
+
if (typeof value === "string") {
|
|
5064
|
+
return truncateFeedbackString(value);
|
|
5065
|
+
}
|
|
5066
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
5067
|
+
return value;
|
|
5068
|
+
}
|
|
5069
|
+
if (typeof value === "bigint") {
|
|
5070
|
+
return truncateFeedbackString(value.toString());
|
|
5071
|
+
}
|
|
5072
|
+
if (value instanceof Error) {
|
|
5073
|
+
return {
|
|
5074
|
+
name: truncateFeedbackString(value.name),
|
|
5075
|
+
message: truncateFeedbackString(value.message),
|
|
5076
|
+
stack: truncateFeedbackString(value.stack || "")
|
|
5077
|
+
};
|
|
5078
|
+
}
|
|
5079
|
+
if (value instanceof Date) {
|
|
5080
|
+
return value.toISOString();
|
|
5081
|
+
}
|
|
5082
|
+
if (Array.isArray(value)) {
|
|
5083
|
+
return value.slice(0, MAX_FEEDBACK_ARRAY_ITEMS).map((entry) => sanitizeFeedbackValue(entry, depth + 1, seen));
|
|
5084
|
+
}
|
|
5085
|
+
if (typeof value === "object") {
|
|
5086
|
+
if (seen.has(value)) {
|
|
5087
|
+
return "[Circular]";
|
|
5088
|
+
}
|
|
5089
|
+
seen.add(value);
|
|
5090
|
+
const entries = Object.entries(value).slice(0, MAX_FEEDBACK_OBJECT_KEYS);
|
|
5091
|
+
const sanitized = {};
|
|
5092
|
+
for (const [key, entryValue] of entries) {
|
|
5093
|
+
sanitized[key] = sanitizeFeedbackValue(entryValue, depth + 1, seen);
|
|
5094
|
+
}
|
|
5095
|
+
return sanitized;
|
|
5096
|
+
}
|
|
5097
|
+
return truncateFeedbackString(String(value));
|
|
5098
|
+
}
|
|
4991
5099
|
var JobImplementation = class {
|
|
4992
5100
|
id;
|
|
4993
5101
|
client;
|
|
@@ -4996,9 +5104,20 @@ var JobImplementation = class {
|
|
|
4996
5104
|
_resolveResult;
|
|
4997
5105
|
_rejectResult;
|
|
4998
5106
|
eventListeners = /* @__PURE__ */ new Map();
|
|
4999
|
-
|
|
5107
|
+
metadata;
|
|
5108
|
+
constructor(id, client, initialState) {
|
|
5000
5109
|
this.id = id;
|
|
5001
5110
|
this.client = client;
|
|
5111
|
+
this.metadata = {
|
|
5112
|
+
source: "sdk",
|
|
5113
|
+
status: "queued",
|
|
5114
|
+
code: truncateFeedbackString(initialState.code),
|
|
5115
|
+
domainRevision: initialState.domainRevision,
|
|
5116
|
+
createdAt: initialState.createdAt,
|
|
5117
|
+
stdout: [],
|
|
5118
|
+
stderr: [],
|
|
5119
|
+
toolCalls: []
|
|
5120
|
+
};
|
|
5002
5121
|
this._resultPromise = new Promise((resolve, reject) => {
|
|
5003
5122
|
this._resolveResult = resolve;
|
|
5004
5123
|
this._rejectResult = reject;
|
|
@@ -5006,69 +5125,98 @@ var JobImplementation = class {
|
|
|
5006
5125
|
this.client.on("exec.completed", (data) => {
|
|
5007
5126
|
const execData = data;
|
|
5008
5127
|
if (execData.execId === id || execData.jobId === id) {
|
|
5009
|
-
this.status = "succeeded";
|
|
5010
|
-
this.emit("status", this.status);
|
|
5011
5128
|
if (execData.error) {
|
|
5012
|
-
this.
|
|
5129
|
+
this.finalize("failed", void 0, execData.error);
|
|
5013
5130
|
} else {
|
|
5014
|
-
this.
|
|
5131
|
+
this.finalize("succeeded", execData.result);
|
|
5015
5132
|
}
|
|
5133
|
+
this.emit("status", this.status);
|
|
5016
5134
|
}
|
|
5017
5135
|
});
|
|
5018
5136
|
this.client.on("exec.progress", (data) => {
|
|
5019
5137
|
const progressData = data;
|
|
5020
5138
|
if (progressData.execId === id || progressData.jobId === id) {
|
|
5021
5139
|
if (progressData.stdout) {
|
|
5140
|
+
this.markStarted();
|
|
5141
|
+
this.metadata.stdout = [...this.metadata.stdout, truncateFeedbackString(progressData.stdout)].slice(-100);
|
|
5022
5142
|
this.emit("stdout", progressData.stdout);
|
|
5023
5143
|
}
|
|
5024
5144
|
if (progressData.stderr) {
|
|
5145
|
+
this.markStarted();
|
|
5146
|
+
this.metadata.stderr = [...this.metadata.stderr, truncateFeedbackString(progressData.stderr)].slice(-100);
|
|
5025
5147
|
this.emit("stderr", progressData.stderr);
|
|
5026
5148
|
}
|
|
5027
5149
|
}
|
|
5028
5150
|
});
|
|
5029
5151
|
this.client.on(`job.${id}.status`, (status) => {
|
|
5030
|
-
|
|
5031
|
-
this.
|
|
5152
|
+
const normalizedStatus = normalizeJobStatus(status);
|
|
5153
|
+
this.status = normalizedStatus;
|
|
5154
|
+
this.metadata.status = normalizedStatus;
|
|
5155
|
+
if (normalizedStatus === "running") {
|
|
5156
|
+
this.markStarted();
|
|
5157
|
+
}
|
|
5158
|
+
if (normalizedStatus === "failed" || normalizedStatus === "timeout" || normalizedStatus === "canceled") {
|
|
5159
|
+
this.finalize(normalizedStatus);
|
|
5160
|
+
}
|
|
5161
|
+
if (normalizedStatus === "succeeded") {
|
|
5162
|
+
this.finalize("succeeded");
|
|
5163
|
+
}
|
|
5164
|
+
this.emit("status", normalizedStatus);
|
|
5032
5165
|
});
|
|
5033
5166
|
this.client.on(`job.${id}.stdout`, (line) => {
|
|
5167
|
+
this.markStarted();
|
|
5168
|
+
this.metadata.stdout = [...this.metadata.stdout, truncateFeedbackString(String(line))].slice(-100);
|
|
5034
5169
|
this.emit("stdout", line);
|
|
5035
5170
|
});
|
|
5036
5171
|
this.client.on(`job.${id}.stderr`, (line) => {
|
|
5172
|
+
this.markStarted();
|
|
5173
|
+
this.metadata.stderr = [...this.metadata.stderr, truncateFeedbackString(String(line))].slice(-100);
|
|
5037
5174
|
this.emit("stderr", line);
|
|
5038
5175
|
});
|
|
5039
5176
|
this.client.on(`job.${id}.result`, (result) => {
|
|
5040
|
-
this.
|
|
5041
|
-
this._resolveResult(result);
|
|
5177
|
+
this.finalize("succeeded", result);
|
|
5042
5178
|
});
|
|
5043
5179
|
this.client.on(`job.${id}.error`, (error) => {
|
|
5044
|
-
this.
|
|
5045
|
-
this._rejectResult(error);
|
|
5180
|
+
this.finalize("failed", void 0, error);
|
|
5046
5181
|
});
|
|
5047
5182
|
this.client.on("job.completed", (data) => {
|
|
5048
5183
|
const jobData = data;
|
|
5049
5184
|
if (jobData.jobId === id) {
|
|
5050
|
-
this.
|
|
5185
|
+
this.finalize("succeeded", jobData.result);
|
|
5051
5186
|
this.emit("status", this.status);
|
|
5052
|
-
this._resolveResult(jobData.result);
|
|
5053
5187
|
}
|
|
5054
5188
|
});
|
|
5055
5189
|
this.client.on("job.failed", (data) => {
|
|
5056
5190
|
const jobData = data;
|
|
5057
5191
|
if (jobData.jobId === id) {
|
|
5058
|
-
this.
|
|
5192
|
+
this.finalize("failed", void 0, jobData.error || new Error("Job failed"));
|
|
5059
5193
|
this.emit("status", this.status);
|
|
5060
|
-
this._rejectResult(jobData.error || new Error("Job failed"));
|
|
5061
5194
|
}
|
|
5062
5195
|
});
|
|
5063
5196
|
this.client.on("tool.call.start", (data) => {
|
|
5064
5197
|
const d = data;
|
|
5065
5198
|
if (d.jobId === id) {
|
|
5199
|
+
this.metadata.toolCalls = this.upsertToolCall({
|
|
5200
|
+
callId: d.callId,
|
|
5201
|
+
toolName: d.toolName,
|
|
5202
|
+
input: sanitizeFeedbackValue(d.input),
|
|
5203
|
+
startedAt: d.timestamp || Date.now()
|
|
5204
|
+
});
|
|
5066
5205
|
this.emit("toolCallStart", { callId: d.callId, toolName: d.toolName, input: d.input, timestamp: d.timestamp });
|
|
5067
5206
|
}
|
|
5068
5207
|
});
|
|
5069
5208
|
this.client.on("tool.call.end", (data) => {
|
|
5070
5209
|
const d = data;
|
|
5071
5210
|
if (d.jobId === id) {
|
|
5211
|
+
const completedAt = d.timestamp || Date.now();
|
|
5212
|
+
this.metadata.toolCalls = this.upsertToolCall({
|
|
5213
|
+
callId: d.callId,
|
|
5214
|
+
toolName: d.toolName,
|
|
5215
|
+
output: sanitizeFeedbackValue(d.result),
|
|
5216
|
+
error: d.error ? truncateFeedbackString(d.error) : void 0,
|
|
5217
|
+
completedAt,
|
|
5218
|
+
durationMs: typeof d.durationMs === "number" ? d.durationMs : void 0
|
|
5219
|
+
});
|
|
5072
5220
|
this.emit("toolCallEnd", { callId: d.callId, toolName: d.toolName, result: d.result, error: d.error, durationMs: d.durationMs, timestamp: d.timestamp });
|
|
5073
5221
|
}
|
|
5074
5222
|
});
|
|
@@ -5076,12 +5224,87 @@ var JobImplementation = class {
|
|
|
5076
5224
|
get result() {
|
|
5077
5225
|
return this._resultPromise;
|
|
5078
5226
|
}
|
|
5227
|
+
async leaveFeedback(input) {
|
|
5228
|
+
const sentiment = input.sentiment;
|
|
5229
|
+
if (sentiment !== "good" && sentiment !== "bad") {
|
|
5230
|
+
throw new Error('Job feedback sentiment must be "good" or "bad".');
|
|
5231
|
+
}
|
|
5232
|
+
const comment = typeof input.comment === "string" ? input.comment.trim() : "";
|
|
5233
|
+
const response = await this.client.call("job.feedback", {
|
|
5234
|
+
jobId: this.id,
|
|
5235
|
+
sentiment,
|
|
5236
|
+
comment: comment || void 0,
|
|
5237
|
+
metadata: this.buildFeedbackMetadata()
|
|
5238
|
+
});
|
|
5239
|
+
this.emit("feedback", response);
|
|
5240
|
+
return response;
|
|
5241
|
+
}
|
|
5079
5242
|
on(event, handler) {
|
|
5080
5243
|
if (!this.eventListeners.has(event)) {
|
|
5081
5244
|
this.eventListeners.set(event, []);
|
|
5082
5245
|
}
|
|
5083
5246
|
this.eventListeners.get(event).push(handler);
|
|
5084
5247
|
}
|
|
5248
|
+
buildFeedbackMetadata() {
|
|
5249
|
+
const startedAt = this.metadata.startedAt;
|
|
5250
|
+
const completedAt = this.metadata.completedAt;
|
|
5251
|
+
return {
|
|
5252
|
+
...this.metadata,
|
|
5253
|
+
durationMs: typeof startedAt === "number" && typeof completedAt === "number" ? completedAt - startedAt : this.metadata.durationMs ?? null,
|
|
5254
|
+
stdout: [...this.metadata.stdout],
|
|
5255
|
+
stderr: [...this.metadata.stderr],
|
|
5256
|
+
toolCalls: this.metadata.toolCalls.slice(0, MAX_FEEDBACK_TOOL_CALLS).map((call) => ({ ...call }))
|
|
5257
|
+
};
|
|
5258
|
+
}
|
|
5259
|
+
markStarted(timestamp = Date.now()) {
|
|
5260
|
+
if (!this.metadata.startedAt) {
|
|
5261
|
+
this.metadata.startedAt = timestamp;
|
|
5262
|
+
}
|
|
5263
|
+
if (this.status === "queued") {
|
|
5264
|
+
this.status = "running";
|
|
5265
|
+
}
|
|
5266
|
+
if (this.metadata.status === "queued") {
|
|
5267
|
+
this.metadata.status = "running";
|
|
5268
|
+
}
|
|
5269
|
+
}
|
|
5270
|
+
finalize(status, result, error) {
|
|
5271
|
+
if (!this.metadata.startedAt) {
|
|
5272
|
+
this.metadata.startedAt = Date.now();
|
|
5273
|
+
}
|
|
5274
|
+
this.status = status;
|
|
5275
|
+
this.metadata.status = status;
|
|
5276
|
+
this.metadata.completedAt = this.metadata.completedAt || Date.now();
|
|
5277
|
+
this.metadata.durationMs = this.metadata.completedAt - this.metadata.startedAt;
|
|
5278
|
+
if (result !== void 0) {
|
|
5279
|
+
this.metadata.result = sanitizeFeedbackValue(result);
|
|
5280
|
+
this._resolveResult(result);
|
|
5281
|
+
}
|
|
5282
|
+
if (error !== void 0) {
|
|
5283
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5284
|
+
this.metadata.error = truncateFeedbackString(message);
|
|
5285
|
+
this._rejectResult(error);
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
upsertToolCall(next) {
|
|
5289
|
+
const callId = next.callId || `tool-call-${Date.now()}`;
|
|
5290
|
+
const existingIndex = this.metadata.toolCalls.findIndex((entry) => entry.callId === callId);
|
|
5291
|
+
const existing = existingIndex >= 0 ? this.metadata.toolCalls[existingIndex] : void 0;
|
|
5292
|
+
const merged = {
|
|
5293
|
+
...existing,
|
|
5294
|
+
...next,
|
|
5295
|
+
callId,
|
|
5296
|
+
toolName: next.toolName || existing?.toolName
|
|
5297
|
+
};
|
|
5298
|
+
if (merged.durationMs === void 0 && typeof merged.startedAt === "number" && typeof merged.completedAt === "number") {
|
|
5299
|
+
merged.durationMs = merged.completedAt - merged.startedAt;
|
|
5300
|
+
}
|
|
5301
|
+
if (existingIndex >= 0) {
|
|
5302
|
+
const updated = [...this.metadata.toolCalls];
|
|
5303
|
+
updated[existingIndex] = merged;
|
|
5304
|
+
return updated.slice(-MAX_FEEDBACK_TOOL_CALLS);
|
|
5305
|
+
}
|
|
5306
|
+
return [...this.metadata.toolCalls, merged].slice(-MAX_FEEDBACK_TOOL_CALLS);
|
|
5307
|
+
}
|
|
5085
5308
|
emit(event, data) {
|
|
5086
5309
|
const handlers = this.eventListeners.get(event);
|
|
5087
5310
|
if (handlers) {
|
|
@@ -5222,7 +5445,7 @@ function normalizeUser(user) {
|
|
|
5222
5445
|
permissions: Array.isArray(user.permissions) ? user.permissions : []
|
|
5223
5446
|
};
|
|
5224
5447
|
}
|
|
5225
|
-
var Environment = class
|
|
5448
|
+
var Environment = class extends Session {
|
|
5226
5449
|
envData;
|
|
5227
5450
|
_apiKey;
|
|
5228
5451
|
_apiEndpoint;
|
|
@@ -5282,6 +5505,22 @@ var Environment = class _Environment extends Session {
|
|
|
5282
5505
|
return this._apiEndpoint.replace(/\/orchestrator\/graphql$/, "").replace(/\/$/, "");
|
|
5283
5506
|
}
|
|
5284
5507
|
}
|
|
5508
|
+
async controlPlaneRequest(path, options = {}) {
|
|
5509
|
+
const runtimeBase = this.getRuntimeBaseUrl();
|
|
5510
|
+
const url = `${runtimeBase}${path}`;
|
|
5511
|
+
const response = await fetch(url, {
|
|
5512
|
+
...options,
|
|
5513
|
+
headers: {
|
|
5514
|
+
"Authorization": `Bearer ${this._apiKey}`,
|
|
5515
|
+
"Content-Type": "application/json",
|
|
5516
|
+
...options.headers
|
|
5517
|
+
}
|
|
5518
|
+
});
|
|
5519
|
+
if (!response.ok) {
|
|
5520
|
+
throw new Error(`Control Plane API Error (${response.status}): ${await response.text()}`);
|
|
5521
|
+
}
|
|
5522
|
+
return response.json();
|
|
5523
|
+
}
|
|
5285
5524
|
/**
|
|
5286
5525
|
* Close the session and disconnect from the sandbox.
|
|
5287
5526
|
*
|
|
@@ -5878,105 +6117,84 @@ var Environment = class _Environment extends Session {
|
|
|
5878
6117
|
* ```
|
|
5879
6118
|
*/
|
|
5880
6119
|
async recordObject(options) {
|
|
5881
|
-
const
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
6120
|
+
const results = await this.recordObjects([options]);
|
|
6121
|
+
return results[0];
|
|
6122
|
+
}
|
|
6123
|
+
/**
|
|
6124
|
+
* Batch version of `recordObject()`.
|
|
6125
|
+
*
|
|
6126
|
+
* Sends several upserts through the control-plane batch endpoint so the
|
|
6127
|
+
* server can collapse the graph mutations into far fewer round trips.
|
|
6128
|
+
*/
|
|
6129
|
+
async recordObjects(records) {
|
|
6130
|
+
if (!Array.isArray(records) || records.length === 0) {
|
|
6131
|
+
return [];
|
|
6132
|
+
}
|
|
6133
|
+
const response = await this.controlPlaneRequest(
|
|
6134
|
+
`/control/environments/${this.environmentId}/records/batch`,
|
|
6135
|
+
{
|
|
6136
|
+
method: "POST",
|
|
6137
|
+
body: JSON.stringify({ records })
|
|
6138
|
+
}
|
|
5885
6139
|
);
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
6140
|
+
return Array.isArray(response.items) ? response.items : [];
|
|
6141
|
+
}
|
|
6142
|
+
/**
|
|
6143
|
+
* Queue a background record import for this environment.
|
|
6144
|
+
*/
|
|
6145
|
+
async enqueueRecordImport(records, options = {}) {
|
|
6146
|
+
return this.controlPlaneRequest(
|
|
6147
|
+
`/control/environments/${this.environmentId}/record-imports`,
|
|
6148
|
+
{
|
|
6149
|
+
method: "POST",
|
|
6150
|
+
body: JSON.stringify({
|
|
6151
|
+
records,
|
|
6152
|
+
batchSize: options.batchSize
|
|
6153
|
+
})
|
|
6154
|
+
}
|
|
5895
6155
|
);
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
model { path }
|
|
5905
|
-
}
|
|
5906
|
-
}
|
|
5907
|
-
}`
|
|
6156
|
+
}
|
|
6157
|
+
/**
|
|
6158
|
+
* List queued or completed record imports for this environment.
|
|
6159
|
+
*/
|
|
6160
|
+
async listRecordImports(status) {
|
|
6161
|
+
const suffix = status ? `?status=${encodeURIComponent(status)}` : "";
|
|
6162
|
+
const response = await this.controlPlaneRequest(
|
|
6163
|
+
`/control/environments/${this.environmentId}/record-imports${suffix}`
|
|
5908
6164
|
);
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
6165
|
+
return Array.isArray(response.items) ? response.items : [];
|
|
6166
|
+
}
|
|
6167
|
+
/**
|
|
6168
|
+
* Fetch the latest aggregate import counters for this environment.
|
|
6169
|
+
*/
|
|
6170
|
+
async getRecordImportSummary() {
|
|
6171
|
+
return this.controlPlaneRequest(
|
|
6172
|
+
`/control/environments/${this.environmentId}/record-imports/summary`
|
|
5917
6173
|
);
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
} else if (typeof value === "number") {
|
|
5941
|
-
await this.graphql(
|
|
5942
|
-
`mutation {
|
|
5943
|
-
at(path: "${instancePath}") {
|
|
5944
|
-
at(submodel: "${fieldName}") {
|
|
5945
|
-
set_number_value(value: ${value}) { done }
|
|
5946
|
-
}
|
|
5947
|
-
}
|
|
5948
|
-
}`
|
|
5949
|
-
);
|
|
5950
|
-
} else if (typeof value === "boolean") {
|
|
5951
|
-
await this.graphql(
|
|
5952
|
-
`mutation {
|
|
5953
|
-
at(path: "${instancePath}") {
|
|
5954
|
-
at(submodel: "${fieldName}") {
|
|
5955
|
-
set_boolean_value(value: ${value}) { done }
|
|
5956
|
-
}
|
|
5957
|
-
}
|
|
5958
|
-
}`
|
|
5959
|
-
);
|
|
5960
|
-
}
|
|
5961
|
-
}
|
|
5962
|
-
}
|
|
5963
|
-
if (relationships) {
|
|
5964
|
-
const rels = await this.getRelationships(className);
|
|
5965
|
-
const relMap = {};
|
|
5966
|
-
for (const rel of rels) {
|
|
5967
|
-
const submodelLeaf = rel.local_submodel.path.includes(":") ? rel.local_submodel.path.split(":").pop() : rel.local_submodel.path;
|
|
5968
|
-
relMap[submodelLeaf] = rel.foreign_model.path;
|
|
5969
|
-
}
|
|
5970
|
-
for (const [submodelName, targets] of Object.entries(relationships)) {
|
|
5971
|
-
const foreignClass = relMap[submodelName];
|
|
5972
|
-
const targetList = Array.isArray(targets) ? targets : [targets];
|
|
5973
|
-
for (const target of targetList) {
|
|
5974
|
-
const targetGraphPath = foreignClass ? _Environment.toGraphPath(foreignClass, target) : target;
|
|
5975
|
-
await this.attach(instancePath, submodelName, targetGraphPath);
|
|
5976
|
-
}
|
|
6174
|
+
}
|
|
6175
|
+
/**
|
|
6176
|
+
* Convenience helper returning queued + processing records for this environment.
|
|
6177
|
+
*/
|
|
6178
|
+
async getAwaitingRecordCount() {
|
|
6179
|
+
const summary = await this.getRecordImportSummary();
|
|
6180
|
+
return summary.awaitingRecords;
|
|
6181
|
+
}
|
|
6182
|
+
/**
|
|
6183
|
+
* Fetch a single record import by id.
|
|
6184
|
+
*/
|
|
6185
|
+
async getRecordImport(importId) {
|
|
6186
|
+
return this.controlPlaneRequest(`/control/record-imports/${importId}`);
|
|
6187
|
+
}
|
|
6188
|
+
/**
|
|
6189
|
+
* Cancel a queued/background record import.
|
|
6190
|
+
*/
|
|
6191
|
+
async cancelRecordImport(importId) {
|
|
6192
|
+
return this.controlPlaneRequest(
|
|
6193
|
+
`/control/record-imports/${importId}/cancel`,
|
|
6194
|
+
{
|
|
6195
|
+
method: "POST"
|
|
5977
6196
|
}
|
|
5978
|
-
|
|
5979
|
-
return { path: instancePath, id, created: !alreadyExists };
|
|
6197
|
+
);
|
|
5980
6198
|
}
|
|
5981
6199
|
// ==================== PUBLISH TOOLS ====================
|
|
5982
6200
|
/**
|