@neta-art/cohub 7.0.0 → 8.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.
@@ -1296,39 +1296,43 @@ z.object({
1296
1296
  }).optional()
1297
1297
  }).strict();
1298
1298
  //#endregion
1299
- //#region ../protocol/dist/ui-command.js
1299
+ //#region ../protocol/dist/desktop-command.js
1300
1300
  /**
1301
- * Lets an agent drive the Cohub frontend that originated the work. Routing comes
1301
+ * Lets an agent drive the Cohub desktop that originated the app. Routing comes
1302
1302
  * from request provenance, never a caller-supplied target, so a command only
1303
1303
  * reaches the actor's own instances.
1304
+ *
1305
+ * The canonical command is `desktop.open`. The legacy `preview.show` shape is
1306
+ * accepted on input and normalized, so older clients keep working, but commands
1307
+ * are always stored and dispatched in the canonical form.
1304
1308
  */
1305
- const UI_COMMAND_VERSION = 1;
1309
+ const DESKTOP_COMMAND_VERSION = 1;
1306
1310
  /** Persisted and broadcast, so every field is capped; MAX_BYTES bounds the whole. */
1307
- const UI_COMMAND_PAYLOAD_MAX_BYTES = 32 * 1024;
1308
- const UI_COMMAND_MAX_BYTES = 40 * 1024;
1309
- const UI_COMMAND_LAUNCH_MAX_LENGTH = 2048;
1310
- const UI_COMMAND_DEFAULT_TIMEOUT_MS = 600 * 1e3;
1311
- const UI_COMMAND_MAX_TIMEOUT_MS = 720 * 60 * 1e3;
1312
- const UI_COMMAND_SETTLEMENT_GRACE_SECONDS = 600;
1311
+ const DESKTOP_COMMAND_PAYLOAD_MAX_BYTES = 32 * 1024;
1312
+ const DESKTOP_COMMAND_MAX_BYTES = 40 * 1024;
1313
+ const DESKTOP_COMMAND_LAUNCH_MAX_LENGTH = 2048;
1314
+ const DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS = 600 * 1e3;
1315
+ const DESKTOP_COMMAND_MAX_TIMEOUT_MS = 720 * 60 * 1e3;
1316
+ const DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS = 600;
1313
1317
  /** Keeps pending commands reportable for the full wait window plus settlement grace. */
