{"owner":"facebook","repo":"facebook-ios-sdk","hasSkills":true,"totalSkillsCount":5,"totalTokensCount":3545,"categories":["anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":[".llms/rules/llms.md",".llms/skills/runbooks.md",".llms/skills/objc-interop.md",".llms/skills/testing.md",".llms/skills/public-api-design.md"],"skills":{".llms/rules/llms.md":"---\noncalls: ['sdk']\n---\n\n# Facebook iOS SDK — Coding Rules\n\nThese constraints apply to every change. Violating them will break builds or reviews.\n\n## Diff Summaries Are Published to Public GitHub\n\nThis repo is mirrored to GitHub, and ShipIt exports the **whole** commit message.\nThe `Summary` and `Test Plan` you write in Phabricator appear verbatim in public\nhistory. Treat every word as a public release: once pushed it is cloned, forked,\nand indexed, and amending the diff later does not retract what was mirrored.\n\nWrite the summary for an external reader. Describe *what changed and why* in\nterms of the public API and the code in this repo. Do not paste in anything whose\naudience is internal.\n\nKeep out of `Summary` and `Test Plan`:\n\n- **Internal identifiers** — task numbers (`T…`), SEV numbers, and internal-only\n  diff references. Say \"tracked internally\" or restate the substance instead.\n- **Internal URLs** — `internalfb.com`, `fburl.com`, Phabricator, wikis,\n  dashboards, Scuba/ODS links. An external reader cannot open them anyway.\n- **Unreleased plans** — launch dates, rollout percentages, upcoming products,\n  deprecations that have not been announced.\n- **Gating and config names** — GateKeepers, JustKnobs, sitevars, experiment\n  names, and their values.\n- **Infrastructure detail** — hostnames, service names, capacity, internal\n  metrics, and raw log excerpts that embed any of the above.\n- **People** — names, unixnames, and org structure in the prose. (The\n  `Reviewers` / `Subscribers` / `Differential Revision` trailers are generated by\n  `jf` and are exported regardless; that is expected. Everything you type is not.)\n\nCI signal names and script paths that already live in this repo (for example\n`ios-sdk-unit-tests`, `ci/unit_tests.py`) are fine — they are public here.\n\nBefore `jf submit`, scan the message:\n\n```bash\ngit log -1 --format=%B | grep -inE 'T[0-9]{6,}|internalfb|fburl|phabricator|\\bGK\\b|justknob|sitevar|SEV[0-9]'\n```\n\nHits in the body need rewording; hits in the generated trailers are expected.\n\n## Style\n\n- 2-space indentation (no tabs), 120-char line length\n- Trailing commas mandatory on multi-line collections\n- Imports sorted; `@testable` imports first\n- Classes must be `final` unless explicitly `open`\n- Modifier order: `public override` (not `override public`)\n- Max cyclomatic complexity: 11\n\n## Copyright Header (every Swift/ObjC file)\n\n```swift\n/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n * All rights reserved.\n *\n * This source code is licensed under the license found in the\n * LICENSE file in the root directory of this source tree.\n */\n```\n\n## Naming\n\n- Public types: clean names (`LoginManager`), ObjC name via `@objc(FBSDKLoginManager)`\n- Internal types: underscore prefix (`_ErrorFactory`, `_BridgeAPI`)\n- Protocols: `-ing`/`-Providing`/`-Creating` suffixes (`ErrorCreating`, `URLOpening`)\n- Factory protocols: `*FactoryProtocol` (`GraphRequestFactoryProtocol`)\n- SPM naming: `FBSDK` prefix = ObjC target, no prefix = Swift target\n  (e.g., `FBSDKLoginKit` vs `FacebookLogin`)\n- Extensions for splitting types: `Settings+AutoLogAppEvents.swift`\n- Private constant namespacing: `private enum Keys { static let ... }`\n\n## Dependency Properties\n\nProperties in `ObjectDependencies` / `TypeDependencies` must be in **alphabetical\norder** by name. Types must always be protocols, never concrete types.\n\n## Public API — Dual Swift/ObjC Interfaces\n\nNew public methods using Swift-only types (`Result`, enums with associated values,\nstructs) require dual interfaces: `@nonobjc` Swift-preferred + `@available(swift,\nobsoleted: 0.1) @objc` ObjC-compatible, both delegating to a shared `private`\nimplementation. See `.llms/skills/public-api-design.md` for the full pattern.\n\n## Deployment Targets\n\n| Target | Minimum iOS |\n|--------|-------------|\n| SDK modules (`FBSDKCoreKit`, `FBSDKLoginKit`, etc.) | 15.0 |\n| Hackbook test app (`internal/testing/Hackbook`) | 15.0 |\n| CoffeeShop test app (`internal/testing/CoffeeShop`) | 15.0 |\n\nEverything inherits `15.0` from `xcodegen_project_common.yml` and\n`Configurations/Platform/iOS.xcconfig`; the podspecs and `Package.swift` declare\nthe same floor to consumers. Xcode 27 does not accept a deployment target below\n15.0, so do not lower these.\n\nDo NOT use APIs newer than the target's minimum without `@available` checks.\n\n## Simulator Destinations\n\nWhen building for iOS Simulator from the CLI, always query available\ndestinations first (`xcodebuild -scheme <Scheme> -showdestinations`) rather\nthan hardcoding device names. Device names change with each iOS/Xcode\ngeneration (e.g., iOS 26 has `iPhone 17 Pro`, not `iPhone 16`).\n\n## Build Settings\n\n- Warnings are errors (`GCC_TREAT_WARNINGS_AS_ERRORS = YES`)\n- `BUILD_LIBRARY_FOR_DISTRIBUTION = YES` — API stability required\n- Use xcconfig files — never add settings directly to targets\n- Swift 5.0, C++11, ARC enabled\n\n## Module Dependency Boundaries\n\n```\nBasics (L0) → AEM (L1) → Core (L2) → Login / Share / Gaming (L3)\n                                        Gaming also imports Share\n```\n\n| Source module | May import |\n|---|---|\n| `FBSDKCoreKit_Basics` | *(none)* |\n| `FBAEMKit` | `FBSDKCoreKit_Basics` |\n| `FBSDKCoreKit` | `FBSDKCoreKit_Basics`, `FBAEMKit` |\n| `FBSDKLoginKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics` |\n| `FBSDKShareKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics` |\n| `FBSDKGamingServicesKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics`, `FBSDKShareKit` |\n\nException: `CoreKitConfigurator.swift` uses `@testable import FBAEMKit` for\ncomposition-root wiring. System frameworks are always allowed.\n\n## New Files\n\nUse `./scripts/new-file.sh <Kit> <Path>` to scaffold source + test files. After:\nrun `./generate-projects.sh` and verify target membership in `project.yml` (both\nStatic and Dynamic targets; TV targets if cross-platform).\n\nBefore creating a new test double, check `TestTools/TestTools/` — shared doubles\nlike `TestSettings`, `TestGraphRequestFactory`, etc. already exist there.\n\n## Do Not Modify\n\nNever edit these files without explicit instruction:\n- `Package.swift` binary checksums or remote URLs\n- `.swiftformat`, `.swiftlint.yml` (tooling config)\n- `build/` directory (generated artifacts)\n- `*.xcframework` files (prebuilt binaries)\n\n## Test Verification\n\nAfter completing source changes, run `./scripts/test.sh <Kit>`. Changes to\n`FBSDKCoreKit_Basics` or `FBSDKCoreKit` may break downstream — run\n`./scripts/test.sh` (no args) for those. Fix failures before considering the\ntask done.\n\n| Directory | Kit |\n|-----------|-----|\n| `FBSDKCoreKit_Basics/` | `BasicKit` |\n| `FBAEMKit/` | `AEMKit` |\n| `FBSDKCoreKit/` | `CoreKit` |\n| `FBSDKLoginKit/` | `LoginKit` |\n| `FBSDKShareKit/` | `ShareKit` |\n| `FBSDKGamingServicesKit/` | `GamingKit` |\n",".llms/skills/runbooks.md":"---\noncalls: ['sdk']\n---\n\n# Common-Task Runbooks\n\nStep-by-step guides for multi-step workflows. Follow every step in order.\n\n---\n\n## Runbook A: Adding a New Public API Method\n\n1. **Determine if dual interface is needed.** Does the method use Swift-only types\n   (`Result`, enums with associated values, structs)? If yes → dual interface\n   required. If the types are ObjC-compatible (classes, `NSObject` subclasses,\n   primitives) → a single `@objc` method is sufficient.\n\n2. **For dual interface:** follow the pattern in `.llms/skills/public-api-design.md`.\n\n3. **For ObjC-only types:** a single `@objc` method is sufficient. No dual\n   interface needed.\n\n4. **Update `CHANGELOG.md`** — add an entry under the `[next]` section describing\n   the new API.\n\n---\n\n## Runbook B: Adding a New Dependency to a Type\n\n1. **Define a protocol** for the dependency. Use `-ing`/`-Providing`/`-Creating`\n   suffix (e.g., `TokenRefreshing`, `DataProviding`, `RequestCreating`).\n   Factory protocols use `*FactoryProtocol` (e.g., `GraphRequestFactoryProtocol`).\n\n2. **Add the protocol property** to `ObjectDependencies` or `TypeDependencies` in\n   the type's `DependentAsObject` / `DependentAsType` extension. Properties must be\n   in **alphabetical order** by name.\n\n3. **Wire the concrete implementation:**\n   - **For types in CoreKit:** add wiring in `CoreKitConfigurator`\n     (`FBSDKCoreKit/FBSDKCoreKit/Internal/Configuration/CoreKitConfigurator.swift`)\n     using components from `CoreKitComponents`\n     (`FBSDKCoreKit/FBSDKCoreKit/Internal/Configuration/CoreKitComponents.swift`).\n   - **For types in other modules (Login, Share, Gaming):** wire via\n     `defaultDependencies` in the type itself. See\n     `FBSDKLoginKit/FBSDKLoginKit/LoginManager.swift:72-95` for the pattern.\n\n4. **Create a test double** named `Test<Type>` in the module's\n   `<Module>/<Module>Tests/Helpers/` directory.\n\n5. **Update `setUp()`** in the relevant test file to inject the test double via\n   `setDependencies()`.\n\n6. **Run module tests:** `./scripts/test.sh <Kit>`\n\n---\n\n## Runbook C: Deprecating an API\n\n1. **Add the deprecation annotation** to the old method or property:\n   ```swift\n   @available(\n     *,\n     deprecated,\n     message: \"\"\"\n       This property is deprecated and will be removed in the next major release. \\\n       Use `newName` instead.\n       \"\"\"\n   )\n   ```\n\n2. **Make the deprecated API delegate to the replacement** — no logic duplication.\n   - For properties: deprecated computed property forwards to the new property.\n   - For methods: deprecated method calls the replacement method.\n\n   Reference: `FBSDKCoreKit/FBSDKCoreKit/Settings.swift:65-76`\n\n3. **Run module tests:** `./scripts/test.sh <Kit>`\n4. **Update `CHANGELOG.md`** — add a deprecation entry under the `[next]` section.\n",".llms/skills/objc-interop.md":"---\noncalls: ['sdk']\napply_to_path: '.*\\.(m|h)$'\n---\n\n# Objective-C Interop Conventions\n\n## Header Imports — CocoaPods vs SPM\n\nGate header imports to support both CocoaPods and SPM builds:\n\n```objc\n#ifdef FBSDKCOCOAPODS\n#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>\n#else\n#import \"FBSDKCoreKit+Internal.h\"\n#endif\n```\n\nAlways use `FBSDKCOCOAPODS` as the preprocessor macro for this gate.\n\n## Public Headers\n\nPublic ObjC headers must be placed in the module's `include/` directory so they\nare visible to SPM consumers.\n\n## Naming\n\nSee `.llms/rules/llms.md` \"Naming\" for full conventions. Key point: the `FBSDK`\nprefix is only used in the `@objc()` name, never in the Swift name.\n",".llms/skills/testing.md":"---\noncalls: ['sdk']\napply_to_path: '.*Tests.*\\.swift'\n---\n\n# Testing Conventions\n\n## Class Declaration\n- All test classes **must** be `final`.\n\n## Implicitly Unwrapped Optionals (IUOs)\n- Test properties set in `setUp()` use implicitly unwrapped optionals.\n- Wrap them in swiftlint disable/enable comments:\n```swift\n// swiftlint:disable implicitly_unwrapped_optional\nvar loginManager: LoginManager!\nvar settings: TestSettings!\n// swiftlint:enable implicitly_unwrapped_optional\n```\n\n## setUp() and Dependency Injection\n- `setUp()` must create all test doubles and inject dependencies via `setDependencies()`.\n- Call `super.setUp()` first.\n\n## Imports\n- Use `@testable import` for the module under test.\n- Import `TestTools` for shared test doubles.\n- Imports must be sorted, with `@testable` imports first.\n\n## Test Double Naming\n- Pattern: `Test<RealType>` (e.g., `TestSettings`, `TestGraphRequestFactory`).\n- Live in `<Module>Tests/Helpers/` or in the shared `TestTools` module.\n\n## Sample Data\n- Use `Sample*` factory types: `SampleAccessTokens`, `SampleError`, `SampleURLs`.\n\n## Assertions on Interactions\n- Test doubles use `captured*` properties to record interactions:\n```swift\nXCTAssertEqual(factory.capturedGraphPath, \"/me\")\nXCTAssertTrue(delegate.capturedDidComplete)\n```\n\n## File Location\n- Module-specific tests: `<Module>/<Module>Tests/`\n- Module-specific helpers: `<Module>/<Module>Tests/Helpers/`\n- Shared test doubles: `TestTools/TestTools/`\n",".llms/skills/public-api-design.md":"---\noncalls: ['sdk']\n---\n\n# Public API Design — Dual Swift/ObjC Interface Pattern\n\nThe SDK is migrating from Objective-C to Swift. New public APIs that involve\nSwift-only types (enums with associated values, `Result`, structs) must follow\nthe **dual-interface pattern** established by `LoginManager.logIn()`:\n\n1. A **Swift-preferred** method marked `@nonobjc`, using Swift-native types\n2. An **ObjC-compatible** method marked `@available(swift, obsoleted: 0.1)` and\n   `@objc(selectorName:)`, using ObjC-bridgeable types (`(Type?, Error?) -> Void`)\n3. Both delegate to a **shared private implementation**\n\n## Example (from LoginManager)\n\n```swift\n// MARK: - Swift API (preferred)\n\n@nonobjc\npublic func logIn(\n  viewController: UIViewController? = nil,\n  configuration: LoginConfiguration?,\n  completion: @escaping LoginResultBlock  // Swift-only LoginResult enum\n) {\n  commonLogIn(/* ... */)\n}\n\n// MARK: - ObjC API (legacy-compatible)\n\n@available(swift, obsoleted: 0.1)\n@objc(logInFromViewController:configuration:completion:)\npublic func logIn(\n  from viewController: UIViewController?,\n  configuration: LoginConfiguration?,\n  completion: @escaping (LoginManagerLoginResult?, Error?) -> Void\n) {\n  commonLogIn(/* ... */)\n}\n\n// MARK: - Shared Implementation\n\nprivate func commonLogIn(/* ... */) {\n  // Core logic here\n}\n```\n\nReference: `FBSDKLoginKit/FBSDKLoginKit/LoginManager.swift:128-199`\n\n## When to Use This Pattern\n\n- The method returns or accepts Swift-only types\n- The method is `public` and part of the SDK's external API surface\n- The type is already `@objc`-annotated (like `LoginManager`)\n\n## When NOT Needed\n\n- Internal types (not part of public API)\n- Types that are naturally ObjC-compatible (`@objc` enums with `Int` raw values,\n  `NSObject` subclasses)\n- Types already documented as Swift-only in `Package.swift`\n\n## Key Annotations\n\n| Annotation | Purpose |\n|-----------|---------|\n| `@nonobjc` | Hides the method from ObjC callers |\n| `@available(swift, obsoleted: 0.1)` | Hides the method from Swift callers |\n| `@objc(selectorName:)` | Exposes the method to ObjC with a specific selector |\n"},"files":{".llms/rules/llms.md":"---\noncalls: ['sdk']\n---\n\n# Facebook iOS SDK — Coding Rules\n\nThese constraints apply to every change. Violating them will break builds or reviews.\n\n## Diff Summaries Are Published to Public GitHub\n\nThis repo is mirrored to GitHub, and ShipIt exports the **whole** commit message.\nThe `Summary` and `Test Plan` you write in Phabricator appear verbatim in public\nhistory. Treat every word as a public release: once pushed it is cloned, forked,\nand indexed, and amending the diff later does not retract what was mirrored.\n\nWrite the summary for an external reader. Describe *what changed and why* in\nterms of the public API and the code in this repo. Do not paste in anything whose\naudience is internal.\n\nKeep out of `Summary` and `Test Plan`:\n\n- **Internal identifiers** — task numbers (`T…`), SEV numbers, and internal-only\n  diff references. Say \"tracked internally\" or restate the substance instead.\n- **Internal URLs** — `internalfb.com`, `fburl.com`, Phabricator, wikis,\n  dashboards, Scuba/ODS links. An external reader cannot open them anyway.\n- **Unreleased plans** — launch dates, rollout percentages, upcoming products,\n  deprecations that have not been announced.\n- **Gating and config names** — GateKeepers, JustKnobs, sitevars, experiment\n  names, and their values.\n- **Infrastructure detail** — hostnames, service names, capacity, internal\n  metrics, and raw log excerpts that embed any of the above.\n- **People** — names, unixnames, and org structure in the prose. (The\n  `Reviewers` / `Subscribers` / `Differential Revision` trailers are generated by\n  `jf` and are exported regardless; that is expected. Everything you type is not.)\n\nCI signal names and script paths that already live in this repo (for example\n`ios-sdk-unit-tests`, `ci/unit_tests.py`) are fine — they are public here.\n\nBefore `jf submit`, scan the message:\n\n```bash\ngit log -1 --format=%B | grep -inE 'T[0-9]{6,}|internalfb|fburl|phabricator|\\bGK\\b|justknob|sitevar|SEV[0-9]'\n```\n\nHits in the body need rewording; hits in the generated trailers are expected.\n\n## Style\n\n- 2-space indentation (no tabs), 120-char line length\n- Trailing commas mandatory on multi-line collections\n- Imports sorted; `@testable` imports first\n- Classes must be `final` unless explicitly `open`\n- Modifier order: `public override` (not `override public`)\n- Max cyclomatic complexity: 11\n\n## Copyright Header (every Swift/ObjC file)\n\n```swift\n/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n * All rights reserved.\n *\n * This source code is licensed under the license found in the\n * LICENSE file in the root directory of this source tree.\n */\n```\n\n## Naming\n\n- Public types: clean names (`LoginManager`), ObjC name via `@objc(FBSDKLoginManager)`\n- Internal types: underscore prefix (`_ErrorFactory`, `_BridgeAPI`)\n- Protocols: `-ing`/`-Providing`/`-Creating` suffixes (`ErrorCreating`, `URLOpening`)\n- Factory protocols: `*FactoryProtocol` (`GraphRequestFactoryProtocol`)\n- SPM naming: `FBSDK` prefix = ObjC target, no prefix = Swift target\n  (e.g., `FBSDKLoginKit` vs `FacebookLogin`)\n- Extensions for splitting types: `Settings+AutoLogAppEvents.swift`\n- Private constant namespacing: `private enum Keys { static let ... }`\n\n## Dependency Properties\n\nProperties in `ObjectDependencies` / `TypeDependencies` must be in **alphabetical\norder** by name. Types must always be protocols, never concrete types.\n\n## Public API — Dual Swift/ObjC Interfaces\n\nNew public methods using Swift-only types (`Result`, enums with associated values,\nstructs) require dual interfaces: `@nonobjc` Swift-preferred + `@available(swift,\nobsoleted: 0.1) @objc` ObjC-compatible, both delegating to a shared `private`\nimplementation. See `.llms/skills/public-api-design.md` for the full pattern.\n\n## Deployment Targets\n\n| Target | Minimum iOS |\n|--------|-------------|\n| SDK modules (`FBSDKCoreKit`, `FBSDKLoginKit`, etc.) | 15.0 |\n| Hackbook test app (`internal/testing/Hackbook`) | 15.0 |\n| CoffeeShop test app (`internal/testing/CoffeeShop`) | 15.0 |\n\nEverything inherits `15.0` from `xcodegen_project_common.yml` and\n`Configurations/Platform/iOS.xcconfig`; the podspecs and `Package.swift` declare\nthe same floor to consumers. Xcode 27 does not accept a deployment target below\n15.0, so do not lower these.\n\nDo NOT use APIs newer than the target's minimum without `@available` checks.\n\n## Simulator Destinations\n\nWhen building for iOS Simulator from the CLI, always query available\ndestinations first (`xcodebuild -scheme <Scheme> -showdestinations`) rather\nthan hardcoding device names. Device names change with each iOS/Xcode\ngeneration (e.g., iOS 26 has `iPhone 17 Pro`, not `iPhone 16`).\n\n## Build Settings\n\n- Warnings are errors (`GCC_TREAT_WARNINGS_AS_ERRORS = YES`)\n- `BUILD_LIBRARY_FOR_DISTRIBUTION = YES` — API stability required\n- Use xcconfig files — never add settings directly to targets\n- Swift 5.0, C++11, ARC enabled\n\n## Module Dependency Boundaries\n\n```\nBasics (L0) → AEM (L1) → Core (L2) → Login / Share / Gaming (L3)\n                                        Gaming also imports Share\n```\n\n| Source module | May import |\n|---|---|\n| `FBSDKCoreKit_Basics` | *(none)* |\n| `FBAEMKit` | `FBSDKCoreKit_Basics` |\n| `FBSDKCoreKit` | `FBSDKCoreKit_Basics`, `FBAEMKit` |\n| `FBSDKLoginKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics` |\n| `FBSDKShareKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics` |\n| `FBSDKGamingServicesKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics`, `FBSDKShareKit` |\n\nException: `CoreKitConfigurator.swift` uses `@testable import FBAEMKit` for\ncomposition-root wiring. System frameworks are always allowed.\n\n## New Files\n\nUse `./scripts/new-file.sh <Kit> <Path>` to scaffold source + test files. After:\nrun `./generate-projects.sh` and verify target membership in `project.yml` (both\nStatic and Dynamic targets; TV targets if cross-platform).\n\nBefore creating a new test double, check `TestTools/TestTools/` — shared doubles\nlike `TestSettings`, `TestGraphRequestFactory`, etc. already exist there.\n\n## Do Not Modify\n\nNever edit these files without explicit instruction:\n- `Package.swift` binary checksums or remote URLs\n- `.swiftformat`, `.swiftlint.yml` (tooling config)\n- `build/` directory (generated artifacts)\n- `*.xcframework` files (prebuilt binaries)\n\n## Test Verification\n\nAfter completing source changes, run `./scripts/test.sh <Kit>`. Changes to\n`FBSDKCoreKit_Basics` or `FBSDKCoreKit` may break downstream — run\n`./scripts/test.sh` (no args) for those. Fix failures before considering the\ntask done.\n\n| Directory | Kit |\n|-----------|-----|\n| `FBSDKCoreKit_Basics/` | `BasicKit` |\n| `FBAEMKit/` | `AEMKit` |\n| `FBSDKCoreKit/` | `CoreKit` |\n| `FBSDKLoginKit/` | `LoginKit` |\n| `FBSDKShareKit/` | `ShareKit` |\n| `FBSDKGamingServicesKit/` | `GamingKit` |\n",".llms/skills/runbooks.md":"---\noncalls: ['sdk']\n---\n\n# Common-Task Runbooks\n\nStep-by-step guides for multi-step workflows. Follow every step in order.\n\n---\n\n## Runbook A: Adding a New Public API Method\n\n1. **Determine if dual interface is needed.** Does the method use Swift-only types\n   (`Result`, enums with associated values, structs)? If yes → dual interface\n   required. If the types are ObjC-compatible (classes, `NSObject` subclasses,\n   primitives) → a single `@objc` method is sufficient.\n\n2. **For dual interface:** follow the pattern in `.llms/skills/public-api-design.md`.\n\n3. **For ObjC-only types:** a single `@objc` method is sufficient. No dual\n   interface needed.\n\n4. **Update `CHANGELOG.md`** — add an entry under the `[next]` section describing\n   the new API.\n\n---\n\n## Runbook B: Adding a New Dependency to a Type\n\n1. **Define a protocol** for the dependency. Use `-ing`/`-Providing`/`-Creating`\n   suffix (e.g., `TokenRefreshing`, `DataProviding`, `RequestCreating`).\n   Factory protocols use `*FactoryProtocol` (e.g., `GraphRequestFactoryProtocol`).\n\n2. **Add the protocol property** to `ObjectDependencies` or `TypeDependencies` in\n   the type's `DependentAsObject` / `DependentAsType` extension. Properties must be\n   in **alphabetical order** by name.\n\n3. **Wire the concrete implementation:**\n   - **For types in CoreKit:** add wiring in `CoreKitConfigurator`\n     (`FBSDKCoreKit/FBSDKCoreKit/Internal/Configuration/CoreKitConfigurator.swift`)\n     using components from `CoreKitComponents`\n     (`FBSDKCoreKit/FBSDKCoreKit/Internal/Configuration/CoreKitComponents.swift`).\n   - **For types in other modules (Login, Share, Gaming):** wire via\n     `defaultDependencies` in the type itself. See\n     `FBSDKLoginKit/FBSDKLoginKit/LoginManager.swift:72-95` for the pattern.\n\n4. **Create a test double** named `Test<Type>` in the module's\n   `<Module>/<Module>Tests/Helpers/` directory.\n\n5. **Update `setUp()`** in the relevant test file to inject the test double via\n   `setDependencies()`.\n\n6. **Run module tests:** `./scripts/test.sh <Kit>`\n\n---\n\n## Runbook C: Deprecating an API\n\n1. **Add the deprecation annotation** to the old method or property:\n   ```swift\n   @available(\n     *,\n     deprecated,\n     message: \"\"\"\n       This property is deprecated and will be removed in the next major release. \\\n       Use `newName` instead.\n       \"\"\"\n   )\n   ```\n\n2. **Make the deprecated API delegate to the replacement** — no logic duplication.\n   - For properties: deprecated computed property forwards to the new property.\n   - For methods: deprecated method calls the replacement method.\n\n   Reference: `FBSDKCoreKit/FBSDKCoreKit/Settings.swift:65-76`\n\n3. **Run module tests:** `./scripts/test.sh <Kit>`\n4. **Update `CHANGELOG.md`** — add a deprecation entry under the `[next]` section.\n",".llms/skills/objc-interop.md":"---\noncalls: ['sdk']\napply_to_path: '.*\\.(m|h)$'\n---\n\n# Objective-C Interop Conventions\n\n## Header Imports — CocoaPods vs SPM\n\nGate header imports to support both CocoaPods and SPM builds:\n\n```objc\n#ifdef FBSDKCOCOAPODS\n#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>\n#else\n#import \"FBSDKCoreKit+Internal.h\"\n#endif\n```\n\nAlways use `FBSDKCOCOAPODS` as the preprocessor macro for this gate.\n\n## Public Headers\n\nPublic ObjC headers must be placed in the module's `include/` directory so they\nare visible to SPM consumers.\n\n## Naming\n\nSee `.llms/rules/llms.md` \"Naming\" for full conventions. Key point: the `FBSDK`\nprefix is only used in the `@objc()` name, never in the Swift name.\n",".llms/skills/testing.md":"---\noncalls: ['sdk']\napply_to_path: '.*Tests.*\\.swift'\n---\n\n# Testing Conventions\n\n## Class Declaration\n- All test classes **must** be `final`.\n\n## Implicitly Unwrapped Optionals (IUOs)\n- Test properties set in `setUp()` use implicitly unwrapped optionals.\n- Wrap them in swiftlint disable/enable comments:\n```swift\n// swiftlint:disable implicitly_unwrapped_optional\nvar loginManager: LoginManager!\nvar settings: TestSettings!\n// swiftlint:enable implicitly_unwrapped_optional\n```\n\n## setUp() and Dependency Injection\n- `setUp()` must create all test doubles and inject dependencies via `setDependencies()`.\n- Call `super.setUp()` first.\n\n## Imports\n- Use `@testable import` for the module under test.\n- Import `TestTools` for shared test doubles.\n- Imports must be sorted, with `@testable` imports first.\n\n## Test Double Naming\n- Pattern: `Test<RealType>` (e.g., `TestSettings`, `TestGraphRequestFactory`).\n- Live in `<Module>Tests/Helpers/` or in the shared `TestTools` module.\n\n## Sample Data\n- Use `Sample*` factory types: `SampleAccessTokens`, `SampleError`, `SampleURLs`.\n\n## Assertions on Interactions\n- Test doubles use `captured*` properties to record interactions:\n```swift\nXCTAssertEqual(factory.capturedGraphPath, \"/me\")\nXCTAssertTrue(delegate.capturedDidComplete)\n```\n\n## File Location\n- Module-specific tests: `<Module>/<Module>Tests/`\n- Module-specific helpers: `<Module>/<Module>Tests/Helpers/`\n- Shared test doubles: `TestTools/TestTools/`\n",".llms/skills/public-api-design.md":"---\noncalls: ['sdk']\n---\n\n# Public API Design — Dual Swift/ObjC Interface Pattern\n\nThe SDK is migrating from Objective-C to Swift. New public APIs that involve\nSwift-only types (enums with associated values, `Result`, structs) must follow\nthe **dual-interface pattern** established by `LoginManager.logIn()`:\n\n1. A **Swift-preferred** method marked `@nonobjc`, using Swift-native types\n2. An **ObjC-compatible** method marked `@available(swift, obsoleted: 0.1)` and\n   `@objc(selectorName:)`, using ObjC-bridgeable types (`(Type?, Error?) -> Void`)\n3. Both delegate to a **shared private implementation**\n\n## Example (from LoginManager)\n\n```swift\n// MARK: - Swift API (preferred)\n\n@nonobjc\npublic func logIn(\n  viewController: UIViewController? = nil,\n  configuration: LoginConfiguration?,\n  completion: @escaping LoginResultBlock  // Swift-only LoginResult enum\n) {\n  commonLogIn(/* ... */)\n}\n\n// MARK: - ObjC API (legacy-compatible)\n\n@available(swift, obsoleted: 0.1)\n@objc(logInFromViewController:configuration:completion:)\npublic func logIn(\n  from viewController: UIViewController?,\n  configuration: LoginConfiguration?,\n  completion: @escaping (LoginManagerLoginResult?, Error?) -> Void\n) {\n  commonLogIn(/* ... */)\n}\n\n// MARK: - Shared Implementation\n\nprivate func commonLogIn(/* ... */) {\n  // Core logic here\n}\n```\n\nReference: `FBSDKLoginKit/FBSDKLoginKit/LoginManager.swift:128-199`\n\n## When to Use This Pattern\n\n- The method returns or accepts Swift-only types\n- The method is `public` and part of the SDK's external API surface\n- The type is already `@objc`-annotated (like `LoginManager`)\n\n## When NOT Needed\n\n- Internal types (not part of public API)\n- Types that are naturally ObjC-compatible (`@objc` enums with `Int` raw values,\n  `NSObject` subclasses)\n- Types already documented as Swift-only in `Package.swift`\n\n## Key Annotations\n\n| Annotation | Purpose |\n|-----------|---------|\n| `@nonobjc` | Hides the method from ObjC callers |\n| `@available(swift, obsoleted: 0.1)` | Hides the method from Swift callers |\n| `@objc(selectorName:)` | Exposes the method to ObjC with a specific selector |\n"},"items":[{"name":"llms.md","path":".llms/rules/llms.md","rawUrl":"https://raw.githubusercontent.com/facebook/facebook-ios-sdk/HEAD/.llms/rules/llms.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"---\noncalls: ['sdk']\n---\n\n# Facebook iOS SDK — Coding Rules\n\nThese constraints apply to every change. Violating them will break builds or reviews.\n\n## Diff Summaries Are Published to Public GitHub\n\nThis repo is mirrored to GitHub, and ShipIt exports the **whole** commit message.\nThe `Summary` and `Test Plan` you write in Phabricator appear verbatim in public\nhistory. Treat every word as a public release: once pushed it is cloned, forked,\nand indexed, and amending the diff later does not retract what was mirrored.\n\nWrite the summary for an external reader. Describe *what changed and why* in\nterms of the public API and the code in this repo. Do not paste in anything whose\naudience is internal.\n\nKeep out of `Summary` and `Test Plan`:\n\n- **Internal identifiers** — task numbers (`T…`), SEV numbers, and internal-only\n  diff references. Say \"tracked internally\" or restate the substance instead.\n- **Internal URLs** — `internalfb.com`, `fburl.com`, Phabricator, wikis,\n  dashboards, Scuba/ODS links. An external reader cannot open them anyway.\n- **Unreleased plans** — launch dates, rollout percentages, upcoming products,\n  deprecations that have not been announced.\n- **Gating and config names** — GateKeepers, JustKnobs, sitevars, experiment\n  names, and their values.\n- **Infrastructure detail** — hostnames, service names, capacity, internal\n  metrics, and raw log excerpts that embed any of the above.\n- **People** — names, unixnames, and org structure in the prose. (The\n  `Reviewers` / `Subscribers` / `Differential Revision` trailers are generated by\n  `jf` and are exported regardless; that is expected. Everything you type is not.)\n\nCI signal names and script paths that already live in this repo (for example\n`ios-sdk-unit-tests`, `ci/unit_tests.py`) are fine — they are public here.\n\nBefore `jf submit`, scan the message:\n\n```bash\ngit log -1 --format=%B | grep -inE 'T[0-9]{6,}|internalfb|fburl|phabricator|\\bGK\\b|justknob|sitevar|SEV[0-9]'\n```\n\nHits in the body need rewording; hits in the generated trailers are expected.\n\n## Style\n\n- 2-space indentation (no tabs), 120-char line length\n- Trailing commas mandatory on multi-line collections\n- Imports sorted; `@testable` imports first\n- Classes must be `final` unless explicitly `open`\n- Modifier order: `public override` (not `override public`)\n- Max cyclomatic complexity: 11\n\n## Copyright Header (every Swift/ObjC file)\n\n```swift\n/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n * All rights reserved.\n *\n * This source code is licensed under the license found in the\n * LICENSE file in the root directory of this source tree.\n */\n```\n\n## Naming\n\n- Public types: clean names (`LoginManager`), ObjC name via `@objc(FBSDKLoginManager)`\n- Internal types: underscore prefix (`_ErrorFactory`, `_BridgeAPI`)\n- Protocols: `-ing`/`-Providing`/`-Creating` suffixes (`ErrorCreating`, `URLOpening`)\n- Factory protocols: `*FactoryProtocol` (`GraphRequestFactoryProtocol`)\n- SPM naming: `FBSDK` prefix = ObjC target, no prefix = Swift target\n  (e.g., `FBSDKLoginKit` vs `FacebookLogin`)\n- Extensions for splitting types: `Settings+AutoLogAppEvents.swift`\n- Private constant namespacing: `private enum Keys { static let ... }`\n\n## Dependency Properties\n\nProperties in `ObjectDependencies` / `TypeDependencies` must be in **alphabetical\norder** by name. Types must always be protocols, never concrete types.\n\n## Public API — Dual Swift/ObjC Interfaces\n\nNew public methods using Swift-only types (`Result`, enums with associated values,\nstructs) require dual interfaces: `@nonobjc` Swift-preferred + `@available(swift,\nobsoleted: 0.1) @objc` ObjC-compatible, both delegating to a shared `private`\nimplementation. See `.llms/skills/public-api-design.md` for the full pattern.\n\n## Deployment Targets\n\n| Target | Minimum iOS |\n|--------|-------------|\n| SDK modules (`FBSDKCoreKit`, `FBSDKLoginKit`, etc.) | 15.0 |\n| Hackbook test app (`internal/testing/Hackbook`) | 15.0 |\n| CoffeeShop test app (`internal/testing/CoffeeShop`) | 15.0 |\n\nEverything inherits `15.0` from `xcodegen_project_common.yml` and\n`Configurations/Platform/iOS.xcconfig`; the podspecs and `Package.swift` declare\nthe same floor to consumers. Xcode 27 does not accept a deployment target below\n15.0, so do not lower these.\n\nDo NOT use APIs newer than the target's minimum without `@available` checks.\n\n## Simulator Destinations\n\nWhen building for iOS Simulator from the CLI, always query available\ndestinations first (`xcodebuild -scheme <Scheme> -showdestinations`) rather\nthan hardcoding device names. Device names change with each iOS/Xcode\ngeneration (e.g., iOS 26 has `iPhone 17 Pro`, not `iPhone 16`).\n\n## Build Settings\n\n- Warnings are errors (`GCC_TREAT_WARNINGS_AS_ERRORS = YES`)\n- `BUILD_LIBRARY_FOR_DISTRIBUTION = YES` — API stability required\n- Use xcconfig files — never add settings directly to targets\n- Swift 5.0, C++11, ARC enabled\n\n## Module Dependency Boundaries\n\n```\nBasics (L0) → AEM (L1) → Core (L2) → Login / Share / Gaming (L3)\n                                        Gaming also imports Share\n```\n\n| Source module | May import |\n|---|---|\n| `FBSDKCoreKit_Basics` | *(none)* |\n| `FBAEMKit` | `FBSDKCoreKit_Basics` |\n| `FBSDKCoreKit` | `FBSDKCoreKit_Basics`, `FBAEMKit` |\n| `FBSDKLoginKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics` |\n| `FBSDKShareKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics` |\n| `FBSDKGamingServicesKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics`, `FBSDKShareKit` |\n\nException: `CoreKitConfigurator.swift` uses `@testable import FBAEMKit` for\ncomposition-root wiring. System frameworks are always allowed.\n\n## New Files\n\nUse `./scripts/new-file.sh <Kit> <Path>` to scaffold source + test files. After:\nrun `./generate-projects.sh` and verify target membership in `project.yml` (both\nStatic and Dynamic targets; TV targets if cross-platform).\n\nBefore creating a new test double, check `TestTools/TestTools/` — shared doubles\nlike `TestSettings`, `TestGraphRequestFactory`, etc. already exist there.\n\n## Do Not Modify\n\nNever edit these files without explicit instruction:\n- `Package.swift` binary checksums or remote URLs\n- `.swiftformat`, `.swiftlint.yml` (tooling config)\n- `build/` directory (generated artifacts)\n- `*.xcframework` files (prebuilt binaries)\n\n## Test Verification\n\nAfter completing source changes, run `./scripts/test.sh <Kit>`. Changes to\n`FBSDKCoreKit_Basics` or `FBSDKCoreKit` may break downstream — run\n`./scripts/test.sh` (no args) for those. Fix failures before considering the\ntask done.\n\n| Directory | Kit |\n|-----------|-----|\n| `FBSDKCoreKit_Basics/` | `BasicKit` |\n| `FBAEMKit/` | `AEMKit` |\n| `FBSDKCoreKit/` | `CoreKit` |\n| `FBSDKLoginKit/` | `LoginKit` |\n| `FBSDKShareKit/` | `ShareKit` |\n| `FBSDKGamingServicesKit/` | `GamingKit` |\n","frontmatter":{"oncalls":["sdk"]},"isInternal":false,"tokens":1766,"sizeBytes":6767},{"name":"objc-interop.md","path":".llms/skills/objc-interop.md","rawUrl":"https://raw.githubusercontent.com/facebook/facebook-ios-sdk/HEAD/.llms/skills/objc-interop.md","title":"Skills Skill","category":"anthropic-skill","format":"markdown","content":"---\noncalls: ['sdk']\napply_to_path: '.*\\.(m|h)$'\n---\n\n# Objective-C Interop Conventions\n\n## Header Imports — CocoaPods vs SPM\n\nGate header imports to support both CocoaPods and SPM builds:\n\n```objc\n#ifdef FBSDKCOCOAPODS\n#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>\n#else\n#import \"FBSDKCoreKit+Internal.h\"\n#endif\n```\n\nAlways use `FBSDKCOCOAPODS` as the preprocessor macro for this gate.\n\n## Public Headers\n\nPublic ObjC headers must be placed in the module's `include/` directory so they\nare visible to SPM consumers.\n\n## Naming\n\nSee `.llms/rules/llms.md` \"Naming\" for full conventions. Key point: the `FBSDK`\nprefix is only used in the `@objc()` name, never in the Swift name.\n","frontmatter":{"oncalls":["sdk"],"apply_to_path":".*\\.(m|h)$"},"isInternal":false,"tokens":192,"sizeBytes":680},{"name":"public-api-design.md","path":".llms/skills/public-api-design.md","rawUrl":"https://raw.githubusercontent.com/facebook/facebook-ios-sdk/HEAD/.llms/skills/public-api-design.md","title":"Skills Skill","category":"anthropic-skill","format":"markdown","content":"---\noncalls: ['sdk']\n---\n\n# Public API Design — Dual Swift/ObjC Interface Pattern\n\nThe SDK is migrating from Objective-C to Swift. New public APIs that involve\nSwift-only types (enums with associated values, `Result`, structs) must follow\nthe **dual-interface pattern** established by `LoginManager.logIn()`:\n\n1. A **Swift-preferred** method marked `@nonobjc`, using Swift-native types\n2. An **ObjC-compatible** method marked `@available(swift, obsoleted: 0.1)` and\n   `@objc(selectorName:)`, using ObjC-bridgeable types (`(Type?, Error?) -> Void`)\n3. Both delegate to a **shared private implementation**\n\n## Example (from LoginManager)\n\n```swift\n// MARK: - Swift API (preferred)\n\n@nonobjc\npublic func logIn(\n  viewController: UIViewController? = nil,\n  configuration: LoginConfiguration?,\n  completion: @escaping LoginResultBlock  // Swift-only LoginResult enum\n) {\n  commonLogIn(/* ... */)\n}\n\n// MARK: - ObjC API (legacy-compatible)\n\n@available(swift, obsoleted: 0.1)\n@objc(logInFromViewController:configuration:completion:)\npublic func logIn(\n  from viewController: UIViewController?,\n  configuration: LoginConfiguration?,\n  completion: @escaping (LoginManagerLoginResult?, Error?) -> Void\n) {\n  commonLogIn(/* ... */)\n}\n\n// MARK: - Shared Implementation\n\nprivate func commonLogIn(/* ... */) {\n  // Core logic here\n}\n```\n\nReference: `FBSDKLoginKit/FBSDKLoginKit/LoginManager.swift:128-199`\n\n## When to Use This Pattern\n\n- The method returns or accepts Swift-only types\n- The method is `public` and part of the SDK's external API surface\n- The type is already `@objc`-annotated (like `LoginManager`)\n\n## When NOT Needed\n\n- Internal types (not part of public API)\n- Types that are naturally ObjC-compatible (`@objc` enums with `Int` raw values,\n  `NSObject` subclasses)\n- Types already documented as Swift-only in `Package.swift`\n\n## Key Annotations\n\n| Annotation | Purpose |\n|-----------|---------|\n| `@nonobjc` | Hides the method from ObjC callers |\n| `@available(swift, obsoleted: 0.1)` | Hides the method from Swift callers |\n| `@objc(selectorName:)` | Exposes the method to ObjC with a specific selector |\n","frontmatter":{"oncalls":["sdk"]},"isInternal":false,"tokens":528,"sizeBytes":2114},{"name":"runbooks.md","path":".llms/skills/runbooks.md","rawUrl":"https://raw.githubusercontent.com/facebook/facebook-ios-sdk/HEAD/.llms/skills/runbooks.md","title":"Skills Skill","category":"anthropic-skill","format":"markdown","content":"---\noncalls: ['sdk']\n---\n\n# Common-Task Runbooks\n\nStep-by-step guides for multi-step workflows. Follow every step in order.\n\n---\n\n## Runbook A: Adding a New Public API Method\n\n1. **Determine if dual interface is needed.** Does the method use Swift-only types\n   (`Result`, enums with associated values, structs)? If yes → dual interface\n   required. If the types are ObjC-compatible (classes, `NSObject` subclasses,\n   primitives) → a single `@objc` method is sufficient.\n\n2. **For dual interface:** follow the pattern in `.llms/skills/public-api-design.md`.\n\n3. **For ObjC-only types:** a single `@objc` method is sufficient. No dual\n   interface needed.\n\n4. **Update `CHANGELOG.md`** — add an entry under the `[next]` section describing\n   the new API.\n\n---\n\n## Runbook B: Adding a New Dependency to a Type\n\n1. **Define a protocol** for the dependency. Use `-ing`/`-Providing`/`-Creating`\n   suffix (e.g., `TokenRefreshing`, `DataProviding`, `RequestCreating`).\n   Factory protocols use `*FactoryProtocol` (e.g., `GraphRequestFactoryProtocol`).\n\n2. **Add the protocol property** to `ObjectDependencies` or `TypeDependencies` in\n   the type's `DependentAsObject` / `DependentAsType` extension. Properties must be\n   in **alphabetical order** by name.\n\n3. **Wire the concrete implementation:**\n   - **For types in CoreKit:** add wiring in `CoreKitConfigurator`\n     (`FBSDKCoreKit/FBSDKCoreKit/Internal/Configuration/CoreKitConfigurator.swift`)\n     using components from `CoreKitComponents`\n     (`FBSDKCoreKit/FBSDKCoreKit/Internal/Configuration/CoreKitComponents.swift`).\n   - **For types in other modules (Login, Share, Gaming):** wire via\n     `defaultDependencies` in the type itself. See\n     `FBSDKLoginKit/FBSDKLoginKit/LoginManager.swift:72-95` for the pattern.\n\n4. **Create a test double** named `Test<Type>` in the module's\n   `<Module>/<Module>Tests/Helpers/` directory.\n\n5. **Update `setUp()`** in the relevant test file to inject the test double via\n   `setDependencies()`.\n\n6. **Run module tests:** `./scripts/test.sh <Kit>`\n\n---\n\n## Runbook C: Deprecating an API\n\n1. **Add the deprecation annotation** to the old method or property:\n   ```swift\n   @available(\n     *,\n     deprecated,\n     message: \"\"\"\n       This property is deprecated and will be removed in the next major release. \\\n       Use `newName` instead.\n       \"\"\"\n   )\n   ```\n\n2. **Make the deprecated API delegate to the replacement** — no logic duplication.\n   - For properties: deprecated computed property forwards to the new property.\n   - For methods: deprecated method calls the replacement method.\n\n   Reference: `FBSDKCoreKit/FBSDKCoreKit/Settings.swift:65-76`\n\n3. **Run module tests:** `./scripts/test.sh <Kit>`\n4. **Update `CHANGELOG.md`** — add a deprecation entry under the `[next]` section.\n","frontmatter":{"oncalls":["sdk"]},"isInternal":false,"tokens":702,"sizeBytes":2796},{"name":"testing.md","path":".llms/skills/testing.md","rawUrl":"https://raw.githubusercontent.com/facebook/facebook-ios-sdk/HEAD/.llms/skills/testing.md","title":"Skills Skill","category":"anthropic-skill","format":"markdown","content":"---\noncalls: ['sdk']\napply_to_path: '.*Tests.*\\.swift'\n---\n\n# Testing Conventions\n\n## Class Declaration\n- All test classes **must** be `final`.\n\n## Implicitly Unwrapped Optionals (IUOs)\n- Test properties set in `setUp()` use implicitly unwrapped optionals.\n- Wrap them in swiftlint disable/enable comments:\n```swift\n// swiftlint:disable implicitly_unwrapped_optional\nvar loginManager: LoginManager!\nvar settings: TestSettings!\n// swiftlint:enable implicitly_unwrapped_optional\n```\n\n## setUp() and Dependency Injection\n- `setUp()` must create all test doubles and inject dependencies via `setDependencies()`.\n- Call `super.setUp()` first.\n\n## Imports\n- Use `@testable import` for the module under test.\n- Import `TestTools` for shared test doubles.\n- Imports must be sorted, with `@testable` imports first.\n\n## Test Double Naming\n- Pattern: `Test<RealType>` (e.g., `TestSettings`, `TestGraphRequestFactory`).\n- Live in `<Module>Tests/Helpers/` or in the shared `TestTools` module.\n\n## Sample Data\n- Use `Sample*` factory types: `SampleAccessTokens`, `SampleError`, `SampleURLs`.\n\n## Assertions on Interactions\n- Test doubles use `captured*` properties to record interactions:\n```swift\nXCTAssertEqual(factory.capturedGraphPath, \"/me\")\nXCTAssertTrue(delegate.capturedDidComplete)\n```\n\n## File Location\n- Module-specific tests: `<Module>/<Module>Tests/`\n- Module-specific helpers: `<Module>/<Module>Tests/Helpers/`\n- Shared test doubles: `TestTools/TestTools/`\n","frontmatter":{"oncalls":["sdk"],"apply_to_path":".*Tests.*\\.swift"},"isInternal":false,"tokens":357,"sizeBytes":1457}],"systemPromptSnippet":"<yakaai_skills repo=\"facebook/facebook-ios-sdk\">\n<!-- File: .llms/rules/llms.md (Tokens: ~1766 | Category: anthropic-skill) -->\n---\noncalls: ['sdk']\n---\n\n# Facebook iOS SDK — Coding Rules\n\nThese constraints apply to every change. Violating them will break builds or reviews.\n\n## Diff Summaries Are Published to Public GitHub\n\nThis repo is mirrored to GitHub, and ShipIt exports the **whole** commit message.\nThe `Summary` and `Test Plan` you write in Phabricator appear verbatim in public\nhistory. Treat every word as a public release: once pushed it is cloned, forked,\nand indexed, and amending the diff later does not retract what was mirrored.\n\nWrite the summary for an external reader. Describe *what changed and why* in\nterms of the public API and the code in this repo. Do not paste in anything whose\naudience is internal.\n\nKeep out of `Summary` and `Test Plan`:\n\n- **Internal identifiers** — task numbers (`T…`), SEV numbers, and internal-only\n  diff references. Say \"tracked internally\" or restate the substance instead.\n- **Internal URLs** — `internalfb.com`, `fburl.com`, Phabricator, wikis,\n  dashboards, Scuba/ODS links. An external reader cannot open them anyway.\n- **Unreleased plans** — launch dates, rollout percentages, upcoming products,\n  deprecations that have not been announced.\n- **Gating and config names** — GateKeepers, JustKnobs, sitevars, experiment\n  names, and their values.\n- **Infrastructure detail** — hostnames, service names, capacity, internal\n  metrics, and raw log excerpts that embed any of the above.\n- **People** — names, unixnames, and org structure in the prose. (The\n  `Reviewers` / `Subscribers` / `Differential Revision` trailers are generated by\n  `jf` and are exported regardless; that is expected. Everything you type is not.)\n\nCI signal names and script paths that already live in this repo (for example\n`ios-sdk-unit-tests`, `ci/unit_tests.py`) are fine — they are public here.\n\nBefore `jf submit`, scan the message:\n\n```bash\ngit log -1 --format=%B | grep -inE 'T[0-9]{6,}|internalfb|fburl|phabricator|\\bGK\\b|justknob|sitevar|SEV[0-9]'\n```\n\nHits in the body need rewording; hits in the generated trailers are expected.\n\n## Style\n\n- 2-space indentation (no tabs), 120-char line length\n- Trailing commas mandatory on multi-line collections\n- Imports sorted; `@testable` imports first\n- Classes must be `final` unless explicitly `open`\n- Modifier order: `public override` (not `override public`)\n- Max cyclomatic complexity: 11\n\n## Copyright Header (every Swift/ObjC file)\n\n```swift\n/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n * All rights reserved.\n *\n * This source code is licensed under the license found in the\n * LICENSE file in the root directory of this source tree.\n */\n```\n\n## Naming\n\n- Public types: clean names (`LoginManager`), ObjC name via `@objc(FBSDKLoginManager)`\n- Internal types: underscore prefix (`_ErrorFactory`, `_BridgeAPI`)\n- Protocols: `-ing`/`-Providing`/`-Creating` suffixes (`ErrorCreating`, `URLOpening`)\n- Factory protocols: `*FactoryProtocol` (`GraphRequestFactoryProtocol`)\n- SPM naming: `FBSDK` prefix = ObjC target, no prefix = Swift target\n  (e.g., `FBSDKLoginKit` vs `FacebookLogin`)\n- Extensions for splitting types: `Settings+AutoLogAppEvents.swift`\n- Private constant namespacing: `private enum Keys { static let ... }`\n\n## Dependency Properties\n\nProperties in `ObjectDependencies` / `TypeDependencies` must be in **alphabetical\norder** by name. Types must always be protocols, never concrete types.\n\n## Public API — Dual Swift/ObjC Interfaces\n\nNew public methods using Swift-only types (`Result`, enums with associated values,\nstructs) require dual interfaces: `@nonobjc` Swift-preferred + `@available(swift,\nobsoleted: 0.1) @objc` ObjC-compatible, both delegating to a shared `private`\nimplementation. See `.llms/skills/public-api-design.md` for the full pattern.\n\n## Deployment Targets\n\n| Target | Minimum iOS |\n|--------|-------------|\n| SDK modules (`FBSDKCoreKit`, `FBSDKLoginKit`, etc.) | 15.0 |\n| Hackbook test app (`internal/testing/Hackbook`) | 15.0 |\n| CoffeeShop test app (`internal/testing/CoffeeShop`) | 15.0 |\n\nEverything inherits `15.0` from `xcodegen_project_common.yml` and\n`Configurations/Platform/iOS.xcconfig`; the podspecs and `Package.swift` declare\nthe same floor to consumers. Xcode 27 does not accept a deployment target below\n15.0, so do not lower these.\n\nDo NOT use APIs newer than the target's minimum without `@available` checks.\n\n## Simulator Destinations\n\nWhen building for iOS Simulator from the CLI, always query available\ndestinations first (`xcodebuild -scheme <Scheme> -showdestinations`) rather\nthan hardcoding device names. Device names change with each iOS/Xcode\ngeneration (e.g., iOS 26 has `iPhone 17 Pro`, not `iPhone 16`).\n\n## Build Settings\n\n- Warnings are errors (`GCC_TREAT_WARNINGS_AS_ERRORS = YES`)\n- `BUILD_LIBRARY_FOR_DISTRIBUTION = YES` — API stability required\n- Use xcconfig files — never add settings directly to targets\n- Swift 5.0, C++11, ARC enabled\n\n## Module Dependency Boundaries\n\n```\nBasics (L0) → AEM (L1) → Core (L2) → Login / Share / Gaming (L3)\n                                        Gaming also imports Share\n```\n\n| Source module | May import |\n|---|---|\n| `FBSDKCoreKit_Basics` | *(none)* |\n| `FBAEMKit` | `FBSDKCoreKit_Basics` |\n| `FBSDKCoreKit` | `FBSDKCoreKit_Basics`, `FBAEMKit` |\n| `FBSDKLoginKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics` |\n| `FBSDKShareKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics` |\n| `FBSDKGamingServicesKit` | `FBSDKCoreKit`, `FBSDKCoreKit_Basics`, `FBSDKShareKit` |\n\nException: `CoreKitConfigurator.swift` uses `@testable import FBAEMKit` for\ncomposition-root wiring. System frameworks are always allowed.\n\n## New Files\n\nUse `./scripts/new-file.sh <Kit> <Path>` to scaffold source + test files. After:\nrun `./generate-projects.sh` and verify target membership in `project.yml` (both\nStatic and Dynamic targets; TV targets if cross-platform).\n\nBefore creating a new test double, check `TestTools/TestTools/` — shared doubles\nlike `TestSettings`, `TestGraphRequestFactory`, etc. already exist there.\n\n## Do Not Modify\n\nNever edit these files without explicit instruction:\n- `Package.swift` binary checksums or remote URLs\n- `.swiftformat`, `.swiftlint.yml` (tooling config)\n- `build/` directory (generated artifacts)\n- `*.xcframework` files (prebuilt binaries)\n\n## Test Verification\n\nAfter completing source changes, run `./scripts/test.sh <Kit>`. Changes to\n`FBSDKCoreKit_Basics` or `FBSDKCoreKit` may break downstream — run\n`./scripts/test.sh` (no args) for those. Fix failures before considering the\ntask done.\n\n| Directory | Kit |\n|-----------|-----|\n| `FBSDKCoreKit_Basics/` | `BasicKit` |\n| `FBAEMKit/` | `AEMKit` |\n| `FBSDKCoreKit/` | `CoreKit` |\n| `FBSDKLoginKit/` | `LoginKit` |\n| `FBSDKShareKit/` | `ShareKit` |\n| `FBSDKGamingServicesKit/` | `GamingKit` |\n\n<!-- File: .llms/skills/objc-interop.md (Tokens: ~192 | Category: anthropic-skill) -->\n---\noncalls: ['sdk']\napply_to_path: '.*\\.(m|h)$'\n---\n\n# Objective-C Interop Conventions\n\n## Header Imports — CocoaPods vs SPM\n\nGate header imports to support both CocoaPods and SPM builds:\n\n```objc\n#ifdef FBSDKCOCOAPODS\n#import <FBSDKCoreKit/FBSDKCoreKit+Internal.h>\n#else\n#import \"FBSDKCoreKit+Internal.h\"\n#endif\n```\n\nAlways use `FBSDKCOCOAPODS` as the preprocessor macro for this gate.\n\n## Public Headers\n\nPublic ObjC headers must be placed in the module's `include/` directory so they\nare visible to SPM consumers.\n\n## Naming\n\nSee `.llms/rules/llms.md` \"Naming\" for full conventions. Key point: the `FBSDK`\nprefix is only used in the `@objc()` name, never in the Swift name.\n\n<!-- File: .llms/skills/public-api-design.md (Tokens: ~528 | Category: anthropic-skill) -->\n---\noncalls: ['sdk']\n---\n\n# Public API Design — Dual Swift/ObjC Interface Pattern\n\nThe SDK is migrating from Objective-C to Swift. New public APIs that involve\nSwift-only types (enums with associated values, `Result`, structs) must follow\nthe **dual-interface pattern** established by `LoginManager.logIn()`:\n\n1. A **Swift-preferred** method marked `@nonobjc`, using Swift-native types\n2. An **ObjC-compatible** method marked `@available(swift, obsoleted: 0.1)` and\n   `@objc(selectorName:)`, using ObjC-bridgeable types (`(Type?, Error?) -> Void`)\n3. Both delegate to a **shared private implementation**\n\n## Example (from LoginManager)\n\n```swift\n// MARK: - Swift API (preferred)\n\n@nonobjc\npublic func logIn(\n  viewController: UIViewController? = nil,\n  configuration: LoginConfiguration?,\n  completion: @escaping LoginResultBlock  // Swift-only LoginResult enum\n) {\n  commonLogIn(/* ... */)\n}\n\n// MARK: - ObjC API (legacy-compatible)\n\n@available(swift, obsoleted: 0.1)\n@objc(logInFromViewController:configuration:completion:)\npublic func logIn(\n  from viewController: UIViewController?,\n  configuration: LoginConfiguration?,\n  completion: @escaping (LoginManagerLoginResult?, Error?) -> Void\n) {\n  commonLogIn(/* ... */)\n}\n\n// MARK: - Shared Implementation\n\nprivate func commonLogIn(/* ... */) {\n  // Core logic here\n}\n```\n\nReference: `FBSDKLoginKit/FBSDKLoginKit/LoginManager.swift:128-199`\n\n## When to Use This Pattern\n\n- The method returns or accepts Swift-only types\n- The method is `public` and part of the SDK's external API surface\n- The type is already `@objc`-annotated (like `LoginManager`)\n\n## When NOT Needed\n\n- Internal types (not part of public API)\n- Types that are naturally ObjC-compatible (`@objc` enums with `Int` raw values,\n  `NSObject` subclasses)\n- Types already documented as Swift-only in `Package.swift`\n\n## Key Annotations\n\n| Annotation | Purpose |\n|-----------|---------|\n| `@nonobjc` | Hides the method from ObjC callers |\n| `@available(swift, obsoleted: 0.1)` | Hides the method from Swift callers |\n| `@objc(selectorName:)` | Exposes the method to ObjC with a specific selector |\n\n<!-- File: .llms/skills/runbooks.md (Tokens: ~702 | Category: anthropic-skill) -->\n---\noncalls: ['sdk']\n---\n\n# Common-Task Runbooks\n\nStep-by-step guides for multi-step workflows. Follow every step in order.\n\n---\n\n## Runbook A: Adding a New Public API Method\n\n1. **Determine if dual interface is needed.** Does the method use Swift-only types\n   (`Result`, enums with associated values, structs)? If yes → dual interface\n   required. If the types are ObjC-compatible (classes, `NSObject` subclasses,\n   primitives) → a single `@objc` method is sufficient.\n\n2. **For dual interface:** follow the pattern in `.llms/skills/public-api-design.md`.\n\n3. **For ObjC-only types:** a single `@objc` method is sufficient. No dual\n   interface needed.\n\n4. **Update `CHANGELOG.md`** — add an entry under the `[next]` section describing\n   the new API.\n\n---\n\n## Runbook B: Adding a New Dependency to a Type\n\n1. **Define a protocol** for the dependency. Use `-ing`/`-Providing`/`-Creating`\n   suffix (e.g., `TokenRefreshing`, `DataProviding`, `RequestCreating`).\n   Factory protocols use `*FactoryProtocol` (e.g., `GraphRequestFactoryProtocol`).\n\n2. **Add the protocol property** to `ObjectDependencies` or `TypeDependencies` in\n   the type's `DependentAsObject` / `DependentAsType` extension. Properties must be\n   in **alphabetical order** by name.\n\n3. **Wire the concrete implementation:**\n   - **For types in CoreKit:** add wiring in `CoreKitConfigurator`\n     (`FBSDKCoreKit/FBSDKCoreKit/Internal/Configuration/CoreKitConfigurator.swift`)\n     using components from `CoreKitComponents`\n     (`FBSDKCoreKit/FBSDKCoreKit/Internal/Configuration/CoreKitComponents.swift`).\n   - **For types in other modules (Login, Share, Gaming):** wire via\n     `defaultDependencies` in the type itself. See\n     `FBSDKLoginKit/FBSDKLoginKit/LoginManager.swift:72-95` for the pattern.\n\n4. **Create a test double** named `Test<Type>` in the module's\n   `<Module>/<Module>Tests/Helpers/` directory.\n\n5. **Update `setUp()`** in the relevant test file to inject the test double via\n   `setDependencies()`.\n\n6. **Run module tests:** `./scripts/test.sh <Kit>`\n\n---\n\n## Runbook C: Deprecating an API\n\n1. **Add the deprecation annotation** to the old method or property:\n   ```swift\n   @available(\n     *,\n     deprecated,\n     message: \"\"\"\n       This property is deprecated and will be removed in the next major release. \\\n       Use `newName` instead.\n       \"\"\"\n   )\n   ```\n\n2. **Make the deprecated API delegate to the replacement** — no logic duplication.\n   - For properties: deprecated computed property forwards to the new property.\n   - For methods: deprecated method calls the replacement method.\n\n   Reference: `FBSDKCoreKit/FBSDKCoreKit/Settings.swift:65-76`\n\n3. **Run module tests:** `./scripts/test.sh <Kit>`\n4. **Update `CHANGELOG.md`** — add a deprecation entry under the `[next]` section.\n\n<!-- File: .llms/skills/testing.md (Tokens: ~357 | Category: anthropic-skill) -->\n---\noncalls: ['sdk']\napply_to_path: '.*Tests.*\\.swift'\n---\n\n# Testing Conventions\n\n## Class Declaration\n- All test classes **must** be `final`.\n\n## Implicitly Unwrapped Optionals (IUOs)\n- Test properties set in `setUp()` use implicitly unwrapped optionals.\n- Wrap them in swiftlint disable/enable comments:\n```swift\n// swiftlint:disable implicitly_unwrapped_optional\nvar loginManager: LoginManager!\nvar settings: TestSettings!\n// swiftlint:enable implicitly_unwrapped_optional\n```\n\n## setUp() and Dependency Injection\n- `setUp()` must create all test doubles and inject dependencies via `setDependencies()`.\n- Call `super.setUp()` first.\n\n## Imports\n- Use `@testable import` for the module under test.\n- Import `TestTools` for shared test doubles.\n- Imports must be sorted, with `@testable` imports first.\n\n## Test Double Naming\n- Pattern: `Test<RealType>` (e.g., `TestSettings`, `TestGraphRequestFactory`).\n- Live in `<Module>Tests/Helpers/` or in the shared `TestTools` module.\n\n## Sample Data\n- Use `Sample*` factory types: `SampleAccessTokens`, `SampleError`, `SampleURLs`.\n\n## Assertions on Interactions\n- Test doubles use `captured*` properties to record interactions:\n```swift\nXCTAssertEqual(factory.capturedGraphPath, \"/me\")\nXCTAssertTrue(delegate.capturedDidComplete)\n```\n\n## File Location\n- Module-specific tests: `<Module>/<Module>Tests/`\n- Module-specific helpers: `<Module>/<Module>Tests/Helpers/`\n- Shared test doubles: `TestTools/TestTools/`\n</yakaai_skills>"}