@joai/sdk 4.8.0 → 6.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.
Files changed (3) hide show
  1. package/dist/index.d.mts +564 -3985
  2. package/dist/index.mjs +97 -240
  3. package/package.json +5 -2
package/dist/index.mjs CHANGED
@@ -1,238 +1,5 @@
1
+ import { HttpService, getApiBaseUrl, isCompleteAddressInput } from "@joai/core";
1
2
  import { WarpClient } from "@joai/warps";
2
- //#region ../core/dist/index.mjs
3
- const toSubdomainBaseUrl = (env, subdomain) => {
4
- if (env === "local") return `http://${subdomain}.joai--api.test`;
5
- if (env === "devnet") return `https://devnet-${subdomain}.joai.ai`;
6
- if (env === "testnet") return `https://testnet-${subdomain}.joai.ai`;
7
- return `https://${subdomain}.joai.ai`;
8
- };
9
- const getApiBaseUrl = (env) => toSubdomainBaseUrl(env, "api");
10
- var HttpService = class {
11
- constructor(baseUrl, cookies, authToken, options) {
12
- this.get = async (url, options) => await this.request("GET", url, void 0, options);
13
- this.post = async (url, data, options) => await this.request("POST", url, data, options);
14
- this.put = async (url, data, options) => await this.request("PUT", url, data, options);
15
- this.patch = async (url, data, options) => await this.request("PATCH", url, data, options);
16
- this.delete = async (url, options) => await this.request("DELETE", url, void 0, options);
17
- this.getCsrfToken = () => {
18
- if (typeof document === "undefined") return null;
19
- const match = document.cookie.match(/(?:^|;\s*)XSRF-TOKEN=([^;]*)/);
20
- return match ? decodeURIComponent(match[1]) : null;
21
- };
22
- this.request = async (httpMethod, url, data, options, isRetry) => {
23
- const requestUrl = url.startsWith("http") ? url : `${this.baseUrl}/${url}`;
24
- const requestInfo = this.getRequestInfo(httpMethod, data, options);
25
- const response = await this.convertResponse(this.fetchFn(requestUrl, requestInfo));
26
- if (response.original.status === 419 && !isRetry) {
27
- await this.refreshCsrfToken();
28
- return this.request(httpMethod, url, data, options, true);
29
- }
30
- if (response.original.status === 401) this.onUnauthorized(response);
31
- if (response.original.status === 429) {
32
- console.warn(`[HTTP 429] ${httpMethod} ${requestUrl}`);
33
- this.onTooManyRequests(response);
34
- }
35
- if (response.original.status === 503) this.onMaintenanceMode(response);
36
- if (response.ok) this.onSuccessfulResponse(response);
37
- return response;
38
- };
39
- this.refreshCsrfToken = async () => {
40
- await this.fetchFn(`${this.csrfBaseUrl}/sanctum/csrf-cookie`, {
41
- method: "GET",
42
- credentials: "include",
43
- headers: {
44
- Accept: "application/json",
45
- ...this.headers
46
- }
47
- });
48
- };
49
- this.convertResponse = async (apiRes) => {
50
- try {
51
- const response = await apiRes;
52
- const body = response.status === 204 ? {} : await response.json();
53
- return {
54
- data: body.data || null,
55
- meta: body.meta,
56
- body,
57
- errors: body.errors || [],
58
- ok: response.ok && !(body.errors && body.errors.length > 0),
59
- noContent: response.status === 204,
60
- paymentRequired: response.status === 402,
61
- original: response
62
- };
63
- } catch (error) {
64
- this.onNetworkError(error);
65
- const anyError = error;
66
- return {
67
- data: {},
68
- errors: anyError.response && (anyError.response.data || {}).errors,
69
- body: {},
70
- ok: false,
71
- noContent: false,
72
- paymentRequired: false,
73
- original: anyError
74
- };
75
- }
76
- };
77
- this.getRequestInfo = (httpMethod = "GET", data, options) => {
78
- const isJson = options?.isJson !== false;
79
- const isFormData = data instanceof FormData;
80
- const situationalHeaders = options?.headers || {};
81
- const csrfToken = httpMethod !== "GET" ? this.getCsrfToken() : null;
82
- const headers = {
83
- Accept: "application/json",
84
- ...this.authToken ? { Authorization: `Bearer ${this.authToken}` } : {},
85
- ...csrfToken ? { "X-XSRF-TOKEN": csrfToken } : {},
86
- ...situationalHeaders,
87
- ...this.headers
88
- };
89
- if (isJson && !isFormData) headers["Content-Type"] = "application/json";
90
- return {
91
- method: httpMethod,
92
- credentials: "include",
93
- headers,
94
- body: httpMethod !== "GET" ? isJson && !isFormData ? JSON.stringify(data || {}) : data : void 0
95
- };
96
- };
97
- this.baseUrl = baseUrl;
98
- this.authToken = authToken || null;
99
- this.fetchFn = options?.customFetch ?? globalThis.fetch.bind(globalThis);
100
- this.csrfBaseUrl = options?.csrfBaseUrl ?? baseUrl;
101
- this.onNetworkError = () => {};
102
- this.onSuccessfulResponse = () => {};
103
- this.onUnauthorized = () => {};
104
- this.onMaintenanceMode = () => {};
105
- this.onTooManyRequests = () => {};
106
- this.headers = {
107
- ...options?.refererUrl ? { Referer: options.refererUrl } : {},
108
- ...cookies ? { Cookie: cookies } : {},
109
- ...options?.headers ?? {}
110
- };
111
- }
112
- };
113
- const OUTBOUND_CHANNELS = [
114
- {
115
- id: "email",
116
- supportsHtml: true,
117
- requiresSubject: true,
118
- settingsKey: "email_provider"
119
- },
120
- {
121
- id: "whatsapp",
122
- supportsHtml: false,
123
- requiresSubject: false
124
- },
125
- {
126
- id: "whatsapp-personal",
127
- supportsHtml: false,
128
- requiresSubject: false
129
- },
130
- {
131
- id: "sms",
132
- supportsHtml: false,
133
- requiresSubject: false
134
- },
135
- {
136
- id: "push",
137
- supportsHtml: false,
138
- requiresSubject: true
139
- }
140
- ];
141
- const AUTOMATION_SEND_CHANNELS = OUTBOUND_CHANNELS.filter((channel) => channel.id === "email" || channel.id === "whatsapp-personal");
142
- OUTBOUND_CHANNELS.map((channel) => channel.id).filter((id) => id !== "whatsapp-personal");
143
- AUTOMATION_SEND_CHANNELS[0];
144
- Object.values({
145
- Billing: "billing",
146
- Shipping: "shipping"
147
- });
148
- Object.values({
149
- Pending: "pending",
150
- ReadyForPickup: "ready_for_pickup",
151
- Shipped: "shipped",
152
- Delivered: "delivered",
153
- Cancelled: "cancelled"
154
- });
155
- Object.values({
156
- Shipping: "shipping",
157
- Pickup: "pickup"
158
- });
159
- Object.values({
160
- Requested: "requested",
161
- Approved: "approved",
162
- Rejected: "rejected",
163
- Received: "received",
164
- Closed: "closed"
165
- });
166
- Object.values({
167
- Approved: "approved",
168
- Rejected: "rejected",
169
- Received: "received",
170
- Closed: "closed"
171
- });
172
- const isCompleteAddressInput = (address) => Boolean(address.name.trim() && address.addressOne.trim() && address.city.trim() && address.zipCode.trim() && address.country.trim());
173
- Object.values({
174
- Board: "board",
175
- Shop: "shop",
176
- SmartLinks: "smart-links",
177
- Contacts: "contacts",
178
- Forms: "forms",
179
- Appointments: "appointments",
180
- Workspace: "workspace",
181
- Meeting: "meeting",
182
- VoiceDictation: "voice-dictation",
183
- Heartbeats: "heartbeats",
184
- Wallets: "wallets",
185
- Campaigns: "campaigns",
186
- Automations: "automations",
187
- News: "news",
188
- Sites: "sites",
189
- Contracts: "contracts",
190
- Artifacts: "artifacts"
191
- });
192
- /** Permission string values — must match joai--api `UserPermission::value`. */
193
- const UserPermissions = {
194
- BillingManage: "billing-manage",
195
- TeamManage: "team-manage",
196
- TeamView: "team-view",
197
- ContentEdit: "content-edit",
198
- ContentPublish: "content-publish",
199
- TeamMemberInvite: "team-member-invite",
200
- TeamMemberRemove: "team-member-remove",
201
- TeamSecretView: "team-secret-view",
202
- TeamSecretManage: "team-secret-manage",
203
- AgentExecute: "agent-execute",
204
- AgentWalletManage: "agent-wallet-manage",
205
- SwarmCreate: "swarm-create"
206
- };
207
- Object.values(UserPermissions);
208
- const teamManageOr = (...permissions) => ({ permissionsAny: [UserPermissions.TeamManage, ...permissions] });
209
- const permissionPresetRules = {
210
- teamManage: { permissions: [UserPermissions.TeamManage] },
211
- teamView: teamManageOr(UserPermissions.TeamView),
212
- billingManage: teamManageOr(UserPermissions.BillingManage),
213
- agentTooling: teamManageOr(UserPermissions.AgentExecute),
214
- secretView: teamManageOr(UserPermissions.TeamSecretView),
215
- secretManage: teamManageOr(UserPermissions.TeamSecretManage),
216
- teamMemberInvite: teamManageOr(UserPermissions.TeamMemberInvite),
217
- teamMemberRemove: teamManageOr(UserPermissions.TeamMemberRemove),
218
- agentWalletManage: teamManageOr(UserPermissions.AgentWalletManage),
219
- swarmCreate: teamManageOr(UserPermissions.SwarmCreate)
220
- };
221
- permissionPresetRules.teamManage;
222
- permissionPresetRules.teamView;
223
- permissionPresetRules.agentTooling;
224
- permissionPresetRules.billingManage;
225
- /** Team member roles — values must match joai--api `UserRole::toName()`. */
226
- const UserRoles = {
227
- Owner: "owner",
228
- Admin: "admin",
229
- Member: "member",
230
- Developer: "developer"
231
- };
232
- Object.values(UserRoles);
233
- UserRoles.Member, UserRoles.Developer, UserRoles.Admin;
234
- UserRoles.Member;
235
- //#endregion
236
3
  //#region src/resources/agents.ts
