@pitcher/js-api 1.29.0 → 1.31.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/js-api.esm.js +488 -56
- package/js-api.esm.js.map +1 -1
- package/js-api.umd.min.js +32 -11
- package/js-api.umd.min.js.map +1 -1
- package/lib/ai-tasks/__tests__/weekly-focus.spec.d.ts +1 -0
- package/lib/ai-tasks/weekly-focus.d.ts +241 -0
- package/lib/apps/browser/appTypes.d.ts +28 -0
- package/lib/apps/browser/components/ContextMenu/TranslateFileButton.test.d.ts +1 -0
- package/lib/apps/browser/stores/api.d.ts +6 -1
- package/lib/apps/browser/stores/api.filesFoldersDeleter.test.d.ts +1 -0
- package/lib/apps/browser/stores/app.d.ts +5 -0
- package/lib/apps/browser/stores/app.selectionPruneScope.test.d.ts +1 -0
- package/lib/apps/browser/stores/upload.d.ts +26 -1
- package/lib/apps/browser/stores/upload.types.d.ts +9 -0
- package/lib/apps/browser/util/lifecycle.d.ts +57 -0
- package/lib/apps/browser/util/lifecycle.test.d.ts +1 -0
- package/lib/apps/canvas-builder/components/container/PopupApps/PopupAppModal.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/components/container/PresentationTools/PresentationToolsButtons.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/components/ui/BottomSheetModal/BottomSheetModal.integration.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/components/ui/BottomSheetModal/BottomSheetModal.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/components/ui/DynamicContent/section-component-bindings.util.d.ts +32 -0
- package/lib/apps/canvas-builder/components/ui/DynamicContent/useDynamicContent.d.ts +6 -0
- package/lib/apps/canvas-builder/components/ui/Link/Link.util.d.ts +8 -1
- package/lib/apps/canvas-builder/components/ui/Link/Link.util.test.d.ts +1 -0
- package/lib/apps/canvas-builder/components/ui/Multimedia/Multimedia.ldAsset.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/components/ui/SectionList/SectionItemModal.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/composables/useCanvas.d.ts +286 -10
- package/lib/apps/canvas-builder/composables/useCanvas.saveEcho.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/composables/useCanvasBlocks.d.ts +40 -2
- package/lib/apps/canvas-builder/composables/useCanvasExit.d.ts +1 -0
- package/lib/apps/canvas-builder/composables/useCanvasHistory.d.ts +38 -2
- package/lib/apps/canvas-builder/composables/useCanvasTheme.d.ts +4 -2
- package/lib/apps/canvas-builder/composables/useContentSelector.d.ts +8 -1
- package/lib/apps/canvas-builder/composables/useInstalledEmbeddables.d.ts +1 -1
- package/lib/apps/canvas-builder/composables/useNavigatorDrawer.d.ts +27 -0
- package/lib/apps/canvas-builder/composables/useNavigatorDrawer.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/composables/usePopupApps.d.ts +43 -4
- package/lib/apps/canvas-builder/composables/usePopupApps.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/composables/usePresentationTools.d.ts +112 -0
- package/lib/apps/canvas-builder/composables/usePresentationTools.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/types/canvas.d.ts +66 -3
- package/lib/apps/canvas-builder/util/canvas.util.d.ts +12 -0
- package/lib/apps/canvas-builder/util/completionWizard.util.d.ts +347 -0
- package/lib/apps/canvas-builder/util/completionWizard.util.test.d.ts +1 -0
- package/lib/apps/canvas-builder/util/fullscreenMode.util.d.ts +7 -0
- package/lib/apps/canvas-builder/util/fullscreenMode.util.test.d.ts +1 -0
- package/lib/apps/canvas-builder/util/iframe.util.d.ts +24 -2
- package/lib/apps/canvas-builder/util/iframe.util.test.d.ts +1 -0
- package/lib/apps/canvas-builder/util/lazySections.util.d.ts +35 -0
- package/lib/apps/canvas-builder/util/lazySections.util.test.d.ts +1 -0
- package/lib/apps/canvas-selector/stores/app.d.ts +14 -0
- package/lib/apps/collection-player/components/AppHeader.spec.d.ts +1 -0
- package/lib/apps/collection-player/composables/collection-navigation.util.d.ts +27 -0
- package/lib/apps/collection-player/composables/collection-navigation.util.spec.d.ts +1 -0
- package/lib/apps/collection-player/composables/speaker-notes.use.d.ts +14 -0
- package/lib/apps/collection-player/composables/speaker-notes.use.spec.d.ts +1 -0
- package/lib/apps/collection-player/stores/app.store.d.ts +8 -1
- package/lib/apps/collection-player/stores/showNotesToggle.spec.d.ts +1 -0
- package/lib/apps/content-selector/appTypes.d.ts +16 -0
- package/lib/apps/content-selector/components/Assets.uploaderRefresh.spec.d.ts +1 -0
- package/lib/apps/content-selector/components/Content/AllContent/List/expandFileGuard.spec.d.ts +1 -0
- package/lib/apps/content-selector/stores/app.d.ts +1 -1
- package/lib/apps/notes/NotesApp.accountNotes.spec.d.ts +1 -0
- package/lib/apps/notes/NotesApp.speakerNotes.spec.d.ts +1 -0
- package/lib/apps/notes/composables/useAccountNotes.d.ts +14 -0
- package/lib/apps/notes/composables/useAccountNotes.spec.d.ts +1 -0
- package/lib/apps/notes/composables/useAccountOnlyNotesGate.d.ts +21 -0
- package/lib/apps/notes/composables/useAccountOnlyNotesGate.spec.d.ts +1 -0
- package/lib/apps/notes/composables/useActiveSlideNotes.d.ts +42 -0
- package/lib/apps/notes/composables/useActiveSlideNotes.spec.d.ts +1 -0
- package/lib/components/CFileAccessManagement/collaborationApi.d.ts +2 -0
- package/lib/components/CFilePanel/Details.spec.d.ts +1 -0
- package/lib/components/CFilePanel/KeyMessages.spec.d.ts +1 -0
- package/lib/components/CFilePanel/Summary.spec.d.ts +1 -0
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.annotations.use.d.ts +5 -1
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.formFields.use.d.ts +8 -0
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.link.use.d.ts +1 -1
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.overlayItems.use.d.ts +1 -1
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.use.d.ts +4 -9
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.util.d.ts +53 -1
- package/lib/components/CFileViewer/pdf/CFileViewerFullscreen.pdf.use.d.ts +1 -1
- package/lib/components/CFileViewer/pdf/__tests__/CFileViewer.pdf.annotations.text.test.d.ts +1 -0
- package/lib/components/CGlobalLoader/CGlobalLoaderMark.spec.d.ts +1 -0
- package/lib/components/CGlobalLoader/globalLoader.paths.d.ts +2 -0
- package/lib/components/CGlobalSearch/globalSearchTarget.util.d.ts +31 -0
- package/lib/components/CGlobalSearch/globalSearchTarget.util.test.d.ts +1 -0
- package/lib/components/CRichTextEditor/extensions/paragraphExtended.d.ts +7 -1
- package/lib/components/CRichTextEditor/extensions/paragraphExtended.test.d.ts +1 -0
- package/lib/components/canvases/CanvasesManagementBulk.use.d.ts +12 -2
- package/lib/components/masterCanvases/CMasterCanvasesManagement.use.d.ts +86 -0
- package/lib/components/masterCanvases/CMasterCanvasesManagement.use.spec.d.ts +1 -0
- package/lib/components/masterCanvases/CMasterCanvasesPendingShareCell.spec.d.ts +1 -0
- package/lib/components/masterCanvases/CMasterCanvasesSharedWithCell.use.d.ts +39 -0
- package/lib/components/masterCanvases/CMasterCanvasesSharedWithCell.use.spec.d.ts +1 -0
- package/lib/components/masterCanvases/createFromMaster.use.d.ts +255 -0
- package/lib/components/masterCanvases/createFromMaster.use.spec.d.ts +1 -0
- package/lib/components/masterCanvases/masterCanvasDocuments.use.d.ts +56 -0
- package/lib/components/masterCanvases/masterCanvasDocuments.use.spec.d.ts +1 -0
- package/lib/components/masterCanvases/masterCanvasShares.use.d.ts +103 -0
- package/lib/components/masterCanvases/masterCanvasShares.use.spec.d.ts +1 -0
- package/lib/components/masterCanvases/masterFromCanvas.use.d.ts +122 -0
- package/lib/components/masterCanvases/masterFromCanvas.use.spec.d.ts +1 -0
- package/lib/components/masterCanvases/masterFromTemplate.use.d.ts +50 -0
- package/lib/components/masterCanvases/masterFromTemplate.use.spec.d.ts +1 -0
- package/lib/components/savedCanvases/CSavedCanvasesManagement.use.d.ts +204 -0
- package/lib/components/savedCanvases/savedCanvasDocuments.use.d.ts +111 -0
- package/lib/components/savedCanvases/savedCanvasDocuments.use.spec.d.ts +1 -0
- package/lib/components/savedCanvases/smartFolders/SmartFolders.use.d.ts +4 -0
- package/lib/composables/useCourseOnlyApps.d.ts +1 -1
- package/lib/composables/usePdfInterpolation.d.ts +2 -2
- package/lib/composables/useWindowEvents.d.ts +1 -1
- package/lib/constants/cdp.const.d.ts +2 -0
- package/lib/constants/translationLanguages.const.d.ts +150 -0
- package/lib/constants/translationLanguages.const.spec.d.ts +1 -0
- package/lib/main.lib.d.ts +7 -0
- package/lib/sdk/api/HighLevelApi.d.ts +19 -6
- package/lib/sdk/api/modules/ai.d.ts +43 -1
- package/lib/sdk/api/modules/ai.spec.d.ts +1 -0
- package/lib/sdk/api/modules/appsDb.d.ts +4 -4
- package/lib/sdk/api/modules/canvas.d.ts +20 -0
- package/lib/sdk/api/modules/ui/types.ui.d.ts +25 -0
- package/lib/sdk/interfaces.d.ts +31 -1
- package/lib/sdk/main.d.ts +46 -0
- package/lib/sdk/payload.types.d.ts +149 -0
- package/lib/sdk/platform.d.ts +27 -0
- package/lib/sdk/platform.spec.d.ts +1 -0
- package/lib/sdk/singleton-scope.spec.d.ts +1 -0
- package/lib/sdk/utils/httpFetch.spec.d.ts +1 -0
- package/lib/theme/canvasUiUnoPreset.test.d.ts +1 -0
- package/lib/types/ai-tasks.const.d.ts +39 -1
- package/lib/types/app.d.ts +55 -1
- package/lib/types/call.d.ts +14 -0
- package/lib/types/canvases.d.ts +15 -0
- package/lib/types/launchDarkly.types.d.ts +8 -3
- package/lib/types/organizationSettings.types.d.ts +39 -0
- package/lib/util/aiSummary.d.ts +30 -0
- package/lib/util/aiSummary.spec.d.ts +1 -0
- package/lib/util/network.d.ts +35 -0
- package/lib/util/user.d.ts +18 -0
- package/lib/util/user.test.d.ts +1 -0
- package/package.json +1 -1
- package/types/openapi/models/Canvas.d.ts +1 -0
- package/types/openapi/models/CanvasCreate.d.ts +1 -0
- package/types/openapi/models/CanvasCreateRequest.d.ts +1 -0
- package/types/openapi/models/CanvasRecommendedFile.d.ts +1 -1
- package/types/openapi/models/CanvasRetrieve.d.ts +1 -0
- package/types/openapi/models/CanvasUpdate.d.ts +1 -0
- package/types/openapi/models/CanvasUpdateRequest.d.ts +1 -0
- package/types/openapi/models/DeletedCanvas.d.ts +1 -0
- package/types/openapi/models/DeletedEnvironment.d.ts +0 -1
- package/types/openapi/models/Environment.d.ts +0 -1
- package/types/openapi/models/EnvironmentRequest.d.ts +0 -1
- package/types/openapi/models/File.d.ts +3 -1
- package/types/openapi/models/FileRetrieve.d.ts +2 -0
- package/types/openapi/models/PatchedCanvasUpdateRequest.d.ts +1 -0
- package/types/openapi/models/PatchedEnvironmentRequest.d.ts +0 -1
- package/types/openapi/models/SharedLink.d.ts +6 -0
- package/types/openapi/models/SharedLinkCreateRequest.d.ts +5 -0
package/js-api.esm.js
CHANGED
|
@@ -2385,6 +2385,261 @@ function resolvePiaSearchMode(config) {
|
|
|
2385
2385
|
return "off";
|
|
2386
2386
|
}
|
|
2387
2387
|
|
|
2388
|
+
const WINDOW_DAYS = 6;
|
|
2389
|
+
const MAX_RANK_MEETINGS = 12;
|
|
2390
|
+
const HERO_MAX_CHARS = 400;
|
|
2391
|
+
const REASON_MAX_CHARS = 140;
|
|
2392
|
+
const DEFAULT_MAX_PICKS = 5;
|
|
2393
|
+
const TITLE_MAX_CHARS = 70;
|
|
2394
|
+
const ACCOUNT_NAME_MAX_CHARS = 60;
|
|
2395
|
+
const SECTION_LABEL_MAX_CHARS = 40;
|
|
2396
|
+
const FIELD_LABEL_MAX_CHARS = 30;
|
|
2397
|
+
const FIELD_VALUE_MAX_CHARS = 60;
|
|
2398
|
+
const WEEKLY_FOCUS_RANKING_RULES = `You rank a sales rep's upcoming meetings by how much they need preparation.
|
|
2399
|
+
|
|
2400
|
+
Below are {{meeting_count}} numbered meetings, each with its account's CRM context (deals, tasks, recent calls).
|
|
2401
|
+
|
|
2402
|
+
Pick the {{max_picks}} most important. Pick fewer only if the list has fewer meetings.
|
|
2403
|
+
|
|
2404
|
+
Rules:
|
|
2405
|
+
- Highest priority first; ties go to the earlier meeting.
|
|
2406
|
+
- Strongest signals: an overdue or due-soon high-priority task, a poorly rated recent interaction, a deal closing within days. Routine meetings on healthy accounts rank last.
|
|
2407
|
+
- {{account_rule}}
|
|
2408
|
+
- Each "reason": ONE sentence, max {{reason_max_chars}} characters, only facts from the data — name the deal, task, rating, or date that makes it matter.
|
|
2409
|
+
- "hero": 1-2 sentences, max {{hero_max_chars}} characters, summarizing the week in plain business language.
|
|
2410
|
+
- Never invent facts. Never repeat field names, codes, or IDs.`;
|
|
2411
|
+
const ONE_PER_ACCOUNT_RULE = "Pick at most ONE meeting per account: when an account has several meetings, pick only its most important one.";
|
|
2412
|
+
const MULTI_PER_ACCOUNT_RULE = "Prefer spreading picks across different accounts, but you may pick two meetings on the same account when each is genuinely high priority on its own.";
|
|
2413
|
+
function effectiveMaxPicks(maxPicks) {
|
|
2414
|
+
if (typeof maxPicks !== "number" || !Number.isFinite(maxPicks)) return DEFAULT_MAX_PICKS;
|
|
2415
|
+
return Math.min(8, Math.max(1, Math.floor(maxPicks)));
|
|
2416
|
+
}
|
|
2417
|
+
function clamp(value, max) {
|
|
2418
|
+
const trimmed = value.trim();
|
|
2419
|
+
return trimmed.length > max ? trimmed.slice(0, max - 1).trimEnd() + "…" : trimmed;
|
|
2420
|
+
}
|
|
2421
|
+
function fill(template2, tokens) {
|
|
2422
|
+
return template2.replace(
|
|
2423
|
+
/\{\{(\w+)\}\}/g,
|
|
2424
|
+
(match, key) => Object.prototype.hasOwnProperty.call(tokens, key) ? tokens[key] : match
|
|
2425
|
+
);
|
|
2426
|
+
}
|
|
2427
|
+
const DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
2428
|
+
function startOfDayUtcMs(date, timeZone) {
|
|
2429
|
+
if (!timeZone) return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate());
|
|
2430
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
2431
|
+
timeZone,
|
|
2432
|
+
year: "numeric",
|
|
2433
|
+
month: "2-digit",
|
|
2434
|
+
day: "2-digit"
|
|
2435
|
+
}).formatToParts(date);
|
|
2436
|
+
const get = (type) => Number(parts.find((p) => p.type === type)?.value);
|
|
2437
|
+
return Date.UTC(get("year"), get("month") - 1, get("day"));
|
|
2438
|
+
}
|
|
2439
|
+
function daysAgo(iso, options) {
|
|
2440
|
+
const now = options?.now ?? /* @__PURE__ */ new Date();
|
|
2441
|
+
const todayMs = startOfDayUtcMs(now, options?.timeZone);
|
|
2442
|
+
const dateOnly = DATE_ONLY.exec(iso);
|
|
2443
|
+
if (dateOnly) {
|
|
2444
|
+
const [y, m, d] = [+dateOnly[1], +dateOnly[2] - 1, +dateOnly[3]];
|
|
2445
|
+
const thenMs = Date.UTC(y, m, d);
|
|
2446
|
+
const back = new Date(thenMs);
|
|
2447
|
+
if (back.getUTCFullYear() !== y || back.getUTCMonth() !== m || back.getUTCDate() !== d) return null;
|
|
2448
|
+
return Math.round((todayMs - thenMs) / 864e5);
|
|
2449
|
+
}
|
|
2450
|
+
const then = new Date(iso);
|
|
2451
|
+
if (Number.isNaN(then.getTime())) return null;
|
|
2452
|
+
return Math.round((todayMs - startOfDayUtcMs(then, options?.timeZone)) / 864e5);
|
|
2453
|
+
}
|
|
2454
|
+
function weeklyWindowMeetings(meetings, options) {
|
|
2455
|
+
const now = options?.now ?? /* @__PURE__ */ new Date();
|
|
2456
|
+
const nowMs = now.getTime();
|
|
2457
|
+
return meetings.filter((meeting) => {
|
|
2458
|
+
const days = daysAgo(meeting.meeting_time, { now, timeZone: options?.timeZone });
|
|
2459
|
+
if (days === null) return false;
|
|
2460
|
+
if (!DATE_ONLY.test(meeting.meeting_time)) {
|
|
2461
|
+
const t = new Date(meeting.meeting_time).getTime();
|
|
2462
|
+
if (Number.isNaN(t) || t <= nowMs) return false;
|
|
2463
|
+
}
|
|
2464
|
+
const offset = -days;
|
|
2465
|
+
return offset >= 0 && offset <= WINDOW_DAYS;
|
|
2466
|
+
}).sort((a, b) => sortableTime(a.meeting_time) - sortableTime(b.meeting_time));
|
|
2467
|
+
}
|
|
2468
|
+
function sortableTime(iso) {
|
|
2469
|
+
const t = Date.parse(iso);
|
|
2470
|
+
return Number.isNaN(t) ? Number.POSITIVE_INFINITY : t;
|
|
2471
|
+
}
|
|
2472
|
+
function relativeDays(days) {
|
|
2473
|
+
if (days === 0) return "today";
|
|
2474
|
+
if (days === 1) return "yesterday";
|
|
2475
|
+
if (days < 0) return days === -1 ? "tomorrow" : `in ${-days} days`;
|
|
2476
|
+
return `${days} days ago`;
|
|
2477
|
+
}
|
|
2478
|
+
function formatWhen(iso, timeZone) {
|
|
2479
|
+
if (DATE_ONLY.test(iso)) return iso;
|
|
2480
|
+
const date = new Date(iso);
|
|
2481
|
+
if (Number.isNaN(date.getTime())) return iso;
|
|
2482
|
+
const day = date.toLocaleDateString("en-US", {
|
|
2483
|
+
weekday: "short",
|
|
2484
|
+
month: "short",
|
|
2485
|
+
day: "numeric",
|
|
2486
|
+
...timeZone && { timeZone }
|
|
2487
|
+
});
|
|
2488
|
+
const time = date.toLocaleTimeString("en-US", {
|
|
2489
|
+
hour: "numeric",
|
|
2490
|
+
minute: "2-digit",
|
|
2491
|
+
...timeZone && { timeZone }
|
|
2492
|
+
});
|
|
2493
|
+
return `${day} ${time}`.trim();
|
|
2494
|
+
}
|
|
2495
|
+
function meetingBlock(index, meeting, context, options) {
|
|
2496
|
+
const when = formatWhen(meeting.meeting_time, options.timeZone);
|
|
2497
|
+
const offset = -(daysAgo(meeting.meeting_time, options) ?? 0);
|
|
2498
|
+
const day = offset === 0 ? "today" : offset === 1 ? "tomorrow" : `in ${offset} days`;
|
|
2499
|
+
const attendees = meeting.attendee_count ?? 0;
|
|
2500
|
+
const head = `${index}. "${clamp(meeting.meeting_subject, TITLE_MAX_CHARS)}" — ${clamp(meeting.account_name, ACCOUNT_NAME_MAX_CHARS)} — ${when} (${day})` + (attendees > 0 ? ` — ${attendees} attendee${attendees === 1 ? "" : "s"}` : "");
|
|
2501
|
+
const lines = [head];
|
|
2502
|
+
for (const section of context?.sections ?? []) {
|
|
2503
|
+
if (section.items.length === 0) continue;
|
|
2504
|
+
const first = section.items[0];
|
|
2505
|
+
const fieldList = first.fields ?? [];
|
|
2506
|
+
const fields = section.fields_curated && fieldList.length > 0 ? " · " + fieldList.slice(0, 3).map((f) => `${clamp(f.label, FIELD_LABEL_MAX_CHARS)}: ${clamp(f.value, FIELD_VALUE_MAX_CHARS)}`).join(" · ") : "";
|
|
2507
|
+
const age = first.days_ago != null ? ` (${relativeDays(first.days_ago)})` : "";
|
|
2508
|
+
const count = section.items.length > 1 ? `${section.items.length} records; key: ` : "";
|
|
2509
|
+
lines.push(
|
|
2510
|
+
` ${clamp(section.label, SECTION_LABEL_MAX_CHARS)}: ${count}${clamp(first.title, TITLE_MAX_CHARS)}${fields}${age}`
|
|
2511
|
+
);
|
|
2512
|
+
}
|
|
2513
|
+
return lines.join("\n");
|
|
2514
|
+
}
|
|
2515
|
+
function template(variables) {
|
|
2516
|
+
const meetings = variables.meetings;
|
|
2517
|
+
const context = variables.context ?? {};
|
|
2518
|
+
const maxPicks = effectiveMaxPicks(variables.max_picks);
|
|
2519
|
+
const onePerAccount = variables.one_per_account !== false;
|
|
2520
|
+
const options = { now: variables.now, timeZone: variables.time_zone };
|
|
2521
|
+
const blocks = meetings.map((m, i) => meetingBlock(i + 1, m, context[m.account_id], options)).join("\n");
|
|
2522
|
+
const rules = fill(variables.ranking_rules || WEEKLY_FOCUS_RANKING_RULES, {
|
|
2523
|
+
meeting_count: String(meetings.length),
|
|
2524
|
+
max_picks: String(maxPicks),
|
|
2525
|
+
reason_max_chars: String(REASON_MAX_CHARS),
|
|
2526
|
+
hero_max_chars: String(HERO_MAX_CHARS),
|
|
2527
|
+
account_rule: onePerAccount ? ONE_PER_ACCOUNT_RULE : MULTI_PER_ACCOUNT_RULE
|
|
2528
|
+
});
|
|
2529
|
+
return `${rules}
|
|
2530
|
+
|
|
2531
|
+
Answer with JSON ONLY — no other text. The object has exactly two keys:
|
|
2532
|
+
"hero": the summary as one string.
|
|
2533
|
+
"top": an array with one entry per picked meeting, highest priority first. Each entry is an object with "m" (the picked meeting's number from the list below, as an integer) and "reason" (one sentence as a string).
|
|
2534
|
+
|
|
2535
|
+
MEETINGS:
|
|
2536
|
+
${blocks}`;
|
|
2537
|
+
}
|
|
2538
|
+
function tryParse(slice) {
|
|
2539
|
+
try {
|
|
2540
|
+
return JSON.parse(slice);
|
|
2541
|
+
} catch {
|
|
2542
|
+
const repaired = slice.replace(/[“”]/g, '"').replace(/[‘’]/g, "'").replace(/,\s*([}\]])/g, "$1");
|
|
2543
|
+
try {
|
|
2544
|
+
return JSON.parse(repaired);
|
|
2545
|
+
} catch {
|
|
2546
|
+
return null;
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
function looksLikeResponse(o) {
|
|
2551
|
+
return Array.isArray(o.top);
|
|
2552
|
+
}
|
|
2553
|
+
function extractJson(raw) {
|
|
2554
|
+
let fallback = null;
|
|
2555
|
+
for (let start = raw.indexOf("{"); start !== -1; start = raw.indexOf("{", start + 1)) {
|
|
2556
|
+
let depth = 0;
|
|
2557
|
+
let inString = false;
|
|
2558
|
+
let escaped = false;
|
|
2559
|
+
for (let i = start; i < raw.length; i++) {
|
|
2560
|
+
const ch = raw[i];
|
|
2561
|
+
if (inString) {
|
|
2562
|
+
if (escaped) escaped = false;
|
|
2563
|
+
else if (ch === "\\") escaped = true;
|
|
2564
|
+
else if (ch === '"') inString = false;
|
|
2565
|
+
} else if (ch === '"') {
|
|
2566
|
+
inString = true;
|
|
2567
|
+
} else if (ch === "{") {
|
|
2568
|
+
depth += 1;
|
|
2569
|
+
} else if (ch === "}") {
|
|
2570
|
+
depth -= 1;
|
|
2571
|
+
if (depth === 0) {
|
|
2572
|
+
const parsed = tryParse(raw.slice(start, i + 1));
|
|
2573
|
+
if (parsed) {
|
|
2574
|
+
if (looksLikeResponse(parsed)) return parsed;
|
|
2575
|
+
if (!fallback) fallback = parsed;
|
|
2576
|
+
}
|
|
2577
|
+
break;
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
return fallback;
|
|
2583
|
+
}
|
|
2584
|
+
function normalizeWeeklyFocus(parsed) {
|
|
2585
|
+
const raw = parsed ?? {};
|
|
2586
|
+
const top = [];
|
|
2587
|
+
if (Array.isArray(raw.top)) {
|
|
2588
|
+
for (const pick of raw.top) {
|
|
2589
|
+
const m = typeof pick?.m === "number" ? pick.m : Number(pick?.m);
|
|
2590
|
+
const reason = typeof pick?.reason === "string" ? pick.reason.trim() : "";
|
|
2591
|
+
if (!Number.isInteger(m) || !reason) continue;
|
|
2592
|
+
top.push({ m, reason: clamp(reason, REASON_MAX_CHARS) });
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
const hero = typeof raw.hero === "string" ? clamp(raw.hero, HERO_MAX_CHARS) : "";
|
|
2596
|
+
return { hero, top };
|
|
2597
|
+
}
|
|
2598
|
+
function extractWeeklyFocus(rawText) {
|
|
2599
|
+
const parsed = extractJson(rawText ?? "");
|
|
2600
|
+
if (!parsed) return { hero: "", top: [] };
|
|
2601
|
+
return normalizeWeeklyFocus(parsed);
|
|
2602
|
+
}
|
|
2603
|
+
function resolveWeeklyFocusPicks(output, rankedMeetings, options = {}) {
|
|
2604
|
+
const maxPicks = effectiveMaxPicks(options.maxPicks);
|
|
2605
|
+
const onePerAccount = options.onePerAccount !== false;
|
|
2606
|
+
const windowCount = options.windowCount ?? rankedMeetings.length;
|
|
2607
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2608
|
+
const pickedAccounts = /* @__PURE__ */ new Set();
|
|
2609
|
+
const top = [];
|
|
2610
|
+
let dropped = 0;
|
|
2611
|
+
for (const pick of output.top ?? []) {
|
|
2612
|
+
const meeting = Number.isInteger(pick.m) ? rankedMeetings[pick.m - 1] : void 0;
|
|
2613
|
+
const reason = typeof pick.reason === "string" ? pick.reason.trim() : "";
|
|
2614
|
+
if (!meeting || !reason || seen.has(meeting.event_id)) {
|
|
2615
|
+
dropped += 1;
|
|
2616
|
+
continue;
|
|
2617
|
+
}
|
|
2618
|
+
if (onePerAccount && pickedAccounts.has(meeting.account_id)) {
|
|
2619
|
+
dropped += 1;
|
|
2620
|
+
continue;
|
|
2621
|
+
}
|
|
2622
|
+
seen.add(meeting.event_id);
|
|
2623
|
+
pickedAccounts.add(meeting.account_id);
|
|
2624
|
+
top.push({ event_id: meeting.event_id, rank: top.length + 1, reason: clamp(reason, REASON_MAX_CHARS) });
|
|
2625
|
+
if (top.length >= maxPicks) break;
|
|
2626
|
+
}
|
|
2627
|
+
return { top, collapsed_count: Math.max(0, windowCount - top.length), dropped };
|
|
2628
|
+
}
|
|
2629
|
+
function weeklyFocusTarget(rankedMeetings, options = {}) {
|
|
2630
|
+
const onePerAccount = options.onePerAccount !== false;
|
|
2631
|
+
const ceiling = onePerAccount ? new Set(rankedMeetings.map((m) => m.account_id)).size : rankedMeetings.length;
|
|
2632
|
+
return Math.min(effectiveMaxPicks(options.maxPicks), ceiling);
|
|
2633
|
+
}
|
|
2634
|
+
function prepareWeeklyFocusMeetings(meetings, options) {
|
|
2635
|
+
const windowMeetings = weeklyWindowMeetings(meetings, options);
|
|
2636
|
+
return {
|
|
2637
|
+
windowMeetings,
|
|
2638
|
+
rankedMeetings: windowMeetings.slice(0, MAX_RANK_MEETINGS),
|
|
2639
|
+
windowCount: windowMeetings.length
|
|
2640
|
+
};
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2388
2643
|
const PIA_SEARCH_ROUTE = "/core/api/protected/pia-prepare/pia-search";
|
|
2389
2644
|
const CAPABILITIES_TIMEOUT_MS = 3e3;
|
|
2390
2645
|
const ON_DEVICE_MAX_TOKENS = 512;
|
|
@@ -2419,6 +2674,32 @@ function apiOriginFromEnv(env) {
|
|
|
2419
2674
|
if (typeof orgDomain === "string" && orgDomain.length > 0) return normalizeOrigin(orgDomain);
|
|
2420
2675
|
throw new Error("piaSearchAnswer: no customer domain found in env (token_claims / organization metadata)");
|
|
2421
2676
|
}
|
|
2677
|
+
async function postJsonWithTimeout(url, body, accessToken, timeoutMs, label) {
|
|
2678
|
+
const controller = new AbortController();
|
|
2679
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2680
|
+
try {
|
|
2681
|
+
const response = await fetch(url, {
|
|
2682
|
+
method: "POST",
|
|
2683
|
+
signal: controller.signal,
|
|
2684
|
+
headers: {
|
|
2685
|
+
"Content-Type": "application/json",
|
|
2686
|
+
Authorization: `Bearer ${accessToken}`
|
|
2687
|
+
},
|
|
2688
|
+
body: JSON.stringify(body)
|
|
2689
|
+
});
|
|
2690
|
+
if (!response.ok) {
|
|
2691
|
+
throw new Error(`${label} ${response.status}`);
|
|
2692
|
+
}
|
|
2693
|
+
return await response.json();
|
|
2694
|
+
} catch (error) {
|
|
2695
|
+
if (error?.name === "AbortError") {
|
|
2696
|
+
throw new Error(`${label} online request timed out after ${timeoutMs}ms`);
|
|
2697
|
+
}
|
|
2698
|
+
throw error;
|
|
2699
|
+
} finally {
|
|
2700
|
+
clearTimeout(timer);
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2422
2703
|
function buildOnDevicePrompt(query, contextText) {
|
|
2423
2704
|
const context = typeof contextText === "string" && contextText.trim().length > 0 ? contextText.trim() : "No content context was provided.";
|
|
2424
2705
|
return `You are PIA, a sales content assistant. Answer the rep's question using ONLY the CONTEXT below — do not invent content that is not in it.
|
|
@@ -2428,7 +2709,7 @@ ${context}
|
|
|
2428
2709
|
|
|
2429
2710
|
QUESTION: ${query}
|
|
2430
2711
|
|
|
2431
|
-
Answer concisely in plain text. If the context does not contain the answer, say you could not find it in the available content.`;
|
|
2712
|
+
Answer concisely in plain text. If the context does not contain the answer, say you could not find it in the available content. Refer to content by its name only — do not include any file ids or codes in your answer.`;
|
|
2432
2713
|
}
|
|
2433
2714
|
async function aiGetCapabilities() {
|
|
2434
2715
|
const env = await highLevelApi.API.request("get_env");
|
|
@@ -2443,6 +2724,17 @@ function aiComplete(payload) {
|
|
|
2443
2724
|
}
|
|
2444
2725
|
return highLevelApi.API.request("ai.complete", payload);
|
|
2445
2726
|
}
|
|
2727
|
+
function asCitations(value) {
|
|
2728
|
+
if (!Array.isArray(value)) return void 0;
|
|
2729
|
+
const citations = value.flatMap((entry) => {
|
|
2730
|
+
if (!entry || typeof entry !== "object") return [];
|
|
2731
|
+
const { file_id: fileId, page_indices: pageIndices } = entry;
|
|
2732
|
+
if (typeof fileId !== "string" || fileId === "" || !Array.isArray(pageIndices)) return [];
|
|
2733
|
+
const pages = pageIndices.filter((page) => Number.isInteger(page) && page >= 0);
|
|
2734
|
+
return pages.length > 0 ? [{ file_id: fileId, page_indices: pages }] : [];
|
|
2735
|
+
});
|
|
2736
|
+
return citations.length > 0 ? citations : void 0;
|
|
2737
|
+
}
|
|
2446
2738
|
async function piaSearchAnswer(payload) {
|
|
2447
2739
|
if (!payload || typeof payload.query !== "string" || payload.query.trim() === "") {
|
|
2448
2740
|
return Promise.reject(new Error("query is required and must be a non-empty string"));
|
|
@@ -2474,41 +2766,152 @@ async function piaSearchAnswer(payload) {
|
|
|
2474
2766
|
if (!instanceId) {
|
|
2475
2767
|
throw new Error("piaSearchAnswer: instance_id could not be resolved from the payload or env");
|
|
2476
2768
|
}
|
|
2477
|
-
const
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
}
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2769
|
+
const data = await postJsonWithTimeout(
|
|
2770
|
+
`${apiOriginFromEnv(env)}${PIA_SEARCH_ROUTE}`,
|
|
2771
|
+
{
|
|
2772
|
+
query: payload.query,
|
|
2773
|
+
instance_id: instanceId,
|
|
2774
|
+
...Array.isArray(payload.file_ids) && payload.file_ids.length > 0 && { file_ids: payload.file_ids },
|
|
2775
|
+
...payload.include_document_text === true && { include_document_text: true },
|
|
2776
|
+
...Array.isArray(payload.expansion_terms) && payload.expansion_terms.length > 0 && { expansion_terms: payload.expansion_terms }
|
|
2777
|
+
},
|
|
2778
|
+
env.pitcher.access_token,
|
|
2779
|
+
ONLINE_TIMEOUT_MS,
|
|
2780
|
+
"pia_search"
|
|
2781
|
+
);
|
|
2782
|
+
const output = data?.pia_search ?? {};
|
|
2783
|
+
const citations = asCitations(output.citations);
|
|
2784
|
+
return {
|
|
2785
|
+
answer: typeof output.answer === "string" ? output.answer : "",
|
|
2786
|
+
cited_file_ids: Array.isArray(output.cited_file_ids) ? output.cited_file_ids : [],
|
|
2787
|
+
...citations && { citations },
|
|
2788
|
+
...output.confidence && { confidence: output.confidence },
|
|
2789
|
+
source: "online"
|
|
2790
|
+
};
|
|
2791
|
+
}
|
|
2792
|
+
const WEEKLY_FOCUS_ROUTE = "/core/api/protected/pia-prepare/weekly-focus";
|
|
2793
|
+
const weeklyFocusOutputReserve = (maxPicks) => 220 + 60 * maxPicks;
|
|
2794
|
+
const ON_DEVICE_COMPLETE_TIMEOUT_MS = 12e4;
|
|
2795
|
+
async function weeklyFocusRank(payload) {
|
|
2796
|
+
if (!payload || !Array.isArray(payload.meetings)) {
|
|
2797
|
+
return Promise.reject(new Error("meetings is required and must be an array"));
|
|
2798
|
+
}
|
|
2799
|
+
const env = await highLevelApi.API.request("get_env");
|
|
2800
|
+
const timeZone = payload.time_zone || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
2801
|
+
const { windowMeetings, rankedMeetings, windowCount } = prepareWeeklyFocusMeetings(payload.meetings, { timeZone });
|
|
2802
|
+
if (rankedMeetings.length === 0) {
|
|
2803
|
+
return { hero: "", top: [], collapsed_count: 0, source: env?.mode === "IOS" ? "on_device" : "online" };
|
|
2804
|
+
}
|
|
2805
|
+
const maxPicks = effectiveMaxPicks(payload.max_picks);
|
|
2806
|
+
const resolveOptions = {
|
|
2807
|
+
maxPicks,
|
|
2808
|
+
onePerAccount: payload.one_per_account,
|
|
2809
|
+
windowCount
|
|
2810
|
+
};
|
|
2811
|
+
if (env?.mode === "IOS") {
|
|
2812
|
+
try {
|
|
2813
|
+
const capabilities = await withTimeout(
|
|
2814
|
+
highLevelApi.API.request("ai.get_capabilities"),
|
|
2815
|
+
CAPABILITIES_TIMEOUT_MS,
|
|
2816
|
+
"ai.get_capabilities"
|
|
2817
|
+
);
|
|
2818
|
+
if (capabilities?.available) {
|
|
2819
|
+
const prompt = template({
|
|
2820
|
+
meetings: rankedMeetings,
|
|
2821
|
+
context: payload.context,
|
|
2822
|
+
max_picks: maxPicks,
|
|
2823
|
+
one_per_account: payload.one_per_account,
|
|
2824
|
+
time_zone: timeZone
|
|
2825
|
+
});
|
|
2826
|
+
const runOnce = async () => {
|
|
2827
|
+
const completion = await withTimeout(
|
|
2828
|
+
aiComplete({ prompt, max_tokens: weeklyFocusOutputReserve(maxPicks) }),
|
|
2829
|
+
ON_DEVICE_COMPLETE_TIMEOUT_MS,
|
|
2830
|
+
"ai.complete"
|
|
2831
|
+
);
|
|
2832
|
+
const parsed2 = extractWeeklyFocus(completion.text);
|
|
2833
|
+
return { parsed: parsed2, resolved: resolveWeeklyFocusPicks(parsed2, rankedMeetings, resolveOptions) };
|
|
2834
|
+
};
|
|
2835
|
+
let attempt = await runOnce();
|
|
2836
|
+
if (attempt.resolved.top.length < weeklyFocusTarget(rankedMeetings, resolveOptions)) {
|
|
2837
|
+
try {
|
|
2838
|
+
const second = await runOnce();
|
|
2839
|
+
if (second.resolved.top.length > attempt.resolved.top.length) attempt = second;
|
|
2840
|
+
} catch (error) {
|
|
2841
|
+
console.warn("[weeklyFocusRank] on-device retry failed, keeping the first attempt:", error);
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
const { parsed, resolved } = attempt;
|
|
2845
|
+
if (resolved.top.length > 0 || parsed.hero) {
|
|
2846
|
+
return {
|
|
2847
|
+
hero: parsed.hero,
|
|
2848
|
+
top: resolved.top,
|
|
2849
|
+
collapsed_count: resolved.collapsed_count,
|
|
2850
|
+
source: "on_device"
|
|
2851
|
+
};
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
} catch (error) {
|
|
2855
|
+
console.warn("[weeklyFocusRank] on-device path unavailable, falling back to online:", error);
|
|
2507
2856
|
}
|
|
2508
|
-
throw error;
|
|
2509
|
-
} finally {
|
|
2510
|
-
clearTimeout(timer);
|
|
2511
2857
|
}
|
|
2858
|
+
const instanceId = payload.instance_id || env?.pitcher?.instance?.id;
|
|
2859
|
+
if (!instanceId) {
|
|
2860
|
+
throw new Error("weeklyFocusRank: instance_id could not be resolved from the payload or env");
|
|
2861
|
+
}
|
|
2862
|
+
const data = await postJsonWithTimeout(
|
|
2863
|
+
`${apiOriginFromEnv(env)}${WEEKLY_FOCUS_ROUTE}`,
|
|
2864
|
+
{
|
|
2865
|
+
instance_id: instanceId,
|
|
2866
|
+
// Send the WINDOW, not the caller's whole calendar. The route re-windows
|
|
2867
|
+
// anyway (idempotent — same rule, same zone), so this only drops meetings
|
|
2868
|
+
// it would have dropped, while keeping `collapsed_count` correct: the route
|
|
2869
|
+
// derives the window size from what it receives, so sending the
|
|
2870
|
+
// already-capped 12 would understate it. It also keeps a caller with a long
|
|
2871
|
+
// history from tripping the route's 500-meeting body cap over meetings
|
|
2872
|
+
// outside the week entirely.
|
|
2873
|
+
meetings: windowMeetings,
|
|
2874
|
+
time_zone: timeZone,
|
|
2875
|
+
...payload.context && { context: payload.context },
|
|
2876
|
+
// Clamped, not raw: the route 400s on out-of-range values.
|
|
2877
|
+
...payload.max_picks !== void 0 && { max_picks: maxPicks },
|
|
2878
|
+
...payload.one_per_account !== void 0 && { one_per_account: payload.one_per_account }
|
|
2879
|
+
},
|
|
2880
|
+
env.pitcher.access_token,
|
|
2881
|
+
ONLINE_TIMEOUT_MS,
|
|
2882
|
+
"weekly_focus"
|
|
2883
|
+
);
|
|
2884
|
+
const output = data?.weekly_focus ?? {};
|
|
2885
|
+
return {
|
|
2886
|
+
hero: typeof output.hero === "string" ? output.hero : "",
|
|
2887
|
+
top: Array.isArray(output.top) ? output.top : [],
|
|
2888
|
+
collapsed_count: typeof output.collapsed_count === "number" ? output.collapsed_count : 0,
|
|
2889
|
+
source: "online"
|
|
2890
|
+
};
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
const PLATFORM_TYPE = {
|
|
2894
|
+
web: "web",
|
|
2895
|
+
ios: "ios",
|
|
2896
|
+
android: "android",
|
|
2897
|
+
windows: "windows",
|
|
2898
|
+
macos: "macos"
|
|
2899
|
+
};
|
|
2900
|
+
|
|
2901
|
+
const WEB_MODE = "WEB";
|
|
2902
|
+
function isNativeHost(mode) {
|
|
2903
|
+
return typeof mode === "string" && mode !== "" && mode !== WEB_MODE;
|
|
2904
|
+
}
|
|
2905
|
+
const PLATFORM_TYPE_BY_MODE = {
|
|
2906
|
+
WEB: PLATFORM_TYPE.web,
|
|
2907
|
+
IOS: PLATFORM_TYPE.ios,
|
|
2908
|
+
MACOS: PLATFORM_TYPE.macos,
|
|
2909
|
+
WINDOWS: PLATFORM_TYPE.windows,
|
|
2910
|
+
ANDROID: PLATFORM_TYPE.android
|
|
2911
|
+
};
|
|
2912
|
+
function platformTypeForMode(mode) {
|
|
2913
|
+
if (!mode) return void 0;
|
|
2914
|
+
return Object.prototype.hasOwnProperty.call(PLATFORM_TYPE_BY_MODE, mode) ? PLATFORM_TYPE_BY_MODE[mode] : void 0;
|
|
2512
2915
|
}
|
|
2513
2916
|
|
|
2514
2917
|
const APPS_DB_BASE_PATH = "/core/api/protected/appsdb";
|
|
@@ -2519,7 +2922,7 @@ async function fetchAppsDbContext() {
|
|
|
2519
2922
|
let origin = claimsDomain || metadataDomain || "";
|
|
2520
2923
|
if (origin && !origin.startsWith("http")) origin = `https://${origin}`;
|
|
2521
2924
|
return {
|
|
2522
|
-
|
|
2925
|
+
isNative: isNativeHost(env?.mode ?? env?.pitcher?.mode),
|
|
2523
2926
|
origin,
|
|
2524
2927
|
accessToken: env?.pitcher?.access_token ?? "",
|
|
2525
2928
|
instanceId: env?.pitcher?.instance?.id
|
|
@@ -2658,7 +3061,7 @@ async function appsDbGetEntries(payload) {
|
|
|
2658
3061
|
return Promise.reject(new Error("type is required and must be a non-empty string"));
|
|
2659
3062
|
}
|
|
2660
3063
|
const ctx = await getAppsDbContext();
|
|
2661
|
-
if (ctx.
|
|
3064
|
+
if (ctx.isNative) {
|
|
2662
3065
|
try {
|
|
2663
3066
|
return await highLevelApi.API.request("appsdb_get_entries", payload);
|
|
2664
3067
|
} catch (error) {
|
|
@@ -2675,7 +3078,7 @@ async function appsDbUpsertEntry(payload) {
|
|
|
2675
3078
|
return Promise.reject(new Error("type is required when creating an entry (no id provided)"));
|
|
2676
3079
|
}
|
|
2677
3080
|
const ctx = await getAppsDbContext();
|
|
2678
|
-
if (ctx.
|
|
3081
|
+
if (ctx.isNative) {
|
|
2679
3082
|
try {
|
|
2680
3083
|
return await highLevelApi.API.request("appsdb_upsert_entry", payload);
|
|
2681
3084
|
} catch (error) {
|
|
@@ -2692,7 +3095,7 @@ async function appsDbDeleteEntry(payload) {
|
|
|
2692
3095
|
return Promise.reject(new Error("id is required and must be a non-empty string"));
|
|
2693
3096
|
}
|
|
2694
3097
|
const ctx = await getAppsDbContext();
|
|
2695
|
-
if (ctx.
|
|
3098
|
+
if (ctx.isNative) {
|
|
2696
3099
|
try {
|
|
2697
3100
|
return await highLevelApi.API.request("appsdb_delete_entry", payload);
|
|
2698
3101
|
} catch (error) {
|
|
@@ -2735,7 +3138,7 @@ async function appsDbPsql(payload) {
|
|
|
2735
3138
|
return Promise.reject(new Error("query is required and must be a non-empty string"));
|
|
2736
3139
|
}
|
|
2737
3140
|
const ctx = await getAppsDbContext();
|
|
2738
|
-
if (ctx.
|
|
3141
|
+
if (ctx.isNative) {
|
|
2739
3142
|
const parsed = parseSimplePsql(payload.query);
|
|
2740
3143
|
let mirrorUnavailable = false;
|
|
2741
3144
|
if (parsed && await isDeviceOffline()) {
|
|
@@ -3871,6 +4274,7 @@ const modules = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
|
3871
4274
|
openWebViewAlwaysOnTop,
|
|
3872
4275
|
patchCoreFolder,
|
|
3873
4276
|
piaSearchAnswer,
|
|
4277
|
+
postJsonWithTimeout,
|
|
3874
4278
|
query,
|
|
3875
4279
|
refreshAccessToken,
|
|
3876
4280
|
refreshServiceToken,
|
|
@@ -3898,7 +4302,8 @@ const modules = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
|
3898
4302
|
updateCanvasIndicators,
|
|
3899
4303
|
updateFile,
|
|
3900
4304
|
updateFolder,
|
|
3901
|
-
updateMyUser
|
|
4305
|
+
updateMyUser,
|
|
4306
|
+
weeklyFocusRank
|
|
3902
4307
|
}, Symbol.toStringTag, { value: 'Module' }));
|
|
3903
4308
|
|
|
3904
4309
|
class EventEmitter {
|
|
@@ -4177,24 +4582,32 @@ function paramsSerializer(params) {
|
|
|
4177
4582
|
}
|
|
4178
4583
|
return searchParams.toString();
|
|
4179
4584
|
}
|
|
4585
|
+
function isNonRetryableStatus(status) {
|
|
4586
|
+
if (typeof status !== "number") return false;
|
|
4587
|
+
if (status >= 200 && status < 300) return true;
|
|
4588
|
+
return status >= 400 && status < 500;
|
|
4589
|
+
}
|
|
4180
4590
|
async function fetchWithRetry(url, options, remainingRetries = MAX_RETRIES) {
|
|
4181
4591
|
try {
|
|
4182
4592
|
const response = await fetch(url, options);
|
|
4183
4593
|
if (!response.ok) {
|
|
4184
|
-
if (response.status === 401) {
|
|
4594
|
+
if (response.status === 401 && remainingRetries > 0) {
|
|
4185
4595
|
const newToken = await refreshToken();
|
|
4186
4596
|
options.headers = options.headers || {};
|
|
4187
4597
|
options.headers.Authorization = `Bearer ${newToken}`;
|
|
4188
|
-
return fetchWithRetry(url, options, remainingRetries);
|
|
4598
|
+
return fetchWithRetry(url, options, remainingRetries - 1);
|
|
4189
4599
|
} else if (response.status >= 500 && response.status < 600 && remainingRetries > 0) {
|
|
4190
4600
|
const delay = BASE_DELAY * Math.pow(2, MAX_RETRIES - remainingRetries);
|
|
4191
4601
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
4192
4602
|
return fetchWithRetry(url, options, remainingRetries - 1);
|
|
4193
4603
|
} else {
|
|
4194
|
-
const
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4604
|
+
const raw = await response.text().catch(() => "");
|
|
4605
|
+
let message = response.statusText;
|
|
4606
|
+
try {
|
|
4607
|
+
message = JSON.parse(raw)?.message || response.statusText;
|
|
4608
|
+
} catch {
|
|
4609
|
+
}
|
|
4610
|
+
const error = new Error(`HTTP error! status: ${response.status}, message: ${message}`);
|
|
4198
4611
|
error.status = response.status;
|
|
4199
4612
|
throw error;
|
|
4200
4613
|
}
|
|
@@ -4202,9 +4615,23 @@ async function fetchWithRetry(url, options, remainingRetries = MAX_RETRIES) {
|
|
|
4202
4615
|
if (response.status === 204 || response.status === 205) {
|
|
4203
4616
|
return;
|
|
4204
4617
|
}
|
|
4205
|
-
|
|
4618
|
+
const body = await response.text();
|
|
4619
|
+
if (!body) {
|
|
4620
|
+
const error = new Error(
|
|
4621
|
+
`Empty response body for status ${response.status} (expected JSON)`
|
|
4622
|
+
);
|
|
4623
|
+
error.status = response.status;
|
|
4624
|
+
throw error;
|
|
4625
|
+
}
|
|
4626
|
+
try {
|
|
4627
|
+
return JSON.parse(body);
|
|
4628
|
+
} catch (parseError) {
|
|
4629
|
+
;
|
|
4630
|
+
parseError.status = response.status;
|
|
4631
|
+
throw parseError;
|
|
4632
|
+
}
|
|
4206
4633
|
} catch (error) {
|
|
4207
|
-
if (remainingRetries > 0 && !(error instanceof TypeError) && error.status
|
|
4634
|
+
if (remainingRetries > 0 && !(error instanceof TypeError) && !isNonRetryableStatus(error.status)) {
|
|
4208
4635
|
const delay = BASE_DELAY * Math.pow(2, MAX_RETRIES - remainingRetries);
|
|
4209
4636
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
4210
4637
|
return fetchWithRetry(url, options, remainingRetries - 1);
|
|
@@ -4380,16 +4807,17 @@ const onlineRestApiHandlers = {
|
|
|
4380
4807
|
},
|
|
4381
4808
|
update_canvas: async (params) => {
|
|
4382
4809
|
check();
|
|
4383
|
-
const { id, fields, ...canvasData } = params;
|
|
4810
|
+
const { id, fields, lazy_sections, ...canvasData } = params;
|
|
4811
|
+
const lazyQs = lazy_sections === true ? "lazy_sections=true" : "";
|
|
4384
4812
|
const useCoreEndpoint = env?.launch_darkly?.enable_canvas_core_patch === true;
|
|
4385
4813
|
if (useCoreEndpoint) {
|
|
4386
4814
|
const origin = env.pitcher.token_claims["https://pitcher.com/claims/urls"].custom_domain;
|
|
4387
|
-
const
|
|
4388
|
-
const url = `${origin}/core/api/protected/v1/canvases/${id}${
|
|
4815
|
+
const qs = [fields ? `fields=${encodeURIComponent(fields)}` : "", lazyQs].filter(Boolean).join("&");
|
|
4816
|
+
const url = `${origin}/core/api/protected/v1/canvases/${id}${qs ? `?${qs}` : ""}`;
|
|
4389
4817
|
const res2 = await http.patchUrl(url, canvasData);
|
|
4390
4818
|
return res2;
|
|
4391
4819
|
}
|
|
4392
|
-
const res = await http.patch(`/canvases/${id}`, { fields, ...canvasData });
|
|
4820
|
+
const res = await http.patch(`/canvases/${id}${lazyQs ? `?${lazyQs}` : ""}`, { fields, ...canvasData });
|
|
4393
4821
|
return res;
|
|
4394
4822
|
},
|
|
4395
4823
|
delete_canvas: async (params) => {
|
|
@@ -4405,7 +4833,8 @@ const onlineRestApiHandlers = {
|
|
|
4405
4833
|
} catch (e) {
|
|
4406
4834
|
if (e?.status === 404) {
|
|
4407
4835
|
link = await http.post("/shared-links", {
|
|
4408
|
-
canvas_id: params.id
|
|
4836
|
+
canvas_id: params.id,
|
|
4837
|
+
...params.brand_id ? { brand_id: params.brand_id } : {}
|
|
4409
4838
|
});
|
|
4410
4839
|
} else {
|
|
4411
4840
|
throw e;
|
|
@@ -5500,12 +5929,15 @@ async function sendPeerConnectivityEvent(payload, options) {
|
|
|
5500
5929
|
let highLevelApi;
|
|
5501
5930
|
let prevOptions;
|
|
5502
5931
|
function usePitcherApi(options) {
|
|
5503
|
-
if (!highLevelApi || !isEqual(options, prevOptions)) {
|
|
5932
|
+
if (!highLevelApi || options !== void 0 && !isEqual(options, prevOptions)) {
|
|
5504
5933
|
highLevelApi = createHighLevelApi(options);
|
|
5505
|
-
prevOptions = options;
|
|
5934
|
+
prevOptions = options === void 0 ? void 0 : { ...options };
|
|
5506
5935
|
}
|
|
5507
5936
|
return highLevelApi;
|
|
5508
5937
|
}
|
|
5938
|
+
function createScopedPitcherApi(options) {
|
|
5939
|
+
return createHighLevelApi({ ...prevOptions, ...options });
|
|
5940
|
+
}
|
|
5509
5941
|
function enhanceWithSnakeCase(api) {
|
|
5510
5942
|
Object.entries(api).forEach(([key, value]) => {
|
|
5511
5943
|
const newKey = snakeCase(key);
|
|
@@ -5553,5 +5985,5 @@ function useApi(options) {
|
|
|
5553
5985
|
|
|
5554
5986
|
window.postRobot = pr;
|
|
5555
5987
|
|
|
5556
|
-
export { ADMIN_API_METHOD_TYPES, ADMIN_API_TYPES, ADMIN_MESSAGE, ADMIN_MESSAGE_TYPES, DEFAULT_PEER_CONNECTIVITY_VERSION, DSR_API_METHOD_TYPES, DSR_API_TYPES, DSR_MESSAGE, DSR_MESSAGE_TYPES, PEER_CONNECTIVITY_EVENT, PEER_CONNECTIVITY_HANDLER_MATCH_ALL, PITCHER_EVENT, PeerConnectivityActions, PitcherBroadcastedEventName, PitcherEventName, PitcherExternalEventName, PitcherMessageType, PitcherResponseStatus, UI_API_METHOD_TYPES, UI_MESSAGE, UI_MESSAGE_TYPES, UI_NATIVE_MESSAGE_TYPES, getAvailableApis, highLevelApi, registerPeerConnectivityHandler, sendPeerConnectivityEvent, useAdmin, useApi, useDsr, usePitcherApi, useUi };
|
|
5988
|
+
export { ADMIN_API_METHOD_TYPES, ADMIN_API_TYPES, ADMIN_MESSAGE, ADMIN_MESSAGE_TYPES, DEFAULT_PEER_CONNECTIVITY_VERSION, DSR_API_METHOD_TYPES, DSR_API_TYPES, DSR_MESSAGE, DSR_MESSAGE_TYPES, PEER_CONNECTIVITY_EVENT, PEER_CONNECTIVITY_HANDLER_MATCH_ALL, PITCHER_EVENT, PeerConnectivityActions, PitcherBroadcastedEventName, PitcherEventName, PitcherExternalEventName, PitcherMessageType, PitcherResponseStatus, UI_API_METHOD_TYPES, UI_MESSAGE, UI_MESSAGE_TYPES, UI_NATIVE_MESSAGE_TYPES, WEB_MODE, createScopedPitcherApi, getAvailableApis, highLevelApi, isNativeHost, platformTypeForMode, registerPeerConnectivityHandler, sendPeerConnectivityEvent, useAdmin, useApi, useDsr, usePitcherApi, useUi };
|
|
5557
5989
|
//# sourceMappingURL=js-api.esm.js.map
|