@inneranimalmedia/agentsam-sdk 1.9.0 → 2.0.0-alpha.identity
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/DEVELOPMENT.md +20 -4
- package/README.md +11 -3
- package/docs/RELEASES.iam-mirror.md +2 -2
- package/docs/RELEASES.md +2 -2
- package/docs/identity/README.md +11 -0
- package/examples/gorilla-shell/README.md +7 -14
- package/package.json +8 -3
- package/packages/identity/README.md +68 -0
- package/packages/identity/backend/README.md +26 -0
- package/packages/identity/docs/getting-started.md +16 -0
- package/packages/identity/examples/cloudflare-worker/README.md +5 -0
- package/packages/identity/examples/legendary-os/README.md +27 -0
- package/packages/identity/package.json +29 -0
- package/packages/identity/src/adapters/cloudflare-d1/index.js +4 -0
- package/packages/identity/src/adapters/inneranimalmedia/README.md +7 -0
- package/packages/identity/src/contracts/external-identity.js +35 -0
- package/packages/identity/src/contracts/identity.js +17 -0
- package/packages/identity/src/contracts/provider.js +8 -0
- package/packages/identity/src/contracts/session.js +9 -0
- package/packages/identity/src/core/accounts.js +4 -0
- package/packages/identity/src/core/browser-paths.js +34 -0
- package/packages/identity/src/core/constants.js +9 -0
- package/packages/identity/src/core/errors.js +8 -0
- package/packages/identity/src/core/http-json.js +10 -0
- package/packages/identity/src/core/identity.js +4 -0
- package/packages/identity/src/core/index.js +10 -0
- package/packages/identity/src/core/password-crypto.js +53 -0
- package/packages/identity/src/core/recovery.js +4 -0
- package/packages/identity/src/core/sessions.js +59 -0
- package/packages/identity/src/frontend/auth-portal/README.md +30 -0
- package/packages/identity/src/frontend/auth-portal/pages/login.html +821 -0
- package/packages/identity/src/frontend/auth-portal/pages/reset.html +582 -0
- package/packages/identity/src/frontend/auth-portal/pages/signup.html +835 -0
- package/packages/identity/src/index.js +118 -0
- package/packages/identity/src/migrations/README.md +5 -0
- package/packages/identity/src/oauth/README.md +4 -0
- package/packages/identity/src/oauth/callback.js +24 -0
- package/packages/identity/src/provider-contract.js +61 -0
- package/packages/identity/src/providers/email/index.js +39 -0
- package/packages/identity/src/providers/gcp/index.js +58 -0
- package/packages/identity/src/providers/github/index.js +14 -0
- package/packages/identity/src/providers/github/mapper.js +22 -0
- package/packages/identity/src/providers/github/oauth.js +43 -0
- package/packages/identity/src/providers/github/profile.js +34 -0
- package/packages/identity/src/providers/google/index.js +14 -0
- package/packages/identity/src/providers/google/mapper.js +32 -0
- package/packages/identity/src/providers/google/oauth.js +41 -0
- package/packages/identity/src/providers/google/profile.js +14 -0
- package/packages/identity/src/providers/index.js +25 -0
- package/packages/identity/tests/identity.test.mjs +74 -0
- package/python/README.md +8 -1
- package/python/agentsam_sdk/repository/__init__.py +4 -18
- package/python/docs/gaps.md +9 -0
- package/python/docs/tooling.md +5 -1
- package/python/tests/test_d1_bloat.py +1 -1
- package/src/index.js +16 -0
- package/src/lib/core-client.js +5 -0
- package/templates/gorilla-shell/App.tsx +28 -28
- package/templates/gorilla-shell/README.md +15 -3
- package/test/smoke.mjs +5 -0
- package/examples/gorilla-shell/App.tsx +0 -540
- package/examples/gorilla-shell/index.html +0 -15
- package/examples/gorilla-shell/main.jsx +0 -9
- package/examples/gorilla-shell/package.json +0 -19
- package/examples/gorilla-shell/vite.config.js +0 -10
- package/src/commands/http-server.js +0 -97
package/DEVELOPMENT.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Developing agentsam-sdk with Inner Animal Media
|
|
2
2
|
|
|
3
3
|
## Local smoke test
|
|
4
4
|
|
|
@@ -47,9 +47,25 @@ npx agentsam init \
|
|
|
47
47
|
2. `npm test` passes
|
|
48
48
|
3. Bump version in root `package.json`
|
|
49
49
|
4. Confirm `files` includes consumer surfaces (`src`, `bin`, `python`, `protocol`, …)
|
|
50
|
-
5. `npm
|
|
51
|
-
6.
|
|
52
|
-
7.
|
|
50
|
+
5. `bash scripts/npm-publish-preflight.sh` — must print `npm whoami: inneranimalmedia`
|
|
51
|
+
6. `npm publish --tag alpha --access public` (or `--tag latest` for stable)
|
|
52
|
+
7. Tag: `git tag vX.Y.Z && git push origin vX.Y.Z`
|
|
53
|
+
8. Record pairing in [`docs/RELEASES.md`](./docs/RELEASES.md): `iam@<40-sha> ↔ @inneranimalmedia/agentsam-sdk@X.Y.Z`
|
|
54
|
+
|
|
55
|
+
### Publish 404 (`PUT … Not found`)
|
|
56
|
+
|
|
57
|
+
npm returns **404** (not 403) when you are logged in as the **wrong user** for scope `@inneranimalmedia`.
|
|
58
|
+
|
|
59
|
+
- Registry maintainer for this package: **`inneranimalmedia`** (see `npm view @inneranimalmedia/agentsam-sdk maintainers`)
|
|
60
|
+
- Fix: `npm whoami` must be `inneranimalmedia`
|
|
61
|
+
```bash
|
|
62
|
+
npm logout
|
|
63
|
+
npm login # npm user inneranimalmedia (org owner), not personal GitHub-linked account
|
|
64
|
+
bash scripts/npm-publish-preflight.sh
|
|
65
|
+
npm publish --tag alpha --access public
|
|
66
|
+
```
|
|
67
|
+
- If you use a team org on npmjs.com, invite your daily npm user as **Developer** on the org with publish rights.
|
|
68
|
+
- Always pass `--access public` (already in `package.json` `publishConfig`; flag is harmless).
|
|
53
69
|
|
|
54
70
|
Workspace packages under `packages/*` (e.g. `@inneranimalmedia/agentsam-shell-kit`) stay
|
|
55
71
|
`private: true` until separately ready — they are **not** the root publish identity.
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Agent Sam is a full-stack autonomous agent SDK built on Cloudflare Workers, D1,
|
|
|
6
6
|
|
|
7
7
|
**Repo:** [github.com/SamPrimeaux/agentsam-sdk](https://github.com/SamPrimeaux/agentsam-sdk) · **npm:** `@inneranimalmedia/agentsam-sdk`
|
|
8
8
|
|
|
9
|
-
**Protocol (dual-home, no drift):** [`protocol/README.md`](./protocol/README.md) — every tool/feature lands in this repo **and** `inneranimalmedia/agentsam-sdk/`; npm publish is manual after mirror. Python lane: [`python/`](./python/).
|
|
9
|
+
**Protocol (dual-home, no drift):** [`protocol/README.md`](./protocol/README.md) — every tool/feature lands in this repo **and** `inneranimalmedia/agentsam-sdk/`; npm publish is manual after mirror. Python lane: [`python/`](./python/) (stdlib-only). Optional network Python package: [`packages/agentsam-site-scrape/`](./packages/agentsam-site-scrape/) (live experimental; does not break the stdlib core).
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -78,17 +78,25 @@ npx @inneranimalmedia/agentsam-sdk shell
|
|
|
78
78
|
| Piece | Location |
|
|
79
79
|
|-------|----------|
|
|
80
80
|
| Slash command registry | `src/lib/slash-commands.js` |
|
|
81
|
-
| Phase 0 visual prototype | `examples/gorilla-shell/` |
|
|
81
|
+
| Phase 0 visual prototype | `templates/gorilla-shell/` (canonical; `examples/gorilla-shell/` is a pointer) |
|
|
82
82
|
| Architecture + phases | [docs/CLI_SHELL.md](./docs/CLI_SHELL.md) |
|
|
83
83
|
|
|
84
84
|
Run the prototype:
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
|
-
cd
|
|
87
|
+
cd templates/gorilla-shell && npm install && npm run dev
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
---
|
|
91
91
|
|
|
92
|
+
## Architecture (CORE default)
|
|
93
|
+
|
|
94
|
+
`src/lib/core-client.js` defaults to `https://inneranimalmedia.com`. **Correct as designed** for serving many client projects: the npm package is a thin delivery/CLI client; intelligence, tool catalog, and policy live server-side on IAM CORE.
|
|
95
|
+
|
|
96
|
+
Without an IAM backend (or `IAM_CORE_URL` / `AGENTSAM_CORE_URL` override), strangers who `npm install` get **scaffold + local CLI only** — not a freestanding hosted Agent Sam.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
92
100
|
## Installation
|
|
93
101
|
|
|
94
102
|
```bash
|
|
@@ -8,10 +8,10 @@ Canonical npm-side table also lives in the SDK repo: `docs/RELEASES.md`.
|
|
|
8
8
|
| npm version | Published (UTC) | IAM git SHA (40) | Notes |
|
|
9
9
|
|-------------|-----------------|------------------|-------|
|
|
10
10
|
| 1.7.0 | 2026-07-14 | _(pre-receipt)_ | Prior publish |
|
|
11
|
-
| 1.9.0 |
|
|
11
|
+
| 1.9.0 | 2026-08-05T07:12:21.726Z | `fc1628505cb3c9946c149e4c468c2e264d6f381e` | `repository.inspect` + `--dupes`; mirrored from IAM agentsam-sdk |
|
|
12
12
|
| 1.8.0 | 2026-08-02T13:57:12.080Z | `580547301e370b77ec26bd72558979d335feedd9` | `python/` + `protocol/` in tarball; `repository.scan_bloat`; shell-kit under `packages/` |
|
|
13
13
|
|
|
14
|
-
**Latest pairing
|
|
14
|
+
**Latest pairing :** `iam@fc1628505cb3c9946c149e4c468c2e264d6f381e` ↔ `@inneranimalmedia/agentsam-sdk@1.9.0`
|
|
15
15
|
|
|
16
16
|
### Receipt rules
|
|
17
17
|
|
package/docs/RELEASES.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
| npm version | Published (UTC) | IAM git SHA (40) | Notes |
|
|
4
4
|
|-------------|-----------------|------------------|-------|
|
|
5
5
|
| 1.7.0 | 2026-07-14 | _(pre-receipt)_ | Prior publish |
|
|
6
|
-
| 1.9.0 |
|
|
6
|
+
| 1.9.0 | 2026-08-05T07:12:21.726Z | `fc1628505cb3c9946c149e4c468c2e264d6f381e` | `python/agentsam_sdk/repository/inspect.py` (`--dupes`); CLI `agentsam repository inspect` |
|
|
7
7
|
| 1.8.0 | 2026-08-02T13:57:12.080Z | `580547301e370b77ec26bd72558979d335feedd9` | `python/` + `protocol/` in npm `files`; `repository.scan_bloat`; shell-kit folded to `packages/agentsam-shell-kit` (private). SDK git at publish: `ac52669b89ddb16fad87c42fe53f2c93ef13bd1a`. |
|
|
8
8
|
|
|
9
|
-
**Pairing
|
|
9
|
+
**Pairing :** `iam@fc1628505cb3c9946c149e4c468c2e264d6f381e` ↔ `@inneranimalmedia/agentsam-sdk@1.9.0`
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# AgentSam SDK — Identity module
|
|
2
|
+
|
|
3
|
+
See [`packages/identity/README.md`](../packages/identity/README.md).
|
|
4
|
+
|
|
5
|
+
Customer import:
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import { createIdentityClient } from '@inneranimalmedia/agentsam-sdk';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Alpha: `@inneranimalmedia/agentsam-sdk@2.0.0-alpha.identity`
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
# Gorilla Shell (
|
|
1
|
+
# Gorilla Shell example (superseded)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Canonical scaffold:** [`../../templates/gorilla-shell/`](../../templates/gorilla-shell/)
|
|
4
4
|
|
|
5
|
-
This
|
|
6
|
-
|
|
7
|
-
## Run locally
|
|
5
|
+
This directory previously mirrored an older demo that hard-coded IAM D1/host
|
|
6
|
+
literals. Run and customize from `templates/gorilla-shell` instead:
|
|
8
7
|
|
|
9
8
|
```bash
|
|
10
|
-
cd
|
|
9
|
+
cd templates/gorilla-shell
|
|
11
10
|
npm install
|
|
12
11
|
npm run dev
|
|
13
12
|
```
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- Gorilla launch screen + sprite reactions
|
|
18
|
-
- Themes: NIGHT, DAY, LAVA, VOID
|
|
19
|
-
- Six demo scenarios (deploy, benchmark, D1, tail, samiam, wrangler)
|
|
20
|
-
- Slash command registry lives in `../../src/lib/slash-commands.js`
|
|
21
|
-
|
|
22
|
-
Full architecture: [docs/CLI_SHELL.md](../../docs/CLI_SHELL.md)
|
|
14
|
+
Demo CLI strings there use `{{PROJECT_NAME}}`, `{{D1_DATABASE_ID}}`,
|
|
15
|
+
`{{DASHBOARD_HOST}}`, and related placeholders — not live platform IDs.
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inneranimalmedia/agentsam-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-alpha.identity",
|
|
4
4
|
"description": "Agent Sam is a full-stack AI agent SDK for autonomous task execution \u2014 covering data management, creative workflows, design commands, and multi-step agentic pipelines.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./src/index.js",
|
|
9
|
+
"./identity": "./packages/identity/src/index.js",
|
|
10
|
+
"./identity/oauth/callback": "./packages/identity/src/oauth/callback.js",
|
|
9
11
|
"./package.json": "./package.json"
|
|
10
12
|
},
|
|
11
13
|
"bin": {
|
|
@@ -14,6 +16,7 @@
|
|
|
14
16
|
},
|
|
15
17
|
"files": [
|
|
16
18
|
"src",
|
|
19
|
+
"packages/identity",
|
|
17
20
|
"templates",
|
|
18
21
|
"docs",
|
|
19
22
|
"examples",
|
|
@@ -26,10 +29,12 @@
|
|
|
26
29
|
"DEVELOPMENT.md"
|
|
27
30
|
],
|
|
28
31
|
"workspaces": [
|
|
29
|
-
"packages
|
|
32
|
+
"packages/agentsam-shell-kit",
|
|
33
|
+
"packages/identity"
|
|
30
34
|
],
|
|
31
35
|
"scripts": {
|
|
32
|
-
"test": "node test/smoke.mjs",
|
|
36
|
+
"test": "node test/smoke.mjs && npm --prefix packages/identity test",
|
|
37
|
+
"test:identity": "npm --prefix packages/identity test",
|
|
33
38
|
"smoke": "node test/smoke.mjs",
|
|
34
39
|
"prepublishOnly": "npm test"
|
|
35
40
|
},
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Identity (`packages/identity`)
|
|
2
|
+
|
|
3
|
+
**Package #1** inside `@inneranimalmedia/agentsam-sdk` — not a separate npm product.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
inneranimalmedia (reference) → agentsam-sdk (product) → Legendary-OS (first external proof)
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Customer API
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import { createIdentityClient } from '@inneranimalmedia/agentsam-sdk';
|
|
13
|
+
|
|
14
|
+
const identity = createIdentityClient({
|
|
15
|
+
portal: { brand: { name: 'Legendary OS', logoUrl: '/logo.svg' } },
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
identity.providers.google();
|
|
19
|
+
identity.login(request); // → Identity Service (server-side)
|
|
20
|
+
identity.session.fromRequest(request);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Layout
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
src/
|
|
27
|
+
core/ identity · sessions · accounts · recovery
|
|
28
|
+
providers/ google · github · gcp · email
|
|
29
|
+
oauth/ authorize/callback (extract from IAM — next sprint)
|
|
30
|
+
adapters/ inneranimalmedia · cloudflare-d1
|
|
31
|
+
contracts/
|
|
32
|
+
frontend/auth-portal/pages/ login · signup · reset (verbatim IAM HTML)
|
|
33
|
+
migrations/
|
|
34
|
+
examples/legendary-os/
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## SDK philosophy
|
|
38
|
+
|
|
39
|
+
Ship: contracts, clients, adapters, scaffolding.
|
|
40
|
+
|
|
41
|
+
Do **not** ship in the client bundle: password DB logic, OAuth secrets, D1 assumptions.
|
|
42
|
+
|
|
43
|
+
## Publish (alpha)
|
|
44
|
+
|
|
45
|
+
From `main` after tests pass:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm test
|
|
49
|
+
npm publish --tag alpha
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Install in a customer app:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install @inneranimalmedia/agentsam-sdk@alpha
|
|
56
|
+
# or pin: @inneranimalmedia/agentsam-sdk@2.0.0-alpha.identity
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Subpath imports:
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import { createIdentityClient } from '@inneranimalmedia/agentsam-sdk';
|
|
63
|
+
import { finalizeInboundOAuth } from '@inneranimalmedia/agentsam-sdk/identity/oauth/callback';
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## IAM design lab
|
|
67
|
+
|
|
68
|
+
`inneranimalmedia/packages/agentsam-identity/` — contracts experiments only; **not** the package owner.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Backend — identity runtime
|
|
2
|
+
|
|
3
|
+
Worker-side identity: providers, OAuth finalize, sessions, adapters.
|
|
4
|
+
|
|
5
|
+
## IAM extraction map (stable production — do not rewrite)
|
|
6
|
+
|
|
7
|
+
| SDK target | IAM source today | Notes |
|
|
8
|
+
|------------|------------------|-------|
|
|
9
|
+
| `providers/google/*` | `src/core/auth/providers/google.js` | ✅ ported Sprint 2 |
|
|
10
|
+
| `providers/github/*` | `src/core/auth/providers/github.js` | ✅ ported Sprint 2 |
|
|
11
|
+
| `oauth/callback.js` | `src/api/oauth-login-callbacks.js` → `finalizeInboundOAuth` | **bulletproof path** |
|
|
12
|
+
| `oauth/authorize.js` | `src/api/auth.js` OAuth start handlers | PKCE + state |
|
|
13
|
+
| `core/session-service.js` | `src/core/auth.js` | cookie, `createLoginSession`, revoke |
|
|
14
|
+
| `core/account-linking.js` | `ensureIdentityPlaneBeforeSession`, `ensureAppUser` | account_identities |
|
|
15
|
+
| `adapters/inneranimalmedia/*` | D1 writes in auth side-effects | tenant/workspace stays adapter-only |
|
|
16
|
+
|
|
17
|
+
## Rule
|
|
18
|
+
|
|
19
|
+
Move files; **do not** change OAuth behavior until IAM runs parallel proof (existing users, Google/GitHub callbacks, session cookie).
|
|
20
|
+
|
|
21
|
+
## Public entry
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { createIdentity, GoogleProvider } from '@agentsam/identity';
|
|
25
|
+
// resolves to backend/index.js
|
|
26
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Getting started with @agentsam/identity
|
|
2
|
+
|
|
3
|
+
1. Install: `npm install @agentsam/identity`
|
|
4
|
+
2. Configure providers and storage adapter
|
|
5
|
+
3. Wire Worker routes for OAuth callback + session cookie
|
|
6
|
+
|
|
7
|
+
Full plan: Phase 1–9 in IAM `plans/active/AGENTSAM-IDENTITY-SDK-PRODUCTIZATION-2026-08.md`
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
import { createIdentity, GoogleProvider } from '@agentsam/identity';
|
|
11
|
+
|
|
12
|
+
const identity = createIdentity({
|
|
13
|
+
providers: [GoogleProvider],
|
|
14
|
+
storage: { adapter: 'cloudflare-d1', binding: 'DB' },
|
|
15
|
+
});
|
|
16
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Legendary-OS — @agentsam/identity customer proof
|
|
2
|
+
|
|
3
|
+
Target: fresh install path (Phase 7).
|
|
4
|
+
|
|
5
|
+
## Day 1
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @agentsam/identity
|
|
9
|
+
npx agentsam identity init --adapter cloudflare-d1
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Day 2 proof checklist
|
|
13
|
+
|
|
14
|
+
- [ ] Email signup → session cookie
|
|
15
|
+
- [ ] Email login
|
|
16
|
+
- [ ] Logout clears session
|
|
17
|
+
- [ ] Google OAuth round-trip
|
|
18
|
+
- [ ] GitHub OAuth round-trip
|
|
19
|
+
|
|
20
|
+
## Day 3
|
|
21
|
+
|
|
22
|
+
- [ ] Workspace creation on first login
|
|
23
|
+
- [ ] Dashboard requires auth
|
|
24
|
+
|
|
25
|
+
Record curl transcripts and D1 row counts in `PROOF.md` when complete.
|
|
26
|
+
|
|
27
|
+
See: `inneranimalmedia/plans/active/AGENTSAM-IDENTITY-SDK-PRODUCTIZATION-2026-08.md`
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@inneranimalmedia/agentsam-sdk-identity",
|
|
3
|
+
"version": "2.0.0-alpha.identity",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Identity module for @inneranimalmedia/agentsam-sdk (workspace — publish via root SDK)",
|
|
7
|
+
"main": "./src/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.js",
|
|
10
|
+
"./provider-contract": "./src/provider-contract.js",
|
|
11
|
+
"./providers": "./src/providers/index.js",
|
|
12
|
+
"./providers/google": "./src/providers/google/index.js",
|
|
13
|
+
"./providers/github": "./src/providers/github/index.js",
|
|
14
|
+
"./providers/gcp": "./src/providers/gcp/index.js",
|
|
15
|
+
"./providers/email": "./src/providers/email/index.js",
|
|
16
|
+
"./contracts/identity": "./src/contracts/identity.js",
|
|
17
|
+
"./contracts/session": "./src/contracts/session.js",
|
|
18
|
+
"./contracts/provider": "./src/contracts/provider.js",
|
|
19
|
+
"./contracts/external-identity": "./src/contracts/external-identity.js",
|
|
20
|
+
"./oauth/callback": "./src/oauth/callback.js",
|
|
21
|
+
"./frontend/auth-portal/*": "./src/frontend/auth-portal/*"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"test": "node --test tests/*.test.mjs"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# InnerAnimalMedia adapter (Sprint 3+)
|
|
2
|
+
|
|
3
|
+
Maps IAM D1 tables (`auth_users`, `accounts`, `account_identities`, `auth_sessions`, …)
|
|
4
|
+
into portable AgentSam Identity contracts.
|
|
5
|
+
|
|
6
|
+
IAM-specific behavior (tenant resolution, workspace membership, OAuth callback wiring)
|
|
7
|
+
stays here — not in `providers/`.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portable external identity shape — storage-agnostic.
|
|
3
|
+
* Adapters map this into application-specific account_identities rows.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** @typedef {import('../provider-contract.js').NormalizedExternalIdentity} NormalizedExternalIdentity */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {Partial<NormalizedExternalIdentity> & { provider: string; subject: string }} input
|
|
10
|
+
* @returns {NormalizedExternalIdentity}
|
|
11
|
+
*/
|
|
12
|
+
export function normalizeExternalIdentity(input) {
|
|
13
|
+
const provider = String(input?.provider || '').trim().toLowerCase();
|
|
14
|
+
const subject = String(input?.subject || '').trim();
|
|
15
|
+
if (!provider || !subject) {
|
|
16
|
+
throw new Error('external_identity_requires_provider_and_subject');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const email =
|
|
20
|
+
typeof input?.email === 'string' && input.email.trim()
|
|
21
|
+
? input.email.trim().toLowerCase()
|
|
22
|
+
: null;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
provider,
|
|
26
|
+
subject,
|
|
27
|
+
email,
|
|
28
|
+
emailVerified: input?.emailVerified === true,
|
|
29
|
+
name: typeof input?.name === 'string' && input.name.trim() ? input.name.trim() : null,
|
|
30
|
+
avatar: typeof input?.avatar === 'string' && input.avatar.trim() ? input.avatar.trim() : null,
|
|
31
|
+
username:
|
|
32
|
+
typeof input?.username === 'string' && input.username.trim() ? input.username.trim() : null,
|
|
33
|
+
raw: input?.raw && typeof input.raw === 'object' ? input.raw : null,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentSam Identity contracts.
|
|
3
|
+
*
|
|
4
|
+
* These are intentionally storage-agnostic. The IAM adapter maps them to
|
|
5
|
+
* existing D1 tables (auth_users, accounts, memberships, sessions).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const IdentityContractVersion = '1.0';
|
|
9
|
+
|
|
10
|
+
export function normalizeIdentityUser(user) {
|
|
11
|
+
return {
|
|
12
|
+
id: user?.id ?? null,
|
|
13
|
+
email: user?.email ?? null,
|
|
14
|
+
displayName: user?.displayName ?? user?.name ?? null,
|
|
15
|
+
type: user?.type ?? 'human',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Session contract shared by identity adapters. */
|
|
2
|
+
export function normalizeIdentitySession(session) {
|
|
3
|
+
return {
|
|
4
|
+
id: session?.id ?? null,
|
|
5
|
+
userId: session?.userId ?? session?.user_id ?? null,
|
|
6
|
+
expiresAt: session?.expiresAt ?? session?.expires_at ?? null,
|
|
7
|
+
revokedAt: session?.revokedAt ?? session?.revoked_at ?? null,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { AUTH_LOGIN_PATH, AUTH_SIGNUP_PATH } from './constants.js';
|
|
2
|
+
|
|
3
|
+
export function sanitizeBrowserNextPath(raw) {
|
|
4
|
+
if (raw == null) return null;
|
|
5
|
+
const s = String(raw).trim();
|
|
6
|
+
if (!s.startsWith('/') || s.startsWith('//')) return null;
|
|
7
|
+
if (/^[a-zA-Z][a-zA-Z+\-.]*:/.test(s) || s.includes('://')) return null;
|
|
8
|
+
|
|
9
|
+
let pathname = s;
|
|
10
|
+
let search = '';
|
|
11
|
+
const q = s.indexOf('?');
|
|
12
|
+
if (q !== -1) {
|
|
13
|
+
pathname = s.slice(0, q);
|
|
14
|
+
search = s.slice(q);
|
|
15
|
+
}
|
|
16
|
+
const lower = pathname.toLowerCase();
|
|
17
|
+
if (lower === '/login' || lower === '/auth/signin') pathname = AUTH_LOGIN_PATH;
|
|
18
|
+
else if (lower === '/signup' || lower === '/auth/register') pathname = AUTH_SIGNUP_PATH;
|
|
19
|
+
|
|
20
|
+
return pathname + search;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Customer adapter may supply apexDomain override for Set-Cookie. */
|
|
24
|
+
export function getApexDomain(hostname, opts = {}) {
|
|
25
|
+
const override = opts?.apexDomain != null ? String(opts.apexDomain).trim() : '';
|
|
26
|
+
if (override) return override;
|
|
27
|
+
if (!hostname) return '';
|
|
28
|
+
const parts = hostname.split('.');
|
|
29
|
+
if (parts.length >= 2) {
|
|
30
|
+
if (hostname.endsWith('.workers.dev') || hostname.endsWith('.pages.dev')) return '';
|
|
31
|
+
return parts.slice(-2).join('.');
|
|
32
|
+
}
|
|
33
|
+
return hostname;
|
|
34
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** SDK-portable session/auth path constants. */
|
|
2
|
+
export const AUTH_COOKIE_NAME = 'session';
|
|
3
|
+
export const AUTH_SESSION_TTL_SECONDS = 30 * 24 * 60 * 60;
|
|
4
|
+
export const MIN_AGENT_SESSION_TTL_SECONDS = 60;
|
|
5
|
+
export const MAX_AGENT_SESSION_TTL_SECONDS = 86400;
|
|
6
|
+
export const DEFAULT_AGENT_SESSION_TTL_SECONDS = 900;
|
|
7
|
+
export const AUTH_LOGIN_PATH = '/auth/login';
|
|
8
|
+
export const AUTH_SIGNUP_PATH = '/auth/signup';
|
|
9
|
+
export const DASHBOARD_AFTER_LOGIN_PATH = '/dashboard/home';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
function jsonStringifySafe(value) {
|
|
2
|
+
return JSON.stringify(value, (_k, v) => (typeof v === 'bigint' ? v.toString() : v));
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function jsonResponse(body, status = 200) {
|
|
6
|
+
return new Response(jsonStringifySafe(body), {
|
|
7
|
+
status: Number(status) || 200,
|
|
8
|
+
headers: { 'Content-Type': 'application/json' },
|
|
9
|
+
});
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { AuthError } from './errors.js';
|
|
2
|
+
export { sanitizeBrowserNextPath, getApexDomain } from './browser-paths.js';
|
|
3
|
+
export { verifyPassword, hashPassword } from './password-crypto.js';
|
|
4
|
+
export { jsonResponse } from './http-json.js';
|
|
5
|
+
export {
|
|
6
|
+
trimSessionField,
|
|
7
|
+
buildSessionKvPayload,
|
|
8
|
+
normalizeIdentitySession,
|
|
9
|
+
isInboundOAuthSuccess,
|
|
10
|
+
} from './sessions.js';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
function hexToBytes(hex) {
|
|
2
|
+
const arr = [];
|
|
3
|
+
for (let i = 0; i < hex.length; i += 2) arr.push(parseInt(hex.slice(i, i + 2), 16));
|
|
4
|
+
return new Uint8Array(arr);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export async function verifyPassword(password, saltHex, hashHex) {
|
|
8
|
+
try {
|
|
9
|
+
const salt = hexToBytes(saltHex);
|
|
10
|
+
const key = await crypto.subtle.importKey(
|
|
11
|
+
'raw',
|
|
12
|
+
new TextEncoder().encode(password),
|
|
13
|
+
{ name: 'PBKDF2' },
|
|
14
|
+
false,
|
|
15
|
+
['deriveBits'],
|
|
16
|
+
);
|
|
17
|
+
const derived = await crypto.subtle.deriveBits(
|
|
18
|
+
{ name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-256' },
|
|
19
|
+
key,
|
|
20
|
+
256,
|
|
21
|
+
);
|
|
22
|
+
const derivedHex = Array.from(new Uint8Array(derived))
|
|
23
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
24
|
+
.join('');
|
|
25
|
+
return derivedHex === hashHex.toLowerCase();
|
|
26
|
+
} catch (e) {
|
|
27
|
+
console.warn('[verifyPassword] failed', e.message);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function hashPassword(password) {
|
|
33
|
+
const salt = crypto.getRandomValues(new Uint8Array(32));
|
|
34
|
+
const saltHex = Array.from(salt)
|
|
35
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
36
|
+
.join('');
|
|
37
|
+
const key = await crypto.subtle.importKey(
|
|
38
|
+
'raw',
|
|
39
|
+
new TextEncoder().encode(password),
|
|
40
|
+
{ name: 'PBKDF2' },
|
|
41
|
+
false,
|
|
42
|
+
['deriveBits'],
|
|
43
|
+
);
|
|
44
|
+
const derived = await crypto.subtle.deriveBits(
|
|
45
|
+
{ name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-256' },
|
|
46
|
+
key,
|
|
47
|
+
256,
|
|
48
|
+
);
|
|
49
|
+
const hashHex = Array.from(new Uint8Array(derived))
|
|
50
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
51
|
+
.join('');
|
|
52
|
+
return { saltHex, hashHex };
|
|
53
|
+
}
|