@salesforce/afv-skills 1.46.0 → 1.48.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 (317) hide show
  1. package/package.json +1 -1
  2. package/skills/agentforce-observe/SKILL.md +32 -4
  3. package/skills/agentforce-observe/references/ahm-alerts.md +719 -0
  4. package/skills/consumer-goods-promotion-bo-api-deploy/SKILL.md +275 -0
  5. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/README.md +32 -0
  6. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/SetCommentValue.cls +75 -0
  7. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/SetCommentValue.cls-meta.xml +5 -0
  8. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/interview-answers.json +13 -0
  9. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/payloads/copy.json +10 -0
  10. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/payloads/create.json +20 -0
  11. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/payloads/update.json +16 -0
  12. package/skills/consumer-goods-promotion-bo-api-deploy/references/conventions-and-payload-rules.md +273 -0
  13. package/skills/consumer-goods-promotion-bo-api-deploy/references/generate-and-wire.md +236 -0
  14. package/skills/consumer-goods-promotion-bo-api-deploy/references/reference-example-set-comment-value.md +132 -0
  15. package/skills/consumer-goods-promotion-bo-api-deploy/references/smoke-and-verify.md +211 -0
  16. package/skills/dx-devops-project-manage/SKILL.md +197 -0
  17. package/skills/dx-devops-project-manage/examples/common-workflows.md +197 -0
  18. package/skills/dx-devops-project-manage/references/cli-commands.md +295 -0
  19. package/skills/dx-devops-project-manage/scripts/create-project.sh +48 -0
  20. package/skills/dx-devops-project-manage/scripts/list-projects.sh +51 -0
  21. package/skills/dx-devops-project-manage/scripts/update-project.sh +96 -0
  22. package/skills/education-cloud-academic-calendar-generate/SKILL.md +225 -0
  23. package/skills/education-cloud-academic-calendar-generate/examples/quarter-calendar.json +47 -0
  24. package/skills/education-cloud-academic-calendar-generate/examples/sample-output.md +57 -0
  25. package/skills/education-cloud-academic-calendar-generate/examples/semester-calendar.json +54 -0
  26. package/skills/education-cloud-academic-calendar-generate/references/calendar-systems.md +127 -0
  27. package/skills/education-cloud-academic-calendar-generate/references/date-validation.md +222 -0
  28. package/skills/education-cloud-academic-calendar-generate/references/foundation_prerequisites.md +40 -0
  29. package/skills/education-cloud-academic-calendar-generate/scripts/validate_calendar_dates.py +143 -0
  30. package/skills/education-cloud-course-catalog-migrate/SKILL.md +321 -0
  31. package/skills/education-cloud-course-catalog-migrate/references/gotchas-detail.md +16 -0
  32. package/skills/education-cloud-course-catalog-migrate/references/gotchas.md +16 -0
  33. package/skills/education-cloud-course-catalog-migrate/references/large-catalog-handling.md +42 -0
  34. package/skills/education-cloud-course-catalog-migrate/scripts/batch_courses.py +36 -0
  35. package/skills/education-cloud-course-catalog-migrate/scripts/detect_linked_courses.py +51 -0
  36. package/skills/education-cloud-course-catalog-migrate/scripts/detect_modality_variants.py +48 -0
  37. package/skills/education-cloud-course-catalog-migrate/scripts/resolve_api_version.py +43 -0
  38. package/skills/education-cloud-course-catalog-migrate/scripts/split_course_code.py +39 -0
  39. package/skills/education-cloud-course-catalog-migrate/scripts/validate_completeness.py +54 -0
  40. package/skills/education-cloud-domain-configure/SKILL.md +234 -0
  41. package/skills/education-cloud-domain-configure/references/dependent-features.md +198 -0
  42. package/skills/education-cloud-domain-configure/references/domain-features/academic-operations.md +386 -0
  43. package/skills/education-cloud-domain-configure/references/domain-features/alumni-relations.md +155 -0
  44. package/skills/education-cloud-domain-configure/references/domain-features/cross-domain-dependencies.md +18 -0
  45. package/skills/education-cloud-domain-configure/references/domain-features/industriessettings-toggle-reference.md +43 -0
  46. package/skills/education-cloud-domain-configure/references/domain-features/mentoring.md +198 -0
  47. package/skills/education-cloud-domain-configure/references/domain-features/recruitment-admissions.md +315 -0
  48. package/skills/education-cloud-domain-configure/references/domain-features/student-management.md +155 -0
  49. package/skills/education-cloud-domain-configure/references/domain-features/student-success.md +249 -0
  50. package/skills/education-cloud-domain-configure/references/domain-features.md +27 -0
  51. package/skills/education-cloud-domain-configure/references/gotchas-extended.md +23 -0
  52. package/skills/education-cloud-domain-configure/references/toggle-write-path.md +67 -0
  53. package/skills/education-cloud-domain-configure/scripts/check_license_provisioned.py +62 -0
  54. package/skills/education-cloud-domain-configure/scripts/check_org_edition.py +44 -0
  55. package/skills/education-cloud-domain-configure/scripts/check_permission_assigned.py +39 -0
  56. package/skills/education-cloud-multi-campus-configure/SKILL.md +7 -0
  57. package/skills/education-cloud-multi-campus-configure/references/foundation_prerequisites.md +1 -2
  58. package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +177 -0
  59. package/skills/education-cloud-student-recruitment-agent-configure/references/agent-and-subagents.md +151 -0
  60. package/skills/education-cloud-student-recruitment-agent-configure/references/customer-narration.md +34 -0
  61. package/skills/education-cloud-student-recruitment-agent-configure/references/execution-model.md +54 -0
  62. package/skills/education-cloud-student-recruitment-agent-configure/references/flows.md +82 -0
  63. package/skills/education-cloud-student-recruitment-agent-configure/references/grounding.md +199 -0
  64. package/skills/education-cloud-student-recruitment-agent-configure/references/permissions.md +183 -0
  65. package/skills/education-cloud-student-recruitment-agent-configure/references/platform-enablement.md +82 -0
  66. package/skills/education-cloud-student-recruitment-agent-configure/references/prerequisites.md +158 -0
  67. package/skills/education-cloud-student-recruitment-agent-configure/references/routing.md +141 -0
  68. package/skills/experience-cms-brand-apply/SKILL.md +5 -5
  69. package/skills/experience-cms-brand-create/SKILL.md +2 -2
  70. package/skills/experience-cms-content-generate/SKILL.md +1 -0
  71. package/skills/experience-cms-content-render/SKILL.md +173 -0
  72. package/skills/experience-cms-content-render/assets/angular/DetailPage.component.ts +25 -0
  73. package/skills/experience-cms-content-render/assets/angular/MediaRenderer.component.ts +133 -0
  74. package/skills/experience-cms-content-render/assets/angular/TypeList.component.ts +38 -0
  75. package/skills/experience-cms-content-render/assets/angular/TypeRenderer.component.ts +90 -0
  76. package/skills/experience-cms-content-render/assets/angular/cms-content.component.ts +248 -0
  77. package/skills/experience-cms-content-render/assets/angular/cms-item.service.ts +100 -0
  78. package/skills/experience-cms-content-render/assets/react/DetailPage.tsx +20 -0
  79. package/skills/experience-cms-content-render/assets/react/MediaRenderer.tsx +129 -0
  80. package/skills/experience-cms-content-render/assets/react/TypeList.tsx +40 -0
  81. package/skills/experience-cms-content-render/assets/react/TypeRenderer.tsx +64 -0
  82. package/skills/experience-cms-content-render/assets/react/heuristicRenderer.tsx +310 -0
  83. package/skills/experience-cms-content-render/assets/react/useCmsItem.ts +129 -0
  84. package/skills/experience-cms-content-render/assets/shared/cmsContentType.ts +49 -0
  85. package/skills/experience-cms-content-render/assets/shared/cmsCore.types.ts +96 -0
  86. package/skills/experience-cms-content-render/assets/shared/externalRefs.ts +55 -0
  87. package/skills/experience-cms-content-render/references/bulk-loading.md +60 -0
  88. package/skills/experience-cms-content-render/references/codegen-guardrails.md +111 -0
  89. package/skills/experience-cms-content-render/references/detail-pages.md +87 -0
  90. package/skills/experience-cms-content-render/references/embed-recipes.md +127 -0
  91. package/skills/experience-cms-content-render/references/failure-modes.md +96 -0
  92. package/skills/experience-cms-content-render/references/heuristic-render-rules.md +131 -0
  93. package/skills/experience-cms-content-render/references/init-scaffold.md +122 -0
  94. package/skills/experience-cms-content-render/references/interaction-model.md +173 -0
  95. package/skills/experience-cms-content-render/references/package-api.md +106 -0
  96. package/skills/experience-cms-content-render/references/schema-sync.md +114 -0
  97. package/skills/experience-cms-content-render/references/styling-scopes.md +65 -0
  98. package/skills/experience-cms-content-render/references/verify.md +49 -0
  99. package/skills/experience-cms-content-type-generate/SKILL.md +2 -2
  100. package/skills/experience-content-media-stock-image-search/SKILL.md +5 -4
  101. package/skills/experience-search-coordinate/SKILL.md +198 -0
  102. package/skills/experience-search-coordinate/assets/search-payload-template.json +25 -0
  103. package/skills/experience-search-coordinate/references/content-route.md +313 -0
  104. package/skills/experience-search-coordinate/references/content-type-discovery.md +57 -0
  105. package/skills/experience-search-coordinate/references/media-route.md +172 -0
  106. package/skills/experience-search-coordinate/references/scope-resolution.md +14 -0
  107. package/skills/experience-ui-bundle-localize/SKILL.md +1 -1
  108. package/skills/experience-ui-bundle-localize/references/i18n-setup.md +5 -3
  109. package/skills/experience-ui-bundle-project-generate/SKILL.md +18 -14
  110. package/skills/experience-ui-bundle-project-generate/references/angular-project-generate.md +22 -0
  111. package/skills/experience-ui-bundle-project-generate/references/react-project-generate.md +20 -0
  112. package/skills/experience-ui-bundle-salesforce-data-access/SKILL.md +58 -54
  113. package/skills/experience-ui-bundle-salesforce-data-access/references/caching.md +6 -0
  114. package/skills/experience-ui-bundle-salesforce-data-access/references/graphiti-cli.md +2 -2
  115. package/skills/experience-ui-bundle-salesforce-data-access/references/migration.md +6 -0
  116. package/skills/experience-ui-bundle-salesforce-data-access/references/rest-and-integration.md +2 -1
  117. package/skills/experience-ui-bundle-salesforce-data-access/references/sdk-api.md +6 -0
  118. package/skills/experience-ui-bundle-site-generate/SKILL.md +59 -8
  119. package/skills/experience-ui-bundle-site-generate/references/configure-metadata-digital-experience.md +8 -3
  120. package/skills/experience-ui-bundle-site-generate/references/configure-metadata-language-settings.md +120 -0
  121. package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +336 -0
  122. package/skills/life-sciences-fieldsalesrep-coordinate/references/orchestration-flow.md +143 -0
  123. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-application-flexipage-mapping.md +127 -0
  124. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-deploy-commands.md +116 -0
  125. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-lifesci-metadata-deploy.md +111 -0
  126. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-overview.md +312 -0
  127. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-profile-layout-assignments.md +171 -0
  128. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-state-tracking.md +64 -0
  129. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-2-starter-config-trigger-handlers.md +122 -0
  130. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-4-user-provisioning-overview.md +335 -0
  131. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-4-user-provisioning-user-provisioning-details.md +140 -0
  132. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-execution-state-and-recovery.md +196 -0
  133. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-metadata-cache-generation.md +155 -0
  134. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-overview.md +307 -0
  135. package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-visit-creation-data.md +211 -0
  136. package/skills/life-sciences-fieldsalesrep-coordinate/references/state-machine-and-changes.md +108 -0
  137. package/skills/life-sciences-kam-coordinate/SKILL.md +241 -0
  138. package/skills/life-sciences-kam-coordinate/references/orchestration-flow.md +152 -0
  139. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-application-flexipage-mapping.md +79 -0
  140. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-deploy-commands.md +131 -0
  141. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-kam-config-records.md +85 -0
  142. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-lifesci-metadata-deploy.md +112 -0
  143. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-overview.md +202 -0
  144. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-profile-layout-assignments.md +67 -0
  145. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-state-tracking.md +65 -0
  146. package/skills/life-sciences-kam-coordinate/references/stage-2-starter-config-trigger-handlers.md +123 -0
  147. package/skills/life-sciences-kam-coordinate/references/stage-4-participant-role-and-sprint.md +89 -0
  148. package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +337 -0
  149. package/skills/life-sciences-kam-coordinate/references/stage-5-data-creation-data.md +248 -0
  150. package/skills/life-sciences-kam-coordinate/references/stage-6-ipad-validation-script.md +35 -0
  151. package/skills/life-sciences-kam-coordinate/references/stage-6-metadata-cache-generation.md +155 -0
  152. package/skills/life-sciences-kam-coordinate/references/stage-6-user-provisioning-details.md +146 -0
  153. package/skills/life-sciences-kam-coordinate/references/stage-6-user-provisioning-overview.md +89 -0
  154. package/skills/life-sciences-kam-coordinate/references/state-machine-and-changes.md +114 -0
  155. package/skills/life-sciences-prerequisites-validate/SKILL.md +138 -0
  156. package/skills/life-sciences-prerequisites-validate/references/checks-org-settings.md +190 -0
  157. package/skills/life-sciences-prerequisites-validate/references/checks-user-and-package.md +211 -0
  158. package/skills/life-sciences-territory-configure/SKILL.md +217 -0
  159. package/skills/life-sciences-territory-configure/references/territory-metadata.md +262 -0
  160. package/skills/platform-dsar-policy-manage/SKILL.md +272 -0
  161. package/skills/platform-dsar-policy-manage/references/configure.md +106 -0
  162. package/skills/platform-dsar-policy-manage/references/export-and-history.md +123 -0
  163. package/skills/platform-dsar-policy-manage/references/gap-analysis-guide.md +150 -0
  164. package/skills/platform-dsar-policy-manage/references/gap-scan.md +129 -0
  165. package/skills/platform-dsar-policy-manage/references/headless-sor.md +59 -0
  166. package/skills/platform-dsar-policy-manage/references/report-format.md +59 -0
  167. package/skills/platform-dsar-policy-manage/scripts/tests/__init__.py +0 -0
  168. package/skills/platform-dsar-policy-manage/scripts/tests/test_validate_policy_tree.py +76 -0
  169. package/skills/platform-dsar-policy-manage/scripts/validate-policy-tree.py +130 -0
  170. package/skills/platform-salesforce-connect-adapter-generate/SKILL.md +359 -0
  171. package/skills/platform-salesforce-connect-adapter-generate/references/official-examples.md +69 -0
  172. package/skills/platform-salesforce-connect-adapter-generate/references/scenarios.md +187 -0
  173. package/skills/service-agentforce-channel-configure/SKILL.md +33 -28
  174. package/skills/service-agentforce-human-escalation-configure/SKILL.md +205 -0
  175. package/skills/service-agentforce-human-escalation-configure/assets/escalation-thresholds.instructions.md +37 -0
  176. package/skills/service-agentforce-human-escalation-configure/assets/force-app/main/default/flows/Human_Escalation_Outbound_Flow.flow-meta.xml +173 -0
  177. package/skills/service-agentforce-human-escalation-configure/assets/package.xml +8 -0
  178. package/skills/service-agentforce-human-escalation-configure/assets/sfdx-project.json +5 -0
  179. package/skills/service-agentforce-human-escalation-configure/references/classifier-contracts.md +103 -0
  180. package/skills/service-agentforce-human-escalation-configure/references/escalation-mechanism.md +63 -0
  181. package/skills/service-agentforce-human-escalation-configure/references/failure-policy.md +44 -0
  182. package/skills/service-agentforce-human-escalation-configure/references/nga-escalation.md +57 -0
  183. package/skills/service-agentforce-human-escalation-configure/references/runtime-verification.md +72 -0
  184. package/skills/service-agentforce-human-escalation-configure/scripts/classify-agent-active.mjs +49 -0
  185. package/skills/service-agentforce-human-escalation-configure/scripts/classify-nga-escalation.mjs +166 -0
  186. package/skills/service-agentforce-human-escalation-configure/scripts/extract-outbound-route.mjs +67 -0
  187. package/skills/service-agentforce-human-escalation-configure/scripts/patch-escalation-surfaces.mjs +131 -0
  188. package/skills/service-agentforce-human-escalation-configure/scripts/tests/__init__.py +0 -0
  189. package/skills/service-agentforce-human-escalation-configure/scripts/tests/_bootstrap.py +249 -0
  190. package/skills/service-agentforce-human-escalation-configure/scripts/tests/test_escalation_contracts.py +899 -0
  191. package/skills/service-agentforce-human-escalation-configure/scripts/verify-and-configure.sh +705 -0
  192. package/skills/service-agentforce-human-escalation-configure/scripts/verify-escalation-config.mjs +89 -0
  193. package/skills/service-de-channel-routing-configure/SKILL.md +13 -5
  194. package/skills/service-de-channel-routing-configure/scripts/tests/test_skill_contract.py +25 -0
  195. package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +23 -10
  196. package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +63 -48
  197. package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +6 -2
  198. package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +20 -27
  199. package/skills/service-native-voice-recording-transcription-configure/SKILL.md +47 -27
  200. package/skills/service-native-voice-recording-transcription-configure/references/thunderbird-voice-settings.md +13 -9
  201. package/skills/service-native-voice-recording-transcription-configure/scripts/enable-recording-transcription.sh +104 -45
  202. package/skills/service-omni-agent-users-create/SKILL.md +96 -0
  203. package/skills/service-omni-agent-users-create/assets/create-users.apex.template +80 -0
  204. package/skills/service-omni-agent-users-create/references/apex-patterns.md +135 -0
  205. package/skills/service-omni-agent-users-create/references/apex-template-notes.md +40 -0
  206. package/skills/service-omni-agent-users-create/scripts/detect-and-create.sh +206 -0
  207. package/skills/service-omni-agent-users-create/scripts/detect-existing.sh +122 -0
  208. package/skills/service-omni-agent-users-create/scripts/run-create.sh +298 -0
  209. package/skills/service-omni-agent-users-create/scripts/tests/test_user_create_security.py +171 -0
  210. package/skills/service-omni-agent-work-sharing-configure/SKILL.md +78 -0
  211. package/skills/service-omni-agent-work-sharing-configure/references/api-notes.md +31 -0
  212. package/skills/service-omni-agent-work-sharing-configure/scripts/configure-and-report.sh +186 -0
  213. package/skills/service-omni-agent-work-sharing-configure/scripts/tests/_bootstrap.py +120 -0
  214. package/skills/service-omni-agent-work-sharing-configure/scripts/tests/test_agent_work_sharing_contracts.py +93 -0
  215. package/skills/service-omni-base-settings-configure/SKILL.md +77 -0
  216. package/skills/service-omni-base-settings-configure/assets/force-app/main/default/settings/OmniChannel.settings-meta.xml +8 -0
  217. package/skills/service-omni-base-settings-configure/assets/package.xml +8 -0
  218. package/skills/service-omni-base-settings-configure/assets/sfdx-project.json +12 -0
  219. package/skills/service-omni-base-settings-configure/references/api-notes.md +121 -0
  220. package/skills/service-omni-base-settings-configure/scripts/configure-and-report.sh +164 -0
  221. package/skills/service-omni-base-settings-configure/scripts/detect-existing.sh +69 -0
  222. package/skills/service-omni-channel-setup-coordinate/SKILL.md +168 -0
  223. package/skills/service-omni-channel-setup-coordinate/examples/output-templates.md +161 -0
  224. package/skills/service-omni-channel-setup-coordinate/references/gap-catalog.md +99 -0
  225. package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +1542 -0
  226. package/skills/service-omni-channel-setup-coordinate/scripts/tests/__init__.py +0 -0
  227. package/skills/service-omni-channel-setup-coordinate/scripts/tests/_bootstrap.py +223 -0
  228. package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +804 -0
  229. package/skills/service-omni-command-center-analyze/SKILL.md +84 -0
  230. package/skills/service-omni-command-center-analyze/references/api-notes.md +54 -0
  231. package/skills/service-omni-command-center-analyze/scripts/analyze.sh +198 -0
  232. package/skills/service-omni-command-center-analyze/scripts/tests/_bootstrap.py +115 -0
  233. package/skills/service-omni-command-center-analyze/scripts/tests/test_command_center_analyze_contracts.py +165 -0
  234. package/skills/service-omni-permission-set-assign/SKILL.md +88 -0
  235. package/skills/service-omni-permission-set-assign/assets/package.xml +8 -0
  236. package/skills/service-omni-permission-set-assign/references/api-notes.md +143 -0
  237. package/skills/service-omni-permission-set-assign/scripts/verify-and-assign.sh +397 -0
  238. package/skills/service-omni-presence-status-deploy/SKILL.md +87 -0
  239. package/skills/service-omni-presence-status-deploy/assets/package.xml +12 -0
  240. package/skills/service-omni-presence-status-deploy/references/api-notes.md +115 -0
  241. package/skills/service-omni-presence-status-deploy/scripts/deploy-and-report.sh +422 -0
  242. package/skills/service-omni-presence-user-config-deploy/SKILL.md +80 -0
  243. package/skills/service-omni-presence-user-config-deploy/references/api-notes.md +60 -0
  244. package/skills/service-omni-presence-user-config-deploy/scripts/deploy-and-report.sh +261 -0
  245. package/skills/service-omni-presence-user-config-deploy/scripts/tests/_bootstrap.py +106 -0
  246. package/skills/service-omni-presence-user-config-deploy/scripts/tests/test_presence_user_config_contracts.py +142 -0
  247. package/skills/service-omni-queue-deploy/SKILL.md +91 -0
  248. package/skills/service-omni-queue-deploy/references/api-notes.md +140 -0
  249. package/skills/service-omni-queue-deploy/scripts/verify-and-align.sh +470 -0
  250. package/skills/service-omni-queue-members-assign/SKILL.md +93 -0
  251. package/skills/service-omni-queue-members-assign/references/api-notes.md +144 -0
  252. package/skills/service-omni-queue-members-assign/scripts/tests/_bootstrap.py +67 -0
  253. package/skills/service-omni-queue-members-assign/scripts/tests/test_queue_members_contracts.py +73 -0
  254. package/skills/service-omni-queue-members-assign/scripts/verify-and-bind.sh +362 -0
  255. package/skills/service-omni-queue-routing-config-deploy/SKILL.md +101 -0
  256. package/skills/service-omni-queue-routing-config-deploy/references/api-notes.md +127 -0
  257. package/skills/service-omni-queue-routing-config-deploy/scripts/tests/_bootstrap.py +90 -0
  258. package/skills/service-omni-queue-routing-config-deploy/scripts/tests/test_queue_routing_config_contracts.py +70 -0
  259. package/skills/service-omni-queue-routing-config-deploy/scripts/upsert-and-report.sh +538 -0
  260. package/skills/service-omni-routing-flow-deploy/SKILL.md +111 -0
  261. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Case_Trigger.SkillsBased.flow-meta.xml +94 -0
  262. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Case_Trigger.flow-meta.xml +88 -0
  263. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_Cases.flow-meta.xml +144 -0
  264. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCall_Trigger.SkillsBased.flow-meta.xml +94 -0
  265. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCall_Trigger.flow-meta.xml +88 -0
  266. package/skills/service-omni-routing-flow-deploy/assets/force-app/main/default/flows/Omni_Route_VoiceCalls.flow-meta.xml +144 -0
  267. package/skills/service-omni-routing-flow-deploy/assets/package.xml +11 -0
  268. package/skills/service-omni-routing-flow-deploy/assets/sfdx-project.json +11 -0
  269. package/skills/service-omni-routing-flow-deploy/references/api-notes.md +265 -0
  270. package/skills/service-omni-routing-flow-deploy/scripts/deploy-and-report.sh +684 -0
  271. package/skills/service-omni-service-channel-configure/SKILL.md +83 -0
  272. package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/Cases.serviceChannel-meta.xml +9 -0
  273. package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/Incidents.serviceChannel-meta.xml +9 -0
  274. package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/MessagingSessions.serviceChannel-meta.xml +9 -0
  275. package/skills/service-omni-service-channel-configure/assets/force-app/main/default/serviceChannels/VoiceCalls.serviceChannel-meta.xml +9 -0
  276. package/skills/service-omni-service-channel-configure/assets/package.xml +11 -0
  277. package/skills/service-omni-service-channel-configure/assets/sfdx-project.json +12 -0
  278. package/skills/service-omni-service-channel-configure/references/api-notes.md +84 -0
  279. package/skills/service-omni-service-channel-configure/scripts/deploy-and-report.sh +383 -0
  280. package/skills/service-omni-sidebar-configure/SKILL.md +77 -0
  281. package/skills/service-omni-sidebar-configure/references/api-notes.md +51 -0
  282. package/skills/service-omni-sidebar-configure/scripts/enable-and-report.sh +315 -0
  283. package/skills/service-omni-sidebar-configure/scripts/tests/_bootstrap.py +142 -0
  284. package/skills/service-omni-sidebar-configure/scripts/tests/test_sidebar_contracts.py +139 -0
  285. package/skills/service-omni-skills-based-routing-configure/SKILL.md +81 -0
  286. package/skills/service-omni-skills-based-routing-configure/references/api-notes.md +50 -0
  287. package/skills/service-omni-skills-based-routing-configure/scripts/configure-and-report.sh +270 -0
  288. package/skills/service-omni-skills-based-routing-configure/scripts/tests/_bootstrap.py +120 -0
  289. package/skills/service-omni-skills-based-routing-configure/scripts/tests/test_sbr_contracts.py +129 -0
  290. package/skills/service-omni-supervisor-config-deploy/SKILL.md +97 -0
  291. package/skills/service-omni-supervisor-config-deploy/assets/force-app/main/default/omniSupervisorConfigs/Omni_Supervisor.omniSupervisorConfig-meta.xml +9 -0
  292. package/skills/service-omni-supervisor-config-deploy/assets/package.xml +8 -0
  293. package/skills/service-omni-supervisor-config-deploy/assets/sfdx-project.json +12 -0
  294. package/skills/service-omni-supervisor-config-deploy/references/api-notes.md +205 -0
  295. package/skills/service-omni-supervisor-config-deploy/scripts/deploy-and-report.sh +586 -0
  296. package/skills/service-omni-supervisor-config-deploy/scripts/tests/_bootstrap.py +153 -0
  297. package/skills/service-omni-supervisor-config-deploy/scripts/tests/test_supervisor_config_contracts.py +116 -0
  298. package/skills/service-omni-supervisor-permset-assign/SKILL.md +88 -0
  299. package/skills/service-omni-supervisor-permset-assign/references/api-notes.md +48 -0
  300. package/skills/service-omni-supervisor-permset-assign/scripts/verify-and-assign.sh +316 -0
  301. package/skills/service-omni-supervisor-surface-deploy/SKILL.md +85 -0
  302. package/skills/service-omni-supervisor-surface-deploy/references/api-notes.md +47 -0
  303. package/skills/service-omni-supervisor-surface-deploy/scripts/deploy-and-report.sh +216 -0
  304. package/skills/service-omni-supervisor-surface-deploy/scripts/tests/_bootstrap.py +95 -0
  305. package/skills/service-omni-supervisor-surface-deploy/scripts/tests/test_supervisor_surface_contracts.py +154 -0
  306. package/skills/service-omni-supervisor-users-create/SKILL.md +92 -0
  307. package/skills/service-omni-supervisor-users-create/assets/create-supervisors.apex.template +72 -0
  308. package/skills/service-omni-supervisor-users-create/references/apex-patterns.md +73 -0
  309. package/skills/service-omni-supervisor-users-create/references/apex-template-notes.md +41 -0
  310. package/skills/service-omni-supervisor-users-create/scripts/detect-and-create.sh +197 -0
  311. package/skills/service-omni-supervisor-users-create/scripts/detect-existing.sh +112 -0
  312. package/skills/service-omni-supervisor-users-create/scripts/run-create.sh +296 -0
  313. package/skills/service-omni-work-skill-routing-configure/SKILL.md +80 -0
  314. package/skills/service-omni-work-skill-routing-configure/references/api-notes.md +67 -0
  315. package/skills/service-omni-work-skill-routing-configure/scripts/configure-and-report.sh +262 -0
  316. package/skills/service-omni-work-skill-routing-configure/scripts/tests/_bootstrap.py +121 -0
  317. package/skills/service-omni-work-skill-routing-configure/scripts/tests/test_work_skill_routing_contracts.py +161 -0