1314
- const UI_COMMAND_PENDING_TTL_SECONDS = 43800;
1315
- const UI_COMMAND_TERMINAL_TTL_SECONDS = 1800;
1316
- const UI_COMMAND_TERMINAL_STATUSES = [
1318
+ const DESKTOP_COMMAND_PENDING_TTL_SECONDS = 43800;
1319
+ const DESKTOP_COMMAND_TERMINAL_TTL_SECONDS = 1800;
1320
+ const DESKTOP_COMMAND_TERMINAL_STATUSES = [
1317
1321
  "applied",
1318
1322
  "no_active_client",
1319
- "ui_host_unavailable",
1323
+ "desktop_host_unavailable",
1320
1324
  "rejected",
1321
1325
  "unsupported",
1322
1326
  "timeout"
1323
1327
  ];
1324
- const isTerminalUiCommandStatus = (status) => UI_COMMAND_TERMINAL_STATUSES.includes(status);
1328
+ const isTerminalDesktopCommandStatus = (status) => DESKTOP_COMMAND_TERMINAL_STATUSES.includes(status);
1325
1329
  const METHOD_RE = /^[A-Za-z][A-Za-z0-9_.:-]{0,63}$/;
1326
- const isUiSurfaceMethod = (value) => typeof value === "string" && METHOD_RE.test(value);
1327
- const UI_COMMAND_ID_RE = /^[A-Za-z0-9_-]{1,64}$/;
1328
- const parseUiCommandId = (value) => {
1330
+ const isDesktopCallMethod = (value) => typeof value === "string" && METHOD_RE.test(value);
1331
+ const DESKTOP_COMMAND_ID_RE = /^[A-Za-z0-9_-]{1,64}$/;
1332
+ const parseDesktopCommandId = (value) => {
1329
1333
  if (typeof value !== "string") return null;
1330
1334
  const trimmed = value.trim();
1331
- return UI_COMMAND_ID_RE.test(trimmed) ? trimmed : null;
1335
+ return DESKTOP_COMMAND_ID_RE.test(trimmed) ? trimmed : null;
1332
1336
  };
1333
1337
  const isRecord$1 = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
1334
1338
  const asTrimmed = (value) => {
@@ -1346,7 +1350,7 @@ const parseLaunch = (value) => {
1346
1350
  ...hash ? { hash: hash.startsWith("#") ? hash : `#${hash}` } : {}
1347
1351
  };
1348
1352
  };
1349
- const measureUiCommandPayload = (value) => {
1353
+ const measureDesktopCommandPayload = (value) => {
1350
1354
  if (value === void 0) return 0;
1351
1355
  try {
1352
1356
  return new TextEncoder().encode(JSON.stringify(value) ?? "").length;
@@ -1354,118 +1358,131 @@ const measureUiCommandPayload = (value) => {
1354
1358
  return null;
1355
1359
  }
1356
1360
  };
1357
- const parseUiCommand = (input) => {
1361
+ /**
1362
+ * Parse a desktop command from untrusted input.
1363
+ *
1364
+ * Accepts both the canonical `desktop.open` shape (`target` / `call`) and the
1365
+ * legacy `preview.show` shape (`preview` / `request`); the result is always
1366
+ * canonical so every later stage handles a single form.
1367
+ */
1368
+ const parseDesktopCommand = (input) => {
1358
1369
  if (!isRecord$1(input)) return {
1359
1370
  command: null,
1360
1371
  error: "command must be an object"
1361
1372
  };
1362
- if (input.type !== "preview.show") return {
1373
+ const legacy = input.type === "preview.show";
1374
+ if (input.type !== "desktop.open" && !legacy) return {
1363
1375
  command: null,
1364
- error: "command.type must be one of: preview.show"
1376
+ error: "command.type must be one of: desktop.open"
1365
1377
  };
1366
- const preview = input.preview;
1367
- if (!isRecord$1(preview)) return {
1378
+ const target = isRecord$1(input.target) ? input.target : isRecord$1(input.preview) ? input.preview : null;
1379
+ if (!target) return {
1368
1380
  command: null,
1369
- error: "command.preview is required"
1381
+ error: "command.target is required"
1370
1382
  };
1371
- if (preview.kind !== "work" && preview.kind !== "file") return {
1383
+ const kind = target.kind === "app" || legacy && target.kind === "work" ? "app" : target.kind === "file" ? "file" : null;
1384
+ if (!kind) return {
1372
1385
  command: null,
1373
- error: "command.preview.kind must be one of: work, file"
1386
+ error: "command.target.kind must be one of: app, file"
1374
1387
  };
1375
- if (preview.kind === "file") {
1376
- const path = asTrimmed(preview.path);
1388
+ if (kind === "file") {
1389
+ const path = asTrimmed(target.path);
1377
1390
  if (!path) return {
1378
1391
  command: null,
1379
- error: "command.preview.path is required"
1392
+ error: "command.target.path is required"
1380
1393
  };
1381
1394
  if (path.length > 2048 || path.startsWith("/") || path.includes("\0") || path.includes("\\") || path.split("/").some((segment) => segment === "..")) return {
1382
1395
  command: null,
1383
- error: "command.preview.path must be a relative Space file path"
1396
+ error: "command.target.path must be a relative Space file path"
1384
1397
  };
1385
- const command = {
1386
- type: "preview.show",
1387
- preview: {
1388
- kind: "file",
1389
- path
1390
- }
1398
+ if (input.call !== void 0 && input.call !== null) return {
1399
+ command: null,
1400
+ error: "command.call is only supported for app targets"
1391
1401
  };
1392
- if (input.request !== void 0 && input.request !== null) return {
1402
+ if (legacy && input.request !== void 0 && input.request !== null) return {
1393
1403
  command: null,
1394
- error: "command.request is only supported for Work previews"
1404
+ error: "command.call is only supported for app targets"
1395
1405
  };
1396
1406
  return {
1397
- command,
1407
+ command: {
1408
+ type: "desktop.open",
1409
+ target: {
1410
+ kind: "file",
1411
+ path
1412
+ }
1413
+ },
1398
1414
  error: null
1399
1415
  };
1400
1416
  }
1401
- const workId = asTrimmed(preview.workId);
1402
- if (!workId) return {
1417
+ const appId = asTrimmed(target.appId ?? target.workId);
1418
+ if (!appId) return {
1403
1419
  command: null,
1404
- error: "command.preview.workId is required"
1420
+ error: "command.target.appId is required"
1405
1421
  };
1406
- if (!isUuid(workId)) return {
1422
+ if (!isUuid(appId)) return {
1407
1423
  command: null,
1408
- error: "command.preview.workId must be a Work id"
1424
+ error: "command.target.appId must be an App id"
1409
1425
  };
1410
- const label = asTrimmed(preview.label);
1426
+ const label = asTrimmed(target.label);
1411
1427
  if (label && label.length > 200) return {
1412
1428
  command: null,
1413
- error: `command.preview.label exceeds 200 characters`
1429
+ error: `command.target.label exceeds 200 characters`
1414
1430
  };
1415
- const launch = parseLaunch(preview.launch);
1431
+ const launch = parseLaunch(target.launch);
1416
1432
  if (launch) {
1417
1433
  for (const [field, value] of [["search", launch.search], ["hash", launch.hash]]) if (value && value.length > 2048) return {
1418
1434
  command: null,
1419
- error: `command.preview.launch.${field} exceeds ${UI_COMMAND_LAUNCH_MAX_LENGTH} characters`
1435
+ error: `command.target.launch.${field} exceeds ${DESKTOP_COMMAND_LAUNCH_MAX_LENGTH} characters`
1420
1436
  };
1421
1437
  }
1422
- let request;
1423
- if (input.request !== void 0 && input.request !== null) {
1424
- if (!isRecord$1(input.request)) return {
1438
+ const callSource = input.call !== void 0 ? input.call : input.request;
1439
+ let call;
1440
+ if (callSource !== void 0 && callSource !== null) {
1441
+ if (!isRecord$1(callSource)) return {
1425
1442
  command: null,
1426
- error: "command.request must be an object"
1443
+ error: "command.call must be an object"
1427
1444
  };
1428
- const method = asTrimmed(input.request.method);
1445
+ const method = asTrimmed(callSource.method);
1429
1446
  if (!method) return {
1430
1447
  command: null,
1431
- error: "command.request.method is required"
1448
+ error: "command.call.method is required"
1432
1449
  };
1433
- if (!isUiSurfaceMethod(method)) return {
1450
+ if (!isDesktopCallMethod(method)) return {
1434
1451
  command: null,
1435
- error: "command.request.method has an unsupported format"
1452
+ error: "command.call.method has an unsupported format"
1436
1453
  };
1437
- const size = measureUiCommandPayload(input.request.input);
1454
+ const size = measureDesktopCommandPayload(callSource.input);
1438
1455
  if (size === null) return {
1439
1456
  command: null,
1440
- error: "command.request.input must be JSON-serializable"
1457
+ error: "command.call.input must be JSON-serializable"
1441
1458
  };
1442
1459
  if (size > 32768) return {
1443
1460
  command: null,
1444
- error: `command.request.input exceeds ${UI_COMMAND_PAYLOAD_MAX_BYTES} bytes`
1461
+ error: `command.call.input exceeds ${DESKTOP_COMMAND_PAYLOAD_MAX_BYTES} bytes`
1445
1462
  };
1446
- request = {
1463
+ call = {
1447
1464
  method,
1448
- ...input.request.input === void 0 ? {} : { input: input.request.input }
1465
+ ...callSource.input === void 0 ? {} : { input: callSource.input }
1449
1466
  };
1450
1467
  }
1451
1468
  const command = {
1452
- type: "preview.show",
1453
- preview: {
1454
- kind: "work",
1455
- workId,
1469
+ type: "desktop.open",
1470
+ target: {
1471
+ kind: "app",
1472
+ appId,
1456
1473
  ...label ? { label } : {},
1457
1474
  ...launch ? { launch } : {}
1458
1475
  },
1459
- ...request ? { request } : {}
1476
+ ...call ? { call } : {}
1460
1477
  };
1461
- const totalSize = measureUiCommandPayload(command);
1478
+ const totalSize = measureDesktopCommandPayload(command);
1462
1479
  if (totalSize === null) return {
1463
1480
  command: null,
1464
1481
  error: "command must be JSON-serializable"
1465
1482
  };
1466
1483
  if (totalSize > 40960) return {
1467
1484
  command: null,
1468
- error: `command exceeds ${UI_COMMAND_MAX_BYTES} bytes`
1485
+ error: `command exceeds ${DESKTOP_COMMAND_MAX_BYTES} bytes`
1469
1486
  };
1470
1487
  return {
1471
1488
  command,
@@ -3113,7 +3130,7 @@ var SpaceEventsApi = class {
3113
3130
  handler(event);
3114
3131
  return;
3115
3132
  }
3116
- if (type === "work.version.published" && event.type === "work.version.published") {
3133
+ if (type === "app.version.published" && event.type === "app.version.published") {
3117
3134
  handler(event);
3118
3135
  return;
3119
3136
  }
@@ -4000,79 +4017,6 @@ var TasksApi = class {
4000
4017
  }
4001
4018
  };
4002
4019
  //#endregion
4003
- //#region src/apis/ui-commands.ts
4004
- const DEFAULT_POLL_INTERVAL_MS = 300;
4005
- const resolveTimeoutMs = (timeoutMs) => {
4006
- const value = timeoutMs ?? 6e5;
4007
- if (!Number.isFinite(value) || value <= 0 || value > 432e5) throw new RangeError(`timeoutMs must be between 1 and ${UI_COMMAND_MAX_TIMEOUT_MS} milliseconds`);
4008
- return value;
4009
- };
4010
- const sleep = (ms, signal) => new Promise((resolve, reject) => {
4011
- if (signal?.aborted) {
4012
- reject(/* @__PURE__ */ new Error("aborted"));
4013
- return;
4014
- }
4015
- const timer = setTimeout(() => {
4016
- signal?.removeEventListener("abort", onAbort);
4017
- resolve();
4018
- }, ms);
4019
- const onAbort = () => {
4020
- clearTimeout(timer);
4021
- reject(/* @__PURE__ */ new Error("aborted"));
4022
- };
4023
- signal?.addEventListener("abort", onAbort, { once: true });
4024
- });
4025
- var UiCommandsApi = class {
4026
- transport;
4027
- constructor(transport) {
4028
- this.transport = transport;
4029
- }
4030
- create(input) {
4031
- return this.transport.request("/api/ui/commands", {
4032
- method: "POST",
4033
- headers: { "Content-Type": "application/json" },
4034
- body: JSON.stringify(input)
4035
- });
4036
- }
4037
- get(commandId) {
4038
- return this.transport.request(`/api/ui/commands/${encodeURIComponent(commandId)}`);
4039
- }
4040
- reportResult(commandId, input) {
4041
- return this.transport.request(`/api/ui/commands/${encodeURIComponent(commandId)}/result`, {
4042
- method: "POST",
4043
- headers: { "Content-Type": "application/json" },
4044
- body: JSON.stringify(input)
4045
- });
4046
- }
4047
- async run(input, options = {}) {
4048
- const { command } = await this.create(input);
4049
- if (isTerminalUiCommandStatus(command.status)) return command;
4050
- return this.wait(command.commandId, options);
4051
- }
4052
- async wait(commandId, options = {}) {
4053
- const timeoutMs = resolveTimeoutMs(options.timeoutMs);
4054
- const pollIntervalMs = Math.max(50, options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
4055
- const deadline = Date.now() + timeoutMs;
4056
- let latest = (await this.get(commandId)).command;
4057
- while (!isTerminalUiCommandStatus(latest.status)) {
4058
- const remaining = deadline - Date.now();
4059
- if (remaining <= 0) break;
4060
- await sleep(Math.min(pollIntervalMs, remaining), options.signal);
4061
- latest = (await this.get(commandId)).command;
4062
- }
4063
- if (isTerminalUiCommandStatus(latest.status)) return latest;
4064
- return {
4065
- ...latest,
4066
- status: "timeout",
4067
- error: {
4068
- code: "timeout",
4069
- message: "No Cohub frontend reported a result before the timeout."
4070
- },
4071
- settledAt: (/* @__PURE__ */ new Date()).toISOString()
4072
- };
4073
- }
4074
- };
4075
- //#endregion
4076
4020
  //#region src/apis/user.ts
4077
4021
  const usageDate = (value) => value instanceof Date ? value.toISOString() : value;
4078
4022
  var UserApi = class {
@@ -4200,131 +4144,208 @@ var ReferralsApi = class {
4200
4144
  }
4201
4145
  };
4202
4146
  //#endregion
4203
- //#region src/apis/works.ts
4204
- var WorksApi = class {
4147
+ //#region src/apis/apps.ts
4148
+ var AppsApi = class {
4205
4149
  transport;
4206
4150
  constructor(transport) {
4207
4151
  this.transport = transport;
4208
4152
  }
4209
4153
  listBySpace(spaceId) {
4210
- return this.transport.request(`/api/works/space/${spaceId}`);
4154
+ return this.transport.request(`/api/apps/space/${spaceId}`);
4211
4155
  }
4212
4156
  get(id) {
4213
- return this.transport.request(`/api/works/${id}`);
4157
+ return this.transport.request(`/api/apps/${id}`);
4214
4158
  }
4215
4159
  /**
4216
- * Loads a published work's metadata + owner info by id (public access model).
4217
- * Used by the standalone work auth broker page.
4160
+ * Loads a published app's metadata + owner info by id (public access model).
4161
+ * Used by the standalone app auth broker page.
4218
4162
  */
4219
4163
  getPublicById(id) {
4220
- return this.transport.request(`/api/works/${id}/public`);
4164
+ return this.transport.request(`/api/apps/${id}/public`);
4221
4165
  }
4222
- getBySlug(username, spaceSlug, workSlug, options) {
4223
- return this.transport.request(`/api/works/by-slug/${encodeURIComponent(username)}/${encodeURIComponent(spaceSlug)}/${encodeURIComponent(workSlug)}`, options?.signal ? { signal: options.signal } : void 0);
4166
+ getBySlug(username, spaceSlug, appSlug, options) {
4167
+ return this.transport.request(`/api/apps/by-slug/${encodeURIComponent(username)}/${encodeURIComponent(spaceSlug)}/${encodeURIComponent(appSlug)}`, options?.signal ? { signal: options.signal } : void 0);
4224
4168
  }
4225
4169
  create(input) {
4226
- return this.transport.request("/api/works", {
4170
+ return this.transport.request("/api/apps", {
4227
4171
  method: "POST",
4228
4172
  headers: { "Content-Type": "application/json" },
4229
4173
  body: JSON.stringify(input)
4230
4174
  });
4231
4175
  }
4232
4176
  update(id, input) {
4233
- return this.transport.request(`/api/works/${id}`, {
4177
+ return this.transport.request(`/api/apps/${id}`, {
4234
4178
  method: "PATCH",
4235
4179
  headers: { "Content-Type": "application/json" },
4236
4180
  body: JSON.stringify(input)
4237
4181
  });
4238
4182
  }
4239
4183
  delete(id) {
4240
- return this.transport.request(`/api/works/${id}`, { method: "DELETE" });
4184
+ return this.transport.request(`/api/apps/${id}`, { method: "DELETE" });
4241
4185
  }
4242
- getStats(workId) {
4243
- return this.transport.request(`/api/works/${workId}/stats`);
4186
+ getStats(appId) {
4187
+ return this.transport.request(`/api/apps/${appId}/stats`);
4244
4188
  }
4245
- listPromotions(workId) {
4246
- return this.transport.request(`/api/works/${workId}/promotions`);
4189
+ listPromotions(appId) {
4190
+ return this.transport.request(`/api/apps/${appId}/promotions`);
4247
4191
  }
4248
- createPromotion(workId, input) {
4249
- return this.transport.request(`/api/works/${workId}/promotions`, {
4192
+ createPromotion(appId, input) {
4193
+ return this.transport.request(`/api/apps/${appId}/promotions`, {
4250
4194
  method: "POST",
4251
4195
  headers: { "Content-Type": "application/json" },
4252
4196
  body: JSON.stringify(input)
4253
4197
  });
4254
4198
  }
4255
- getPromotionStats(workId, promotionId) {
4256
- return this.transport.request(`/api/works/${workId}/promotions/${promotionId}/stats`);
4199
+ getPromotionStats(appId, promotionId) {
4200
+ return this.transport.request(`/api/apps/${appId}/promotions/${promotionId}/stats`);
4257
4201
  }
4258
- recordPromotionEvent(workId, promotionId, input) {
4259
- return this.transport.request(`/api/works/${workId}/promotions/${promotionId}/events`, {
4202
+ recordPromotionEvent(appId, promotionId, input) {
4203
+ return this.transport.request(`/api/apps/${appId}/promotions/${promotionId}/events`, {
4260
4204
  method: "POST",
4261
4205
  headers: { "Content-Type": "application/json" },
4262
4206
  body: JSON.stringify(input)
4263
4207
  });
4264
4208
  }
4265
- recordPromotionRegistration(workId, promotionId, input) {
4266
- return this.transport.request(`/api/works/${workId}/promotions/${promotionId}/registration`, {
4209
+ recordPromotionRegistration(appId, promotionId, input) {
4210
+ return this.transport.request(`/api/apps/${appId}/promotions/${promotionId}/registration`, {
4267
4211
  method: "POST",
4268
4212
  headers: input ? { "Content-Type": "application/json" } : void 0,
4269
4213
  body: input ? JSON.stringify(input) : void 0
4270
4214
  });
4271
4215
  }
4272
- listVersions(workId) {
4273
- return this.transport.request(`/api/works/${workId}/versions`);
4216
+ listVersions(appId) {
4217
+ return this.transport.request(`/api/apps/${appId}/versions`);
4274
4218
  }
4275
- publishVersion(workId, input) {
4276
- return this.transport.request(`/api/works/${workId}/versions`, {
4219
+ publishVersion(appId, input) {
4220
+ return this.transport.request(`/api/apps/${appId}/versions`, {
4277
4221
  method: "POST",
4278
4222
  headers: input ? { "Content-Type": "application/json" } : void 0,
4279
4223
  body: input ? JSON.stringify(input) : void 0
4280
4224
  });
4281
4225
  }
4282
- createSession(workId) {
4283
- return this.transport.request(`/api/works/${workId}/session`, { method: "POST" });
4226
+ createSession(appId) {
4227
+ return this.transport.request(`/api/apps/${appId}/session`, { method: "POST" });
4228
+ }
4229
+ authorize(appId, input) {
4230
+ return this.transport.request(`/api/apps/${appId}/authorize`, {
4231
+ method: "POST",
4232
+ headers: { "Content-Type": "application/json" },
4233
+ body: JSON.stringify(input)
4234
+ });
4235
+ }
4236
+ };
4237
+ //#endregion
4238
+ //#region src/apis/desktop-commands.ts
4239
+ const DEFAULT_POLL_INTERVAL_MS = 300;
4240
+ const resolveTimeoutMs = (timeoutMs) => {
4241
+ const value = timeoutMs ?? 6e5;
4242
+ if (!Number.isFinite(value) || value <= 0 || value > 432e5) throw new RangeError(`timeoutMs must be between 1 and ${DESKTOP_COMMAND_MAX_TIMEOUT_MS} milliseconds`);
4243
+ return value;
4244
+ };
4245
+ const sleep = (ms, signal) => new Promise((resolve, reject) => {
4246
+ if (signal?.aborted) {
4247
+ reject(/* @__PURE__ */ new Error("aborted"));
4248
+ return;
4249
+ }
4250
+ const timer = setTimeout(() => {
4251
+ signal?.removeEventListener("abort", onAbort);
4252
+ resolve();
4253
+ }, ms);
4254
+ const onAbort = () => {
4255
+ clearTimeout(timer);
4256
+ reject(/* @__PURE__ */ new Error("aborted"));
4257
+ };
4258
+ signal?.addEventListener("abort", onAbort, { once: true });
4259
+ });
4260
+ var DesktopCommandsApi = class {
4261
+ transport;
4262
+ constructor(transport) {
4263
+ this.transport = transport;
4264
+ }
4265
+ create(input) {
4266
+ return this.transport.request("/api/desktop/commands", {
4267
+ method: "POST",
4268
+ headers: { "Content-Type": "application/json" },
4269
+ body: JSON.stringify(input)
4270
+ });
4271
+ }
4272
+ get(commandId) {
4273
+ return this.transport.request(`/api/desktop/commands/${encodeURIComponent(commandId)}`);
4284
4274
  }
4285
- authorize(workId, input) {
4286
- return this.transport.request(`/api/works/${workId}/authorize`, {
4275
+ reportResult(commandId, input) {
4276
+ return this.transport.request(`/api/desktop/commands/${encodeURIComponent(commandId)}/result`, {
4287
4277
  method: "POST",
4288
4278
  headers: { "Content-Type": "application/json" },
4289
4279
  body: JSON.stringify(input)
4290
4280
  });
4291
4281
  }
4282
+ async run(input, options = {}) {
4283
+ const { command } = await this.create(input);
4284
+ if (isTerminalDesktopCommandStatus(command.status)) return command;
4285
+ return this.wait(command.commandId, options);
4286
+ }
4287
+ async wait(commandId, options = {}) {
4288
+ const timeoutMs = resolveTimeoutMs(options.timeoutMs);
4289
+ const pollIntervalMs = Math.max(50, options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
4290
+ const deadline = Date.now() + timeoutMs;
4291
+ let latest = (await this.get(commandId)).command;
4292
+ while (!isTerminalDesktopCommandStatus(latest.status)) {
4293
+ const remaining = deadline - Date.now();
4294
+ if (remaining <= 0) break;
4295
+ await sleep(Math.min(pollIntervalMs, remaining), options.signal);
4296
+ latest = (await this.get(commandId)).command;
4297
+ }
4298
+ if (isTerminalDesktopCommandStatus(latest.status)) return latest;
4299
+ return {
4300
+ ...latest,
4301
+ status: "timeout",
4302
+ error: {
4303
+ code: "timeout",
4304
+ message: "No Cohub desktop reported a result before the timeout."
4305
+ },
4306
+ settledAt: (/* @__PURE__ */ new Date()).toISOString()
4307
+ };
4308
+ }
4292
4309
  };
4310
+ /** @deprecated Use `DesktopCommandsApi`. */
4311
+ var UiCommandsApi = class extends DesktopCommandsApi {};
4293
4312
  //#endregion
4294
- //#region src/apis/work-commerce.ts
4295
- var WorkCommerceApi = class {
4313
+ //#region src/apis/app-commerce.ts
4314
+ var AppCommerceApi = class {
4296
4315
  transport;
4297
4316
  constructor(transport) {
4298
4317
  this.transport = transport;
4299
4318
  }
4300
- resolveProducts(workId, input) {
4301
- return this.transport.request(`/api/works/${encodeURIComponent(workId)}/commerce/products/resolve`, {
4319
+ resolveProducts(appId, input) {
4320
+ return this.transport.request(`/api/apps/${encodeURIComponent(appId)}/commerce/products/resolve`, {
4302
4321
  method: "POST",
4303
4322
  headers: { "Content-Type": "application/json" },
4304
4323
  body: JSON.stringify(input)
4305
4324
  });
4306
4325
  }
4307
- getEntitlements(workId) {
4308
- return this.transport.request(`/api/works/${encodeURIComponent(workId)}/commerce/entitlements`);
4326
+ getEntitlements(appId) {
4327
+ return this.transport.request(`/api/apps/${encodeURIComponent(appId)}/commerce/entitlements`);
4309
4328
  }
4310
- consumeCredits(workId, input) {
4311
- return this.transport.request(`/api/works/${encodeURIComponent(workId)}/commerce/credits/consume`, {
4329
+ consumeCredits(appId, input) {
4330
+ return this.transport.request(`/api/apps/${encodeURIComponent(appId)}/commerce/credits/consume`, {
4312
4331
  method: "POST",
4313
4332
  headers: { "Content-Type": "application/json" },
4314
4333
  body: JSON.stringify(input)
4315
4334
  });
4316
4335
  }
4317
- purchase(workId, input) {
4318
- return this.transport.request(`/api/works/${encodeURIComponent(workId)}/commerce/purchase`, {
4336
+ purchase(appId, input) {
4337
+ return this.transport.request(`/api/apps/${encodeURIComponent(appId)}/commerce/purchase`, {
4319
4338
  method: "POST",
4320
4339
  headers: { "Content-Type": "application/json" },
4321
4340
  body: JSON.stringify(input)
4322
4341
  });
4323
4342
  }
4324
- getOrder(workId, orderId) {
4325
- return this.transport.request(`/api/works/${encodeURIComponent(workId)}/commerce/orders/${encodeURIComponent(orderId)}`);
4343
+ getOrder(appId, orderId) {
4344
+ return this.transport.request(`/api/apps/${encodeURIComponent(appId)}/commerce/orders/${encodeURIComponent(orderId)}`);
4326
4345
  }
4327
4346
  };
4347
+ /** @deprecated Use `AppCommerceApi`. */
4348
+ var WorkCommerceApi = class extends AppCommerceApi {};
4328
4349
  //#endregion
4329
4350
  //#region src/http.ts
4330
4351
  var CohubHttpClient = class {
@@ -4344,9 +4365,21 @@ var CohubHttpClient = class {
4344
4365
  cronJobs;
4345
4366
  invite;
4346
4367
  referrals;
4347
- works;
4348
- workCommerce;
4349
- ui;
4368
+ apps;
4369
+ appCommerce;
4370
+ /** @deprecated Use `apps`. */
4371
+ get works() {
4372
+ return this.apps;
4373
+ }
4374
+ /** @deprecated Use `appCommerce`. */
4375
+ get workCommerce() {
4376
+ return this.appCommerce;
4377
+ }
4378
+ desktop;
4379
+ /** @deprecated Use `desktop`. */
4380
+ get ui() {
4381
+ return this.desktop;
4382
+ }
4350
4383
  transport;
4351
4384
  constructor(options = {}) {
4352
4385
  const apiBaseUrl = resolveApiBaseUrl(options);
@@ -4367,9 +4400,9 @@ var CohubHttpClient = class {
4367
4400
  this.cronJobs = new CronJobsApi(this.transport);
4368
4401
  this.invite = new PublicInviteApi(this.transport);
4369
4402
  this.referrals = new ReferralsApi(this.transport);
4370
- this.works = new WorksApi(this.transport);
4371
- this.workCommerce = new WorkCommerceApi(this.transport);
4372
- this.ui = new UiCommandsApi(this.transport);
4403
+ this.apps = new AppsApi(this.transport);
4404
+ this.appCommerce = new AppCommerceApi(this.transport);
4405
+ this.desktop = new DesktopCommandsApi(this.transport);
4373
4406
  }
4374
4407
  space(spaceId) {
4375
4408
  return new SpaceClient(spaceId, this.transport, null);
@@ -4377,4 +4410,4 @@ var CohubHttpClient = class {
4377
4410
  };
4378
4411
  const createHttpClient = (options) => new CohubHttpClient(options);
4379
4412
  //#endregion
4380
- export { SessionAccessApi as $, isTerminalUiCommandStatus as A, BOARD_ANIMATION_CHANNELS as B, UI_COMMAND_DEFAULT_TIMEOUT_MS as C, UI_COMMAND_SETTLEMENT_GRACE_SECONDS as D, UI_COMMAND_PENDING_TTL_SECONDS as E, BoardItemPatchSchema as F, BoardTrackSchema as G, BoardCompositionInputSchema as H, BoardSemanticMutationSchema as I, BOARD_ARROW_STROKE_SIZE as J, parseBoardCompositionInput as K, BoardEffectInputSchema as L, parseUiCommand as M, parseUiCommandId as N, UI_COMMAND_TERMINAL_TTL_SECONDS as O, BoardAuthoringItemSchema as P, DEFAULT_BOARD_RENDER_LIMITS as Q, BoardEffectSchema as R, ensureRealtimeConnected as S, UI_COMMAND_PAYLOAD_MAX_BYTES as T, BoardCompositionSchema as U, BOARD_ANIMATION_CHANNEL_CAPABILITIES as V, BoardProceduralClipSchema as W, BOARD_BUILTIN_CLIP_KINDS as X, BOARD_BUILTIN_CAPABILITIES as Y, BOARD_BUILTIN_EFFECT_KINDS as Z, SessionGenerationStreamClient as _, ReferralsApi as a, ModelsApi as at, SessionPatchReducer as b, UiCommandsApi as c, ChannelsApi as ct, SpaceClient as d, ReferencesApi as et, SpacePublicFilesApi as f, buildSpacePath as g, buildSpaceInvitePath as h, WorksApi as i, PromptsApi as it, isUiSurfaceMethod as j, UI_COMMAND_VERSION as k, TasksApi as l, PublicInviteApi as m, createHttpClient as n, PublicAssetsApi as nt, UsersApi as o, GenerationsApi as ot, SpacesApi as p, BoardConnectionSchema as q, WorkCommerceApi as r, SkillsApi as rt, UserApi as s, CronJobsApi as st, CohubHttpClient as t, SearchApi as tt, BoardClient as u, createSessionGenerationStreamClient as v, UI_COMMAND_MAX_TIMEOUT_MS as w, createSessionPatchReducer as x, parseAssistantMessageCommit as y, parseBoardEffectInput as z };
4413
+ export { BOARD_BUILTIN_EFFECT_KINDS as $, DESKTOP_COMMAND_TERMINAL_TTL_SECONDS as A, BoardEffectSchema as B, createSessionPatchReducer as C, DESKTOP_COMMAND_PAYLOAD_MAX_BYTES as D, DESKTOP_COMMAND_MAX_TIMEOUT_MS as E, parseDesktopCommandId as F, BoardCompositionSchema as G, BOARD_ANIMATION_CHANNELS as H, BoardAuthoringItemSchema as I, parseBoardCompositionInput as J, BoardProceduralClipSchema as K, BoardItemPatchSchema as L, isDesktopCallMethod as M, isTerminalDesktopCommandStatus as N, DESKTOP_COMMAND_PENDING_TTL_SECONDS as O, parseDesktopCommand as P, BOARD_BUILTIN_CLIP_KINDS as Q, BoardSemanticMutationSchema as R, SessionPatchReducer as S, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS as T, BOARD_ANIMATION_CHANNEL_CAPABILITIES as U, parseBoardEffectInput as V, BoardCompositionInputSchema as W, BOARD_ARROW_STROKE_SIZE as X, BoardConnectionSchema as Y, BOARD_BUILTIN_CAPABILITIES as Z, buildSpaceInvitePath as _, DesktopCommandsApi as a, SkillsApi as at, createSessionGenerationStreamClient as b, ReferralsApi as c, GenerationsApi as ct, TasksApi as d, DEFAULT_BOARD_RENDER_LIMITS as et, BoardClient as f, PublicInviteApi as g, SpacesApi as h, WorkCommerceApi as i, PublicAssetsApi as it, DESKTOP_COMMAND_VERSION as j, DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS as k, UsersApi as l, CronJobsApi as lt, SpacePublicFilesApi as m, createHttpClient as n, ReferencesApi as nt, UiCommandsApi as o, PromptsApi as ot, SpaceClient as p, BoardTrackSchema as q, AppCommerceApi as r, SearchApi as rt, AppsApi as s, ModelsApi as st, CohubHttpClient as t, SessionAccessApi as tt, UserApi as u, ChannelsApi as ut, buildSpacePath as v, ensureRealtimeConnected as w, parseAssistantMessageCommit as x, SessionGenerationStreamClient as y, BoardEffectInputSchema as z };