@poppykit/client 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +3 -2
- package/AUTH.md +27 -2
- package/CHANGELOG.md +11 -0
- package/CONTRIBUTING.md +6 -4
- package/DELIVERY.md +14 -1
- package/INTEGRATIONS.md +36 -6
- package/PROVIDER.md +9 -7
- package/README.md +11 -4
- package/RELEASING.md +1 -1
- package/STORAGE.md +15 -3
- package/dist/adapter-contract.js +1 -1
- package/dist/auth/client-auth.d.ts +10 -7
- package/dist/auth/client-auth.js +211 -83
- package/dist/auth/sqlite-store.js +16 -2
- package/dist/conversation.js +12 -2
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1 -1
- package/dist/integrations.d.ts +6 -1
- package/dist/network/discovery.d.ts +20 -9
- package/dist/network/discovery.js +74 -21
- package/dist/network/redirect.d.ts +3 -0
- package/dist/network/redirect.js +38 -0
- package/dist/network/tasks.d.ts +23 -0
- package/dist/network/tasks.js +45 -0
- package/dist/postgres.js +14 -1
- package/dist/protocol/wire.d.ts +12 -11
- package/dist/protocol/wire.js +33 -7
- package/dist/provider.d.ts +2 -9
- package/dist/provider.js +15 -25
- package/examples/quickstart.mjs +1 -1
- package/package.json +2 -2
package/API.md
CHANGED
|
@@ -5,9 +5,10 @@ for complete option/result types. This map describes the supported integration s
|
|
|
5
5
|
|
|
6
6
|
| Entry point | Main exports | Guide |
|
|
7
7
|
| --- | --- | --- |
|
|
8
|
-
| `@poppykit/client` | `createMetadataResolver`, `createNodeTransport` | [README](README.md), [delivery](DELIVERY.md) |
|
|
8
|
+
| `@poppykit/client` | `createMetadataResolver`, `signInMethods`, `createNodeTransport` | [README](README.md), [delivery](DELIVERY.md) |
|
|
9
9
|
| `@poppykit/client` | `createClientAuth`, `AuthFailure`, authentication/identity/input types | [authentication](AUTH.md) |
|
|
10
10
|
| `@poppykit/client` | `createConversationClient`, `ConversationError`, `parseEventStream` | [delivery](DELIVERY.md) |
|
|
11
|
+
| `@poppykit/client` | `Author`, `AuthorType`, `Message`, `RecordedMessage`, conversation/event types | [delivery](DELIVERY.md) |
|
|
11
12
|
| `@poppykit/client` | `ApiTarget`, `AgentBrowserController`, `FeedbackReport` types | [integrations](INTEGRATIONS.md) |
|
|
12
13
|
| `@poppykit/client/sqlite` | `SqliteAuthStore`, `SqliteConversationStore` | [storage](STORAGE.md) |
|
|
13
14
|
| `@poppykit/client/memory` | `MemoryConversationStore` (non-durable) | [storage](STORAGE.md) |
|
|
@@ -17,7 +18,7 @@ for complete option/result types. This map describes the supported integration s
|
|
|
17
18
|
ClientAuth methods include `start/get/list/target`, `authorization`,
|
|
18
19
|
`beginSignIn/continueSignIn/completeSignIn/cancelSignIn/operation`, `renew`,
|
|
19
20
|
`signOut/retryCleanup/recover`, `authorizedFetch`, `apiTarget/apiFetch`,
|
|
20
|
-
`joinBrowser` and `
|
|
21
|
+
`joinBrowser`, `feedback` and `excludedTasks`. Conversation operations bind one connection, issuer
|
|
21
22
|
and endpoint; never substitute profile names or model-provided URLs for that binding.
|
|
22
23
|
|
|
23
24
|
The [quickstart](examples/quickstart.mjs) is executed by CI. Integration examples
|
package/AUTH.md
CHANGED
|
@@ -5,9 +5,34 @@ replacement, revocation and abandoned-operation recovery. Call `recover()` on
|
|
|
5
5
|
startup. Another live process is never interrupted; an ambiguous dispatched
|
|
6
6
|
exchange is uncertain and must not be replayed.
|
|
7
7
|
|
|
8
|
+
Each `start` creates a new Session Key; only the issuer-specific User ID is reused.
|
|
9
|
+
Renewal uses that Session Key. `Connection.sessionId` remains a local identifier
|
|
10
|
+
for the key's lifetime, not the company's internal Session ID. Token requests
|
|
11
|
+
carry no `session_id`, and token responses need neither it nor `signed_in`.
|
|
12
|
+
The grant determines sign-in state. Omitted signed-in scope inherits the request's
|
|
13
|
+
scope context; an explicit response can narrow it but cannot expand it.
|
|
14
|
+
|
|
15
|
+
After a refresh returns definite `invalid_grant`, the client diagnoses the Session
|
|
16
|
+
with a signed-out assertion before discarding the Account Token. A live Session
|
|
17
|
+
means the Account Token is unusable. An ended key is retired durably before a fresh
|
|
18
|
+
key attempts replacement. Ambiguous refresh responses remain uncertain and are
|
|
19
|
+
never resent. Sign-out still disconnects locally before remote cleanup.
|
|
20
|
+
|
|
21
|
+
Discovery accepts only draft 0.3, checks the final well-known path (including
|
|
22
|
+
cache revalidation), exact issuer and reciprocal `protected_resources`.
|
|
23
|
+
`signInMethods(metadata)` derives Direct/Device from issuer grants and endpoints
|
|
24
|
+
and uses `scopes_supported`; Mediated keeps `auth.mediated.scopes`. Company scope
|
|
25
|
+
names cannot start with `poppy:`. Descriptions come from `auth.scopes` or a listed
|
|
26
|
+
OpenAPI document. Prefer Direct when the user can receive its callback; Device is
|
|
27
|
+
for appropriate device-flow situations. No sign-in method is user consent.
|
|
28
|
+
|
|
8
29
|
Ask `authorization(connectionId, scopes)` for the current grant, missing scopes
|
|
9
|
-
and advertised methods. Choose a method explicitly in `beginSignIn`. Direct
|
|
10
|
-
requires
|
|
30
|
+
and advertised methods, with `scopeDescriptions` from `auth.scopes`. Choose a method explicitly in `beginSignIn`. Direct
|
|
31
|
+
requires a registered HTTPS callback on the client domain, or an RFC 8252 HTTP
|
|
32
|
+
loopback IP callback (`127.0.0.1` or `[::1]`), and an authenticated browser binding.
|
|
33
|
+
Only a loopback registration's port may vary; callback completion and code exchange
|
|
34
|
+
use the exact port selected at initiation. Metadata/network endpoint address
|
|
35
|
+
protections do not change. The URL's `dpop_jkt` binds the code to this Session Key.
|
|
11
36
|
Display its URL in the user's browser. Device returns a checked link/code and
|
|
12
37
|
company identity; call `continueSignIn(operationId)` when its deadline is due.
|
|
13
38
|
Do not automate user approval. Mediated calls the configured `TrustedInput`
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0 — 2026-10-28
|
|
4
|
+
|
|
5
|
+
Target pinned Personal Agent Protocol draft 0.3. Break discovery, Session Key/token, author, browser-controller and feedback contracts; retain explicit storage subpaths. Upgrade normalized auth state 1→2; stop old writers and reset incompatible conversation/outbox state before cutover.
|
|
6
|
+
|
|
7
|
+
Local migration candidate only. Publication and deployment require separate approval.
|
|
8
|
+
|
|
9
|
+
## 0.4.1
|
|
10
|
+
|
|
11
|
+
Support Node 24.21.0 and later within Node 24 under the owner-accepted runtime policy.
|
|
12
|
+
Build, verification and publication tooling read .node-version.
|
|
13
|
+
|
|
3
14
|
## 0.4.0
|
|
4
15
|
|
|
5
16
|
Require Node 24 >=24.22.1 within 24.x. Accept conforming OAuth callback fields,
|
package/CONTRIBUTING.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Contributing
|
|
2
2
|
|
|
3
|
-
Follow the
|
|
4
|
-
and [guides](https://personalagentprotocol.org/docs/0.
|
|
5
|
-
supporting evidence.
|
|
3
|
+
Follow the pinned draft 0.3 [specification](https://personalagentprotocol.org/docs/0.3/spec)
|
|
4
|
+
and [guides](https://personalagentprotocol.org/docs/0.3/guides). Tests/snapshots are
|
|
5
|
+
supporting evidence. This unreleased checkout has completed only the discovery
|
|
6
|
+
stage of migration; auth, wire/storage and integrations still need their stages.
|
|
7
|
+
Demo/business workflows and individual extensions are excluded.
|
|
6
8
|
Code is [MIT](LICENSE); confirm rights for third-party contributions.
|
|
7
9
|
|
|
8
|
-
Use Node 24.
|
|
10
|
+
Use Node 24.21.0, TypeScript 5.9.3 and @types/node 24.10.0.
|
|
9
11
|
Install the packageManager-pinned pnpm and run pnpm install --frozen-lockfile --ignore-scripts.
|
|
10
12
|
|
|
11
13
|
```sh
|
package/DELIVERY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Conversation delivery and transport
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Conversation messages and authorization events now use draft 0.3. Company content, messages,
|
|
4
4
|
unknown events and partial text remain untrusted data for the host application.
|
|
5
5
|
|
|
6
6
|
## Client
|
|
@@ -92,3 +92,16 @@ Pruning is explicit operator policy, never automatic data loss. It preserves old
|
|
|
92
92
|
message receipts and cursor identity. Concurrent reads see a coherent snapshot or
|
|
93
93
|
`cursor_expired`. Invalid/expired waited-POST cursors are rejected before accepting
|
|
94
94
|
the new write; an existing message ID still returns its original receipt.
|
|
95
|
+
|
|
96
|
+
## Unreleased draft 0.3 breaking change
|
|
97
|
+
|
|
98
|
+
Messages now require `author: { type: 'agent' | 'human' }`; protocol `sender` is
|
|
99
|
+
unsupported. Human text must remain the person's exact words. Company authors
|
|
100
|
+
may include `id`, `name` and an HTTPS `image`. Authorization events now contain
|
|
101
|
+
`error: 'insufficient_scope'` and nonempty required `scope`.
|
|
102
|
+
|
|
103
|
+
No backward compatibility is provided. Stop writers and explicitly reset old
|
|
104
|
+
history, outboxes, checkpoints and caller retry handles before cutover, preserving
|
|
105
|
+
configuration. Old pending `sender` requests fail `legacy_message_uncertain`
|
|
106
|
+
without dispatch or mutation. Reconcile uncertain delivery before clearing it;
|
|
107
|
+
never rebuild the body or allocate a replacement ID to hide uncertainty.
|
package/INTEGRATIONS.md
CHANGED
|
@@ -32,8 +32,11 @@ endpoint; extra paths or queries are refused. Query-bearing discovery endpoints
|
|
|
32
32
|
not supported. Protected-resource metadata must name that exact resource and the
|
|
33
33
|
verified company issuer. ES256 DPoP metadata selects DPoP; absence selects Bearer.
|
|
34
34
|
A Bearer-only MCP resource cannot also authorize a conversation. Resource-specific
|
|
35
|
-
credential slots use the shared
|
|
36
|
-
lifecycle.
|
|
35
|
+
credential slots use the shared nonce, cooldown and revocation
|
|
36
|
+
lifecycle. Bearer-only MCP credentials come only from Token Exchange of a current
|
|
37
|
+
DPoP Session Token, preserving its Session and limiting scopes to that subject. The
|
|
38
|
+
issuer must advertise the exchange grant; exchange does not rotate the Account Token.
|
|
39
|
+
DPoP-capable MCP keeps the normal token grants. The wire `token_type` must match verified metadata; there is no fallback
|
|
37
40
|
from DPoP to Bearer. Redirects never forward tokens or proofs. Auth 401 rejection may
|
|
38
41
|
cause one fresh-token retry; unknown results are not automatically retried.
|
|
39
42
|
|
|
@@ -42,6 +45,12 @@ cause one fresh-token retry; unknown results are not automatically retried.
|
|
|
42
45
|
```ts
|
|
43
46
|
await auth.joinBrowser(connectionId, 'https://company.example/account', {
|
|
44
47
|
kind: 'agent-controlled',
|
|
48
|
+
async loadJoinForm(url) {
|
|
49
|
+
// Top-level GET in this isolated browser; verify the final URL and form action
|
|
50
|
+
// are exactly url. Read the hidden code only here, outside model context.
|
|
51
|
+
return controlledBrowser.loadJoinForm(url);
|
|
52
|
+
},
|
|
53
|
+
navigate: url => controlledBrowser.navigateWithoutPostBody(url),
|
|
45
54
|
async postForm({ url, fields, validateRedirect }) {
|
|
46
55
|
// Bind your existing browser controller here. It must enforce this contract:
|
|
47
56
|
// isolated per-session storage; verified TLS/actual peer addresses; no logging;
|
|
@@ -56,13 +65,15 @@ await auth.joinBrowser(connectionId, 'https://company.example/account', {
|
|
|
56
65
|
`controlledBrowser` is the host's existing controller, not an SDK driver. This hook
|
|
57
66
|
is trusted code. Its network layer must reject loopback/private/link-local actual
|
|
58
67
|
connected addresses unless narrowly configured, validate TLS and enforce redirect
|
|
59
|
-
interception. Never replay the
|
|
60
|
-
validator permits only 303 to
|
|
68
|
+
interception. Never replay the code or proof on 307/308 or send it in a URL. The supplied
|
|
69
|
+
validator permits only 303 to an HTTPS company page. After that redirect, the SDK
|
|
70
|
+
asks the controller to navigate to the validated `returnTo`. HttpTransport cannot
|
|
61
71
|
enforce network policy inside an unrelated browser engine. Keep this capability
|
|
62
72
|
separate from the human consent-browser opener. Never join the user's browser.
|
|
63
73
|
Use separate cookies/local storage for each session/user, join just before browsing,
|
|
64
74
|
rejoin on lost recognition and close the context when the session ends. Custom
|
|
65
|
-
controllers own those guarantees; the SDK
|
|
75
|
+
controllers own those guarantees; the SDK signs a Session Key proof with the form
|
|
76
|
+
code as nonce (no access token or identity assertion), and validates the destination and
|
|
66
77
|
navigation contract but cannot inspect their internal browser implementation.
|
|
67
78
|
|
|
68
79
|
## Feedback
|
|
@@ -77,7 +88,11 @@ await auth.feedback(connectionId, {
|
|
|
77
88
|
Signed-out sessions are allowed and no account scope is required. Task and
|
|
78
89
|
description are nonempty strings of at most 200 and 2000 Unicode codepoints. Only
|
|
79
90
|
`missing` is supported client-side. Omit identifiers, personal data and secrets;
|
|
80
|
-
report task limitations rather than individual errors. Success is an empty 202
|
|
91
|
+
report task limitations rather than individual errors. Success is an empty 202
|
|
92
|
+
(returning undefined) or HTTP 200 with an `Alternative`. The SDK validates the latter
|
|
93
|
+
and returns instructions/references as company data, never as user consent. Unlisted
|
|
94
|
+
OpenAPI/MCP references and unknown reference types are ignored; known malformed
|
|
95
|
+
references fail. Web links must be HTTPS. No alternative is executed automatically.
|
|
81
96
|
There are no automatic POST retries (including nonce/auth rejection). A lost
|
|
82
97
|
response can mean accepted; callers decide whether to repeat because the protocol
|
|
83
98
|
defines no deduplication key. Prefer one report per unfulfilled task.
|
|
@@ -85,3 +100,18 @@ defines no deduplication key. Prefer one report per unfulfilled task.
|
|
|
85
100
|
The executable generic caller/controller fixtures are `tests/integrations.test.mts`.
|
|
86
101
|
They exercise the same hooks used by the CLI; installed CLI integration is
|
|
87
102
|
verified separately against immutable candidate tarballs.
|
|
103
|
+
|
|
104
|
+
## Task metadata
|
|
105
|
+
|
|
106
|
+
Call `auth.excludedTasks(connectionId)` before choosing how to perform a task.
|
|
107
|
+
It uses `MetadataResolver.resolveExcludedTasks(document)` (optional for custom
|
|
108
|
+
resolvers), fetches the advertised document without credentials and shares the
|
|
109
|
+
resolver's bounded HTTP cache/revalidation. Alternatives use the feedback validator;
|
|
110
|
+
cached references are checked against current discovery on every read.
|
|
111
|
+
|
|
112
|
+
Discovery exposes `auth.scope_hints`: both fields are required, unknown changes
|
|
113
|
+
become irreversible, and unknown fields are ignored. Missing hints remain unknown.
|
|
114
|
+
Hints and excluded task phrases are company claims, never user approval. The host
|
|
115
|
+
agent decides whether a phrase matches its task. The SDK/CLI intentionally omit the
|
|
116
|
+
SHOULD-level automatic pre-task check: they have no task planner; callers choose
|
|
117
|
+
when to read the metadata. No task-policy engine or alternative executor is supplied.
|
package/PROVIDER.md
CHANGED
|
@@ -14,7 +14,7 @@ Import `createProvider`, `createProviderClient`, and `createResultCipher` from
|
|
|
14
14
|
`@poppykit/client/provider`; durable `SqliteProviderStore` is separately exported
|
|
15
15
|
from `@poppykit/client/provider/sqlite`. Neither is loaded by the core import.
|
|
16
16
|
The wire protocol remains PoppyKit provider **v1**; the 0.2 TypeScript API uses async storage, not a Personal Agent Protocol extension.
|
|
17
|
-
Node 24.x (at least 24.
|
|
17
|
+
Node 24.x (at least 24.21.0) is required for the SQLite reference adapter.
|
|
18
18
|
|
|
19
19
|
An operator supplies HTTPS hosting, a provider client metadata URL, JWKS URL,
|
|
20
20
|
HTTPS callback URL on that same domain, an ES256 signer/KMS, a verified company
|
|
@@ -75,7 +75,6 @@ const provider = createProvider({
|
|
|
75
75
|
const human = await operatorLogin.authenticateEnrollment(request);
|
|
76
76
|
return human ? { subject: human.stableSubject, allowedCompanies: human.companyDomains } : null;
|
|
77
77
|
},
|
|
78
|
-
verifySession: binding => operatorSessionVerifier.owns(binding),
|
|
79
78
|
});
|
|
80
79
|
// Route Fetch Requests under /v1/{operation}, plus the exact public URLs above:
|
|
81
80
|
// await provider.handle(request)
|
|
@@ -99,11 +98,11 @@ but cannot recover another installation's result. Enrollment never accepts calle
|
|
|
99
98
|
subjects, arbitrary audiences, lifetimes, key IDs, raw bytes or signing claims.
|
|
100
99
|
|
|
101
100
|
`identity` takes domain and exact issuer; `begin` registers immutable operation,
|
|
102
|
-
issuer/domain, purpose (`session`, `client-authentication`, `
|
|
103
|
-
optional session and browser return destination. Company metadata is independently
|
|
101
|
+
issuer/domain, purpose (`session`, `client-authentication`, `direct`) and Direct Session Key binding. Company metadata is independently
|
|
104
102
|
resolved and enrollment company policy checked. `assert` takes operation/purpose
|
|
105
|
-
only and constructs a 60-second assertion with fresh 256-bit jti. Browser
|
|
106
|
-
|
|
103
|
+
only and constructs a 60-second assertion with fresh 256-bit jti. Browser-purpose
|
|
104
|
+
operations/assertions and verifySession are removed; browser joining uses the
|
|
105
|
+
locally held Session Key and browser-bound form code. `createProviderClient` binds
|
|
107
106
|
enrollment credentials and automatically registers SDK assertion operations.
|
|
108
107
|
|
|
109
108
|
Direct sign-in uses SDK-generated 256-bit state. Trusted CLI code privately
|
|
@@ -112,7 +111,10 @@ authorization URL. Only its hash is indexed. The callback accepts state, exact
|
|
|
112
111
|
issuer, and exactly one code/error; result ciphertext is sealed atomically with
|
|
113
112
|
the immutable binding. Identical pending callbacks are harmless; conflicting,
|
|
114
113
|
canceled, expired and consumed callbacks fail. `takeResult` requires enrollment,
|
|
115
|
-
installation, operation, issuer and exact
|
|
114
|
+
installation, operation, issuer and exact `sessionKey` thumbprint from the SDK's
|
|
115
|
+
authorization URL `dpop_jkt`; the local `Connection.sessionId` cannot identify a
|
|
116
|
+
company Session. Old Direct operations without the key binding must restart.
|
|
117
|
+
Retrieval consumes within the same
|
|
116
118
|
storage transaction before returning private callback data. Lost retrieval delivery
|
|
117
119
|
is uncertain, never a reason to exchange or retrieve again. SDK code owns PKCE and
|
|
118
120
|
the exchange. Never log request URLs or responses on this route.
|
package/README.md
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
# PoppyKit client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Draft 0.3 migration (2026-10-28), pinned to the public source captured that day.
|
|
4
|
+
Client/CLI 0.5.0 and server 0.4.0 break the earlier protocol contracts. Stop old
|
|
5
|
+
writers and follow the documented storage/reset procedure before compatible
|
|
6
|
+
writers resume. Registry, deployment and live acceptance have separate receipts.
|
|
7
|
+
|
|
8
|
+
The Node 24.21.0 minimum is an owner-accepted compatibility baseline. Use a current patched Node 24 runtime where available; this minimum does not establish that older runtimes contain later security fixes. Build and release CI read `.node-version`.
|
|
9
|
+
|
|
10
|
+
TypeScript SDK for [Personal Agent Protocol draft 0.3](https://personalagentprotocol.org/docs/0.3/spec):
|
|
4
11
|
discovery, authentication, conversations and API/browser/feedback hooks. Your
|
|
5
12
|
application supplies the agent and trusted infrastructure. [MIT](LICENSE).
|
|
6
13
|
|
|
7
14
|
## Install
|
|
8
15
|
|
|
9
|
-
|
|
16
|
+
Use the exact version verified by its protected release workflow; check registry publication before installation.
|
|
10
17
|
|
|
11
|
-
Requires Node **24.x, at least 24.
|
|
18
|
+
Requires Node **24.x, at least 24.21.0**, ESM and HTTPS. CI tests Node 24.21.0 on Linux, macOS and
|
|
12
19
|
Windows; other Node majors are unsupported.
|
|
13
20
|
|
|
14
21
|
```sh
|
|
@@ -18,7 +25,7 @@ npm install @poppykit/client
|
|
|
18
25
|
## Discover a company
|
|
19
26
|
|
|
20
27
|
No credentials or database are needed. Replace `company.example` with a company
|
|
21
|
-
publishing draft 0.
|
|
28
|
+
publishing draft 0.3 discovery:
|
|
22
29
|
|
|
23
30
|
```js
|
|
24
31
|
import { createMetadataResolver, createNodeTransport } from '@poppykit/client';
|
package/RELEASING.md
CHANGED
|
@@ -6,7 +6,7 @@ changing runtime APIs. Each new version needs its own source/artifact evidence.
|
|
|
6
6
|
|
|
7
7
|
## Before tagging
|
|
8
8
|
|
|
9
|
-
- Confirm npm ownership, unused versions, supported Node 24.x (at least 24.
|
|
9
|
+
- Confirm npm ownership, unused versions, supported Node 24.x (at least 24.21.0) and npm>=11.5.1.
|
|
10
10
|
Keep the pinned compiler/dependencies; do not upgrade tooling during a release.
|
|
11
11
|
- Update version, changelog and shipped docs. CLI's client dependency and both
|
|
12
12
|
candidate JSON files must match exact final SDK versions/full source SHAs.
|
package/STORAGE.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Persistence and recovery
|
|
2
2
|
|
|
3
|
-
Use targeted storage contracts. Node 24.x, at least 24.
|
|
3
|
+
Use targeted storage contracts. Node 24.x, at least 24.21.0, is required. The optional `@poppykit/client/sqlite` entry point exports
|
|
4
4
|
`SqliteAuthStore` and `SqliteConversationStore`; importing the client core does not
|
|
5
|
-
load SQLite. `node:sqlite` is experimental in the tested Node 24.
|
|
5
|
+
load SQLite. `node:sqlite` is experimental in the tested Node 24.21.0 runtime.
|
|
6
6
|
Consumers can implement `AuthStore` and `ConversationStore` using their own database.
|
|
7
7
|
|
|
8
8
|
```ts
|
|
@@ -88,6 +88,18 @@ recovery of a token that the issuer rotated but never delivered.
|
|
|
88
88
|
|
|
89
89
|
## Development reset
|
|
90
90
|
|
|
91
|
+
Normalized auth state version 1 upgrades to version 2 atomically on first access
|
|
92
|
+
in both SQLite and PostgreSQL, under the namespace's writer lock. Stop old SDK
|
|
93
|
+
processes before opening the candidate adapters; mixed-version writers are not
|
|
94
|
+
supported. This is a record upgrade, with no SQL schema change. Owner, epoch,
|
|
95
|
+
stable User IDs, grants, scopes, cleanup and internal connection/operation IDs stay.
|
|
96
|
+
Legacy connections discard their volatile token slots and require a fresh key on
|
|
97
|
+
next renewal. Old shared-key references remain retained, but are never used for
|
|
98
|
+
another token request. Prepared old operations are cancelled; dispatched/staged
|
|
99
|
+
ones still pass through `recover()`, preserving rotated tokens and uncertainty.
|
|
100
|
+
Custom targeted adapters must provide the same complete-namespace upgrade under
|
|
101
|
+
their writer lock; the client's fallback also upgrades whole-state snapshots.
|
|
102
|
+
|
|
91
103
|
There is no automatic migration from old whole-state development stores. Stop all
|
|
92
104
|
users of a disposable store, resolve uncertain remote outcomes, and explicitly move
|
|
93
105
|
aside its database and WAL/SHM files and the matching host-managed secret namespace
|
|
@@ -110,7 +122,7 @@ never deletes company history, revokes access or cancels accepted business work.
|
|
|
110
122
|
The optional `@poppykit/client/postgres` exports `PostgresAuthStore` and
|
|
111
123
|
`PostgresConversationStore`; `/provider/postgres` exports `PostgresProviderStore`.
|
|
112
124
|
Install the optional peer `pg@8.23.1` only when choosing these subpaths.
|
|
113
|
-
Protocol-only imports load neither pg nor SQLite. PostgreSQL 17 and Node 24.x (at least 24.
|
|
125
|
+
Protocol-only imports load neither pg nor SQLite. PostgreSQL 17 and Node 24.x (at least 24.21.0)
|
|
114
126
|
are supported; plain PostgreSQL and Supabase transaction pooling use the same adapter.
|
|
115
127
|
There is no Supabase Auth or application dependency.
|
|
116
128
|
|
package/dist/adapter-contract.js
CHANGED
|
@@ -6,7 +6,7 @@ export function runClientConversationAdapterContract(fixture) {
|
|
|
6
6
|
const f = await fixture();
|
|
7
7
|
try {
|
|
8
8
|
const key = { connectionId: 'contract', issuer: 'https://issuer.example/one', endpoint: 'https://company.example/conversations' };
|
|
9
|
-
const row = { ...key, id: 'message', fingerprint: 'original', phase: 'pending', target: null, request: { message: { id: 'message',
|
|
9
|
+
const row = { ...key, id: 'message', fingerprint: 'original', phase: 'pending', target: null, request: { message: { id: 'message', author: { type: 'agent' }, text: 'hello' } } };
|
|
10
10
|
const saved = await Promise.all([f.store.prepareOutbound(key, row), f.second.prepareOutbound(key, { ...row, fingerprint: 'changed' })]);
|
|
11
11
|
assert.equal(saved[0].fingerprint, saved[1].fingerprint);
|
|
12
12
|
saved[0].request.message.text = 'mutated';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Alternative, ExcludedTask } from '../network/tasks.js';
|
|
1
2
|
import type { AuthSelection, AuthStore } from './store.js';
|
|
2
3
|
import type { OperationOwner } from './ownership.js';
|
|
3
4
|
import type { JsonObject } from '../protocol/wire.js';
|
|
@@ -22,10 +23,6 @@ export type AssertionRequest = {
|
|
|
22
23
|
purpose: 'client-authentication';
|
|
23
24
|
} | {
|
|
24
25
|
purpose: 'session';
|
|
25
|
-
} | {
|
|
26
|
-
purpose: 'browser';
|
|
27
|
-
sessionId: string;
|
|
28
|
-
returnTo: string;
|
|
29
26
|
});
|
|
30
27
|
export interface AssertionProvider {
|
|
31
28
|
assert(request: AssertionRequest): Promise<{
|
|
@@ -41,6 +38,7 @@ export interface ProviderIdentity {
|
|
|
41
38
|
}
|
|
42
39
|
export type SignInMethod = 'direct' | 'device' | 'mediated';
|
|
43
40
|
export interface AuthorizationRequirement {
|
|
41
|
+
scopeDescriptions?: Record<string, string>;
|
|
44
42
|
requiredScopes: string[];
|
|
45
43
|
grantedScopes: string[];
|
|
46
44
|
missingScopes: string[];
|
|
@@ -173,7 +171,8 @@ export interface ClientAuth {
|
|
|
173
171
|
apiTarget(connectionId: string, apiUrl: string, destination?: string): Promise<ApiTarget>;
|
|
174
172
|
apiFetch(connectionId: string, request: Request, target: ApiTarget, requiredScopes?: readonly string[]): Promise<Response>;
|
|
175
173
|
joinBrowser(connectionId: string, returnTo: string, controller: AgentBrowserController): Promise<void>;
|
|
176
|
-
feedback(connectionId: string, report: FeedbackReport): Promise<void>;
|
|
174
|
+
feedback(connectionId: string, report: FeedbackReport): Promise<Alternative | void>;
|
|
175
|
+
excludedTasks(connectionId: string): Promise<ExcludedTask[]>;
|
|
177
176
|
}
|
|
178
177
|
export interface CredentialRecord {
|
|
179
178
|
secretRef: string;
|
|
@@ -197,6 +196,7 @@ export interface ConnectionRecord {
|
|
|
197
196
|
slots: Record<string, CredentialRecord>;
|
|
198
197
|
anonymous?: boolean;
|
|
199
198
|
notBefore?: string;
|
|
199
|
+
needsSessionKey?: boolean;
|
|
200
200
|
}
|
|
201
201
|
export interface GrantRecord {
|
|
202
202
|
id: string;
|
|
@@ -239,6 +239,7 @@ export interface OperationRecord {
|
|
|
239
239
|
method?: SignInMethod;
|
|
240
240
|
requiredExistingScopes?: string[];
|
|
241
241
|
signInSessionId?: string;
|
|
242
|
+
signInSessionKey?: string;
|
|
242
243
|
device?: {
|
|
243
244
|
codeRef: string;
|
|
244
245
|
intervalMs: number;
|
|
@@ -270,7 +271,7 @@ export interface CleanupRecord {
|
|
|
270
271
|
notBefore?: string;
|
|
271
272
|
}
|
|
272
273
|
export interface ClientAuthState {
|
|
273
|
-
version: 1;
|
|
274
|
+
version: 1 | 2;
|
|
274
275
|
epoch: string;
|
|
275
276
|
owner: {
|
|
276
277
|
namespace: string;
|
|
@@ -279,7 +280,7 @@ export interface ClientAuthState {
|
|
|
279
280
|
} | null;
|
|
280
281
|
identities: Record<string, {
|
|
281
282
|
userId: string;
|
|
282
|
-
dpopKeyRef
|
|
283
|
+
dpopKeyRef?: string;
|
|
283
284
|
}>;
|
|
284
285
|
connections: Record<string, ConnectionRecord>;
|
|
285
286
|
grants: Record<string, GrantRecord>;
|
|
@@ -294,4 +295,6 @@ export declare class AuthFailure extends Error {
|
|
|
294
295
|
constructor(code: string, connectionId?: string | undefined, retryAfterMs?: number | undefined, retryAt?: string | undefined);
|
|
295
296
|
}
|
|
296
297
|
export declare function initialClientAuthState(): ClientAuthState;
|
|
298
|
+
/** Upgrade a complete namespace under its writer lock; dispatched/staged work still goes through recover(). */
|
|
299
|
+
export declare function upgradeClientAuthState(state: ClientAuthState): void;
|
|
297
300
|
export declare function createClientAuth(options: ClientAuthOptions): ClientAuth;
|