woodsportal-client-sdk 1.1.4-dev.56 → 1.1.4-dev.57

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/README.md CHANGED
@@ -225,6 +225,22 @@ export class ObjectsTableComponent {
225
225
 
226
226
  ---
227
227
 
228
+ ## Cache purge (CRM Sync)
229
+
230
+ Prefer **`POST /api/{hubId}/{portalId}/cache-purge-jobs`** over habitual `cache=false` on list reads. Requires `FEATURE_CACHE_PURGE_API_ENABLED` on the API.
231
+
232
+ | Export | Use |
233
+ |--------|-----|
234
+ | `createCachePurgeJob` | POST + optional warm job poll |
235
+ | `buildCrmListPurgeTarget` / `buildCrmSinglePurgeTarget` | List or detail scope |
236
+ | `buildEngagementPurgeTarget` | `notes` / `emails` / `files` (requires `recordIds`) |
237
+ | `purgeCrmListCache` / `purgeEngagementCaches` | Convenience wrappers returning `PurgeResult` |
238
+ | `purgeCrmObjectDataCache` | Legacy list-only boolean shorthand |
239
+
240
+ API guide: `woodsportal-api/docs/CACHE-PURGE-API.md` in the monorepo. Types: `src/types/cache-purge.ts`; helpers: `src/utils/cache/`.
241
+
242
+ ---
243
+
228
244
  ## Security & privacy
229
245
 
230
246
  - Send credentials and tokens **only over HTTPS** in production.
@@ -1,6 +1,6 @@
1
1
  import { bindStoreWithActions } from '../../chunk-Y5MRAAGK.js';
2
- import { createAdapterHooks } from '../../chunk-XZM2KSXY.js';
3
- import '../../chunk-YSASAXVN.js';
2
+ import { createAdapterHooks } from '../../chunk-YQLDJJ5M.js';
3
+ import '../../chunk-HSJU2Z2S.js';
4
4
  import '../../chunk-2SYUOWTT.js';
5
5
  import { inject, DestroyRef, signal } from '@angular/core';
6
6
 
@@ -1,5 +1,5 @@
1
- import { createAdapterHooks } from '../../chunk-XZM2KSXY.js';
2
- import '../../chunk-YSASAXVN.js';
1
+ import { createAdapterHooks } from '../../chunk-YQLDJJ5M.js';
2
+ import '../../chunk-HSJU2Z2S.js';
3
3
  import '../../chunk-2SYUOWTT.js';
4
4
  import { useSyncExternalStore } from 'react';
5
5
 
@@ -1,6 +1,6 @@
1
1
  import { bindStoreWithActions } from '../../chunk-Y5MRAAGK.js';
2
- import { createAdapterHooks } from '../../chunk-XZM2KSXY.js';
3
- import '../../chunk-YSASAXVN.js';
2
+ import { createAdapterHooks } from '../../chunk-YQLDJJ5M.js';
3
+ import '../../chunk-HSJU2Z2S.js';
4
4
  import '../../chunk-2SYUOWTT.js';
5
5
  import { reactive, onScopeDispose } from 'vue';
6
6
 
@@ -1090,7 +1090,7 @@ var Client = {
1090
1090
  },
1091
1091
  object: {
1092
1092
  list: async (payload = null, param = null) => {
1093
- param.cache = payload.cache;
1093
+ param.cache = payload?.cache !== false ? true : false;
1094
1094
  const params = { hubspotObjectTypeId: payload?.hubspotObjectTypeId };
1095
1095
  const { updateLink, getLinkParams } = useUpdateLink();
1096
1096
  const { getParamDetails: getParamDetails2 } = routeParam;
@@ -1115,7 +1115,7 @@ var Client = {
1115
1115
  "fPn": param?.filterPropertyName,
1116
1116
  "fO": param?.filterOperator,
1117
1117
  "fV": param?.filterValue,
1118
- "c": param?.cache,
1118
+ "c": param?.cache !== false,
1119
1119
  "isPC": param?.isPrimaryCompany,
1120
1120
  "v": param?.view,
1121
1121
  "l": param?.limit,
@@ -3200,6 +3200,223 @@ function formatHubSpotActivityDateTime(timestamp, timeZone = getCurrentTimeZone(
3200
3200
  return formatHubSpotActivityDateTimeParts(timestamp, timeZone)?.formatted ?? "";
3201
3201
  }
3202
3202
 
3203
+ // src/utils/cache/builders.ts
3204
+ function buildCrmListPurgeTarget(objectTypeId, listQuery) {
3205
+ return {
3206
+ domain: "crm_object_data",
3207
+ objectTypeId,
3208
+ views: ["list"],
3209
+ listQuery: listQuery ?? { page: 1, limit: 10, view: "LIST" }
3210
+ };
3211
+ }
3212
+ function buildCrmSinglePurgeTarget(objectTypeId, recordIds, listQuery) {
3213
+ return {
3214
+ domain: "crm_object_data",
3215
+ objectTypeId,
3216
+ views: ["single"],
3217
+ recordIds,
3218
+ listQuery
3219
+ };
3220
+ }
3221
+ function buildEngagementPurgeTarget(objectTypeId, recordIds, views, options) {
3222
+ if (!recordIds.length) {
3223
+ throw new Error("recordIds is required for engagement purge views");
3224
+ }
3225
+ return {
3226
+ domain: "crm_object_data",
3227
+ objectTypeId,
3228
+ recordIds,
3229
+ views,
3230
+ fileIds: options?.fileIds,
3231
+ listQuery: options?.listQuery ?? { page: 1, limit: 10 }
3232
+ };
3233
+ }
3234
+ function buildUserSessionPurgeTarget() {
3235
+ return { domain: "user_session" };
3236
+ }
3237
+ function buildPortalConfigPurgeTarget(objectTypeIds) {
3238
+ return {
3239
+ domain: "portal_object_config",
3240
+ objectTypeIds
3241
+ };
3242
+ }
3243
+ function mergePurgeTargets(...targets) {
3244
+ return targets;
3245
+ }
3246
+ function buildCachePurgeRequest(targets, options) {
3247
+ return {
3248
+ mode: options?.mode ?? "soft",
3249
+ warm: options?.warm ?? true,
3250
+ includeContactAccess: options?.includeContactAccess ?? true,
3251
+ includeShortOnHard: options?.includeShortOnHard ?? false,
3252
+ confirmPortalWide: options?.confirmPortalWide ?? false,
3253
+ targets
3254
+ };
3255
+ }
3256
+
3257
+ // src/utils/cache/createCachePurgeJob.ts
3258
+ function randomIdempotencyKey() {
3259
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
3260
+ return crypto.randomUUID();
3261
+ }
3262
+ return `purge-${Date.now()}-${Math.random().toString(36).slice(2)}`;
3263
+ }
3264
+ function mapErrorCode(status, message) {
3265
+ if (status === 400 || status === 422) {
3266
+ return "VALIDATION";
3267
+ }
3268
+ if (status === 429) {
3269
+ return "RATE_LIMITED";
3270
+ }
3271
+ if (message?.toLowerCase().includes("disabled")) {
3272
+ return "PURGE_API_DISABLED";
3273
+ }
3274
+ return status ? "UNKNOWN" : "NETWORK";
3275
+ }
3276
+ function sleep(ms) {
3277
+ return new Promise((resolve) => setTimeout(resolve, ms));
3278
+ }
3279
+ async function createCachePurgeJob(request, options = {}) {
3280
+ const idempotencyKey = options.idempotencyKey ?? randomIdempotencyKey();
3281
+ try {
3282
+ const headers = { "Idempotency-Key": idempotencyKey };
3283
+ const response = await Client.cache.purge(
3284
+ request,
3285
+ headers
3286
+ );
3287
+ const data = response?.data;
3288
+ const purgeJobId = data?.purgeJobId;
3289
+ let status = data?.status;
3290
+ if (options.waitForWarm && purgeJobId && request.warm !== false) {
3291
+ const timeout = options.pollTimeoutMs ?? 3e4;
3292
+ const interval = options.pollIntervalMs ?? 500;
3293
+ const deadline = Date.now() + timeout;
3294
+ while (Date.now() < deadline) {
3295
+ const statusRes = await Client.cache.purgeStatus(purgeJobId);
3296
+ const job = statusRes?.data;
3297
+ const jobStatus = job?.status;
3298
+ if (jobStatus === "completed") {
3299
+ status = "completed";
3300
+ break;
3301
+ }
3302
+ if (jobStatus === "failed") {
3303
+ return {
3304
+ ok: false,
3305
+ purgeJobId,
3306
+ status: "failed",
3307
+ errorCode: "WARM_FAILED",
3308
+ message: "Cache warm job failed"
3309
+ };
3310
+ }
3311
+ await sleep(interval);
3312
+ }
3313
+ if (status !== "completed") {
3314
+ return {
3315
+ ok: false,
3316
+ purgeJobId,
3317
+ status: status ?? "warming",
3318
+ errorCode: "WARM_FAILED",
3319
+ message: "Timed out waiting for cache warm job"
3320
+ };
3321
+ }
3322
+ }
3323
+ return {
3324
+ ok: true,
3325
+ purgeJobId,
3326
+ status,
3327
+ evicted: data?.evicted,
3328
+ warnings: data?.warnings
3329
+ };
3330
+ } catch (err) {
3331
+ const axiosErr = err;
3332
+ const status = axiosErr.response?.status;
3333
+ const message = axiosErr.response?.data?.message ?? (err instanceof Error ? err.message : "Cache purge request failed");
3334
+ return {
3335
+ ok: false,
3336
+ errorCode: mapErrorCode(status, message),
3337
+ message
3338
+ };
3339
+ }
3340
+ }
3341
+
3342
+ // src/utils/cache/crmCacheRefresh.ts
3343
+ async function purgeCrmObjectDataCache(options) {
3344
+ const result = await purgeCrmListCache(options);
3345
+ return result.ok;
3346
+ }
3347
+ async function purgeCrmListCache(options) {
3348
+ const objectTypeId = options.objectTypeId?.trim();
3349
+ if (!objectTypeId) {
3350
+ return { ok: false, errorCode: "VALIDATION", message: "objectTypeId is required" };
3351
+ }
3352
+ const target = buildCrmListPurgeTarget(objectTypeId, options.listQuery);
3353
+ const request = buildCachePurgeRequest([target], {
3354
+ mode: options.mode,
3355
+ warm: options.warm
3356
+ });
3357
+ return createCachePurgeJob(request, {
3358
+ idempotencyKey: options.idempotencyKey,
3359
+ waitForWarm: options.waitForWarm
3360
+ });
3361
+ }
3362
+ async function purgeCrmRecordCache(options) {
3363
+ const objectTypeId = options.objectTypeId?.trim();
3364
+ if (!objectTypeId || !options.recordIds?.length) {
3365
+ return {
3366
+ ok: false,
3367
+ errorCode: "VALIDATION",
3368
+ message: "objectTypeId and recordIds are required"
3369
+ };
3370
+ }
3371
+ const target = buildCrmSinglePurgeTarget(
3372
+ objectTypeId,
3373
+ options.recordIds,
3374
+ options.listQuery
3375
+ );
3376
+ const request = buildCachePurgeRequest([target], {
3377
+ mode: options.mode,
3378
+ warm: options.warm
3379
+ });
3380
+ return createCachePurgeJob(request, {
3381
+ idempotencyKey: options.idempotencyKey,
3382
+ waitForWarm: options.waitForWarm
3383
+ });
3384
+ }
3385
+ async function purgeEngagementCaches(options) {
3386
+ const objectTypeId = options.objectTypeId?.trim();
3387
+ if (!objectTypeId || !options.recordIds?.length || !options.views?.length) {
3388
+ return {
3389
+ ok: false,
3390
+ errorCode: "VALIDATION",
3391
+ message: "objectTypeId, recordIds, and views are required"
3392
+ };
3393
+ }
3394
+ const target = buildEngagementPurgeTarget(
3395
+ objectTypeId,
3396
+ options.recordIds,
3397
+ options.views,
3398
+ { fileIds: options.fileIds, listQuery: options.listQuery }
3399
+ );
3400
+ const request = buildCachePurgeRequest([target], {
3401
+ mode: options.mode,
3402
+ warm: options.warm
3403
+ });
3404
+ return createCachePurgeJob(request, {
3405
+ idempotencyKey: options.idempotencyKey,
3406
+ waitForWarm: options.waitForWarm
3407
+ });
3408
+ }
3409
+ async function purgeCrmCombined(options) {
3410
+ const request = buildCachePurgeRequest(options.targets, {
3411
+ mode: options.mode,
3412
+ warm: options.warm
3413
+ });
3414
+ return createCachePurgeJob(request, {
3415
+ idempotencyKey: options.idempotencyKey,
3416
+ waitForWarm: options.waitForWarm
3417
+ });
3418
+ }
3419
+
3203
3420
  // src/index.ts
3204
3421
  var api = {
3205
3422
  preLogin,
@@ -3269,6 +3486,6 @@ var routeParam = {
3269
3486
  getParamDetails
3270
3487
  };
3271
3488
 
3272
- export { DEFAULT_HUBSPOT_TIMEZONE, actions2 as actions, actions3 as actions2, actions4 as actions3, actions5 as actions4, actions6 as actions5, actions7 as actions6, api, breadcrumbsDetails, client_exports, emailStore, formatGmtOffset, formatHubSpotActivityDateTime, formatHubSpotActivityDateTimeParts, getCurrentTimeZone, getFieldErrors, getFormErrors, initializeHttpClient, multiObjectStore, normalizeToTimestamp, noteStore, routeParam, store, syncStore, tableStore2 as tableStore, uploaderStore, url };
3273
- //# sourceMappingURL=chunk-YSASAXVN.js.map
3274
- //# sourceMappingURL=chunk-YSASAXVN.js.map
3489
+ export { DEFAULT_HUBSPOT_TIMEZONE, actions2 as actions, actions3 as actions2, actions4 as actions3, actions5 as actions4, actions6 as actions5, actions7 as actions6, api, breadcrumbsDetails, buildCachePurgeRequest, buildCrmListPurgeTarget, buildCrmSinglePurgeTarget, buildEngagementPurgeTarget, buildPortalConfigPurgeTarget, buildUserSessionPurgeTarget, client_exports, createCachePurgeJob, emailStore, formatGmtOffset, formatHubSpotActivityDateTime, formatHubSpotActivityDateTimeParts, getCurrentTimeZone, getFieldErrors, getFormErrors, initializeHttpClient, mergePurgeTargets, multiObjectStore, normalizeToTimestamp, noteStore, purgeCrmCombined, purgeCrmListCache, purgeCrmObjectDataCache, purgeCrmRecordCache, purgeEngagementCaches, routeParam, store, syncStore, tableStore2 as tableStore, uploaderStore, url };
3490
+ //# sourceMappingURL=chunk-HSJU2Z2S.js.map
3491
+ //# sourceMappingURL=chunk-HSJU2Z2S.js.map