Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
See [AGENTS.md](../AGENTS.md) for full agent context and architectural guidance for this repository.

> **Note:** GitHub Copilot has no file-include directive syntax. This file cannot automatically inject `AGENTS.md` content. Read `AGENTS.md` at the repository root and apply all guidance found there.

> **Edit AGENTS.md only** — not this file.
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,13 @@ test-output
.cursor/rules/nx-rules.mdc
.github/instructions/nx.instructions.md

# Gemini local knowledge base files
GEMINI.md
**/GEMINI.md

.claude/worktrees
.claude/settings.local.json
.claude/skills
.claude/CLAUDE.md
.opensource


# Polaris
.polaris-setup-progress.json
.playwright-mcp
Expand Down
139 changes: 139 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# AGENTS.md

This file provides guidance to AI coding agents (Claude Code, Cursor, GitHub Copilot, Gemini, etc.) when working with code in this repository. It follows the open AGENTS.md convention.

> **Note:** CLAUDE.md, GEMINI.md, and `.github/copilot-instructions.md` in this repository are redirects to AGENTS.md. Edit AGENTS.md only.

## Development Commands

```sh
# Install dependencies
pnpm install --frozen-lockfile

# Full repo checks (affected projects only)
pnpm build
pnpm lint
pnpm test
pnpm test:e2e

# CI-parity (build + lint + test + e2e on affected)
pnpm exec nx affected -t build lint test e2e-ci

# Build all publishable packages
pnpm nx run-many -t build --no-agents

# Package-scoped commands (preferred for focused work)
pnpm --filter @forgerock/davinci-client build
pnpm --filter @forgerock/davinci-client lint
pnpm --filter @forgerock/davinci-client test

# Single test file
pnpm --filter @forgerock/davinci-client test -- --run src/lib/<file>.test.ts

# Single e2e suite
pnpm nx e2e <suite-project>

# Keep TS project references in sync
pnpm nx sync:check
```

## Architecture Overview

### Module Structure

The SDK is an **Nx + pnpm monorepo** with a strictly unidirectional dependency hierarchy. Higher layers may depend on lower layers — never the reverse. Enforced via Nx module boundary rules in `eslint.config.mjs`.

**Types layer** (`scope:sdk-types`):

- `@forgerock/sdk-types` — shared TypeScript contracts used across all packages

**Utilities / Effects layer** (`scope:sdk-utilities`, `scope:sdk-effects`):

- `@forgerock/sdk-utilities` — pure, stateless helpers shared across packages
- `packages/sdk-effects/logger` — structured logging
- `packages/sdk-effects/oidc` — OIDC session effects
- `packages/sdk-effects/storage` — storage abstraction
- `packages/sdk-effects/sdk-request-middleware` — request pipeline middleware
- `packages/sdk-effects/iframe-manager` — iframe lifecycle management

**Product client layer** (`scope:package`):

- `@forgerock/oidc-client` — OIDC/OAuth2 authentication
- `@forgerock/journey-client` — PingAM/ForgeRock Journey orchestration
- `@forgerock/davinci-client` — PingOne DaVinci flow orchestration
- `@forgerock/device-client` — device binding and attestation
- `@forgerock/protect` — Ping Protect fraud detection integration

### Key Directory Structure

```
packages/
├── sdk-types/ # Shared TypeScript types (no runtime code)
├── sdk-utilities/ # Pure helper functions
├── sdk-effects/
│ ├── logger/
│ ├── oidc/
│ ├── storage/
│ ├── sdk-request-middleware/
│ └── iframe-manager/
├── davinci-client/src/lib/
│ ├── client.store.ts # Public client facade (factory function)
│ ├── davinci.api.ts # Network layer (RTK Query)
│ ├── client.store.effects.ts # Side-effect orchestration
│ ├── node.reducer.ts # Redux state transitions
│ ├── node.slice.ts # Redux slice
│ ├── davinci.utils.ts # Pure helpers
│ └── davinci.types.ts # Type contracts
├── oidc-client/
├── journey-client/
├── device-client/
└── protect/

e2e/
├── davinci-suites/ # Playwright e2e for DaVinci flows
├── journey-suites/ # Playwright e2e for Journey flows
├── oidc-suites/ # Playwright e2e for OIDC flows
├── protect-suites/
├── am-mock-api/ # Mock AM server for journey e2e
└── mock-api-v2/ # Mock API v2
```

### Internal File Conventions

Architecture is encoded in file names — this is a constraint mechanism, not cosmetic:

| File suffix | Responsibility |
| ----------------------------- | --------------------------------------------------------------------------- |
| `store.ts` | Public client facade and network orchestration entrypoint |
| `*.api.ts` | Network/request boundary (RTK Query, middleware, error handling) |
| `*.effects.ts` | Single isolated side-effect — non-network async, storage, logging |
| `*.micros.ts` | Side-effectful workflows — multi-step async orchestration, polling, retries |
| `*.utils.ts` | Pure helpers and transformations — no side-effects, no state |
| `*.reducer.ts` / `*.slice.ts` | Redux state transitions and mapping |
| `*.types.ts` | Type contracts — no runtime code |

**Key rules:**

- Never put effectful logic in `*.utils.ts` — utils must be pure and stateless; side-effects belong in `*.effects.ts` (single isolated effect) or `*.micros.ts` (multi-step workflow)
- `*.types.ts` files have no runtime code — `type` and `interface` only, no `enum`
- Client packages are initialized via factory functions, never classes or singletons

## Development Notes

### Key Conventions

- **pnpm only.** `preinstall` enforces with `only-allow pnpm`.
- Workspace dependency versions are centralized via **pnpm catalogs** in `pnpm-workspace.yaml`.
- Releases are Changesets-driven (`pnpm ci:version`, `pnpm ci:release`), published from `main`.
- PRs target `main`, pass `pnpm run lint/build/test`, and use Conventional Commit style.

### Branch Strategy

- `main`: production branch, all releases published from here
- Feature branches target `main` via PR

### CI/CD

- GitHub Actions runs `pnpm exec nx affected -t build lint test e2e-ci` on PR/push
- E2E suites are Playwright projects — they start workspace apps via `pnpm nx serve` and, for journey flows, also start `am-mock-api`
- Releases are automated via Changesets on merge to `main`
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@AGENTS.md

> **Note:** This file is a redirect to AGENTS.md. Edit AGENTS.md only.
3 changes: 3 additions & 0 deletions GEMINI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@./AGENTS.md

> **Note:** This file is a redirect to AGENTS.md. Edit AGENTS.md only.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"ci:release": "pnpm nx run-many -t build --no-agents --skip-nx-cache && pnpm publish -r --no-git-checks && changeset tag",
"ci:version": "changeset version && pnpm install --no-frozen-lockfile && pnpm nx format:write --uncommitted",
"circular-dep-check": "madge --circular .",
"clean": "shx rm -rf ./{coverage,dist,docs,node_modules,tmp}/ ./{packages,e2e}/*/{dist,node_modules}/ ./e2e/node_modules/ && git clean -fX -e \"!.env*,nx-cloud.env\" -e \"!**/GEMINI.md\"",
"clean": "shx rm -rf ./{coverage,dist,docs,node_modules,tmp}/ ./{packages,e2e}/*/{dist,node_modules}/ ./e2e/node_modules/ && git clean -fX -e \"!.env*,nx-cloud.env\"",
"commit": "git cz",
"commitlint": "commitlint --edit",
"create-package": "nx g @nx/js:library",
Expand Down
Loading