@salesforce/afv-skills 1.37.0 → 1.38.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/package.json +1 -1
- package/skills/agentforce-generate/README.md +20 -3
- package/skills/agentforce-generate/SKILL.md +253 -440
- package/skills/agentforce-generate/assets/agent-spec-template.md +6 -2
- package/skills/agentforce-generate/assets/agents/order-service.agent +16 -12
- package/skills/agentforce-generate/assets/agents/production-faq.agent +4 -4
- package/skills/agentforce-generate/assets/agents/router-first.agent +5 -5
- package/skills/agentforce-generate/assets/agents/template-single-subagent.agent +4 -4
- package/skills/agentforce-generate/assets/agents/verification-gate.agent +8 -6
- package/skills/agentforce-generate/assets/agents/voice-knowledge-grounded.agent +9 -9
- package/skills/agentforce-generate/assets/agents/voice-service-agent.agent +7 -7
- package/skills/agentforce-generate/assets/patterns/README.md +3 -3
- package/skills/agentforce-generate/assets/patterns/action-callbacks.agent +5 -5
- package/skills/agentforce-generate/assets/patterns/advanced-input-bindings.agent +6 -8
- package/skills/agentforce-generate/assets/patterns/bidirectional-routing.agent +11 -13
- package/skills/agentforce-generate/assets/patterns/critical-input-collection.agent +11 -16
- package/skills/agentforce-generate/assets/patterns/lifecycle-events.agent +2 -3
- package/skills/agentforce-generate/assets/patterns/llm-controlled-actions.agent +6 -7
- package/skills/agentforce-generate/assets/patterns/open-gate-routing.agent +3 -3
- package/skills/agentforce-generate/assets/patterns/prompt-template-action.agent +14 -19
- package/skills/agentforce-generate/assets/patterns/system-instruction-overrides.agent +11 -20
- package/skills/agentforce-generate/references/actions-reference.md +2 -2
- package/skills/agentforce-generate/references/agent-audit-and-repair.md +135 -0
- package/skills/agentforce-generate/references/agent-audit-candidate-verification.md +160 -0
- package/skills/agentforce-generate/references/agent-audit-diagnostic-catalog.md +156 -0
- package/skills/agentforce-generate/references/agent-audit-diagnostics-actions-state.md +176 -0
- package/skills/agentforce-generate/references/agent-audit-diagnostics-architecture-evaluation.md +68 -0
- package/skills/agentforce-generate/references/agent-audit-diagnostics-instructions-routing.md +283 -0
- package/skills/agentforce-generate/references/agent-audit-evaluation-loop.md +191 -0
- package/skills/agentforce-generate/references/agent-audit-repair-report.md +143 -0
- package/skills/agentforce-generate/references/agent-audit-scope-path-review.md +180 -0
- package/skills/agentforce-generate/references/agent-design-and-spec-creation.md +105 -59
- package/skills/agentforce-generate/references/agent-script-core-language.md +144 -61
- package/skills/agentforce-generate/references/agent-subagent-map-diagrams.md +33 -23
- package/skills/agentforce-generate/references/agent-validation-and-debugging.md +37 -11
- package/skills/agentforce-generate/references/agentscript-toolchain.md +112 -0
- package/skills/agentforce-generate/references/architecture-patterns.md +81 -18
- package/skills/agentforce-generate/references/common-control-flow-pitfalls.md +255 -0
- package/skills/agentforce-generate/references/control-flow-actions-sequencing.md +198 -0
- package/skills/agentforce-generate/references/control-flow-lifecycle-side-effects.md +87 -0
- package/skills/agentforce-generate/references/examples.md +22 -22
- package/skills/agentforce-generate/references/instruction-resolution.md +123 -83
- package/skills/agentforce-generate/references/known-issues.md +1 -2
- package/skills/agentforce-generate/references/optimization-pattern-1-data-flow.md +4 -0
- package/skills/agentforce-generate/references/optimization-pattern-2-deterministic-logic.md +33 -0
- package/skills/agentforce-generate/references/optimization-pattern-3-reference-syntax.md +32 -3
- package/skills/agentforce-generate/references/optimization-pattern-4-escalation.md +2 -2
- package/skills/agentforce-generate/references/patterns-by-requirement.md +3 -1
- package/skills/agentforce-generate/references/posture-and-determinism.md +103 -22
- package/skills/agentforce-generate/references/reference-map.md +19 -3
- package/skills/agentforce-generate/references/scoring-rubric.md +1 -1
- package/skills/agentforce-generate/references/voice-latency-heuristics.md +4 -0
- package/skills/agentforce-generate/references/voice-modality-reference.md +4 -4
- package/skills/agentforce-generate/references/zen-of-agentscript.md +139 -23
- package/skills/agentforce-generate/scripts/agentscript-sdk-loader.mjs +133 -0
- package/skills/agentforce-generate/scripts/index-agent.mjs +141 -0
- package/skills/agentforce-generate/scripts/setup-agentscript-sdk.mjs +337 -0
- package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +1 -1
- package/skills/automation-sandbox-post-copy-configure/SKILL.md +433 -0
- package/skills/automation-sandbox-post-copy-configure/assets/api_request_templates.json +89 -0
- package/skills/automation-sandbox-post-copy-configure/examples/sample_config_input.json +40 -0
- package/skills/automation-sandbox-post-copy-configure/examples/sample_execution_summary.md +79 -0
- package/skills/automation-sandbox-post-copy-configure/references/api_endpoints.md +273 -0
- package/skills/automation-sandbox-post-copy-configure/references/authentication.md +94 -0
- package/skills/automation-sandbox-post-copy-configure/references/execution_phasing.md +93 -0
- package/skills/automation-sandbox-post-copy-configure/references/rules_gotchas.md +35 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/classify-patch-result.mjs +88 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/map-metadata-key.mjs +98 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/plan-phases.mjs +98 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/resolve-target-org.mjs +56 -0
- package/skills/design-systems-slds-validate/SKILL.md +14 -13
- package/skills/dx-code-analyzer-custom-rule-create/examples/xpath-examples.md +1 -1
- package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-security.md +1 -1
- package/skills/dx-org-devhub-configure/SKILL.md +268 -0
- package/skills/dx-org-devhub-configure/examples/status-output.md +39 -0
- package/skills/dx-org-devhub-configure/scripts/devhub.sh +650 -0
- package/skills/dx-org-devhub-configure/scripts/test-devhub.sh +116 -0
- package/skills/dx-org-manage/SKILL.md +135 -42
- package/skills/dx-org-manage/assets/derive-alias.sh +95 -0
- package/skills/dx-org-manage/assets/scratch-def.seed.json +6 -0
- package/skills/dx-org-manage/examples/README.md +1 -1
- package/skills/dx-org-manage/examples/scratch-orgs/delete_output.json +8 -0
- package/skills/dx-org-manage/examples/scratch-orgs/display_output.json +23 -0
- package/skills/dx-org-manage/examples/scratch-orgs/list_output.json +58 -0
- package/skills/dx-org-manage/examples/scratch-orgs/resume_output.json +38 -0
- package/skills/dx-org-manage/examples/scratch-orgs/success_definition_file.json +1 -1
- package/skills/dx-org-manage/examples/scratch-orgs/success_edition.json +1 -1
- package/skills/dx-org-manage/examples/scratch-orgs/success_shape.json +41 -0
- package/skills/dx-org-manage/examples/scratch-orgs/success_snapshot.json +1 -1
- package/skills/dx-org-manage/examples/snapshots/error_output.json +3 -3
- package/skills/dx-org-manage/references/creating-scratch-org.md +2 -2
- package/skills/dx-org-manage/references/creating-snapshot.md +1 -2
- package/skills/dx-org-manage/references/definition_file_options.md +24 -0
- package/skills/dx-org-manage/references/edition_types.md +10 -8
- package/skills/dx-org-manage/references/opening-org.md +11 -12
- package/skills/dx-org-manage/references/scratch-org-create.md +303 -0
- package/skills/dx-org-manage/references/scratch-org-operations.md +135 -0
- package/skills/experience-aura-lwc-migrate/SKILL.md +120 -0
- package/skills/experience-aura-lwc-migrate/references/aura-api-expert.md +170 -0
- package/skills/experience-aura-lwc-migrate/references/aura-data-expert.md +172 -0
- package/skills/experience-aura-lwc-migrate/references/aura-migration-guidelines.md +299 -0
- package/skills/experience-aura-lwc-migrate/references/aura-prd-framework.md +79 -0
- package/skills/experience-aura-lwc-migrate/references/aura-redundant-code-expert.md +24 -0
- package/skills/experience-aura-lwc-migrate/references/aura-reference-expert.md +140 -0
- package/skills/experience-aura-lwc-migrate/references/aura-resolver-expert.md +115 -0
- package/skills/experience-aura-lwc-migrate/references/aura-slots-expert.md +67 -0
- package/skills/experience-aura-lwc-migrate/references/aura-style-expert.md +62 -0
- package/skills/experience-aura-lwc-migrate/references/aura-to-lwc-completeness-checklist.md +188 -0
- package/skills/experience-aura-lwc-migrate/references/aura-values-expert.md +67 -0
- package/skills/experience-content-media-search/SKILL.md +17 -12
- package/skills/experience-content-media-stock-image-search/SKILL.md +192 -0
- package/skills/experience-content-media-stock-image-search/scripts/download-stock-image.py +102 -0
- package/skills/experience-lds-best-practices-apply/SKILL.md +245 -0
- package/skills/experience-lds-best-practices-apply/references/adapter-apis.md +1640 -0
- package/skills/experience-lds-best-practices-apply/references/lds-data-consistency.md +126 -0
- package/skills/experience-lds-best-practices-apply/references/lds-expert.md +429 -0
- package/skills/experience-lds-best-practices-apply/references/lds-referential-integrity.md +322 -0
- package/skills/experience-lds-best-practices-apply/references/wire-adapter-types.md +1511 -0
- package/skills/experience-lds-graphql-generate/SKILL.md +222 -0
- package/skills/experience-lds-graphql-generate/references/generation-guide.md +236 -0
- package/skills/experience-lds-graphql-generate/references/generation-mutation.md +277 -0
- package/skills/experience-lds-graphql-generate/references/generation-query.md +237 -0
- package/skills/experience-lds-graphql-generate/scripts/fetch-lds-graphql-schema.sh +230 -0
- package/skills/experience-lds-graphql-generate/scripts/test-lds-graphql-query.sh +128 -0
- package/skills/experience-lwc-accessibility-validate/SKILL.md +112 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-1-1-non-text-content.md +88 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-i-lists.md +52 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-ii-tables.md +106 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-iii-form-labels.md +78 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-iv-regions.md +26 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-1-v-groups.md +66 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-3-5-identify-input.md +70 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-1-4-3-contrast.md +115 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-1-1-keyboard.md +47 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-4-4-link-purpose.md +39 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-4-6-headings-labels.md +50 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-1-pointer-gestures.md +54 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-2-pointer-cancellation.md +49 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-3-label-in-name.md +77 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-2-5-7-dragging-movement.md +45 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-2-1-on-focus.md +55 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-2-2-on-input.md +51 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-3-1-error-identification.md +84 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-3-2-labels-instructions.md +50 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-3-3-3-error-suggestion.md +64 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-4-1-2-i-name.md +105 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-4-1-2-ii-role.md +99 -0
- package/skills/experience-lwc-accessibility-validate/references/reviewers/sc-4-1-2-iii-value.md +97 -0
- package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-1-1-non-text-content.md +83 -0
- package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-1-use-of-color.md +62 -0
- package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-10-resize-reflow.md +18 -0
- package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-11-non-text-contrast.md +43 -0
- package/skills/experience-lwc-accessibility-validate/references/vision/sc-1-4-3-contrast.md +25 -0
- package/skills/experience-lwc-accessibility-validate/scripts/contrast-ratio.py +153 -0
- package/skills/experience-lwc-design-generate/SKILL.md +261 -0
- package/skills/experience-lwc-design-generate/references/figma-to-prd-blueprint.md +66 -0
- package/skills/experience-lwc-design-generate/references/prd-analysis-template.md +17 -0
- package/skills/experience-lwc-design-generate/scripts/check-component-name.sh +75 -0
- package/skills/experience-lwc-design-generate/scripts/detect-project-tools.sh +97 -0
- package/skills/experience-lwc-runtime-observe/SKILL.md +244 -0
- package/skills/experience-lwc-runtime-observe/examples/component-preview-and-dom.md +41 -0
- package/skills/experience-lwc-runtime-observe/scripts/extract-dom.sh +79 -0
- package/skills/experience-lwc-runtime-observe/scripts/open-frontdoor.sh +46 -0
- package/skills/experience-lwc-runtime-observe/scripts/verify-toolchain.sh +48 -0
- package/skills/experience-lwc-security-validate/SKILL.md +151 -0
- package/skills/experience-lwc-security-validate/examples/review-report.md +6 -0
- package/skills/experience-lwc-security-validate/examples/score-report.sarif.json +32 -0
- package/skills/experience-lwc-security-validate/references/lws-security-expert.md +986 -0
- package/skills/experience-lwc-security-validate/references/security-analysis.md +611 -0
- package/skills/experience-lwc-security-validate/scripts/check-lwc-import.sh +166 -0
- package/skills/experience-lwc-security-validate/scripts/validate-sarif.sh +131 -0
- package/skills/experience-ui-bundle-2gp-deploy/SKILL.md +454 -0
- package/skills/experience-ui-bundle-2gp-deploy/assets/CustomApplication.app-meta.xml +12 -0
- package/skills/experience-ui-bundle-2gp-deploy/assets/PermissionSet.permissionset-meta.xml +9 -0
- package/skills/experience-ui-bundle-2gp-deploy/scripts/find-bundle-package-dir.sh +53 -0
- package/skills/experience-ui-bundle-agentforce-client-generate/SKILL.md +104 -26
- package/skills/experience-ui-bundle-agentforce-client-generate/references/constraints.md +35 -24
- package/skills/experience-ui-bundle-agentforce-client-generate/references/examples.md +92 -1
- package/skills/experience-ui-bundle-agentforce-client-generate/references/style-tokens.md +2 -0
- package/skills/experience-ui-bundle-agentforce-client-generate/references/troubleshooting.md +14 -1
- package/skills/experience-ui-bundle-agentforce-client-generate/scripts/detect-framework.sh +67 -0
- package/skills/experience-ui-bundle-deploy/SKILL.md +83 -14
- package/skills/experience-ui-bundle-deploy/assets/Communities.settings-meta.xml +19 -0
- package/skills/experience-ui-bundle-deploy/assets/org-setup.config.template.json +5 -0
- package/skills/experience-ui-bundle-deploy/assets/social-login-auth-providers.apex +158 -0
- package/skills/experience-ui-bundle-deploy/references/config-scaffold.md +13 -1
- package/skills/experience-ui-bundle-deploy/references/social-login.md +179 -0
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +14 -0
- package/skills/experience-ui-bundle-mfa-configure/SKILL.md +6 -5
- package/skills/experience-ui-bundle-mfa-configure/references/social-login.md +15 -7
- package/skills/experience-ui-bundle-salesforce-data-access/SKILL.md +41 -5
- package/skills/experience-ui-bundle-salesforce-data-access/references/caching.md +10 -22
- package/skills/experience-ui-bundle-salesforce-data-access/references/graphql-hand-authoring.md +4 -19
- package/skills/experience-ui-bundle-salesforce-data-access/references/migration.md +5 -0
- package/skills/experience-ui-bundle-salesforce-data-access/references/sdk-api.md +33 -150
- package/skills/mobile-platform-native-capabilities-integrate/references/nfc.md +35 -0
- package/skills/platform-apex-generate/SKILL.md +8 -7
- package/skills/platform-apex-test-generate/SKILL.md +3 -1
- package/skills/platform-apex-test-run/SKILL.md +9 -8
- package/skills/platform-lightning-type-widget-coordinate/SKILL.md +1 -1
- package/skills/platform-lightning-type-widget-coordinate/examples/existing-lightning-type-with-widget-prompt.md +1 -1
- package/skills/platform-lightning-type-widget-coordinate/examples/new-lightning-type-with-widget-prompt.md +1 -1
- package/skills/platform-lightning-type-widget-coordinate/references/validation-gates.md +3 -3
- package/skills/platform-mcp-tool-widget-coordinate/SKILL.md +43 -67
- package/skills/platform-mcp-tool-widget-coordinate/examples/action-name-source-prompt.md +1 -2
- package/skills/platform-mcp-tool-widget-coordinate/examples/apex-invocable-source-prompt.md +2 -3
- package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-list-source-prompt.md +163 -0
- package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-single-source-prompt.md +198 -0
- package/skills/platform-mcp-tool-widget-coordinate/examples/pasted-tool-output-prompt.md +0 -1
- package/skills/platform-mcp-tool-widget-coordinate/references/build-plan-format.md +17 -11
- package/skills/platform-mcp-tool-widget-coordinate/references/mcp-tool-output-discovery.md +48 -15
- package/skills/platform-mcp-tool-widget-coordinate/references/two-clt-modeling.md +73 -10
- package/skills/platform-mcp-tool-widget-coordinate/references/validation-gates.md +48 -8
- package/skills/platform-policy-rule-generate/SKILL.md +22 -12
- package/skills/platform-policy-rule-generate/references/deploy-errors.md +1 -1
- package/skills/platform-policy-rule-generate/references/policy-schema-full.md +8 -29
- package/skills/platform-policy-rule-generate/references/templates-advanced.md +1 -1
- package/skills/platform-sharing-owd-configure/SKILL.md +20 -8
- package/skills/platform-sharing-owd-configure/references/access_levels.md +14 -1
- package/skills/platform-sharing-rules-generate/SKILL.md +67 -35
- package/skills/platform-sharing-rules-generate/examples/create-cases.md +16 -17
- package/skills/platform-sharing-rules-generate/examples/delete-cases.md +34 -79
- package/skills/platform-sharing-rules-generate/examples/edit-cases.md +13 -26
- package/skills/platform-sharing-rules-generate/scripts/count-remaining-rules.sh +33 -0
- package/skills/platform-widget-generate/SKILL.md +3 -5
- package/skills/platform-widget-generate/examples/conditional.json +18 -13
- package/skills/platform-widget-generate/examples/list-with-foreach.json +2 -2
- package/skills/platform-widget-generate/examples/single-object.json +2 -2
- package/skills/platform-widget-generate/references/schema-from-lightning-type.md +27 -6
- package/skills/platform-widget-generate/references/widget-bundle-layout.md +4 -3
- package/skills/service-itsm-agentic-setup-cmdb-access-assign/SKILL.md +287 -0
- package/skills/service-itsm-agentic-setup-cmdb-access-assign/references/mcp-invocation.md +260 -0
- package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/SKILL.md +252 -0
- package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/references/mcp-invocation.md +204 -0
- package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +259 -0
- package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +188 -0
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +197 -0
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/examples/output-templates.md +77 -0
- package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/SKILL.md +316 -0
- package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/references/mcp-invocation.md +221 -0
- package/skills/service-itsm-incident-priority-configure/SKILL.md +168 -0
- package/skills/service-itsm-incident-priority-configure/examples/matrix-operations.md +200 -0
- package/skills/service-itsm-incident-priority-configure/examples/render-matrix.md +54 -0
- package/skills/service-itsm-incident-priority-configure/examples/seed-full-matrix.md +52 -0
- package/skills/service-itsm-incident-priority-configure/references/sf-cli-invocation.md +264 -0
- package/skills/platform-mcp-tool-widget-coordinate/examples/nested-object-source-prompt.md +0 -191
- package/skills/platform-policy-rule-generate/references/fixtures-index.md +0 -29
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: experience-ui-bundle-deploy
|
|
3
|
-
description: "MUST activate when the project
|
|
3
|
+
description: "MUST activate when the project has a uiBundles/*/src/ directory and the task involves deploying to an org or post-deploy org setup. Deploys a UI bundle app and runs ordered setup: org auth, build, metadata deploy, permission-set and role assignment, Experience Cloud self-registration, social login / SSO / IDP linking (Auth Providers + SAML SSO configs on a React site), seed-data import, and GraphQL schema fetch + codegen. Trigger signals: *.network-meta.xml, org-setup.config.json (with a socialLogin block), data-plan.json, sfdx-project.json, or mentions of deploy, org setup, or social login / SSO / IDP linking on an Experience site. DO NOT TRIGGER when: creating a new UI bundle project (use experience-ui-bundle-project-generate); styling pages without deploying (use experience-ui-bundle-frontend-generate); adding a feature such as auth, search, or file upload without deploying (use the matching experience-ui-bundle-*-generate skill); configuring MFA permission sets (use experience-ui-bundle-mfa-configure)."
|
|
4
4
|
metadata:
|
|
5
|
-
version: "1.
|
|
5
|
+
version: "1.2"
|
|
6
6
|
relatedSkills:
|
|
7
7
|
- "experience-ui-bundle-frontend-generate"
|
|
8
|
+
- "experience-ui-bundle-mfa-configure"
|
|
8
9
|
- "experience-ui-bundle-project-generate"
|
|
9
10
|
cliTools:
|
|
10
11
|
- tool: ["jq"]
|
|
@@ -43,10 +44,11 @@ Read these from the project; **ask the user** only for what's missing:
|
|
|
43
44
|
source dir from `sfdx-project.json` (`packageDirectories[0].path` + `/main/default`).
|
|
44
45
|
It exits non-zero if the project file is missing or malformed. Never hardcode
|
|
45
46
|
`force-app/main/default`.
|
|
46
|
-
- **`org-setup.config.json`** (optional) — drives permset assignment, role,
|
|
47
|
-
self-registration. Absent keys mean "skip that step".
|
|
48
|
-
file is missing but `permissionsets/` has permsets to
|
|
49
|
-
skip — scaffold the config or gather equivalent inputs
|
|
47
|
+
- **`org-setup.config.json`** (optional) — drives permset assignment, role,
|
|
48
|
+
self-registration, and social login. Absent keys mean "skip that step".
|
|
49
|
+
**Exception:** if the file is missing but `permissionsets/` has permsets to
|
|
50
|
+
assign, don't silently skip — scaffold the config or gather equivalent inputs
|
|
51
|
+
(see step 4).
|
|
50
52
|
- **`data-plan.json`** (optional, in the project's `data/` dir) — presence enables the data step.
|
|
51
53
|
|
|
52
54
|
## Step 1 — Org authentication (always)
|
|
@@ -168,6 +170,67 @@ running.** Sequence (full detail in `references/self-registration.md`):
|
|
|
168
170
|
`assets/network-selfreg.apex` (idempotent; both are query-then-create; run 4a
|
|
169
171
|
and 4b as two separate `sf apex run` invocations).
|
|
170
172
|
|
|
173
|
+
## Step 6b — Enable social login (config-gated)
|
|
174
|
+
|
|
175
|
+
Run only when `org-setup.config.json` has a `socialLogin` block. If the block is
|
|
176
|
+
absent, `loadSocialLoginConfig` returns null and the step is hidden — no-op
|
|
177
|
+
cleanly and say so. This step is **non-destructive and idempotent** (it only adds
|
|
178
|
+
missing links/members), so — unlike self-registration and data import — it does
|
|
179
|
+
**not** require asking first.
|
|
180
|
+
|
|
181
|
+
This links the site's configured **Auth Providers** (OAuth) and **SAML SSO
|
|
182
|
+
configs** to the site so the built-in Social Login component renders their
|
|
183
|
+
buttons on the React login page. On React (Site Container) sites the SSO admin UI
|
|
184
|
+
is hidden, so the linking is done programmatically via `AuthConfig` /
|
|
185
|
+
`AuthConfigProviders` records — you cannot do it by clicking through Setup. Full
|
|
186
|
+
detail, sub-steps, and port-provenance: `references/social-login.md`.
|
|
187
|
+
|
|
188
|
+
Config shape (see `references/config-scaffold.md` for the full schema):
|
|
189
|
+
|
|
190
|
+
```json
|
|
191
|
+
{ "socialLogin": {
|
|
192
|
+
"communityMemberProfile": "Customer Community User",
|
|
193
|
+
"authProviderNames": ["Google", "My_SAML_Provider"],
|
|
194
|
+
"communityUserPermset": "myapp_Guest_User_Api_Access"
|
|
195
|
+
} }
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Sequence (mirrors reference `org-setup.mjs` `main()` social-login step, which runs
|
|
199
|
+
**after** self-registration and **before** the data/GraphQL steps):
|
|
200
|
+
|
|
201
|
+
Apply the `assets/` templates **verbatim** (like the self-reg/data steps) — full
|
|
202
|
+
runnable commands for each sub-step are in `references/social-login.md`:
|
|
203
|
+
|
|
204
|
+
1. **Derive the site** — run `scripts/derive-site-name.sh` (single
|
|
205
|
+
`*.network-meta.xml`; stop if zero/ambiguous). Social login needs the site to
|
|
206
|
+
resolve its `AuthConfig`.
|
|
207
|
+
2. **Enable "Allow standard external profiles"** — deploy
|
|
208
|
+
`assets/Communities.settings-meta.xml` via Metadata API (from a throwaway
|
|
209
|
+
minimal project; see the reference). Required so the SSO registration handler
|
|
210
|
+
can create users on standard community profiles; without it auth providers fail
|
|
211
|
+
user insert with `FIELD_INTEGRITY_EXCEPTION`. A "already active" warning is a
|
|
212
|
+
non-fatal skip.
|
|
213
|
+
3. **Link Auth Providers to the site `AuthConfig`** — run
|
|
214
|
+
`assets/social-login-auth-providers.apex` verbatim (substitute `<siteName>`,
|
|
215
|
+
`<ProviderNamesList>`, `<ApiVersion>`) to create the missing
|
|
216
|
+
`AuthConfigProviders` junctions, then read its `|DEBUG|` lines (table in the
|
|
217
|
+
reference). All-or-nothing: if any configured `authProviderNames` entry has no
|
|
218
|
+
matching `AuthProvider` (OAuth) or `SamlSsoConfig` (SAML) record, it emits
|
|
219
|
+
`MISSING_PROVIDERS` and links nothing — create/fix them in Setup first.
|
|
220
|
+
Already-linked providers are skipped (idempotent).
|
|
221
|
+
4. **Add the community member profile to `NetworkMemberGroup`** — resolve the
|
|
222
|
+
Network + Profile Ids and create the membership if absent (`sf data` commands in
|
|
223
|
+
the reference). Without it, SSO-registered users hit `NO_ACCESS: User was not
|
|
224
|
+
authorized for the community`.
|
|
225
|
+
5. **(Optional) Assign `communityUserPermset` to community users** — only when
|
|
226
|
+
configured. Grants `ApiEnabled` so `getCurrentUser()` (`/chatter/users/me`)
|
|
227
|
+
works for SSO-created users.
|
|
228
|
+
|
|
229
|
+
> **IMPORTANT:** A `socialLogin` block present but skipped is a silent-failure
|
|
230
|
+
> trap — the app deploys fine, but no social-login buttons ever appear on the
|
|
231
|
+
> login page and there is no error explaining why. Do not silently skip: run the
|
|
232
|
+
> step when the block is present, or state clearly that it was absent.
|
|
233
|
+
|
|
171
234
|
## Step 7 — Data import (presence-driven) — ask first
|
|
172
235
|
|
|
173
236
|
Run `scripts/find-data-plan.sh` first. If it exits non-zero, **skip this step** —
|
|
@@ -211,9 +274,10 @@ that changes objects, fields, or permissions.
|
|
|
211
274
|
|
|
212
275
|
## Done
|
|
213
276
|
|
|
214
|
-
Setup ends here — the
|
|
215
|
-
(`npm run dev:preview`) is a separate
|
|
216
|
-
user asks to preview the site, see
|
|
277
|
+
Setup ends here — the steps above (including the config-gated 6b social login)
|
|
278
|
+
are the complete sequence. Local dev preview (`npm run dev:preview`) is a separate
|
|
279
|
+
developer action, not part of setup; if the user asks to preview the site, see
|
|
280
|
+
`references/dev-preview.md`.
|
|
217
281
|
|
|
218
282
|
## Critical rules
|
|
219
283
|
|
|
@@ -222,14 +286,18 @@ user asks to preview the site, see `references/dev-preview.md`.
|
|
|
222
286
|
- Assign permissions **before** schema fetch — the caller may lack FLS otherwise.
|
|
223
287
|
- Re-run schema fetch + codegen **after every** metadata deploy that changes
|
|
224
288
|
objects, fields, or permissions.
|
|
225
|
-
- Never silently skip permission assignment, self-registration,
|
|
226
|
-
either the convention file is present (run it, asking
|
|
227
|
-
ones) or it's absent (skip cleanly and say so).
|
|
289
|
+
- Never silently skip permission assignment, self-registration, social login, or
|
|
290
|
+
data import — either the convention file/config block is present (run it, asking
|
|
291
|
+
first for the destructive ones) or it's absent (skip cleanly and say so). A
|
|
292
|
+
present-but-skipped `socialLogin` block means no login buttons appear with no
|
|
293
|
+
error to explain it.
|
|
228
294
|
- Discover the source path from `sfdx-project.json`; never hardcode
|
|
229
295
|
`force-app/main/default`.
|
|
230
296
|
- Apply the `assets/` Apex and XML templates **verbatim** — they encode
|
|
231
|
-
duplicate-rule bypass, `allOrNone=false` deletes, idempotency,
|
|
232
|
-
|
|
297
|
+
duplicate-rule bypass, `allOrNone=false` deletes, idempotency, SOQL-safety, and
|
|
298
|
+
(for social login) the all-or-nothing provider pre-check and the
|
|
299
|
+
DML-not-allowed-on-`AuthConfigProviders` REST-callout insert — all easy to get
|
|
300
|
+
wrong by hand.
|
|
233
301
|
|
|
234
302
|
## Interaction order (summary)
|
|
235
303
|
|
|
@@ -239,5 +307,6 @@ user asks to preview the site, see `references/dev-preview.md`.
|
|
|
239
307
|
4. Assign permission sets (config-driven assignee)
|
|
240
308
|
5. Assign role (if configured)
|
|
241
309
|
6. Enable self-registration (if configured — ask first)
|
|
310
|
+
6b. Enable social login (if `socialLogin` configured — idempotent, no ask needed)
|
|
242
311
|
7. Import data (if data plan exists — ask first)
|
|
243
312
|
8. Fetch GraphQL schema + codegen + final build
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
Enables the "Allow using standard external profiles for self-registration,
|
|
4
|
+
user creation, and login" org setting (field enableOotbProfExtUserOpsEnable).
|
|
5
|
+
|
|
6
|
+
Ported VERBATIM from reference org-setup.mjs enableExternalProfiles (lines
|
|
7
|
+
581-586). Required so SSO registration handlers can create users on standard
|
|
8
|
+
community profiles (e.g. "Customer Community User"); without it, auth providers
|
|
9
|
+
fail user insert with FIELD_INTEGRITY_EXCEPTION.
|
|
10
|
+
|
|
11
|
+
This is sub-step 1 of SKILL.md step 6b. Deploy this file via Metadata API
|
|
12
|
+
(the REST/Tooling approaches fail on many org types). See
|
|
13
|
+
references/social-login.md for the exact deploy invocation and the throwaway
|
|
14
|
+
minimal-project layout it needs. If the deploy warns that the setting is
|
|
15
|
+
already active, treat it as a non-fatal skip.
|
|
16
|
+
-->
|
|
17
|
+
<CommunitiesSettings xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
18
|
+
<enableOotbProfExtUserOpsEnable>true</enableOotbProfExtUserOpsEnable>
|
|
19
|
+
</CommunitiesSettings>
|
|
@@ -13,5 +13,10 @@
|
|
|
13
13
|
"selfRegistration": {
|
|
14
14
|
"selfRegProfile": "<Profile API name>",
|
|
15
15
|
"accountName": "<display name>"
|
|
16
|
+
},
|
|
17
|
+
"socialLogin": {
|
|
18
|
+
"communityMemberProfile": "<Profile name, e.g. Customer Community User>",
|
|
19
|
+
"authProviderNames": ["<AuthProvider or SamlSsoConfig DeveloperName>"],
|
|
20
|
+
"communityUserPermset": "<PermissionSet API name (optional)>"
|
|
16
21
|
}
|
|
17
22
|
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Anonymous Apex — link Auth Providers (OAuth + SAML) to a site's AuthConfig
|
|
3
|
+
* by creating AuthConfigProviders junction records (idempotent, all-or-nothing).
|
|
4
|
+
*
|
|
5
|
+
* Ported VERBATIM from reference org-setup.mjs enableAuthProvidersForSite
|
|
6
|
+
* (the generated `apex` template, lines 650-772). Apply this template as-is; do
|
|
7
|
+
* NOT invent your own AuthConfigProviders Apex — DML is not allowed on
|
|
8
|
+
* AuthConfigProviders, the linking must be an HTTP callout to the REST API, and
|
|
9
|
+
* the all-or-nothing failure check must run BEFORE any junction is created. These
|
|
10
|
+
* are easy to get wrong by hand.
|
|
11
|
+
*
|
|
12
|
+
* This is sub-step 2 of SKILL.md step 6b. It runs as a SINGLE `sf apex run`
|
|
13
|
+
* invocation. See references/social-login.md for how to read the |DEBUG| output
|
|
14
|
+
* lines this emits (AUTHCONFIG_FOUND / MISSING_PROVIDERS / INSERTED / etc.).
|
|
15
|
+
*
|
|
16
|
+
* Why programmatic: React (Site Container) sites hide the SSO admin UI, so
|
|
17
|
+
* providers cannot be linked via Setup -> Digital Experiences -> Login &
|
|
18
|
+
* Registration. AuthConfig.AuthOptionsAuthProvider auto-flips to true when the
|
|
19
|
+
* junctions are inserted — no separate update needed.
|
|
20
|
+
*
|
|
21
|
+
* PLACEHOLDERS — substitute before running:
|
|
22
|
+
* <siteName> = the derived site name (base name of the single
|
|
23
|
+
* networks/<siteName>.network-meta.xml). Used in the
|
|
24
|
+
* AuthConfig.Url LIKE match and the log header.
|
|
25
|
+
* <ProviderNamesList> = the socialLogin.authProviderNames values as a
|
|
26
|
+
* comma-separated Apex string-literal list, e.g.
|
|
27
|
+
* 'Google', 'My_SAML_Provider'. Each name MUST be
|
|
28
|
+
* validated against the SOQL-name whitelist first
|
|
29
|
+
* (reject any value containing ' \ or a control char —
|
|
30
|
+
* same guard the permset/self-reg paths use) and then
|
|
31
|
+
* single-quoted. This exact literal is used in BOTH the
|
|
32
|
+
* `DeveloperName IN (...)` clauses AND the requested-name
|
|
33
|
+
* loop below; keep them identical.
|
|
34
|
+
* <ApiVersion> = REST API version for the callout endpoint (e.g. 62.0).
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
// Enable Auth Providers (OAuth + SAML) for community "<siteName>"
|
|
38
|
+
Http http = new Http();
|
|
39
|
+
String baseUrl = Url.getOrgDomainUrl().toExternalForm();
|
|
40
|
+
String token = UserInfo.getSessionId();
|
|
41
|
+
|
|
42
|
+
// Step 1: Find the AuthConfig for this site
|
|
43
|
+
List<AuthConfig> authConfigs = [
|
|
44
|
+
SELECT Id, Url
|
|
45
|
+
FROM AuthConfig
|
|
46
|
+
WHERE Url LIKE '%<siteName>%'
|
|
47
|
+
LIMIT 1
|
|
48
|
+
];
|
|
49
|
+
if (authConfigs.isEmpty()) {
|
|
50
|
+
System.debug('ERROR_NO_AUTHCONFIG');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
AuthConfig ac = authConfigs[0];
|
|
54
|
+
System.debug('AUTHCONFIG_FOUND:' + ac.Id + ':' + ac.Url);
|
|
55
|
+
|
|
56
|
+
// Step 2: Query AuthProvider records by DeveloperName (OAuth providers)
|
|
57
|
+
List<AuthProvider> oauthProviders = [
|
|
58
|
+
SELECT Id, DeveloperName, FriendlyName
|
|
59
|
+
FROM AuthProvider
|
|
60
|
+
WHERE DeveloperName IN (<ProviderNamesList>)
|
|
61
|
+
];
|
|
62
|
+
System.debug('OAUTH_PROVIDERS_FOUND:' + oauthProviders.size());
|
|
63
|
+
|
|
64
|
+
// Step 3: Query SamlSsoConfig records by DeveloperName (SAML providers)
|
|
65
|
+
List<SamlSsoConfig> samlProviders = [
|
|
66
|
+
SELECT Id, DeveloperName
|
|
67
|
+
FROM SamlSsoConfig
|
|
68
|
+
WHERE DeveloperName IN (<ProviderNamesList>)
|
|
69
|
+
];
|
|
70
|
+
System.debug('SAML_PROVIDERS_FOUND:' + samlProviders.size());
|
|
71
|
+
|
|
72
|
+
// Combine both into a unified list with (Id, DeveloperName, Type)
|
|
73
|
+
List<Map<String, String>> allProviders = new List<Map<String, String>>();
|
|
74
|
+
for (AuthProvider ap : oauthProviders) {
|
|
75
|
+
allProviders.add(new Map<String, String>{
|
|
76
|
+
'Id' => ap.Id,
|
|
77
|
+
'DeveloperName' => ap.DeveloperName,
|
|
78
|
+
'Type' => 'OAuth'
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
for (SamlSsoConfig sp : samlProviders) {
|
|
82
|
+
allProviders.add(new Map<String, String>{
|
|
83
|
+
'Id' => sp.Id,
|
|
84
|
+
'DeveloperName' => sp.DeveloperName,
|
|
85
|
+
'Type' => 'SAML'
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (allProviders.isEmpty()) {
|
|
90
|
+
System.debug('ERROR_NO_PROVIDERS');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
System.debug('TOTAL_PROVIDERS_FOUND:' + allProviders.size());
|
|
94
|
+
|
|
95
|
+
// Fail fast if any requested provider name did not resolve to an AuthProvider
|
|
96
|
+
// (OAuth) or SamlSsoConfig (SAML) record. The isEmpty() check above only catches
|
|
97
|
+
// the case where NONE resolve; comparing the found DeveloperNames against the
|
|
98
|
+
// requested list also catches the strict-subset case (e.g. ["Google","Typo"]
|
|
99
|
+
// links Google but must not silently drop "Typo"). This runs BEFORE any junction
|
|
100
|
+
// record is created, so linking is all-or-nothing. Case-insensitive because SOQL
|
|
101
|
+
// "DeveloperName IN (...)" matches case-insensitively, so a stored DeveloperName
|
|
102
|
+
// may differ in case from the configured value and must not read as "missing".
|
|
103
|
+
Set<String> foundProviderNames = new Set<String>();
|
|
104
|
+
for (AuthProvider ap : oauthProviders) {
|
|
105
|
+
foundProviderNames.add(ap.DeveloperName.toLowerCase());
|
|
106
|
+
}
|
|
107
|
+
for (SamlSsoConfig sp : samlProviders) {
|
|
108
|
+
foundProviderNames.add(sp.DeveloperName.toLowerCase());
|
|
109
|
+
}
|
|
110
|
+
List<String> missingProviderNames = new List<String>();
|
|
111
|
+
for (String requestedName : new List<String>{<ProviderNamesList>}) {
|
|
112
|
+
if (!foundProviderNames.contains(requestedName.toLowerCase())) {
|
|
113
|
+
missingProviderNames.add(requestedName);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!missingProviderNames.isEmpty()) {
|
|
117
|
+
System.debug('MISSING_PROVIDERS:' + String.join(missingProviderNames, ','));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Step 4: Check existing AuthConfigProviders to avoid duplicates
|
|
122
|
+
Set<Id> existingProviderIds = new Set<Id>();
|
|
123
|
+
for (AuthConfigProviders acp : [
|
|
124
|
+
SELECT AuthProviderId FROM AuthConfigProviders WHERE AuthConfigId = :ac.Id
|
|
125
|
+
]) {
|
|
126
|
+
existingProviderIds.add(acp.AuthProviderId);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Step 5: Create missing junction records via REST API
|
|
130
|
+
Integer inserted = 0;
|
|
131
|
+
for (Map<String, String> provider : allProviders) {
|
|
132
|
+
String providerId = provider.get('Id');
|
|
133
|
+
String providerName = provider.get('DeveloperName');
|
|
134
|
+
String providerType = provider.get('Type');
|
|
135
|
+
|
|
136
|
+
if (existingProviderIds.contains(providerId)) {
|
|
137
|
+
System.debug('ALREADY_LINKED:' + providerName + ':' + providerType);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
HttpRequest req = new HttpRequest();
|
|
141
|
+
req.setEndpoint(baseUrl + '/services/data/v<ApiVersion>/sobjects/AuthConfigProviders');
|
|
142
|
+
req.setMethod('POST');
|
|
143
|
+
req.setHeader('Authorization', 'Bearer ' + token);
|
|
144
|
+
req.setHeader('Content-Type', 'application/json');
|
|
145
|
+
req.setBody('{"AuthConfigId":"' + ac.Id + '","AuthProviderId":"' + providerId + '"}');
|
|
146
|
+
HttpResponse res = http.send(req);
|
|
147
|
+
if (res.getStatusCode() == 201 || res.getStatusCode() == 200) {
|
|
148
|
+
System.debug('INSERTED:' + providerName + ':' + providerType);
|
|
149
|
+
inserted++;
|
|
150
|
+
} else {
|
|
151
|
+
System.debug('INSERT_FAILED:' + providerName + ':' + providerType + ':' + res.getStatusCode() + ':' + res.getBody());
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (inserted == 0 && existingProviderIds.size() >= allProviders.size()) {
|
|
155
|
+
System.debug('ALL_ALREADY_LINKED');
|
|
156
|
+
} else {
|
|
157
|
+
System.debug('TOTAL_INSERTED:' + inserted);
|
|
158
|
+
}
|
|
@@ -32,7 +32,10 @@ Every top-level key is optional; each object is strict (no extra keys).
|
|
|
32
32
|
},
|
|
33
33
|
"role": { "assignee": "currentUser", "roleName": "<UserRole name>" },
|
|
34
34
|
"selfRegistration": { "selfRegProfile": "<Profile API name>",
|
|
35
|
-
"accountName": "<display name>" }
|
|
35
|
+
"accountName": "<display name>" },
|
|
36
|
+
"socialLogin": { "communityMemberProfile": "<Profile name>",
|
|
37
|
+
"authProviderNames": ["<DeveloperName>", "..."],
|
|
38
|
+
"communityUserPermset": "<PermissionSet API name>" }
|
|
36
39
|
}
|
|
37
40
|
```
|
|
38
41
|
|
|
@@ -48,6 +51,15 @@ Every top-level key is optional; each object is strict (no extra keys).
|
|
|
48
51
|
`roleName` is a non-empty `UserRole` name.
|
|
49
52
|
- **`selfRegistration`** has no license field — the required license is derived
|
|
50
53
|
from `selfRegProfile` (see `references/license-checks.md`).
|
|
54
|
+
- **`socialLogin`** drives step 6b. `communityMemberProfile` (required) is the
|
|
55
|
+
profile added to `NetworkMemberGroup` so SSO-registered users can access the
|
|
56
|
+
site. `authProviderNames` (required, non-empty) are the **DeveloperNames** of
|
|
57
|
+
`AuthProvider` (OAuth) or `SamlSsoConfig` (SAML) records to link to the site's
|
|
58
|
+
`AuthConfig`. `communityUserPermset` (optional) is assigned to SSO-created
|
|
59
|
+
community users so `getCurrentUser()` works (needs `ApiEnabled`). Like
|
|
60
|
+
`selfRegistration`, there is **no `siteName`** — the site is derived from the
|
|
61
|
+
single `networks/<siteName>.network-meta.xml`. Full step detail:
|
|
62
|
+
`references/social-login.md`.
|
|
51
63
|
|
|
52
64
|
## Scaffolding flow (permset folder present, config missing)
|
|
53
65
|
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Social login — auth-provider linking, external profiles, community access
|
|
2
|
+
|
|
3
|
+
Detail for the **socialLogin** step (SKILL.md step 6b). Source of truth: reference
|
|
4
|
+
`org-setup.mjs` `loadSocialLoginConfig` (547-555), `enableExternalProfiles`
|
|
5
|
+
(569-617), `enableAuthProvidersForSite` (638-833), `addCommunityMemberProfile`
|
|
6
|
+
(847-917), `assignPermsetToCommunityUsers` (929-991), and the `main()` social-login
|
|
7
|
+
step (2124-2168). Config schema: `org-setup-config-schema.mjs` (65-81, strict).
|
|
8
|
+
|
|
9
|
+
Verbatim assets this step applies (do not hand-write — parity with the self-reg /
|
|
10
|
+
data steps): `assets/Communities.settings-meta.xml` (sub-step 1) and
|
|
11
|
+
`assets/social-login-auth-providers.apex` (sub-step 2). Sub-steps 3–4 are plain
|
|
12
|
+
`sf data query`/`create record` calls, given below.
|
|
13
|
+
|
|
14
|
+
Run this step **only** when `socialLogin` is configured in `org-setup.config.json`.
|
|
15
|
+
If the block is absent, `loadSocialLoginConfig` returns null and the step is hidden
|
|
16
|
+
— no-op cleanly. Unlike self-registration and data import, this step is
|
|
17
|
+
**non-destructive and idempotent**, so it does **not** require asking first.
|
|
18
|
+
|
|
19
|
+
## Why this is programmatic (not a Setup click-path)
|
|
20
|
+
|
|
21
|
+
On React (Site Container) Experience sites the SSO admin UI is hidden, so auth
|
|
22
|
+
providers cannot be linked to the site by clicking through Setup → Login &
|
|
23
|
+
Registration. The linking is done by creating `AuthConfigProviders` junction
|
|
24
|
+
records that tie each `AuthProvider`/`SamlSsoConfig` to the site's `AuthConfig`.
|
|
25
|
+
DML is not allowed on `AuthConfigProviders`, so the linking is done via Anonymous
|
|
26
|
+
Apex issuing REST callouts — shipped verbatim as
|
|
27
|
+
`assets/social-login-auth-providers.apex` (ported from `enableAuthProvidersForSite`,
|
|
28
|
+
638-833). `AuthConfig.AuthOptionsAuthProvider` auto-flips to true when the
|
|
29
|
+
junctions are inserted — no separate update needed.
|
|
30
|
+
|
|
31
|
+
Apply the `assets/` templates **verbatim**, exactly like the self-reg and data
|
|
32
|
+
steps — the Apex encodes the all-or-nothing pre-check, REST-callout insert
|
|
33
|
+
(DML-not-allowed workaround), and idempotency that are easy to get wrong by hand.
|
|
34
|
+
Do NOT invent your own social-login Apex.
|
|
35
|
+
|
|
36
|
+
Once linked, the site's built-in Social Login component (shipped in 264) renders a
|
|
37
|
+
button per configured provider on the React login page.
|
|
38
|
+
|
|
39
|
+
## Config shape
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{ "socialLogin": {
|
|
43
|
+
"communityMemberProfile": "Customer Community User",
|
|
44
|
+
"authProviderNames": ["Google", "My_SAML_Provider"],
|
|
45
|
+
"communityUserPermset": "myapp_Guest_User_Api_Access"
|
|
46
|
+
} }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- **`communityMemberProfile`** (required) — profile added to
|
|
50
|
+
`NetworkMemberGroup` so SSO-registered users can access the community. Also the
|
|
51
|
+
profile whose community users receive `communityUserPermset` (if set).
|
|
52
|
+
- **`authProviderNames`** (required, non-empty) — the **DeveloperNames** of
|
|
53
|
+
`AuthProvider` (OAuth) and/or `SamlSsoConfig` (SAML) records to link. These are
|
|
54
|
+
DeveloperNames, not friendly labels.
|
|
55
|
+
- **`communityUserPermset`** (optional) — permset assigned to SSO-created community
|
|
56
|
+
users so `getCurrentUser()` (`/chatter/users/me`, via `/sf/api/`) works; the
|
|
57
|
+
standard community profile lacks `ApiEnabled`. Typically the app's
|
|
58
|
+
`*_Guest_User_Api_Access` permset.
|
|
59
|
+
|
|
60
|
+
There is **no `siteName`** — the site is derived (below). All three string values
|
|
61
|
+
are validated against the SOQL-name whitelist before use in any query or generated
|
|
62
|
+
Apex (same guard the permset/self-reg paths use); a `'`, `\`, or control char is a
|
|
63
|
+
config error.
|
|
64
|
+
|
|
65
|
+
## Site derivation (`deriveSiteName`, 418-441)
|
|
66
|
+
|
|
67
|
+
The site is the base name of the **single** `*.network-meta.xml` under
|
|
68
|
+
`<packageDir>/main/default/networks/`. Zero or more than one → STOP (ambiguous; the
|
|
69
|
+
reference throws rather than guessing). Social login needs the site to resolve its
|
|
70
|
+
`AuthConfig` (matched via `AuthConfig.Url LIKE '%<siteName>%'`).
|
|
71
|
+
|
|
72
|
+
## Enablement sequence (mirrors `main()` 2124-2168)
|
|
73
|
+
|
|
74
|
+
Runs **after** self-registration (step 6) and **before** data import / GraphQL.
|
|
75
|
+
Every sub-step is idempotent — run its query first and skip work that already
|
|
76
|
+
exists. Substitute `<org>` with the target-org alias throughout. All three config
|
|
77
|
+
string values (`communityMemberProfile`, each `authProviderNames` entry,
|
|
78
|
+
`communityUserPermset`) MUST be validated against the SOQL-name whitelist before
|
|
79
|
+
use in any query/Apex below — reject any value containing `'`, `\`, or a control
|
|
80
|
+
char (same guard the permset/self-reg paths use); such a value is a config error.
|
|
81
|
+
|
|
82
|
+
### 1. Enable "Allow standard external profiles" (`enableExternalProfiles`, 569-617)
|
|
83
|
+
|
|
84
|
+
An org setting required so SSO registration handlers can create users on standard
|
|
85
|
+
community profiles; without it, auth providers return `FIELD_INTEGRITY_EXCEPTION`
|
|
86
|
+
on user insert. It deploys via Metadata API (REST/Tooling approaches fail on many
|
|
87
|
+
org types), so the `CommunitiesSettings` file needs a minimal throwaway sfdx
|
|
88
|
+
project. Read `assets/Communities.settings-meta.xml` and stage it in a temp dir:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
TMP=$(mktemp -d)
|
|
92
|
+
mkdir -p "$TMP/force-app/main/default/settings"
|
|
93
|
+
printf '{"packageDirectories":[{"path":"force-app","default":true}],"sourceApiVersion":"68.0"}' > "$TMP/sfdx-project.json"
|
|
94
|
+
cp skills/experience-ui-bundle-deploy/assets/Communities.settings-meta.xml \
|
|
95
|
+
"$TMP/force-app/main/default/settings/Communities.settings-meta.xml"
|
|
96
|
+
sf project deploy start --target-org <org> --source-dir "$TMP/force-app" --json
|
|
97
|
+
rm -rf "$TMP"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
A deploy warning that the setting is already active is a **non-fatal skip** — the
|
|
101
|
+
setting may already be on. Continue to sub-step 2.
|
|
102
|
+
|
|
103
|
+
### 2. Link Auth Providers to the site `AuthConfig` (`enableAuthProvidersForSite`, 638-833)
|
|
104
|
+
|
|
105
|
+
Apply `assets/social-login-auth-providers.apex` **verbatim** — do not hand-write
|
|
106
|
+
this. Substitute its placeholders: `<siteName>` (derived above), `<ProviderNamesList>`
|
|
107
|
+
(the whitelisted `authProviderNames` as a comma-separated single-quoted list, e.g.
|
|
108
|
+
`'Google', 'My_SAML_Provider'` — identical in both the `IN (...)` clauses and the
|
|
109
|
+
requested-name loop), and `<ApiVersion>` (e.g. `62.0`). Then run it as ONE call:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
sf apex run --target-org <org> --file assets/social-login-auth-providers.apex
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Read the `|DEBUG|` output lines (match `|DEBUG|` only — `sf apex run` echoes the
|
|
116
|
+
source, which would otherwise false-positive):
|
|
117
|
+
|
|
118
|
+
| `|DEBUG|` line | Meaning → action |
|
|
119
|
+
|----------------|------------------|
|
|
120
|
+
| `ERROR_NO_AUTHCONFIG` | No `AuthConfig` for the site → **fail**: "no AuthConfig found for site `<siteName>`". Publish/activate the site; confirm the derived name matches the org Network. |
|
|
121
|
+
| `ERROR_NO_PROVIDERS` | None of the names resolved → **fail**: none found for those names; create them in Setup first. |
|
|
122
|
+
| `MISSING_PROVIDERS:<names>` | Strict subset resolved → **fail**: "some configured auth providers were not found: `<names>`". Nothing was linked (all-or-nothing; the check runs before any insert). Create/fix them or fix the DeveloperName(s) and re-run. |
|
|
123
|
+
| `INSERT_FAILED:<name>:<type>:<code>:<body>` | A junction insert failed → **fail** after reporting each; `<code>`/`<body>` explain why. |
|
|
124
|
+
| `INSERTED:<name>:<type>` | Newly linked (report `+ <name>`). |
|
|
125
|
+
| `ALREADY_LINKED:<name>:<type>` / `ALL_ALREADY_LINKED` | Idempotent skip — already linked; report and continue. |
|
|
126
|
+
| `TOTAL_INSERTED:<n>` | Success — `<n>` providers newly linked. |
|
|
127
|
+
|
|
128
|
+
Matching is **case-insensitive** (SOQL `DeveloperName IN (...)` is), so a stored
|
|
129
|
+
name differing only in case is not "missing."
|
|
130
|
+
|
|
131
|
+
### 3. Add the community member profile to `NetworkMemberGroup` (`addCommunityMemberProfile`, 847-917)
|
|
132
|
+
|
|
133
|
+
Without it, users created by the SSO registration handler hit `NO_ACCESS: User was
|
|
134
|
+
not authorized for the community`. Resolve the Network + Profile Ids, skip if the
|
|
135
|
+
membership already exists, else create it (idempotent):
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Resolve Ids (<siteName> derived above; <communityMemberProfile> from config)
|
|
139
|
+
sf data query --target-org <org> --json \
|
|
140
|
+
--query "SELECT Id FROM Network WHERE Name = '<siteName>'" # -> <NetworkId>
|
|
141
|
+
sf data query --target-org <org> --json \
|
|
142
|
+
--query "SELECT Id FROM Profile WHERE Name = '<communityMemberProfile>'" # -> <ProfileId>
|
|
143
|
+
# Idempotency check — skip the create if this returns any record
|
|
144
|
+
sf data query --target-org <org> --json \
|
|
145
|
+
--query "SELECT Id FROM NetworkMemberGroup WHERE NetworkId = '<NetworkId>' AND ParentId = '<ProfileId>'"
|
|
146
|
+
# Create only if absent
|
|
147
|
+
sf data create record --target-org <org> --sobject NetworkMemberGroup \
|
|
148
|
+
--values "NetworkId='<NetworkId>' ParentId='<ProfileId>'" --json
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 4. (Optional) Assign `communityUserPermset` to community users (`assignPermsetToCommunityUsers`, 929-991)
|
|
152
|
+
|
|
153
|
+
Only when `communityUserPermset` is configured. Grants `ApiEnabled` so
|
|
154
|
+
`getCurrentUser()` (`/chatter/users/me` via `/sf/api/`) works for SSO-created
|
|
155
|
+
users. Find active community users on `communityMemberProfile` who lack the
|
|
156
|
+
permset, and assign it (idempotent; no users yet → skip, not fatal):
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Resolve the permset Id
|
|
160
|
+
sf data query --target-org <org> --json \
|
|
161
|
+
--query "SELECT Id FROM PermissionSet WHERE Name = '<communityUserPermset>'" # -> <PermSetId>
|
|
162
|
+
# Find users on the profile who do NOT already have it
|
|
163
|
+
sf data query --target-org <org> --json \
|
|
164
|
+
--query "SELECT Id, Username FROM User WHERE Profile.Name = '<communityMemberProfile>' AND IsActive = true AND UserType IN ('CspLitePortal','CustomerSuccess','PowerCustomerSuccess') AND Id NOT IN (SELECT AssigneeId FROM PermissionSetAssignment WHERE PermissionSetId = '<PermSetId>')"
|
|
165
|
+
# For each returned user Id, assign (treat DUPLICATE_VALUE as an already-assigned skip)
|
|
166
|
+
sf data create record --target-org <org> --sobject PermissionSetAssignment \
|
|
167
|
+
--values "PermissionSetId='<PermSetId>' AssigneeId='<UserId>'" --json
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Gotchas
|
|
171
|
+
|
|
172
|
+
| Symptom | Cause | Fix |
|
|
173
|
+
|---------|-------|-----|
|
|
174
|
+
| No social-login buttons on the login page | `socialLogin` block absent or step skipped | Add the block and run step 6b; it links providers to the site `AuthConfig` |
|
|
175
|
+
| "some configured auth providers were not found: X" | A DeveloperName in `authProviderNames` has no `AuthProvider`/`SamlSsoConfig` record | Create it in Setup first, or fix the DeveloperName. Nothing is linked until all resolve |
|
|
176
|
+
| `no AuthConfig found for site "<name>"` | Site not published/active, or name mis-derived | Publish the site; confirm the single `*.network-meta.xml` base name matches the org's Network name |
|
|
177
|
+
| SSO user: `NO_ACCESS: User was not authorized for the community` | `communityMemberProfile` not in `NetworkMemberGroup` | Ensure sub-step 3 ran (profile added to member groups) |
|
|
178
|
+
| SSO user insert fails with `FIELD_INTEGRITY_EXCEPTION` | "Allow standard external profiles" org setting off | Ensure sub-step 1 ran (`enableExternalProfiles`) |
|
|
179
|
+
| `getCurrentUser()` / `/chatter/users/me` fails for SSO users | Community profile lacks `ApiEnabled` | Set `communityUserPermset` so sub-step 4 assigns API access |
|
|
@@ -5,6 +5,7 @@ metadata:
|
|
|
5
5
|
version: "1.1"
|
|
6
6
|
relatedSkills:
|
|
7
7
|
- "experience-ui-bundle-app-coordinate"
|
|
8
|
+
- "experience-ui-bundle-features-generate"
|
|
8
9
|
- "experience-ui-bundle-metadata-generate"
|
|
9
10
|
- "experience-ui-bundle-salesforce-data-access"
|
|
10
11
|
cliTools:
|
|
@@ -51,6 +52,19 @@ A request to rename/rebrand the app (e.g. "call it X everywhere a user would see
|
|
|
51
52
|
|
|
52
53
|
---
|
|
53
54
|
|
|
55
|
+
## Pre-built Features (Check Before Hand-Building)
|
|
56
|
+
|
|
57
|
+
Some capabilities ship as pre-built, tested feature packages. The catalog **evolves and is not something you can know from memory** — never decide from the request wording alone whether a capability "is" or "isn't" a feature. Before hand-writing any non-trivial capability (anything beyond a plain page, component, or styling change) in this skill:
|
|
58
|
+
|
|
59
|
+
1. **Consult the authoritative catalog.** Invoke `experience-ui-bundle-features-generate`, which runs `list` to show the *current* set of installable features. Do not rely on a hardcoded or remembered list — this skill deliberately names none, because any names it listed would go stale.
|
|
60
|
+
2. **Detect whether a matching feature is already installed** in the bundle — inspect `package.json` dependencies and existing `src/` files. If present, use it as-is; do not reinstall or re-implement.
|
|
61
|
+
3. **If a matching feature exists in the catalog but isn't installed**, let `experience-ui-bundle-features-generate` install the tested package. Do not build it from scratch here.
|
|
62
|
+
4. **Only hand-build** a capability that has no matching catalog feature.
|
|
63
|
+
|
|
64
|
+
This gate is **idempotent**: when this skill runs as a phase of `experience-ui-bundle-app-coordinate` (which installs features earlier in its sequence), step 2 finds the feature already present and this collapses to a no-op. It only does real work when the skill was reached directly — the path that would otherwise skip feature detection.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
54
68
|
## Layout and Navigation
|
|
55
69
|
|
|
56
70
|
`appLayout.tsx` is the source of truth for navigation and layout. Every page shares this shell.
|
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
name: experience-ui-bundle-mfa-configure
|
|
3
3
|
description: "Configure Multi-Factor Authentication (MFA) for Salesforce Experience Site users. TRIGGER when: user wants to enable MFA on a community, enforce two-factor authentication for portal users, add MFA to a React Experience Site / Web App, configure ForceTwoFactor permission, create MFA permission sets for external users, or troubleshoot MFA not appearing on login. Also triggers on: MFA community, two-factor portal, ForceTwoFactor permission set, MFA Experience Cloud, MFA React site, identity verification community, MFA experience site, ForceTwoFactor permissionset-meta.xml, MFA permissionset-meta.xml. DO NOT TRIGGER when: configuring org-wide MFA for internal users (that's Setup > Identity Verification), building custom login UI components (use experience-ui-bundle-frontend-generate), or generating generic permission sets without MFA context (use platform-permission-set-generate)."
|
|
4
4
|
metadata:
|
|
5
|
-
version: "1.
|
|
5
|
+
version: "1.1"
|
|
6
6
|
minApiVersion: "47.0"
|
|
7
7
|
cliTools:
|
|
8
|
-
- tool: ["sf"]
|
|
9
|
-
semver: ">=2.0.0"
|
|
10
8
|
- tool: ["jq"]
|
|
11
9
|
semver: ">=1.6"
|
|
10
|
+
- tool: ["sf"]
|
|
11
|
+
semver: ">=2.0.0"
|
|
12
12
|
accessCheck:
|
|
13
13
|
- type: "license"
|
|
14
14
|
value: "Experience Cloud (Customer Community / Customer Community Login)"
|
|
15
15
|
relatedSkills:
|
|
16
|
-
- "platform-permission-set-generate"
|
|
17
16
|
- "dx-org-permission-set-assign"
|
|
17
|
+
- "experience-ui-bundle-deploy"
|
|
18
18
|
- "experience-ui-bundle-frontend-generate"
|
|
19
19
|
- "platform-metadata-deploy"
|
|
20
|
+
- "platform-permission-set-generate"
|
|
20
21
|
---
|
|
21
22
|
|
|
22
23
|
# Enabling MFA on Experience Sites
|
|
@@ -370,7 +371,7 @@ Files generated in the user's project:
|
|
|
370
371
|
| User needs to deploy all project metadata | `platform-metadata-deploy` |
|
|
371
372
|
| User wants to customize the login page UI | `experience-ui-bundle-frontend-generate` |
|
|
372
373
|
| User needs to create a new generic permission set | `platform-permission-set-generate` |
|
|
373
|
-
| User wants IDP/Social Login (different from MFA) | Supported on React sites — the built-in Social Login component renders
|
|
374
|
+
| User wants IDP/Social Login (different from MFA) | Supported on React sites — the built-in Social Login component renders linked Auth Providers on the login page automatically. Create the Auth Providers in Setup, then link them to the React site via the `experience-ui-bundle-deploy` social login step (`socialLogin` in `org-setup.config.json`) — the React SSO admin UI is hidden, so linking is programmatic, not a Setup click-path. See `references/social-login.md`. |
|
|
374
375
|
|
|
375
376
|
---
|
|
376
377
|
|
|
@@ -24,12 +24,20 @@ writing a component.
|
|
|
24
24
|
|
|
25
25
|
## How to enable
|
|
26
26
|
|
|
27
|
-
1. **
|
|
28
|
-
(e.g. Google, Facebook, Salesforce, or a SAML/OpenID Connect provider).
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
1. **Create the Auth Provider(s)** in Setup → Identity → Auth. Providers
|
|
28
|
+
(e.g. Google, Facebook, Salesforce, or a SAML/OpenID Connect provider). This
|
|
29
|
+
part is done in Setup as usual.
|
|
30
|
+
2. **Link the provider(s) to the React site.** Do **not** use Setup → Digital
|
|
31
|
+
Experiences → Login & Registration for this — on React (Site Container) sites
|
|
32
|
+
that SSO admin UI is **hidden**, so the provider cannot be attached to the site
|
|
33
|
+
by clicking through Setup. The link is created programmatically by writing
|
|
34
|
+
`AuthConfigProviders` junction records against the site's `AuthConfig`. Use the
|
|
35
|
+
`experience-ui-bundle-deploy` skill's **social login step** (a `socialLogin`
|
|
36
|
+
block in `org-setup.config.json` with `communityMemberProfile` +
|
|
37
|
+
`authProviderNames`), which runs the shipped org-setup automation and also adds
|
|
38
|
+
the community profile to the site's `NetworkMemberGroup`. See that skill's
|
|
39
|
+
`references/social-login.md` for the mechanism and config.
|
|
40
|
+
3. **Publish** the site. The React login page renders a button per linked
|
|
33
41
|
provider automatically.
|
|
34
42
|
|
|
35
43
|
## How the redirect works (for troubleshooting)
|
|
@@ -56,7 +64,7 @@ writing a component.
|
|
|
56
64
|
|
|
57
65
|
| Symptom | Cause | Fix |
|
|
58
66
|
|---------|-------|-----|
|
|
59
|
-
| No provider buttons on React login page | No Auth Providers
|
|
67
|
+
| No provider buttons on React login page | No Auth Providers created, or created but not linked to the site's `AuthConfig` (React sites can't be linked via the Login & Registration UI — it's hidden) | Create the Auth Providers, then link them via the `experience-ui-bundle-deploy` social login step (`socialLogin` in `org-setup.config.json`), and re-publish |
|
|
60
68
|
| Buttons appear but SSO fails to start | `startURL` points at `/` or `/login` | Set `startURL` to the site home path |
|
|
61
69
|
| Redirect loop after SSO | `startURL` misconfigured | Point `startURL` at the site home path, not the login page |
|
|
62
70
|
| Provider button missing an icon | Auth Provider icon not set | Set the icon on the Auth Provider definition |
|