237
4
  var AgentsResource = class {
238
5
  constructor(http) {
@@ -495,9 +262,41 @@ const readOrderList = (namespace) => {
495
262
  return [];
496
263
  }
497
264
  };
265
+ function buildGuestOrderReturnUrl(ordersPageUrl, orderId, accessToken) {
266
+ try {
267
+ const url = new URL(ordersPageUrl);
268
+ if (url.protocol !== "http:" && url.protocol !== "https:") return ordersPageUrl;
269
+ url.searchParams.set("order", orderId);
270
+ url.searchParams.set("orderAccessToken", accessToken);
271
+ return url.toString();
272
+ } catch {
273
+ return ordersPageUrl;
274
+ }
275
+ }
276
+ function readGuestOrderReturnAccess(search) {
277
+ const query = typeof search === "string" ? new URLSearchParams(search) : search;
278
+ const orderId = query.get("order");
279
+ const accessToken = query.get("orderAccessToken");
280
+ if (!orderId || !accessToken) return null;
281
+ return {
282
+ orderId,
283
+ accessToken
284
+ };
285
+ }
286
+ function stripGuestOrderReturnToken(pathname, search) {
287
+ const query = new URLSearchParams(typeof search === "string" ? search : search.toString());
288
+ query.delete("orderAccessToken");
289
+ const next = query.toString();
290
+ return `${pathname}${next ? `?${next}` : ""}`;
291
+ }
292
+ const absoluteOrdersPageUrl = (ordersPage) => {
293
+ if (/^https?:\/\//i.test(ordersPage)) return ordersPage;
294
+ const origin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
295
+ return new URL(ordersPage, origin).toString();
296
+ };
498
297
  function createGuestCommerceStorage(options) {
499
298
  const maxOrders = options.maxOrders ?? 10;
500
- return {
299
+ const storage = {
501
300
  saveCheckoutDraft(draft) {
502
301
  safeSet(checkoutKey(options.namespace), JSON.stringify(draft));
503
302
  },
@@ -534,8 +333,26 @@ function createGuestCommerceStorage(options) {
534
333
  orderId: entry.orderId,
535
334
  accessToken: entry.accessToken || safeGet(orderAccessKey(options.namespace, entry.orderId))
536
335
  }));
336
+ },
337
+ /** Absolute shop URL from a path or full URL (e.g. orders page). */
338
+ shopUrl(ordersPage) {
339
+ return absoluteOrdersPageUrl(ordersPage);
340
+ },
341
+ /** Thank-you → shop handoff URL with capability token query params. */
342
+ orderReturnUrl(ordersPage, orderId, accessToken) {
343
+ return buildGuestOrderReturnUrl(absoluteOrdersPageUrl(ordersPage), orderId, accessToken);
344
+ },
345
+ /** Persist `order` + `orderAccessToken` from the shop handoff query, then strip the token. */
346
+ claimOrderReturn() {
347
+ if (typeof window === "undefined") return null;
348
+ const access = readGuestOrderReturnAccess(window.location.search);
349
+ if (!access?.accessToken) return null;
350
+ storage.saveOrderAccess(access);
351
+ window.history.replaceState({}, "", stripGuestOrderReturnToken(window.location.pathname, window.location.search));
352
+ return access;
537
353
  }
538
354
  };
355
+ return storage;
539
356
  }