@@ -0,0 +1,310 @@
1
+ /**
2
+ * heuristicRenderer — schema-less body renderer (Init → src/cms/react/heuristicRenderer.tsx).
3
+ * Picks fields by priority (title/image/excerpt), dispatches each value by shape via
4
+ * RenderField, and holds the ONE RichText injection site (Rule 4). Angular parallel:
5
+ * cms-content.component.ts. Rules: references/heuristic-render-rules.md.
6
+ */
7
+ import { type ComponentType, type ReactNode } from 'react';
8
+ import {
9
+ resolveCmsImageUrl,
10
+ decodeRichHtmlEntities,
11
+ } from '@salesforce/ui-bundle-template-feature-cms-toolkit';
12
+ import type { CmsImageField } from '../shared/cmsCore.types';
13
+
14
+ const IMAGE_PRIORITY = ['bannerImage', 'featuredImage', 'heroImage', 'coverImage', 'thumbnail', 'image'];
15
+ const EXCERPT_PRIORITY = ['excerpt', 'summary', 'description', 'subtitle'];
16
+
17
+ const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}/;
18
+ const URL_RE = /^https?:\/\//;
19
+ // Match an HTML tag-open (`<tag`, `</`, `<!`) AND entity-encoded HTML (`&lt;`) — the
20
+ // encoded form has no literal `<`, so a `<`-only check would skip decode entirely, while
21
+ // a bare `<` in prose ("Q4 < projected") must NOT be treated as markup (Rule 4).
22
+ const RICH_TEXT_RE = /<[a-z!/]|&lt;|&#(?:60|x3c);/i;
23
+
24
+ // ISO_DATE_RE only checks the PREFIX, so unparseable strings ("2024-13-99") and SKUs
25
+ // ("1234-56-78") slip through; `Intl.DateTimeFormat.format` throws RangeError on an
26
+ // Invalid Date, which would crash the whole render. Return null on invalid so the
27
+ // caller falls through to the next classifier instead of formatting.
28
+ function formatCmsDate(value: string, options: Intl.DateTimeFormatOptions): string | null {
29
+ const date = new Date(value);
30
+ if (Number.isNaN(date.getTime())) return null;
31
+ return new Intl.DateTimeFormat('en-US', options).format(date);
32
+ }
33
+
34
+ let sanitizer: (html: string) => string = defaultPassThroughSanitizer;
35
+
36
+ function defaultPassThroughSanitizer(html: string): string {
37
+ // Pass-through: Delivery RichText is trusted and already decoded to real HTML;
38
+ // escaping here would undo the decode (Rule 4). Apps add DOMPurify via
39
+ // setRichTextSanitizer for defense-in-depth.
40
+ return html;
41
+ }
42
+
43
+ // Swap in DOMPurify (or similar) at app entry: setRichTextSanitizer(DOMPurify.sanitize).
44
+ export function setRichTextSanitizer(fn: (html: string) => string): void {
45
+ sanitizer = fn;
46
+ }
47
+
48
+ export function richTextSanitizer(html: string): string {
49
+ return sanitizer(html);
50
+ }
51
+
52
+ /** Delivery image field → loadable `src` via the toolkit (resolves the relative
53
+ * Connect-API url; no options passed). Sync. */
54
+ export function resolveImageSrc(field: unknown): string | undefined {
55
+ return resolveCmsImageUrl(field as CmsImageField | undefined);
56
+ }
57
+
58
+ function isImageObject(v: unknown): boolean {
59
+ if (!v || typeof v !== 'object') return false;
60
+ const o = v as { url?: unknown; source?: { type?: unknown } };
61
+ return typeof o.url === 'string' || (o.source != null && typeof o.source.type === 'string');
62
+ }
63
+
64
+ /** Delivery image field → authored alt text. Empty string when the field carries none —
65
+ * a decorative image (WCAG 1.1.1), not a missing attribute. */
66
+ function resolveImageAlt(field: unknown): string {
67
+ if (field && typeof field === 'object') {
68
+ const alt = (field as { altText?: unknown }).altText;
69
+ if (typeof alt === 'string') return alt;
70
+ }
71
+ return '';
72
+ }
73
+
74
+ // RenderField picks a rendering from the value's SHAPE (table:
75
+ // references/heuristic-render-rules.md) and holds the ONE RichText injection path
76
+ // (Rule 4). Do NOT inject RichText anywhere else.
77
+ interface RenderFieldProps {
78
+ name: string;
79
+ value: unknown;
80
+ layout: 'list' | 'detail';
81
+ /** Resolves a `references`-bag contentKey to its media field; undefined for foreign refs. */
82
+ resolveRef?: (contentKey: string) => CmsImageField | undefined;
83
+ TitleSlot?: ComponentType<{ value: string }>;
84
+ ImageSlot?: ComponentType<{ src: string; alt?: string }>;
85
+ RichTextSlot?: ComponentType<{ html: string }>;
86
+ }
87
+
88
+ function RenderField({
89
+ name,
90
+ value,
91
+ layout,
92
+ resolveRef,
93
+ TitleSlot,
94
+ ImageSlot,
95
+ RichTextSlot,
96
+ }: RenderFieldProps): ReactNode {
97
+ if (value == null) return null;
98
+
99
+ if (typeof value === 'string') {
100
+ if (RICH_TEXT_RE.test(value)) {
101
+ // Decode entity-encoded HTML FIRST, THEN sanitize (Rule 4).
102
+ const html = richTextSanitizer(decodeRichHtmlEntities(value));
103
+ if (RichTextSlot) return <RichTextSlot html={html} />;
104
+ // Trusted, decoded HTML → default sanitizer is pass-through (Rule 4).
105
+ return <div dangerouslySetInnerHTML={{ __html: html }} />;
106
+ }
107
+ if (ISO_DATE_RE.test(value)) {
108
+ const label = formatCmsDate(value, { dateStyle: 'medium' });
109
+ // Valid date → <time>; invalid (matched the prefix but unparseable) → fall through.
110
+ if (label) return <time dateTime={value}>{label}</time>;
111
+ }
112
+ if (URL_RE.test(value)) {
113
+ return <a href={value} target="_blank" rel="noopener noreferrer" aria-label={`External link: ${value}`}>{value}</a>;
114
+ }
115
+ if (/title/i.test(name)) {
116
+ return TitleSlot
117
+ ? <TitleSlot value={value} />
118
+ : (layout === 'detail' ? <h1>{value}</h1> : <h2>{value}</h2>);
119
+ }
120
+ return <p>{value}</p>;
121
+ }
122
+
123
+ if (typeof value === 'number') {
124
+ return <span>{new Intl.NumberFormat().format(value)}</span>;
125
+ }
126
+
127
+ if (typeof value === 'boolean') {
128
+ return <span className="badge">{value ? 'Yes' : 'No'}</span>;
129
+ }
130
+
131
+ if (Array.isArray(value)) {
132
+ return (
133
+ <>
134
+ {value.map((v, i) => (
135
+ <RenderField
136
+ key={i}
137
+ name={`${name}[${i}]`}
138
+ value={v}
139
+ layout={layout}
140
+ resolveRef={resolveRef}
141
+ TitleSlot={TitleSlot}
142
+ ImageSlot={ImageSlot}
143
+ RichTextSlot={RichTextSlot}
144
+ />
145
+ ))}
146
+ </>
147
+ );
148
+ }
149
+
150
+ if (typeof value === 'object') {
151
+ const obj = value as Record<string, unknown>;
152
+
153
+ // dateTime shape
154
+ if (typeof obj.dateTime === 'string') {
155
+ const label = formatCmsDate(obj.dateTime, {
156
+ dateStyle: 'medium',
157
+ timeStyle: 'short',
158
+ timeZone: typeof obj.timeZone === 'string' ? obj.timeZone : undefined,
159
+ });
160
+ // Invalid dateTime → skip this field rather than crash the render.
161
+ return label ? <time dateTime={obj.dateTime}>{label}</time> : null;
162
+ }
163
+
164
+ // image-shaped object — the toolkit resolves the src synchronously.
165
+ if (isImageObject(obj)) {
166
+ const src = resolveImageSrc(obj);
167
+ if (!src) return null;
168
+ const alt = resolveImageAlt(obj);
169
+ return ImageSlot
170
+ ? <ImageSlot src={src} alt={alt} />
171
+ : <img src={src} alt={alt} loading="lazy" />;
172
+ }
173
+
174
+ // contentReference shape
175
+ const refObj = (obj as { ref?: { contentKey?: string } }).ref;
176
+ if (refObj && typeof refObj.contentKey === 'string' && resolveRef) {
177
+ const resolved = resolveRef(refObj.contentKey);
178
+ if (!resolved) return null;
179
+ return <span>{(resolved as { title?: string }).title ?? refObj.contentKey}</span>;
180
+ }
181
+
182
+ return null;
183
+ }
184
+
185
+ return null;
186
+ }
187
+
188
+ export interface HeuristicRendererProps {
189
+ body: Record<string, unknown> | undefined;
190
+ loading: boolean;
191
+ error: Error | undefined;
192
+ layout?: 'list' | 'detail' | string;
193
+ /** Optional whitelist — bypasses priority lists and renders only these fields in order. */
194
+ fields?: ReadonlyArray<string>;
195
+ components?: {
196
+ Title?: ComponentType<{ value: string }>;
197
+ Image?: ComponentType<{ src: string; alt?: string }>;
198
+ RichText?: ComponentType<{ html: string }>;
199
+ };
200
+ className?: string;
201
+ resolveRef?: (contentKey: string) => CmsImageField | undefined;
202
+ }
203
+
204
+ export function heuristicRenderer({
205
+ body,
206
+ loading,
207
+ error,
208
+ layout = 'detail',
209
+ fields,
210
+ components,
211
+ className,
212
+ resolveRef,
213
+ }: HeuristicRendererProps): ReactNode {
214
+ if (loading) return <div role="status">Loading…</div>;
215
+ if (error) return <div role="alert">{error.message}</div>;
216
+ if (!body) return null;
217
+
218
+ const normalizedLayout: 'list' | 'detail' = layout === 'list' ? 'list' : 'detail';
219
+ const TitleSlot = components?.Title;
220
+ const ImageSlot = components?.Image;
221
+ const RichTextSlot = components?.RichText;
222
+
223
+ // Whitelist mode.
224
+ if (fields && fields.length > 0) {
225
+ return (
226
+ <article className={className}>
227
+ {fields.map((name) => {
228
+ const value = body[name];
229
+ if (value == null) return null;
230
+ return (
231
+ <RenderField
232
+ key={name}
233
+ name={name}
234
+ value={value}
235
+ layout={normalizedLayout}
236
+ resolveRef={resolveRef}
237
+ TitleSlot={TitleSlot}
238
+ ImageSlot={ImageSlot}
239
+ RichTextSlot={RichTextSlot}
240
+ />
241
+ );
242
+ })}
243
+ </article>
244
+ );
245
+ }
246
+
247
+ // Heuristic mode.
248
+ const title = pickTitle(body);
249
+ const imageField = pickFirstField(body, IMAGE_PRIORITY, isImageObject);
250
+ const excerpt = pickFirstField(body, EXCERPT_PRIORITY, (v) => typeof v === 'string' && v.length > 0);
251
+
252
+ const consumed = new Set<string>();
253
+ if (title?.name) consumed.add(title.name);
254
+ if (imageField?.name) consumed.add(imageField.name);
255
+ if (excerpt?.name) consumed.add(excerpt.name);
256
+
257
+ return (
258
+ <article className={className}>
259
+ {title && (TitleSlot
260
+ ? <TitleSlot value={title.value} />
261
+ : (normalizedLayout === 'detail' ? <h1>{title.value}</h1> : <h2>{title.value}</h2>))}
262
+
263
+ {imageField && (() => {
264
+ const src = resolveImageSrc(imageField.value);
265
+ if (!src) return null;
266
+ const alt = resolveImageAlt(imageField.value);
267
+ return ImageSlot
268
+ ? <ImageSlot src={src} alt={alt} />
269
+ : <img src={src} alt={alt} loading="lazy" />;
270
+ })()}
271
+
272
+ {excerpt && <p>{excerpt.value as string}</p>}
273
+
274
+ {normalizedLayout === 'detail' && Object.entries(body)
275
+ .filter(([k]) => !consumed.has(k))
276
+ .map(([k, v]) => (
277
+ <RenderField
278
+ key={k}
279
+ name={k}
280
+ value={v}
281
+ layout={normalizedLayout}
282
+ resolveRef={resolveRef}
283
+ TitleSlot={TitleSlot}
284
+ ImageSlot={ImageSlot}
285
+ RichTextSlot={RichTextSlot}
286
+ />
287
+ ))}
288
+ </article>
289
+ );
290
+ }
291
+
292
+ function pickTitle(body: Record<string, unknown>): { name: string; value: string } | undefined {
293
+ if (typeof body.title === 'string') return { name: 'title', value: body.title };
294
+ for (const [k, v] of Object.entries(body)) {
295
+ if (typeof v === 'string' && /title/i.test(k)) return { name: k, value: v };
296
+ }
297
+ return undefined;
298
+ }
299
+
300
+ function pickFirstField<T = unknown>(
301
+ body: Record<string, unknown>,
302
+ priority: string[],
303
+ predicate: (v: unknown) => boolean,
304
+ ): { name: string; value: T } | undefined {
305
+ for (const k of priority) {
306
+ const v = body[k];
307
+ if (v != null && predicate(v)) return { name: k, value: v as T };
308
+ }
309
+ return undefined;
310
+ }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * useCmsItem — single-content React hook (Init → src/cms/react/useCmsItem.ts).
3
+ * Owns fetch state + a per-ref cache + inflight dedup (keyed by `ref.name`; never
4
+ * throws — errors → state). Dispatches on ref type: CmsExternalRef (`url`) →
5
+ * getCmsContentByUrl (CDN); CmsRef (`contentKey`) → getCmsContentByKey (Connect).
6
+ *
7
+ * StrictMode-safe (Rule 3): the request is SHARED, so cleanup only sets a local
8
+ * `cancelled` flag gating setState — it never aborts; shared requests get no
9
+ * AbortSignal; `inflight` self-cleans via `.finally(delete)`.
10
+ */
11
+ import { useEffect, useState, useRef } from 'react';
12
+ import {
13
+ getCmsContentByUrl,
14
+ getCmsContentByKey,
15
+ CmsDeliveryError,
16
+ CmsDeliveryNotFoundError,
17
+ ConnectApiError,
18
+ CmsNotFoundError,
19
+ } from '@salesforce/ui-bundle-template-feature-cms-toolkit';
20
+ import type { AnyCmsRef, CmsRef } from '../shared/cmsCore.types';
21
+ import { CMS_CHANNEL_ID_FALLBACK } from '../shared/externalRefs';
22
+
23
+ interface UseCmsItemState<TBody> {
24
+ body: TBody | undefined;
25
+ loading: boolean;
26
+ error: Error | undefined;
27
+ }
28
+
29
+ // Module-scoped: shared across every consumer of the hook in the app.
30
+ const cache = new Map<string, unknown>();
31
+ const inflight = new Map<string, Promise<unknown>>();
32
+
33
+ /** Shared request for a ref — NO abort signal. `CMS_CHANNEL_ID_FALLBACK` is passed
34
+ * as `options.channelId` only when set (empty → catalog supplies it). */
35
+ function createItemRequest<TBody>(ref: AnyCmsRef): Promise<TBody> {
36
+ // Foreign ref — public delivery URL fetched AS-IS (Rule 1).
37
+ if ('url' in ref && typeof ref.url === 'string') {
38
+ return getCmsContentByUrl<TBody>(ref.url);
39
+ }
40
+ // uiBundle-space ref — toolkit remaps the contentKey (fail-open) and reads Connect.
41
+ const channelId = CMS_CHANNEL_ID_FALLBACK || undefined;
42
+ return getCmsContentByKey<TBody>((ref as CmsRef).contentKey, { channelId });
43
+ }
44
+
45
+ export function useCmsItem<TBody = unknown>(
46
+ ref: AnyCmsRef,
47
+ ): UseCmsItemState<TBody> {
48
+ const [state, setState] = useState<UseCmsItemState<TBody>>(() => {
49
+ const cached = cache.get(ref.name) as TBody | undefined;
50
+ return {
51
+ body: cached,
52
+ loading: cached === undefined,
53
+ error: undefined,
54
+ };
55
+ });
56
+
57
+ // Track the ref name so object-identity churn doesn't re-fetch.
58
+ const nameRef = useRef(ref.name);
59
+ nameRef.current = ref.name;
60
+
61
+ useEffect(() => {
62
+ // Local guard only — cleanup suppresses stale setState, never the shared
63
+ // request (Rule 3).
64
+ let cancelled = false;
65
+ const name = ref.name;
66
+
67
+ const cached = cache.get(name) as TBody | undefined;
68
+ if (cached !== undefined) {
69
+ setState({ body: cached, loading: false, error: undefined });
70
+ return () => {
71
+ cancelled = true;
72
+ };
73
+ }
74
+
75
+ setState((prev) => ({ ...prev, loading: true, error: undefined }));
76
+
77
+ // In-flight dedup: reuse a pending promise for this ref (shared, no signal).
78
+ let promise = inflight.get(name) as Promise<TBody> | undefined;
79
+ if (!promise) {
80
+ promise = createItemRequest<TBody>(ref);
81
+ inflight.set(name, promise);
82
+ // Self-cleaning: settled or failed, the entry is always removed so an
83
+ // unmounted consumer can't leave a dead promise to poison retries.
84
+ promise
85
+ .then((body) => {
86
+ cache.set(name, body);
87
+ })
88
+ .catch(() => {
89
+ /* surfaced per-consumer below; swallow to avoid unhandled rejection */
90
+ })
91
+ .finally(() => {
92
+ if (inflight.get(name) === promise) inflight.delete(name);
93
+ });
94
+ }
95
+
96
+ promise
97
+ .then((body) => {
98
+ if (cancelled) return;
99
+ setState({ body, loading: false, error: undefined });
100
+ })
101
+ .catch((err: unknown) => {
102
+ if (cancelled) return;
103
+ // Pass the toolkit's typed errors through as-is; wrap anything else.
104
+ const error =
105
+ err instanceof CmsDeliveryNotFoundError ||
106
+ err instanceof CmsDeliveryError ||
107
+ err instanceof CmsNotFoundError ||
108
+ err instanceof ConnectApiError
109
+ ? err
110
+ : err instanceof Error
111
+ ? err
112
+ // Retain the original non-Error rejection as the cause for debugging.
113
+ : new Error('Unknown CMS fetch error', { cause: err });
114
+ setState({ body: undefined, loading: false, error });
115
+ });
116
+
117
+ return () => {
118
+ cancelled = true;
119
+ };
120
+ }, [ref.name]); // Ref-name is the identity — object churn is ignored.
121
+
122
+ return state;
123
+ }
124
+
125
+ /** Test-only — reset the module cache between runs. */
126
+ export function __resetCmsCacheForTests(): void {
127
+ cache.clear();
128
+ inflight.clear();
129
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * {{Type}} — per-type typed module (codegen-managed). ABOVE marker: user-editable
3
+ * (layouts, slots, className presets), preserved verbatim. BELOW marker: generated
4
+ * from the schema, rewritten on every Schema Sync. Missing/malformed markers → the
5
+ * skill HALTs (never auto-heals). Algorithm: references/schema-sync.md.
6
+ *
7
+ * Tokens: {{Type}} PascalCase · {{type}} camelCase · {{TYPE}} UPPER_SNAKE.
8
+ */
9
+ import type { CmsFieldType, CmsImageField } from '../../shared/cmsCore.types';
10
+
11
+ // <experience-cms-content-render:above-begin>
12
+ // User-editable — layouts, slot overrides, className presets.
13
+ // Preserved across regeneration.
14
+
15
+ export const {{type}}Layouts = {
16
+ card: { fields: ['title', 'bannerImage', 'excerpt'] as const, className: 'cms-{{type}}-card' },
17
+ detail: { fields: undefined, className: 'cms-{{type}}-detail' },
18
+ } as const;
19
+
20
+ export type {{Type}}Layout = keyof typeof {{type}}Layouts;
21
+
22
+ export const {{type}}Slots: {
23
+ Title?: unknown;
24
+ Image?: unknown;
25
+ RichText?: unknown;
26
+ } = {};
27
+
28
+ // <experience-cms-content-render:above-end>
29
+
30
+
31
+ // <experience-cms-content-render:below-begin>
32
+ // GENERATED — do not edit. Regenerated on schema sync.
33
+ //
34
+ // One field per schema entry. Scalars are PLAIN PRIMITIVES (Rule 5) — Text/RichText/
35
+ // URL/Date/DateTime → string, Number → number, Boolean → boolean; only Image →
36
+ // CmsImageField. NEVER `{ value: T }`.
37
+
38
+ export interface {{Type}}Body {
39
+ // One typed property per schema field; the index keeps off-schema fields open.
40
+ [field: string]: string | number | boolean | CmsImageField | undefined;
41
+ }
42
+
43
+ export const {{type}}FieldTypes: Readonly<Record<string, CmsFieldType>> = {
44
+ // One entry per field, mapping lightningType → lowerCamel CmsFieldType literal
45
+ // (Text→'text', RichText→'richText', … — translate the casing, never copy the
46
+ // PascalCase token). E.g.: body: 'richText', excerpt: 'text', bannerImage: 'image'.
47
+ };
48
+
49
+ // <experience-cms-content-render:below-end>
@@ -0,0 +1,96 @@
1
+ /**
2
+ * CMS identity + field-type primitives (FRAMEWORK-AGNOSTIC). Scaffolded once at
3
+ * `src/cms/shared/cmsCore.types.ts`; safe to import, not regenerated. Owns ONLY the
4
+ * app-level ref identity and the codegen field-type enum — delivery/runtime shapes
5
+ * (CmsImageField, CmsContentBody, errors, …) live in the toolkit; do NOT redeclare.
6
+ */
7
+
8
+ // Re-exported so generated `<type>.ts` import the image shape from one local path
9
+ // (relative to `<framework>/types/`) rather than the package specifier.
10
+ export type { CmsImageField } from "@salesforce/ui-bundle-template-feature-cms-toolkit";
11
+
12
+ /** Foreign-ref identity — content addressed by a public unauthenticatedUrl (CDN). */
13
+ export interface CmsExternalRef<K extends string = string> {
14
+ /** Unique catalog name. Convention: EXT_<TITLE_SNAKE>. */
15
+ readonly name: string;
16
+ /** Fully-formed unauthenticatedUrl; immutable across deploys. */
17
+ readonly url: string;
18
+ /** Content-type discriminator (the fqn DeveloperName). REQUIRED and populated on
19
+ * every entry — it binds the ref to its renderer, so a wrong-typed ref is a
20
+ * compile error. Optional/absent would erase K and defeat that guard. */
21
+ readonly cmsType: K;
22
+ /** MEDIA-ONLY, direct-URL path. For standalone media (`image`/`audio`/`video`/
23
+ * `document`) a foreign `url` is the ASSET itself, so MediaRenderer sets it as the
24
+ * element `src`/`href` WITHOUT fetching — there is no body to read `altText`/`title`
25
+ * from. The skill threads these off the search hand-off (or asks the user) at Ref
26
+ * Registration so the accessible name survives. Ignored on non-media refs (news
27
+ * reads its title from the fetched envelope). Both optional; `altText` absent → `''`
28
+ * (decorative image, WCAG 1.1.1); `title` names the document download link. */
29
+ readonly altText?: string;
30
+ readonly title?: string;
31
+ }
32
+
33
+ /**
34
+ * uiBundle-space identity — a `contentKey` read via the authenticated Connect API.
35
+ * The baked-in value is the `sourceContentKey`; the toolkit remaps it to the org's
36
+ * `targetContentKey` via content-metadata.json (fail-open to the baked-in key).
37
+ */
38
+ export interface CmsRef<K extends string = string> {
39
+ /** Unique catalog name. Convention: EXT_<TITLE_SNAKE>. */
40
+ readonly name: string;
41
+ /** sourceContentKey baked into app code; the catalog's remap fallback. */
42
+ readonly contentKey: string;
43
+ /** Content-type discriminator (the fqn DeveloperName). REQUIRED and populated on
44
+ * every entry — it binds the ref to its renderer, so a wrong-typed ref is a
45
+ * compile error. Optional/absent would erase K and defeat that guard. */
46
+ readonly cmsType: K;
47
+ }
48
+
49
+ /** Union of every fetchable ref — branch on `url` (foreign) vs `contentKey`. */
50
+ export type AnyCmsRef<K extends string = string> = CmsExternalRef<K> | CmsRef<K>;
51
+
52
+ /** Codified Lightning field types — feeds the below-marker fieldTypes map per type. */
53
+ export type CmsFieldType =
54
+ | "text"
55
+ | "richText"
56
+ | "image"
57
+ | "date"
58
+ | "dateTime"
59
+ | "number"
60
+ | "boolean"
61
+ | "url"
62
+ | "reference"
63
+ | "unknown";
64
+
65
+ /**
66
+ * Standalone-media discriminator — the fqn DeveloperName of a PREDEFINED CMS media
67
+ * item (`sfdc_cms__{image,audio,video,document}`), stored on the ref as `cmsType`.
68
+ * Media is a predefined type parallel to `news`: the ref binds to `MediaRenderer` at
69
+ * registration time, so dispatch is by `cmsType`, NEVER by body shape (SKILL.md §B1).
70
+ */
71
+ export type CmsMediaType = "image" | "audio" | "video" | "document";
72
+
73
+ /** The `sfdc_cms:media` field every media body carries (key is LITERALLY
74
+ * "sfdc_cms:media", colon, across all four types). `url` is a loadable src; `source`
75
+ * describes the underlying file (`mimeType` picks finer intra-medium choices). */
76
+ export interface CmsMediaField {
77
+ readonly url?: string;
78
+ readonly source?: {
79
+ readonly mimeType?: string;
80
+ readonly ref?: string;
81
+ readonly type?: string;
82
+ readonly fileSize?: number;
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Predefined body for standalone CMS media — UNIFORM across all four media types;
88
+ * they differ only by the envelope fqn (→ `cmsType`) and `source.mimeType`. `title`
89
+ * is envelope-level, lifted into the body by the toolkit (as news); `altText` is
90
+ * optional and absent on audio. The `<TBody>` for `getCmsContentByKey<CmsMediaBody>`.
91
+ */
92
+ export interface CmsMediaBody {
93
+ readonly altText?: string;
94
+ readonly title?: string;
95
+ readonly "sfdc_cms:media": CmsMediaField;
96
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Ref catalog for CMS content (FRAMEWORK-AGNOSTIC). Holds both ref types
3
+ * (CmsExternalRef by `url`, CmsRef by `contentKey`). Scaffolded once at
4
+ * src/cms/shared/externalRefs.ts; each embed appends one entry inside the marker block.
5
+ * Names are EXT_<TITLE_SNAKE>, unique — object-literal keys collide at compile time.
6
+ *
7
+ * ⚠ Do NOT edit the marker block by hand. Add entries via the skill.
8
+ */
9
+ // Only `AnyCmsRef` is used in the empty template; Ref Registration adds
10
+ // CmsExternalRef/CmsRef when it appends an entry (importing them eagerly trips
11
+ // noUnusedLocals TS6196 on a fresh scaffold).
12
+ import type { AnyCmsRef } from './cmsCore.types';
13
+
14
+ // channelId OVERRIDE for CmsRef reads — CAUTION, opt-in only. Prefer the catalog
15
+ // (public/content-metadata.json), which is primary and travels per-org. This constant
16
+ // is baked into SOURCE, so it does NOT travel per-org and will point at the WRONG
17
+ // channel after a cross-org deploy — set it only at your discretion for a local
18
+ // override. The skill does NOT auto-fill it (leave ''); the catalog supplies the
19
+ // channel. Precedence: explicit option > this override > catalog channelId > toolkit
20
+ // throws. Passed as options.channelId only when non-empty.
21
+ // <experience-cms-content-render:channel-fallback-begin>
22
+ export const CMS_CHANNEL_ID_FALLBACK = '';
23
+ // <experience-cms-content-render:channel-fallback-end>
24
+
25
+ // <experience-cms-content-render:external-refs-begin>
26
+ // Skill-managed. Each embed appends one entry here of the form:
27
+ //
28
+ // Foreign ref (public unauthenticatedUrl):
29
+ // EXT_FOOD_BERRIES: {
30
+ // name: 'EXT_FOOD_BERRIES',
31
+ // url: 'https://orgfarm-XXX.cdn.example.salesforce-experience.com/cms/delivery/v64.0/0apSG.../contents/MCABC...?oid=00D...&language=en_US',
32
+ // cmsType: 'news',
33
+ // } satisfies CmsExternalRef<'news'>,
34
+ //
35
+ // uiBundle-space ref (contentKey — remapped via content-metadata.json):
36
+ // EXT_LAUNCH_NEWS: {
37
+ // name: 'EXT_LAUNCH_NEWS',
38
+ // contentKey: 'M3ASD4KHASDB73',
39
+ // cmsType: 'news',
40
+ // } satisfies CmsRef<'news'>,
41
+ //
42
+ // `cmsType` MUST match the `<K>` in `satisfies` — it binds the ref to a per-type
43
+ // renderer at compile time, so a wrong-typed ref is a compile error.
44
+ export const externalRefs = {} as const satisfies Record<string, AnyCmsRef>;
45
+ // <experience-cms-content-render:external-refs-end>
46
+
47
+ /**
48
+ * Typed accessor — prefer over `externalRefs['EXT_X']`: the `cmsType` discriminator
49
+ * flows through, so a wrong-typed ref to a renderer fails at compile time.
50
+ */
51
+ export function ref<Name extends keyof typeof externalRefs>(
52
+ name: Name,
53
+ ): (typeof externalRefs)[Name] {
54
+ return externalRefs[name];
55
+ }