@neta-art/cohub 4.7.1 → 4.8.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.
@@ -275,6 +275,7 @@ declare class WorkRuntimeApi {
275
275
  }): Promise<boolean>;
276
276
  purchase(input: {
277
277
  productKey: string;
278
+ purchaseAttemptId?: string;
278
279
  }): Promise<{
279
280
  providerKey: string | null;
280
281
  checkoutUrl: string | null;
@@ -1312,6 +1313,7 @@ declare class SpaceCommerceApi {
1312
1313
  name: string;
1313
1314
  description?: string;
1314
1315
  amountUsd: number;
1316
+ cohubBalanceUsd?: number;
1315
1317
  status?: "draft" | "active";
1316
1318
  visibility?: "public" | "private";
1317
1319
  }): Promise<{
@@ -2258,6 +2258,11 @@ type SpaceCommerceProduct = {
2258
2258
  validity: string | null;
2259
2259
  creditBenefits: SpaceCommerceProductCreditBenefit[];
2260
2260
  };
2261
+ cohubBalance: {
2262
+ amountUsd: number;
2263
+ amountMinor: number;
2264
+ policyVersion: string;
2265
+ } | null;
2261
2266
  isDefaultPlan: boolean;
2262
2267
  };
2263
2268
  type SpaceCommerceProductBenefitBinding = {
package/dist/index.d.ts CHANGED
@@ -112,6 +112,7 @@ declare class CohubClient {
112
112
  }) => Promise<WorkCommerceCreditConsumeResponse>;
113
113
  purchase: (input: {
114
114
  productKey: string;
115
+ purchaseAttemptId?: string;
115
116
  }) => Promise<{
116
117
  providerKey: string | null;
117
118
  checkoutUrl: string | null;
@@ -157,6 +158,7 @@ type WorkAuthorizeRequest = {
157
158
  type WorkPurchaseRequest = {
158
159
  requestId: string;
159
160
  productKey: string;
161
+ purchaseAttemptId: string;
160
162
  };
161
163
  /**
162
164
  * Reactive dialog state managed by the core. The host (Svelte or React)
package/dist/index.js CHANGED
@@ -94,7 +94,7 @@ const getParentOrigin = () => {
94
94
  return null;
95
95
  }
96
96
  };
97
- const generateRequestId = () => globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
97
+ const generateRequestId = () => globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`;
98
98
  /**
99
99
  * Bridge-mode transport: posts messages to `window.parent` (the Cohub host
100
100
  * embedding the work in an iframe) and listens for the matching reply.
@@ -400,9 +400,11 @@ var WorkRuntimeApi = class {
400
400
  return Boolean(this.token);
401
401
  }
402
402
  async purchase(input) {
403
+ const purchaseAttemptId = input.purchaseAttemptId?.trim() || generateRequestId();
403
404
  return (await this.transport.request({
404
405
  type: "cohub.work.purchase",
405
- productKey: input.productKey
406
+ productKey: input.productKey,
407
+ purchaseAttemptId
406
408
  }, { timeoutMs: 12e4 }))?.checkout ?? null;
407
409
  }
408
410
  async checkoutState() {
@@ -830,7 +832,7 @@ function createWorkBridgeCore(config) {
830
832
  sessionStorage.removeItem(pendingPurchaseStorageKey);
831
833
  } catch {}
832
834
  }
833
- async function createPurchase(productKey) {
835
+ async function createPurchase(productKey, purchaseAttemptId) {
834
836
  const userToken = await getAccessToken();
835
837
  if (!userToken) {
836
838
  await config.requestSignIn(typeof location !== "undefined" ? location.pathname + location.search + location.hash : "/");
@@ -842,7 +844,10 @@ function createWorkBridgeCore(config) {
842
844
  Authorization: `Bearer ${userToken}`,
843
845
  "Content-Type": "application/json"
844
846
  },
845
- body: JSON.stringify({ productKey })
847
+ body: JSON.stringify({
848
+ productKey,
849
+ purchaseAttemptId
850
+ })
846
851
  });
847
852
  if (!response.ok) throw new Error((await response.json().catch(() => null))?.message ?? "Purchase failed.");
848
853
  return (await response.json()).checkout ?? null;
@@ -897,9 +902,18 @@ function createWorkBridgeCore(config) {
897
902
  });
898
903
  return;
899
904
  }
905
+ const purchaseAttemptId = (typeof data.purchaseAttemptId === "string" ? data.purchaseAttemptId.trim() : "") || data.requestId.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 128);
906
+ if (!/^[a-zA-Z0-9_-]{1,128}$/.test(purchaseAttemptId)) {
907
+ reply(data.requestId, {
908
+ type: "cohub.work.error",
909
+ message: "Purchase attempt id is invalid."
910
+ });
911
+ return;
912
+ }
900
913
  state.pendingPurchase = {
901
914
  requestId: data.requestId,
902
- productKey
915
+ productKey,
916
+ purchaseAttemptId
903
917
  };
904
918
  state.purchaseError = null;
905
919
  state.purchaseOpen = true;
@@ -982,7 +996,7 @@ function createWorkBridgeCore(config) {
982
996
  state.purchaseError = null;
983
997
  notify();
984
998
  try {
985
- const checkout = await createPurchase(state.pendingPurchase.productKey);
999
+ const checkout = await createPurchase(state.pendingPurchase.productKey, state.pendingPurchase.purchaseAttemptId);
986
1000
  reply(state.pendingPurchase.requestId, {
987
1001
  type: "cohub.work.purchase.result",
988
1002
  checkout
@@ -656,6 +656,10 @@ if (checkoutState.orderId) {
656
656
  }
657
657
  ```
658
658
 
659
+ `purchase()` creates a purchase attempt ID automatically. If application code
660
+ retries the call after a timeout, pass the same `purchaseAttemptId` to ensure
661
+ the retry resolves to the original Billing order.
662
+
659
663
  ---
660
664
 
661
665
  ## 6. Complete working example
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neta-art/cohub",
3
- "version": "4.7.1",
3
+ "version": "4.8.0",
4
4
  "description": "Cohub SDK for spaces, sessions, boards, and realtime agent collaboration.",
5
5
  "license": "Apache-2.0",
6
6
  "private": false,