540
357
  //#endregion
541
358
  //#region src/commerce/guestCheckout.ts
@@ -663,7 +480,8 @@ async function createGuestCheckoutSnapshot(options) {
663
480
  *
664
481
  * When `pay` is enabled (default), `paymentUrl` is only set from a successful `orders.pay`
665
482
  * response. `order.paymentUrl` from create is the JoAi thank-you URL and must not be used
666
- * as a gateway redirect.
483
+ * as a gateway redirect. After payment, the thank-you page redirects to the team's shop
484
+ * site URL when one is configured (`sites.type = shop`).
667
485
  */
668
486
  async function placeGuestCheckoutOrder(options) {
669
487
  if (!options.acceptedTerms) throw new GuestCheckoutError("terms_required");
@@ -2131,10 +1949,13 @@ var OrdersResource = class {
2131
1949
  return this.http.delete(`orders/${id}`);
2132
1950
  }
2133
1951
  pay(id, provider, accessToken) {
2134
- return this.http.post(`orders/${id}/pay`, provider ? { provider } : {}, orderAccessHeaders(accessToken));
1952
+ return this.http.post(`orders/${id}/pay`, { ...provider ? { provider } : {} }, orderAccessHeaders(accessToken));
2135
1953
  }
2136
- notify(id, type = "confirmation") {
2137
- return this.http.post(`orders/${id}/notify`, { type });
1954
+ notify(id, type = "confirmation", agentId) {
1955
+ return this.http.post(`orders/${id}/notify`, {
1956
+ type,
1957
+ ...agentId ? { agentId } : {}
1958
+ });
2138
1959
  }
2139
1960
  };
2140
1961
  //#endregion
@@ -2907,6 +2728,41 @@ var UpdatesResource = class {
2907
2728
  }
2908
2729
  };
2909
2730
  //#endregion
2731
+ //#region src/resources/social-posts.ts
2732
+ var SocialPostsResource = class {
2733
+ constructor(http) {
2734
+ this.http = http;
2735
+ }
2736
+ connections() {
2737
+ return this.http.get("social-posts/connections");
2738
+ }
2739
+ list(params) {
2740
+ const query = new URLSearchParams();
2741
+ if (params?.status) query.set("status", params.status);
2742
+ if (params?.platform) query.set("platform", params.platform);
2743
+ const qs = query.toString();
2744
+ return this.http.get(`social-posts${qs ? "?" + qs : ""}`);
2745
+ }
2746
+ create(payload) {
2747
+ return this.http.post("social-posts", payload);
2748
+ }
2749
+ update(id, payload) {
2750
+ return this.http.patch(`social-posts/${id}`, payload);
2751
+ }
2752
+ schedule(id, scheduledAt) {
2753
+ return this.http.post(`social-posts/${id}/schedule`, scheduledAt ? { scheduledAt } : {});
2754
+ }
2755
+ cancel(id) {
2756
+ return this.http.post(`social-posts/${id}/cancel`, {});
2757
+ }
2758
+ retry(id) {
2759
+ return this.http.post(`social-posts/${id}/retry`, {});
2760
+ }
2761
+ delete(id) {
2762
+ return this.http.delete(`social-posts/${id}`);
2763
+ }
2764
+ };
2765
+ //#endregion
2910
2766
  //#region src/resources/upgrades.ts
2911
2767
  var UpgradesResource = class {
2912
2768
  constructor(http) {
@@ -3442,6 +3298,7 @@ var JoAiClient = class {
3442
3298
  this.automations = new AutomationsResource(this.http);
3443
3299
  this.segments = new SegmentsResource(this.http);
3444
3300
  this.updates = new UpdatesResource(this.http);
3301
+ this.socialPosts = new SocialPostsResource(this.http);
3445
3302
  this.upgrades = new UpgradesResource(this.http);
3446
3303
  this.users = new UsersResource(this.http);
3447
3304
  this.voice = new VoiceResource(this.http);
@@ -3555,4 +3412,4 @@ var DistributionResource = class {
3555
3412
  }
3556
3413
  };
3557
3414
  //#endregion
3558
- export { AddressesResource, AgentsResource, AlertsResource, ApiTokensResource, AppointmentsResource, AuthResource, AutomationsResource, BillingResource, BlueprintsResource, CachedHttpService, CampaignsResource, CardsResource, CartsResource, ChangelogResource, CharactersResource, CheckoutResource, CommerceResource, ContactsResource, ContentResource, ContractsResource, DeskResource, DistributionResource, DocumentsResource, ElementsResource, EntitiesResource, FlowsResource, FulfillmentsResource, GoalsResource, GuestCheckoutError, HooksResource, IngestionsResource, InquiriesResource, IntegrationsResource, IntentsResource, ItemsResource, JoAiClient, KvResource, LinksResource, LoyaltyResource, McpResource, MeetingsResource, MemoriesResource, MessagesResource, MetricsResource, MissionsResource, NotificationsResource, OfficeResource, OrdersResource, PersonaResource, ProductsResource, ProjectsResource, RemindersResource, ReturnsResource, SegmentsResource, ServicesResource, ShippingResource, ShortcutsResource, SitesResource, SkillsResource, StatsResource, StoreResource, SubscriptionsResource, SwarmsResource, TagsResource, TasksResource, TeamsResource, UpdatesResource, UpgradesResource, UsersResource, VoiceResource, WalletsResource, WarpsResource, WorkspaceResource, assertGuestCheckoutReady, buildGuestCheckoutSnapshotRequest, completePortalSession, createClient, createEmptyGuestCheckoutState, createGuestCheckoutSnapshot, createGuestCommerceStorage, formatOpeningHours, getAuthFragmentToken, isAllowedRedirectUrl, isGuestCheckoutError, isPortalCallbackUrl, openPortalSession, placeGuestCheckoutOrder, sanitizePortalCallbackUrl, toGuestCheckoutDraft };
3415
+ export { AddressesResource, AgentsResource, AlertsResource, ApiTokensResource, AppointmentsResource, AuthResource, AutomationsResource, BillingResource, BlueprintsResource, CachedHttpService, CampaignsResource, CardsResource, CartsResource, ChangelogResource, CharactersResource, CheckoutResource, CommerceResource, ContactsResource, ContentResource, ContractsResource, DeskResource, DistributionResource, DocumentsResource, ElementsResource, EntitiesResource, FlowsResource, FulfillmentsResource, GoalsResource, GuestCheckoutError, HooksResource, IngestionsResource, InquiriesResource, IntegrationsResource, IntentsResource, ItemsResource, JoAiClient, KvResource, LinksResource, LoyaltyResource, McpResource, MeetingsResource, MemoriesResource, MessagesResource, MetricsResource, MissionsResource, NotificationsResource, OfficeResource, OrdersResource, PersonaResource, ProductsResource, ProjectsResource, RemindersResource, ReturnsResource, SegmentsResource, ServicesResource, ShippingResource, ShortcutsResource, SitesResource, SkillsResource, SocialPostsResource, StatsResource, StoreResource, SubscriptionsResource, SwarmsResource, TagsResource, TasksResource, TeamsResource, UpdatesResource, UpgradesResource, UsersResource, VoiceResource, WalletsResource, WarpsResource, WorkspaceResource, assertGuestCheckoutReady, buildGuestCheckoutSnapshotRequest, buildGuestOrderReturnUrl, completePortalSession, createClient, createEmptyGuestCheckoutState, createGuestCheckoutSnapshot, createGuestCommerceStorage, formatOpeningHours, getAuthFragmentToken, isAllowedRedirectUrl, isGuestCheckoutError, isPortalCallbackUrl, openPortalSession, placeGuestCheckoutOrder, readGuestOrderReturnAccess, sanitizePortalCallbackUrl, stripGuestOrderReturnToken, toGuestCheckoutDraft };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joai/sdk",
3
- "version": "4.8.0",
3
+ "version": "6.0.0",
4
4
  "description": "JoAi public API SDK — build with your AI agents",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,10 +35,13 @@
35
35
  "test": "jest --config jest.config.js"
36
36
  },
37
37
  "dependencies": {
38
+ "@joai/core": "^4.14.0",
38
39
  "@joai/warps": "*"
39
40
  },
41
+ "peerDependencies": {
42
+ "@joai/core": "^4.14.0"
43
+ },
40
44
  "devDependencies": {
41
- "@joai/core": "^4.12.0",
42
45
  "tsdown": "^0.21.0",
43
46
  "typescript": "^5.9.3"
44
47
  }