@my-life-buddies/cli 0.25.2 → 0.26.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.
@@ -916,8 +916,26 @@ var PreviewController = class {
916
916
  throw Object.assign(new Error("\u4F1A\u8BDD\u5DF2\u5207\u6362\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5C0F\u6302\u4EF6"), { status: 409 });
917
917
  return result;
918
918
  }
919
+ #productOperationPending = false;
920
+ async simulatorProduct(offerId, input) {
921
+ if (this.#resetting || this.#productOperationPending) throw Object.assign(new Error("\u4F1A\u8BDD\u6B63\u5728\u5904\u7406\u5176\u4ED6\u64CD\u4F5C\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"), { status: 409 });
922
+ const client = this.#requiredSimulator(), revision = this.#conversationRevision;
923
+ if (input && input.conversationRevision !== revision) throw Object.assign(new Error("\u4F1A\u8BDD\u5DF2\u5207\u6362\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5546\u54C1\u5361"), { status: 409 });
924
+ if (!client.productOffer || input && !client.purchaseProduct) throw Object.assign(new Error("\u8BF7\u66F4\u65B0 CLI \u540E\u91CD\u8FDE\uFF0C\u4EE5\u9884\u89C8\u5546\u54C1\u5361"), { status: 501 });
925
+ const state = await client.state();
926
+ if (!state.messages.some((message2) => message2.product?.offerId === offerId)) throw Object.assign(new Error("\u5546\u54C1\u5361\u5DF2\u4E0D\u5728\u5F53\u524D\u5BF9\u8BDD\u4E2D\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00"), { status: 404 });
927
+ if (this.#resetting || this.#productOperationPending || client !== this.#simulator || revision !== this.#conversationRevision) throw Object.assign(new Error("\u4F1A\u8BDD\u5DF2\u5207\u6362\u6216\u6B63\u5728\u8D2D\u4E70\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"), { status: 409 });
928
+ this.#productOperationPending = true;
929
+ try {
930
+ const result = input ? await client.purchaseProduct(offerId, input) : await client.productOffer(offerId);
931
+ if (this.#resetting || client !== this.#simulator || revision !== this.#conversationRevision) throw Object.assign(new Error("\u4F1A\u8BDD\u5DF2\u5207\u6362\uFF0C\u8BF7\u5237\u65B0\u72B6\u6001"), { status: 409 });
932
+ return result;
933
+ } finally {
934
+ this.#productOperationPending = false;
935
+ }
936
+ }
919
937
  async resetSimulator() {
920
- if (this.#resetting || this.#sendingMessage || this.#simulatorState.activeRun) {
938
+ if (this.#resetting || this.#sendingMessage || this.#productOperationPending || this.#simulatorState.activeRun) {
921
939
  throw Object.assign(new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u6216\u64CD\u4F5C\u5B8C\u6210\u540E\u518D\u6E05\u7A7A"), { status: 409, code: "SIMULATOR_BUSY" });
922
940
  }
923
941
  const simulator = this.#requiredSimulator();
@@ -1381,6 +1399,8 @@ var WEB_ASSETS = Object.freeze(/* @__PURE__ */ new Map([
1381
1399
  contentType: "text/css; charset=utf-8",
1382
1400
  body: readFileSync2(new URL("../web/brand.css", import.meta.url))
1383
1401
  }],
1402
+ ["/assets/products.js", { contentType: "text/javascript; charset=utf-8", body: readFileSync2(new URL("../web/products.js", import.meta.url)) }],
1403
+ ["/assets/products.css", { contentType: "text/css; charset=utf-8", body: readFileSync2(new URL("../web/products.css", import.meta.url)) }],
1384
1404
  ["/assets/widgets.js", { contentType: "text/javascript; charset=utf-8", body: readFileSync2(new URL("../web/widgets.js", import.meta.url)) }],
1385
1405
  ["/assets/widgets.css", { contentType: "text/css; charset=utf-8", body: readFileSync2(new URL("../web/widgets.css", import.meta.url)) }],
1386
1406
  ["/assets/app.js", {
@@ -1629,6 +1649,22 @@ data: ${JSON.stringify(value)}
1629
1649
  return apiError(response, failure.status, failure.code, failure.message);
1630
1650
  }
1631
1651
  }
1652
+ const productRoute = /^\/api\/simulator\/products\/([A-Za-z0-9_-]{1,120})(\/mock-purchase)?$/u.exec(url.pathname);
1653
+ if (productRoute) {
1654
+ try {
1655
+ if (request.method === "GET" && !productRoute[2]) return json(response, 200, await options.controller.simulatorProduct(productRoute[1]));
1656
+ if (request.method === "POST" && productRoute[2]) {
1657
+ const body = exactObject(await readJsonBody(request), ["expectedVersion", "idempotencyKey", "conversationRevision"]);
1658
+ if (!body || !Number.isSafeInteger(body.expectedVersion) || Number(body.expectedVersion) < 1 || !Number.isSafeInteger(body.conversationRevision) || !safeIdentifier(body.idempotencyKey, 128))
1659
+ return apiError(response, 400, "INVALID_PURCHASE", "\u8BF7\u91CD\u65B0\u6253\u5F00\u5546\u54C1\u5361\u5E76\u786E\u8BA4\u7248\u672C");
1660
+ return json(response, 200, await options.controller.simulatorProduct(productRoute[1], body));
1661
+ }
1662
+ return apiError(response, 405, "METHOD_NOT_ALLOWED", "\u4E0D\u652F\u6301\u8FD9\u4E2A\u5546\u54C1\u64CD\u4F5C");
1663
+ } catch (cause) {
1664
+ const failure = requestFailure(cause);
1665
+ return apiError(response, failure.status, failure.code, failure.message);
1666
+ }
1667
+ }
1632
1668
  const widgetRoute = /^\/api\/simulator\/widgets(?:\/([^/]+)(?:\/(image|pin|bridge))?)?$/u.exec(url.pathname);
1633
1669
  if (widgetRoute) {
1634
1670
  try {
@@ -2233,10 +2269,10 @@ function object2(value) {
2233
2269
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
2234
2270
  }
2235
2271
  function httpError(status, value) {
2236
- const serverMessage = object2(value)?.error;
2272
+ const serverMessage = object2(object2(value)?.error)?.message ?? object2(value)?.error;
2237
2273
  const message2 = typeof serverMessage === "string" && serverMessage.trim() ? serverMessage.slice(0, 512) : status >= 500 ? "MLB Server \u6682\u65F6\u4E0D\u53EF\u7528" : "\u6A21\u62DF\u5668\u8BF7\u6C42\u672A\u80FD\u5B8C\u6210";
2238
2274
  return Object.assign(new Error(message2), {
2239
- code: "MLB_REQUEST_FAILED",
2275
+ code: typeof object2(object2(value)?.error)?.code === "string" ? object2(object2(value)?.error).code : "MLB_REQUEST_FAILED",
2240
2276
  status,
2241
2277
  publicMessage: message2
2242
2278
  });
@@ -2247,7 +2283,7 @@ function message(value, index) {
2247
2283
  const role = input.author === "buddy" ? "assistant" : input.author === "user" || input.author === "owner" ? "user" : void 0;
2248
2284
  if (!role) return null;
2249
2285
  const messageId = safeText(input.id, `messages[${index}].id`, 256);
2250
- let text2 = input.type === "widget" && input.text === void 0 ? "" : input.text;
2286
+ let text2 = ["widget", "product"].includes(String(input.type)) && input.text === void 0 ? "" : input.text;
2251
2287
  if (typeof text2 !== "string" || Buffer.byteLength(text2, "utf8") > 48 * 1024) {
2252
2288
  throw new Error(`messages[${index}].text is invalid`);
2253
2289
  }
@@ -2275,7 +2311,20 @@ ${options.map((option, i) => `${i + 1}. ${option}`).join("\n")}
2275
2311
  role,
2276
2312
  text: text2,
2277
2313
  createdAt: new Date(input.timestamp).toISOString(),
2278
- ...input.type === "widget" && object2(input.widget) ? { widget: parseWidget(input.widget) } : {}
2314
+ ...input.type === "widget" && object2(input.widget) ? { widget: parseWidget(input.widget) } : {},
2315
+ ...input.type === "product" && role === "assistant" ? { product: parseProduct(input.product) } : {}
2316
+ });
2317
+ }
2318
+ function parseProduct(value) {
2319
+ const product = object2(value);
2320
+ if (!product || !Number.isSafeInteger(product.version) || Number(product.version) < 1) throw new TypeError("\u5546\u54C1\u5361\u7248\u672C\u65E0\u6548");
2321
+ return Object.freeze({
2322
+ offerId: safeText(product.offerId, "offerId", 120),
2323
+ productId: safeText(product.productId, "productId", 120),
2324
+ version: Number(product.version),
2325
+ title: safeText(product.title, "\u5546\u54C1\u540D\u79F0", 512),
2326
+ summary: typeof product.summary === "string" ? product.summary.slice(0, 4096) : "",
2327
+ buttonText: typeof product.buttonText === "string" && product.buttonText.trim() ? product.buttonText.slice(0, 100) : "\u67E5\u770B\u65B9\u6848"
2279
2328
  });
2280
2329
  }
2281
2330
  function widgetId(value) {
@@ -2395,6 +2444,17 @@ var MlbSimulatorClient = class {
2395
2444
  }
2396
2445
  return Object.freeze({ ...details, avatarPreview });
2397
2446
  }
2447
+ async productOffer(offerId) {
2448
+ this.#assertResetComplete();
2449
+ const detail = object2(await this.#request("GET", `/app/product-offers/${encodeURIComponent(safeText(offerId, "offerId", 120))}`, {}));
2450
+ if (detail?.buddyId !== this.#buddyId || detail?.offerId !== offerId || detail.paymentChannel !== "mock" || detail.chargedAmountMinor !== 0)
2451
+ throw httpError(409, { error: "\u4EC5\u652F\u6301\u5F53\u524D DEV \u642D\u5B50\u7684\u96F6\u6263\u8D39\u6A21\u62DF\u8D2D\u4E70" });
2452
+ return detail;
2453
+ }
2454
+ async purchaseProduct(offerId, input) {
2455
+ await this.productOffer(offerId);
2456
+ return this.#request("POST", `/app/product-offers/${encodeURIComponent(offerId)}/mock-purchase`, { body: { expectedVersion: input.expectedVersion, idempotencyKey: safeText(input.idempotencyKey, "\u5E42\u7B49\u952E", 128) } });
2457
+ }
2398
2458
  async widgets() {
2399
2459
  this.#assertResetComplete();
2400
2460
  const id = await this.#ensurePrivate();