@01.software/sdk 0.17.0 → 0.19.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.
package/dist/index.cjs CHANGED
@@ -24,6 +24,7 @@ __export(src_exports, {
24
24
  AuthError: () => AuthError,
25
25
  BaseApi: () => BaseApi,
26
26
  COLLECTIONS: () => COLLECTIONS,
27
+ CUSTOMER_PASSWORD_RESET_OPERATION: () => CUSTOMER_PASSWORD_RESET_OPERATION,
27
28
  CartApi: () => CartApi,
28
29
  Client: () => Client,
29
30
  CollectionClient: () => CollectionClient,
@@ -65,6 +66,7 @@ __export(src_exports, {
65
66
  createAuthError: () => createAuthError,
66
67
  createClient: () => createClient,
67
68
  createConflictError: () => createConflictError,
69
+ createCustomerAuthWebhookHandler: () => createCustomerAuthWebhookHandler,
68
70
  createNotFoundError: () => createNotFoundError,
69
71
  createPermissionError: () => createPermissionError,
70
72
  createRateLimitError: () => createRateLimitError,
@@ -91,6 +93,7 @@ __export(src_exports, {
91
93
  isAuthError: () => isAuthError,
92
94
  isConfigError: () => isConfigError,
93
95
  isConflictError: () => isConflictError,
96
+ isCustomerPasswordResetWebhookEvent: () => isCustomerPasswordResetWebhookEvent,
94
97
  isGoneError: () => isGoneError,
95
98
  isNetworkError: () => isNetworkError,
96
99
  isNotFoundError: () => isNotFoundError,
@@ -529,7 +532,7 @@ async function parseErrorBody(response) {
529
532
  };
530
533
  try {
531
534
  const body = await response.json();
532
- const reason = typeof body.reason === "string" ? body.reason : void 0;
535
+ const reason = typeof body.reason === "string" ? body.reason : typeof body.code === "string" ? body.code : void 0;
533
536
  if (body.errors && Array.isArray(body.errors)) {
534
537
  const fieldErrors = [];
535
538
  for (const e of body.errors) {
@@ -552,6 +555,7 @@ async function parseErrorBody(response) {
552
555
  errorMessage: `HTTP ${response.status}: ${details}`,
553
556
  userMessage: details,
554
557
  reason,
558
+ body,
555
559
  errors: fieldErrors.length > 0 ? fieldErrors : body.errors
556
560
  };
557
561
  }
@@ -560,17 +564,19 @@ async function parseErrorBody(response) {
560
564
  return {
561
565
  errorMessage: `HTTP ${response.status}: ${body.error}`,
562
566
  userMessage: body.error,
563
- reason
567
+ reason,
568
+ body
564
569
  };
565
570
  }
566
571
  if (body.message) {
567
572
  return {
568
573
  errorMessage: `HTTP ${response.status}: ${body.message}`,
569
574
  userMessage: body.message,
570
- reason
575
+ reason,
576
+ body
571
577
  };
572
578
  }
573
- return { ...fallback, reason };
579
+ return { ...fallback, reason, body };
574
580
  } catch {
575
581
  return fallback;
576
582
  }
@@ -587,7 +593,6 @@ async function httpFetch(url, options) {
587
593
  publishableKey,
588
594
  secretKey,
589
595
  customerToken,
590
- tenantId,
591
596
  timeout = DEFAULT_TIMEOUT,
592
597
  debug,
593
598
  retry,
@@ -617,9 +622,6 @@ async function httpFetch(url, options) {
617
622
  if (authToken) {
618
623
  headers.set("Authorization", `Bearer ${authToken}`);
619
624
  }
620
- if (tenantId) {
621
- headers.set("X-Tenant-Id", tenantId);
622
- }
623
625
  if (!headers.has("Content-Type") && requestInit.body && !(requestInit.body instanceof FormData)) {
624
626
  headers.set("Content-Type", "application/json");
625
627
  }
@@ -786,10 +788,9 @@ async function httpFetch(url, options) {
786
788
 
787
789
  // src/core/collection/http-client.ts
788
790
  var HttpClient = class {
789
- constructor(publishableKey, secretKey, getCustomerToken, onUnauthorized, onRequestId, tenantId) {
791
+ constructor(publishableKey, secretKey, getCustomerToken, onUnauthorized, onRequestId) {
790
792
  this.publishableKey = publishableKey;
791
793
  this.secretKey = secretKey;
792
- this.tenantId = tenantId;
793
794
  this.getCustomerToken = getCustomerToken;
794
795
  this.onUnauthorized = onUnauthorized;
795
796
  this.onRequestId = onRequestId;
@@ -799,9 +800,6 @@ var HttpClient = class {
799
800
  publishableKey: this.publishableKey,
800
801
  secretKey: this.secretKey
801
802
  };
802
- if (this.secretKey?.startsWith("pat01_") && this.tenantId) {
803
- opts.tenantId = this.tenantId;
804
- }
805
803
  const token = this.getCustomerToken?.();
806
804
  if (token) {
807
805
  opts.customerToken = token;
@@ -1077,8 +1075,6 @@ var INTERNAL_COLLECTIONS = [
1077
1075
  "track-assets",
1078
1076
  "audiences",
1079
1077
  "email-logs",
1080
- "tenant-auth-settings",
1081
- "tenant-community-settings",
1082
1078
  "api-usage",
1083
1079
  "tenant-analytics-daily",
1084
1080
  "analytics-event-schemas",
@@ -1092,7 +1088,8 @@ var INTERNAL_COLLECTIONS = [
1092
1088
  "webhook-deliveries",
1093
1089
  "audit-logs",
1094
1090
  "plans",
1095
- "webhooks"
1091
+ "webhooks",
1092
+ "event-registrations"
1096
1093
  ];
1097
1094
  var COLLECTIONS = [
1098
1095
  "tenants",
@@ -1126,10 +1123,10 @@ var COLLECTIONS = [
1126
1123
  "documents",
1127
1124
  "document-categories",
1128
1125
  "document-types",
1129
- "posts",
1130
- "post-authors",
1131
- "post-categories",
1132
- "post-tags",
1126
+ "articles",
1127
+ "article-authors",
1128
+ "article-categories",
1129
+ "article-tags",
1133
1130
  "playlists",
1134
1131
  "playlist-categories",
1135
1132
  "playlist-tags",
@@ -1158,14 +1155,19 @@ var COLLECTIONS = [
1158
1155
  "forms",
1159
1156
  "form-submissions",
1160
1157
  // Community
1161
- "threads",
1158
+ "posts",
1162
1159
  "comments",
1163
1160
  "reactions",
1164
1161
  "reaction-types",
1165
1162
  "bookmarks",
1166
- "thread-categories",
1163
+ "post-categories",
1167
1164
  "reports",
1168
- "community-bans"
1165
+ "community-bans",
1166
+ // Events
1167
+ "event-calendars",
1168
+ "events",
1169
+ "event-occurrences",
1170
+ "event-tags"
1169
1171
  ];
1170
1172
 
1171
1173
  // src/core/api/parse-response.ts
@@ -1219,7 +1221,6 @@ var CommunityClient = class {
1219
1221
  constructor(options) {
1220
1222
  this.publishableKey = options.publishableKey ?? "";
1221
1223
  this.secretKey = options.secretKey;
1222
- this.tenantId = options.tenantId;
1223
1224
  this.customerToken = options.customerToken;
1224
1225
  this.onUnauthorized = options.onUnauthorized;
1225
1226
  this.onRequestId = options.onRequestId;
@@ -1231,13 +1232,11 @@ var CommunityClient = class {
1231
1232
  }
1232
1233
  async execute(endpoint, method, body) {
1233
1234
  const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
1234
- const tenantId = this.secretKey?.startsWith("pat01_") && this.tenantId ? this.tenantId : void 0;
1235
1235
  try {
1236
1236
  const response = await httpFetch(endpoint, {
1237
1237
  method,
1238
1238
  publishableKey: this.publishableKey,
1239
1239
  secretKey: this.secretKey,
1240
- tenantId,
1241
1240
  customerToken: token ?? void 0,
1242
1241
  ...token && this.onUnauthorized && { onUnauthorized: this.onUnauthorized },
1243
1242
  ...body !== void 0 && { body: JSON.stringify(body) }
@@ -1250,49 +1249,48 @@ var CommunityClient = class {
1250
1249
  throw err;
1251
1250
  }
1252
1251
  }
1253
- // Threads
1254
- createThread(params) {
1255
- return this.execute("/api/threads", "POST", params);
1252
+ createPost(params) {
1253
+ return this.execute("/api/posts", "POST", params);
1256
1254
  }
1257
- getMyThreads(params) {
1255
+ getMyPosts(params) {
1258
1256
  return this.execute(
1259
- `/api/threads/my${this.buildQuery(params)}`,
1257
+ `/api/posts/my${this.buildQuery(params)}`,
1260
1258
  "GET"
1261
1259
  );
1262
1260
  }
1263
1261
  getTrending(params) {
1264
1262
  return this.execute(
1265
- `/api/threads/trending${this.buildQuery(params)}`,
1263
+ `/api/posts/trending${this.buildQuery(params)}`,
1266
1264
  "GET"
1267
1265
  );
1268
1266
  }
1269
1267
  incrementView(params) {
1270
1268
  return this.execute(
1271
- `/api/threads/${params.threadId}/view`,
1269
+ `/api/posts/${params.postId}/view`,
1272
1270
  "POST"
1273
1271
  );
1274
1272
  }
1275
- reportThread(params) {
1276
- const { threadId, ...body } = params;
1273
+ reportPost(params) {
1274
+ const { postId, ...body } = params;
1277
1275
  return this.execute(
1278
- `/api/threads/${threadId}/report`,
1276
+ `/api/posts/${postId}/report`,
1279
1277
  "POST",
1280
1278
  body
1281
1279
  );
1282
1280
  }
1283
1281
  // Comments
1284
1282
  createComment(params) {
1285
- const { threadId, parentId, body: commentBody } = params;
1286
- const body = { thread: threadId, body: commentBody };
1283
+ const { postId, parentId, body: commentBody } = params;
1284
+ const body = { post: postId, body: commentBody };
1287
1285
  if (parentId !== void 0) {
1288
1286
  body.parent = parentId;
1289
1287
  }
1290
1288
  return this.execute("/api/comments", "POST", body);
1291
1289
  }
1292
1290
  listComments(params) {
1293
- const { threadId, page, limit, rootComment } = params;
1291
+ const { postId, page, limit, rootComment } = params;
1294
1292
  const urlParams = new URLSearchParams();
1295
- urlParams.set("where[thread][equals]", threadId);
1293
+ urlParams.set("where[post][equals]", postId);
1296
1294
  urlParams.set("sort", "-createdAt");
1297
1295
  if (limit !== void 0) urlParams.set("limit", String(limit));
1298
1296
  if (page !== void 0) urlParams.set("page", String(page));
@@ -1326,16 +1324,16 @@ var CommunityClient = class {
1326
1324
  }
1327
1325
  // Reactions
1328
1326
  addReaction(params) {
1329
- const { threadId, type } = params;
1327
+ const { postId, type } = params;
1330
1328
  return this.execute("/api/reactions", "POST", {
1331
- thread: threadId,
1329
+ post: postId,
1332
1330
  type
1333
1331
  });
1334
1332
  }
1335
1333
  removeReaction(params) {
1336
- const { threadId, type } = params;
1334
+ const { postId, type } = params;
1337
1335
  return this.execute(
1338
- `/api/threads/${threadId}/react?type=${encodeURIComponent(type)}`,
1336
+ `/api/posts/${postId}/react?type=${encodeURIComponent(type)}`,
1339
1337
  "DELETE"
1340
1338
  );
1341
1339
  }
@@ -1355,7 +1353,7 @@ var CommunityClient = class {
1355
1353
  }
1356
1354
  getReactionSummary(params) {
1357
1355
  return this.execute(
1358
- `/api/threads/${params.threadId}/reactions`,
1356
+ `/api/posts/${params.postId}/reactions`,
1359
1357
  "GET"
1360
1358
  );
1361
1359
  }
@@ -1368,12 +1366,12 @@ var CommunityClient = class {
1368
1366
  // Bookmarks
1369
1367
  addBookmark(params) {
1370
1368
  return this.execute("/api/bookmarks", "POST", {
1371
- thread: params.threadId
1369
+ post: params.postId
1372
1370
  });
1373
1371
  }
1374
1372
  removeBookmark(params) {
1375
1373
  return this.execute(
1376
- `/api/threads/${params.threadId}/bookmark`,
1374
+ `/api/posts/${params.postId}/bookmark`,
1377
1375
  "DELETE"
1378
1376
  );
1379
1377
  }
@@ -1393,18 +1391,15 @@ var BaseApi = class {
1393
1391
  }
1394
1392
  this.publishableKey = options.publishableKey ?? "";
1395
1393
  this.secretKey = options.secretKey;
1396
- this.tenantId = options.tenantId;
1397
1394
  this.onRequestId = options.onRequestId;
1398
1395
  }
1399
1396
  async request(endpoint, body, options) {
1400
1397
  const method = options?.method ?? "POST";
1401
- const tenantId = this.secretKey.startsWith("pat01_") && this.tenantId ? this.tenantId : void 0;
1402
1398
  try {
1403
1399
  const response = await httpFetch(endpoint, {
1404
1400
  method,
1405
1401
  publishableKey: this.publishableKey,
1406
1402
  secretKey: this.secretKey,
1407
- tenantId,
1408
1403
  ...body !== void 0 && { body: JSON.stringify(body) },
1409
1404
  ...options?.headers && { headers: options.headers }
1410
1405
  });
@@ -1581,15 +1576,6 @@ var CustomerAuth = class {
1581
1576
  body: JSON.stringify({ currentPassword, newPassword })
1582
1577
  });
1583
1578
  }
1584
- /**
1585
- * Verify email using the verification token
1586
- */
1587
- async verifyEmail(token) {
1588
- await this.requestJson("/api/customers/verify-email", {
1589
- method: "POST",
1590
- body: JSON.stringify({ token })
1591
- });
1592
- }
1593
1579
  /**
1594
1580
  * Get the authenticated customer's orders with pagination and optional status filter
1595
1581
  */
@@ -1699,20 +1685,17 @@ var CartApi = class {
1699
1685
  }
1700
1686
  this.publishableKey = options.publishableKey ?? "";
1701
1687
  this.secretKey = options.secretKey;
1702
- this.tenantId = options.tenantId;
1703
1688
  this.customerToken = options.customerToken;
1704
1689
  this.onUnauthorized = options.onUnauthorized;
1705
1690
  this.onRequestId = options.onRequestId;
1706
1691
  }
1707
1692
  async execute(endpoint, method, body) {
1708
1693
  const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
1709
- const tenantId = this.secretKey?.startsWith("pat01_") && this.tenantId ? this.tenantId : void 0;
1710
1694
  try {
1711
1695
  const response = await httpFetch(endpoint, {
1712
1696
  method,
1713
1697
  publishableKey: this.publishableKey,
1714
1698
  secretKey: this.secretKey,
1715
- tenantId,
1716
1699
  customerToken: token ?? void 0,
1717
1700
  ...token && this.onUnauthorized && { onUnauthorized: this.onUnauthorized },
1718
1701
  ...body !== void 0 && { body: JSON.stringify(body) }
@@ -1899,7 +1882,6 @@ var ServerCommerceClient = class {
1899
1882
  const serverOptions = {
1900
1883
  publishableKey: options.publishableKey,
1901
1884
  secretKey: options.secretKey,
1902
- tenantId: options.tenantId,
1903
1885
  onRequestId: options.onRequestId
1904
1886
  };
1905
1887
  const productApi = new ProductApi(serverOptions);
@@ -2309,14 +2291,6 @@ var CustomerHooks = class {
2309
2291
  options
2310
2292
  );
2311
2293
  }
2312
- useCustomerVerifyEmail(options) {
2313
- return createMutation(
2314
- (token) => this.ensureCustomerAuth().verifyEmail(token).then(() => {
2315
- }),
2316
- options,
2317
- this.invalidateMe
2318
- );
2319
- }
2320
2294
  useCustomerRefreshToken(options) {
2321
2295
  return createMutation(
2322
2296
  () => this.ensureCustomerAuth().refreshToken(),
@@ -2361,7 +2335,6 @@ var QueryHooks = class extends CollectionHooks {
2361
2335
  this.useCustomerLogout = (...args) => this._customer.useCustomerLogout(...args);
2362
2336
  this.useCustomerForgotPassword = (...args) => this._customer.useCustomerForgotPassword(...args);
2363
2337
  this.useCustomerResetPassword = (...args) => this._customer.useCustomerResetPassword(...args);
2364
- this.useCustomerVerifyEmail = (...args) => this._customer.useCustomerVerifyEmail(...args);
2365
2338
  this.useCustomerRefreshToken = (...args) => this._customer.useCustomerRefreshToken(...args);
2366
2339
  this.useCustomerUpdateProfile = (...args) => this._customer.useCustomerUpdateProfile(...args);
2367
2340
  this.useCustomerChangePassword = (...args) => this._customer.useCustomerChangePassword(...args);
@@ -2561,7 +2534,6 @@ var ServerClient = class {
2561
2534
  const serverOptions = {
2562
2535
  publishableKey: this.config.publishableKey,
2563
2536
  secretKey: this.config.secretKey,
2564
- tenantId: this.config.tenantId,
2565
2537
  onRequestId
2566
2538
  };
2567
2539
  this.commerce = new ServerCommerceClient(serverOptions);
@@ -2578,8 +2550,7 @@ var ServerClient = class {
2578
2550
  this.config.secretKey,
2579
2551
  void 0,
2580
2552
  void 0,
2581
- onRequestId,
2582
- this.config.tenantId
2553
+ onRequestId
2583
2554
  );
2584
2555
  this.queryClient = getQueryClient();
2585
2556
  this.query = new QueryHooks(this.queryClient, this.collections);
@@ -2745,9 +2716,34 @@ var RealtimeConnection = class {
2745
2716
  function isValidWebhookEvent(data) {
2746
2717
  if (typeof data !== "object" || data === null) return false;
2747
2718
  const obj = data;
2748
- return typeof obj.collection === "string" && (obj.operation === "create" || obj.operation === "update") && typeof obj.data === "object" && obj.data !== null;
2719
+ return typeof obj.collection === "string" && typeof obj.operation === "string" && obj.operation.length > 0 && typeof obj.data === "object" && obj.data !== null;
2720
+ }
2721
+ var CUSTOMER_PASSWORD_RESET_OPERATION = "password-reset";
2722
+ function isRecord(value) {
2723
+ return typeof value === "object" && value !== null;
2724
+ }
2725
+ function hasString(value, key) {
2726
+ return typeof value[key] === "string";
2727
+ }
2728
+ function hasStringOrNumber(value, key) {
2729
+ return typeof value[key] === "string" || typeof value[key] === "number";
2730
+ }
2731
+ function isCustomerPasswordResetWebhookEvent(event) {
2732
+ if (event.collection !== "customers" || event.operation !== CUSTOMER_PASSWORD_RESET_OPERATION || !isRecord(event.data)) {
2733
+ return false;
2734
+ }
2735
+ return hasStringOrNumber(event.data, "customerId") && hasString(event.data, "email") && hasString(event.data, "name") && hasString(event.data, "resetPasswordToken") && hasString(event.data, "resetPasswordExpiresAt");
2749
2736
  }
2750
- async function verifySignature(payload, secret, signature) {
2737
+ function createCustomerAuthWebhookHandler(handlers) {
2738
+ return async (event) => {
2739
+ if (isCustomerPasswordResetWebhookEvent(event) && handlers.passwordReset) {
2740
+ await handlers.passwordReset(event.data, event);
2741
+ return;
2742
+ }
2743
+ await handlers.unhandled?.(event);
2744
+ };
2745
+ }
2746
+ async function verifySignature(payload, secret, signature, timestamp, deliveryId) {
2751
2747
  const encoder = new TextEncoder();
2752
2748
  const key = await crypto.subtle.importKey(
2753
2749
  "raw",
@@ -2762,14 +2758,35 @@ async function verifySignature(payload, secret, signature) {
2762
2758
  const sigBytes = new Uint8Array(
2763
2759
  (signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
2764
2760
  );
2765
- return crypto.subtle.verify("HMAC", key, sigBytes, encoder.encode(payload));
2761
+ return crypto.subtle.verify(
2762
+ "HMAC",
2763
+ key,
2764
+ sigBytes,
2765
+ encoder.encode(`${timestamp}.${deliveryId}.${payload}`)
2766
+ );
2767
+ }
2768
+ function timestampIsFresh(timestamp, toleranceSeconds) {
2769
+ if (!/^\d+$/.test(timestamp)) return false;
2770
+ const timestampMs = Number(timestamp);
2771
+ if (!Number.isFinite(timestampMs)) return false;
2772
+ const skewMs = Math.abs(Date.now() - timestampMs);
2773
+ return skewMs <= toleranceSeconds * 1e3;
2766
2774
  }
2767
2775
  async function handleWebhook(request, handler, options) {
2768
2776
  try {
2769
2777
  const rawBody = await request.text();
2770
2778
  if (options?.secret) {
2771
2779
  const signature = request.headers.get("x-webhook-signature") || "";
2772
- const valid = await verifySignature(rawBody, options.secret, signature);
2780
+ const timestamp = request.headers.get("x-webhook-timestamp") || "";
2781
+ const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
2782
+ const toleranceSeconds = options.toleranceSeconds ?? 300;
2783
+ const valid = Boolean(timestamp && deliveryId) && timestampIsFresh(timestamp, toleranceSeconds) && await verifySignature(
2784
+ rawBody,
2785
+ options.secret,
2786
+ signature,
2787
+ timestamp,
2788
+ deliveryId
2789
+ );
2773
2790
  if (!valid) {
2774
2791
  return new Response(
2775
2792
  JSON.stringify({ error: "Invalid webhook signature" }),