Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ed92e54
Added make file
middt Mar 24, 2026
018df02
Added document, guide to run and troubleshoot
middt Apr 7, 2026
42fd4df
Added plugin support and some performance improvements
middt Apr 7, 2026
8813a42
snapshot
middt Apr 7, 2026
d0b4a88
snapshot
middt Apr 7, 2026
fb0edcf
update docs
middt Apr 7, 2026
0d82b62
Added logger plugin
middt Apr 7, 2026
e45d255
Added logger plugin
middt Apr 7, 2026
dff392e
feat(dart): add morph_core scaffold, docs, and CI (refs #1)
Apr 29, 2026
b4e5b15
docs: add stripped issue body file for gh issue sync
Apr 29, 2026
7c4e39d
docs: link issue #3 (Dart full TS parity epic) and persist issue body
Apr 29, 2026
6d8e527
Merge pull request #2 from burgan-tech/feat/dart-sdk-scaffold
cemal-yilmaz-bt Apr 29, 2026
8a05b8a
feat(dart): port validateAndIndexConfig and config helpers (#3)
Apr 29, 2026
1e1d8e5
Merge pull request #4 from burgan-tech/feat/dart-config-validate
cemal-yilmaz-bt Apr 29, 2026
16e4588
feat(dart): typed MorphConfig, utils, HTTP pipeline scaffolding
Apr 29, 2026
ef9e1dc
Merge pull request #5 from burgan-tech/feat/dart-conversion-full
cemal-yilmaz-bt Apr 29, 2026
55e6964
feat(dart): morph_oauth2 TokenVault, TokenLifecycle, oauth2Plugin parity
Apr 29, 2026
5c288c2
Merge pull request #7 from burgan-tech/feat/dart-morph-oauth2
cemal-yilmaz-bt Apr 29, 2026
700ef74
feat(dart): morph_logger LoggerPluginOptions + loggerPlugin parity
Apr 29, 2026
66d7c66
Merge pull request #9 from burgan-tech/feat/dart-morph-logger-parity
cemal-yilmaz-bt May 4, 2026
12245de
feat(dart): MorphRuntime + plugin install; MorphClient bootstrap
May 4, 2026
0d2af95
refactor(dart): simplify getTokenStatus refresh JWT gate (Gemini review)
May 4, 2026
d22343d
Merge pull request #11 from burgan-tech/feat/dart-morph-runtime-boots…
cemal-yilmaz-bt May 4, 2026
81011cd
docs: refresh dart-parity milestones and backlog (#15)
cemal-yilmaz-bt May 4, 2026
efdbf1c
feat(dart): OAuth redirect base and completeOAuthReturn parity (#16)
cemal-yilmaz-bt May 4, 2026
df6b7aa
feat(dart): MorphClient + HostClient + AuthHandle façade parity (#23)
cemal-yilmaz-bt May 4, 2026
85afdb5
poc: Flutter sample app (poc/flutter-poc) (#25)
cemal-yilmaz-bt May 4, 2026
80492f2
poc: switch flutter-poc to persistent ContextStore storage (#26)
cemal-yilmaz-bt May 4, 2026
9e138f5
feat(poc): Flutter POC feature parity with TS Vue POC (#28)
cemal-yilmaz-bt May 4, 2026
d2c01d8
poc(flutter): web stability, simulation tests & docs (#29)
cemal-yilmaz-bt May 4, 2026
e257149
chore: nest TypeScript SDK under packages/ts (closes #31) (#32)
cemal-yilmaz-bt May 4, 2026
8c9d9cf
docs(dart): align morph_core and morph_storage package metadata (#33)
cemal-yilmaz-bt May 4, 2026
0723761
refactor(poc): address Gemini review — simplify isPocSessionDeadStop …
cemal-yilmaz-bt Jun 1, 2026
0bbf751
fix(dart): address 5 Gemini review findings on PR #37
cemal-yilmaz-bt Jun 1, 2026
6671603
fix(dart): resolve dart analyze --fatal-infos failures
cemal-yilmaz-bt Jun 5, 2026
fdbce85
improvements
Jul 6, 2026
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
32 changes: 32 additions & 0 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Dart (packages)

on:
push:
branches: [main, f/plugin, "feat/**"]
pull_request:
branches: [main, f/plugin]

jobs:
morph_dart:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package:
- morph_core
- morph_oauth2
- morph_logger
defaults:
run:
working-directory: packages/dart/${{ matrix.package }}
steps:
- uses: actions/checkout@v4
- uses: dart-lang/setup-dart@v1
with:
sdk: stable
- name: Install dependencies
run: dart pub get
- name: Analyze
run: dart analyze --fatal-infos
- name: Test
run: dart test
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ dist/
.env
.env.local
.DS_Store

# Dart (packages/dart/*)
.dart_tool/
**/packages/dart/**/.dart_tool/
114 changes: 114 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
.PHONY: help install build dev mock-api \
dart-get dart-analyze dart-test dart-all \
keycloak-up keycloak-down keycloak-setup keycloak-test keycloak-logs \
keycloak-short-tokens keycloak-restore-tokens \
up down stop clean

help: ## Show available targets
@grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-24s\033[0m %s\n", $$1, $$2}'

# ---------------------------------------------------------------------------
# Dependencies & build
# ---------------------------------------------------------------------------

install: ## Install all npm dependencies (packages + vue + mock-api)
cd packages/ts/core && npm install
cd packages/ts/oauth2 && npm install
cd packages/ts/browser-storage && npm install
cd packages/ts/logger && npm install
cd poc/ts-vue && npm install
cd poc/mock-api && npm install

build: ## Build all SDK packages (core → oauth2 → browser-storage → logger)
cd packages/ts/core && npm run build
cd packages/ts/oauth2 && npm run build
cd packages/ts/browser-storage && npm run build
cd packages/ts/logger && npm run build

dart-get: ## Dart: pub get (packages/dart/morph_core)
cd packages/dart/morph_core && dart pub get

dart-analyze: ## Dart: analyze morph_core
cd packages/dart/morph_core && dart analyze --fatal-infos

dart-test: ## Dart: test morph_core
cd packages/dart/morph_core && dart test

dart-all: dart-get dart-analyze dart-test ## Dart: get + analyze + test morph_core

# ---------------------------------------------------------------------------
# Dev servers
# ---------------------------------------------------------------------------

dev: ## Start Vue PoC dev server (http://127.0.0.1:5173)
npm run dev

mock-api: ## Start mock API server (http://localhost:3000)
cd poc/mock-api && npm start

# ---------------------------------------------------------------------------
# Keycloak (Docker)
# ---------------------------------------------------------------------------

keycloak-up: ## Start Keycloak container (port 8080)
docker compose -f poc/keycloak/docker-compose.yml up -d

keycloak-down: ## Stop and remove Keycloak container
docker compose -f poc/keycloak/docker-compose.yml down

keycloak-logs: ## Tail Keycloak container logs
docker compose -f poc/keycloak/docker-compose.yml logs -f

keycloak-setup: ## Run Keycloak realm setup (clients, redirects, lifetimes, tests)
bash poc/keycloak/setup.sh

keycloak-test: ## Run OAuth2 flow smoke tests
bash poc/keycloak/test-flows.sh

keycloak-short-tokens: ## Apply PoC short token lifetimes (15s/30s/20s)
bash poc/keycloak/set-simulation-lifetimes.sh

keycloak-restore-tokens: ## Restore long-lived token lifetimes
bash poc/keycloak/restore-simulation-lifetimes.sh

# ---------------------------------------------------------------------------
# Full stack
# ---------------------------------------------------------------------------

up: keycloak-up ## Start full stack: Keycloak → setup → mock-api (bg) → Vue dev
@-lsof -ti :5173 | xargs kill -9 2>/dev/null || true
@-lsof -ti :3000 | xargs kill -9 2>/dev/null || true
@echo "Waiting for Keycloak to become ready…"
@for i in $$(seq 1 60); do \
curl -sf http://localhost:8080/realms/master > /dev/null 2>&1 && break; \
[ "$$i" -eq 60 ] && { echo "ERROR: Keycloak not ready after 60s"; exit 1; }; \
sleep 1; \
done
bash poc/keycloak/setup.sh
@echo ""
cd poc/mock-api && npm start &
@sleep 1
npm run dev

down: keycloak-down ## Stop Keycloak and kill mock-api / Vite processes
-@pkill -f "node.*poc/mock-api/server.js" 2>/dev/null || true
-@pkill -f "vite.*--host 127.0.0.1" 2>/dev/null || true
-@lsof -ti :5173 | xargs kill -9 2>/dev/null || true
-@lsof -ti :3000 | xargs kill -9 2>/dev/null || true
@echo "All services stopped."

stop: down ## Alias for 'down'

# ---------------------------------------------------------------------------
# Cleanup
# ---------------------------------------------------------------------------

clean: ## Remove node_modules and dist artefacts
rm -rf packages/ts/core/node_modules packages/ts/core/dist
rm -rf packages/ts/oauth2/node_modules packages/ts/oauth2/dist
rm -rf packages/ts/browser-storage/node_modules packages/ts/browser-storage/dist
rm -rf packages/ts/logger/node_modules packages/ts/logger/dist
rm -rf poc/ts-vue/node_modules poc/ts-vue/dist
rm -rf poc/mock-api/node_modules
rm -rf packages/dart/morph_core/.dart_tool
114 changes: 64 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,81 @@

Config-driven, multi-context HTTP client with built-in OAuth2 token lifecycle management.

## Quick start (Vue PoC)
## Quick start

**Prerequisites:** Docker, Node.js 20+, python3, curl

### 1. Keycloak + Mock API
### First time setup

```bash
# Start Keycloak (first run pulls image ~500MB)
cd poc/keycloak && docker compose up -d

# Wait for Keycloak & configure realm (takes ~30s on first run)
bash setup.sh

# Start mock API (separate terminal)
cd poc/mock-api && npm install && node server.js
```

If you see "Realm 'morph' not found", the Docker volume has stale data:

```bash
docker compose down -v && docker compose up -d && bash setup.sh
```

### 2. SDK + Vue app

```bash
# From repository root
cd core && npm install && npm run build
cd ../poc/ts-vue && npm install
cd ../..
npm run dev
```

Opens **http://127.0.0.1:5173/**. Rebuild the SDK after `core/` changes:

```bash
npm run build:core
make install # install all npm dependencies
make build # build all SDK packages
cp poc/ts-vue/.env.example poc/ts-vue/.env # create env with client secrets
make up # start Keycloak + setup + mock API + Vue dev server
```

### 3. Verify
### Day-to-day

```bash
cd poc/keycloak && bash test-flows.sh
make up # start full stack (Keycloak -> setup -> mock API -> Vue)
make down # stop everything
```

All 5 tests should pass (device token, login, refresh rotation, token exchange, JWT decode).

### Optional: Google OAuth

See [docs/poc/google-setup.md](docs/poc/google-setup.md) for external IdP integration.
Opens **http://127.0.0.1:5173/** (Vue PoC). Run `make help` to see all targets.

### Makefile targets

| Target | Description |
|--------|-------------|
| `make install` | Install npm deps for all packages, Vue PoC, and mock API |
| `make build` | Build all SDK packages (core -> oauth2 -> browser-storage) |
| `make up` | Start full stack: Keycloak -> setup -> mock API -> Vue |
| `make down` | Stop all services |
| `make dev` | Start Vue dev server only (http://127.0.0.1:5173) |
| `make mock-api` | Start mock API server only (http://localhost:3000) |
| `make keycloak-up` | Start Keycloak container (port 8080) |
| `make keycloak-down` | Stop Keycloak container |
| `make keycloak-setup` | Run realm setup (clients, redirects, lifetimes, tests) |
| `make keycloak-test` | Run OAuth2 flow smoke tests |
| `make keycloak-logs` | Tail Keycloak logs |
| `make keycloak-short-tokens` | Apply short token lifetimes (15s/30s/20s) |
| `make keycloak-restore-tokens` | Restore long-lived token lifetimes |
| `make clean` | Remove node_modules and dist |

### Services

| Service | URL |
|---------|-----|
| Vue PoC | http://127.0.0.1:5173 |
| Mock API | http://localhost:3000 |
| Keycloak Admin | http://localhost:8080/admin (admin/admin) |

## Documentation

See **[docs/README.md](docs/README.md)** for the full documentation index.

| Document | Description |
|----------|-------------|
| [Overview](docs/overview.md) | System architecture, auth flow diagrams, Keycloak client mapping |
| [PoC Guide](docs/poc-guide.md) | Step-by-step walkthrough of the Vue PoC app |
| [Troubleshooting](docs/troubleshooting.md) | Common errors and fixes |
| [Getting Started](docs/getting-started.md) | SDK installation and basic usage |
| [Writing Plugins](docs/writing-plugins.md) | How to create custom plugins (auth, storage, or utility) |
| [Configuration](docs/configuration.md) | Full config field reference |
| [API Reference](docs/api-reference.md) | Complete public API |
| [Architecture](docs/architecture.md) | Internal design and module structure |
| [Dart parity](docs/dart-parity.md) | Dart/Flutter SDK roadmap (scaffold under `packages/dart/morph_core`) |

## Layout

| Path | Role |
|------|------|
| `core/` | `morph-api-client` TypeScript SDK package |
| `core/src/runtime.ts` | MorphRuntime — thin coordinator |
| `core/src/tokens/` | TokenLifecycle + TokenVault |
| `core/src/http/` | HostPipeline (host HTTP + 401 recovery) |
| `core/src/client/` | MorphClient, HostClient, AuthHandle facades |
| `poc/ts-vue/` | Vue 3 demo app |
| `poc/keycloak/` | Docker Keycloak realm + setup/test scripts |
| `poc/mock-api/` | Mock REST API (Express, validates JWT via Keycloak/Google) |
| `docs/` | Design & API docs |
| Path | Package | Role |
|------|---------|------|
| `packages/ts/core/` | `@morph/core` | Types, config, HTTP pipeline, MorphClient, AuthHandle |
| `packages/ts/oauth2/` | `@morph/oauth2` | TokenLifecycle, TokenVault, OAuth helpers |
| `packages/ts/browser-storage/` | `@morph/browser-storage` | sessionStorage / localStorage adapters |
| `packages/ts/logger/` | `@morph/logger` | Structured logging and HTTP trace plugin |
| `packages/dart/morph_core/` | `morph_core` | **Dart** — config validation + indexes (parity with TS `validate.ts`); runtime/OAuth TBD — [docs/dart-parity.md](docs/dart-parity.md) |
| `poc/ts-vue/` | | Vue 3 demo app |
| `poc/keycloak/` | | Docker Keycloak realm + setup/test scripts |
| `poc/mock-api/` | | Mock REST API (Express, validates JWT) |
| `docs/` | | Design & API docs |
28 changes: 28 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Documentation

## Start here

| Document | Description |
|----------|-------------|
| [Overview](overview.md) | System architecture, auth flow diagrams, Keycloak client mapping, token storage model |
| [PoC Guide](poc-guide.md) | Step-by-step walkthrough of the Vue PoC app (sign-in, token exchange, simulation) |
| [Troubleshooting](troubleshooting.md) | Common errors and how to fix them |

## SDK Reference

| Document | Description |
|----------|-------------|
| [Getting Started](getting-started.md) | SDK installation, initialization, making API calls, providing tokens |
| [Writing Plugins](writing-plugins.md) | How to create custom MorphPlugin implementations (auth, storage, or custom) |
| [Configuration](configuration.md) | Full reference for every config field (providers, contexts, hosts, variables) |
| [API Reference](api-reference.md) | Complete public API: MorphClient, HostClient, AuthHandle, types, errors |
| [Token Lifecycle](token-lifecycle.md) | Token resolution algorithm, refresh, exchange, recovery, session monitoring |
| [Platform Adapters](platform-adapters.md) | StorageProvider (via plugins) and NetworkDelegate interfaces |
| [Architecture](architecture.md) | Internal design: module structure, HTTP pipeline, dependency graph |
| [Dart parity](dart-parity.md) | Dart/Flutter SDK status vs TypeScript ([issue #1](https://github.com/burgan-tech/morph-api-client/issues/1), [issue #3](https://github.com/burgan-tech/morph-api-client/issues/3)), Flutter PoC parity, backlog |

| Document | Description |
|----------|-------------|
| [poc/google-setup.md](poc/google-setup.md) | Google Cloud Console setup for the external IdP integration |
| [poc/simulation.md](poc/simulation.md) | How the simulation panel works (`poc-simulation.json` schema) |
| [poc/test-scenarios.md](poc/test-scenarios.md) | Nine test scenarios with curl recipes for all OAuth flows |
Loading
Loading