@adonis-agora/agent 0.76.3 → 0.77.1
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/CHANGELOG.md +22 -0
- package/dist/providers/agent_provider.d.ts.map +1 -1
- package/dist/providers/agent_provider.js +9 -0
- package/dist/providers/agent_provider.js.map +1 -1
- package/dist/providers/mcp_provider.d.ts.map +1 -1
- package/dist/providers/mcp_provider.js +46 -10
- package/dist/providers/mcp_provider.js.map +1 -1
- package/dist/providers/poppy_connections_provider.d.ts +17 -0
- package/dist/providers/poppy_connections_provider.d.ts.map +1 -0
- package/dist/providers/poppy_connections_provider.js +186 -0
- package/dist/providers/poppy_connections_provider.js.map +1 -0
- package/dist/providers/poppy_provider.d.ts +12 -0
- package/dist/providers/poppy_provider.d.ts.map +1 -0
- package/dist/providers/poppy_provider.js +159 -0
- package/dist/providers/poppy_provider.js.map +1 -0
- package/dist/src/a2a/handler.d.ts.map +1 -1
- package/dist/src/a2a/handler.js +4 -2
- package/dist/src/a2a/handler.js.map +1 -1
- package/dist/src/a2a/turn.d.ts +27 -4
- package/dist/src/a2a/turn.d.ts.map +1 -1
- package/dist/src/a2a/turn.js +66 -12
- package/dist/src/a2a/turn.js.map +1 -1
- package/dist/src/action-proposal-approval.d.ts.map +1 -1
- package/dist/src/action-proposal-approval.js +3 -3
- package/dist/src/action-proposal-approval.js.map +1 -1
- package/dist/src/action-proposal-listeners.d.ts +12 -0
- package/dist/src/action-proposal-listeners.d.ts.map +1 -0
- package/dist/src/action-proposal-listeners.js +27 -0
- package/dist/src/action-proposal-listeners.js.map +1 -0
- package/dist/src/action-proposal-receipt.d.ts +4 -0
- package/dist/src/action-proposal-receipt.d.ts.map +1 -1
- package/dist/src/action-proposal-receipt.js +3 -1
- package/dist/src/action-proposal-receipt.js.map +1 -1
- package/dist/src/action-proposal-worker.d.ts +6 -1
- package/dist/src/action-proposal-worker.d.ts.map +1 -1
- package/dist/src/action-proposal-worker.js +10 -1
- package/dist/src/action-proposal-worker.js.map +1 -1
- package/dist/src/agent-loop.d.ts.map +1 -1
- package/dist/src/agent-loop.js +8 -5
- package/dist/src/agent-loop.js.map +1 -1
- package/dist/src/channels/handler.d.ts +10 -0
- package/dist/src/channels/handler.d.ts.map +1 -1
- package/dist/src/channels/handler.js +47 -1
- package/dist/src/channels/handler.js.map +1 -1
- package/dist/src/channels/texts.d.ts +9 -0
- package/dist/src/channels/texts.d.ts.map +1 -1
- package/dist/src/channels/texts.js +4 -0
- package/dist/src/channels/texts.js.map +1 -1
- package/dist/src/client/sse.d.ts.map +1 -1
- package/dist/src/client/sse.js +3 -0
- package/dist/src/client/sse.js.map +1 -1
- package/dist/src/define_config.d.ts +3 -0
- package/dist/src/define_config.d.ts.map +1 -1
- package/dist/src/define_config.js.map +1 -1
- package/dist/src/genui/channels.d.ts +5 -0
- package/dist/src/genui/channels.d.ts.map +1 -1
- package/dist/src/genui/channels.js +11 -0
- package/dist/src/genui/channels.js.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/auth.d.ts +17 -0
- package/dist/src/mcp/auth.d.ts.map +1 -1
- package/dist/src/mcp/auth.js +56 -1
- package/dist/src/mcp/auth.js.map +1 -1
- package/dist/src/mcp/discovery.d.ts +13 -2
- package/dist/src/mcp/discovery.d.ts.map +1 -1
- package/dist/src/mcp/discovery.js +17 -2
- package/dist/src/mcp/discovery.js.map +1 -1
- package/dist/src/mcp/index.d.ts +1 -1
- package/dist/src/mcp/index.d.ts.map +1 -1
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/mcp/scope.d.ts +13 -0
- package/dist/src/mcp/scope.d.ts.map +1 -0
- package/dist/src/mcp/scope.js +24 -0
- package/dist/src/mcp/scope.js.map +1 -0
- package/dist/src/mcp/server.d.ts +6 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +1 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/poppy/auth.d.ts +77 -0
- package/dist/src/poppy/auth.d.ts.map +1 -0
- package/dist/src/poppy/auth.js +16 -0
- package/dist/src/poppy/auth.js.map +1 -0
- package/dist/src/poppy/conversations.d.ts +249 -0
- package/dist/src/poppy/conversations.d.ts.map +1 -0
- package/dist/src/poppy/conversations.js +1017 -0
- package/dist/src/poppy/conversations.js.map +1 -0
- package/dist/src/poppy/define_config.d.ts +98 -0
- package/dist/src/poppy/define_config.d.ts.map +1 -0
- package/dist/src/poppy/define_config.js +11 -0
- package/dist/src/poppy/define_config.js.map +1 -0
- package/dist/src/poppy/endpoints.d.ts +25 -0
- package/dist/src/poppy/endpoints.d.ts.map +1 -0
- package/dist/src/poppy/endpoints.js +31 -0
- package/dist/src/poppy/endpoints.js.map +1 -0
- package/dist/src/poppy/handler.d.ts +80 -0
- package/dist/src/poppy/handler.d.ts.map +1 -0
- package/dist/src/poppy/handler.js +362 -0
- package/dist/src/poppy/handler.js.map +1 -0
- package/dist/src/poppy/index.d.ts +17 -0
- package/dist/src/poppy/index.d.ts.map +1 -0
- package/dist/src/poppy/index.js +9 -0
- package/dist/src/poppy/index.js.map +1 -0
- package/dist/src/poppy/protocol.d.ts +132 -0
- package/dist/src/poppy/protocol.d.ts.map +1 -0
- package/dist/src/poppy/protocol.js +178 -0
- package/dist/src/poppy/protocol.js.map +1 -0
- package/dist/src/poppy/redis-store.d.ts +27 -0
- package/dist/src/poppy/redis-store.d.ts.map +1 -0
- package/dist/src/poppy/redis-store.js +148 -0
- package/dist/src/poppy/redis-store.js.map +1 -0
- package/dist/src/poppy/runtime.d.ts +6 -0
- package/dist/src/poppy/runtime.d.ts.map +1 -0
- package/dist/src/poppy/runtime.js +12 -0
- package/dist/src/poppy/runtime.js.map +1 -0
- package/dist/src/poppy/server_middleware.d.ts +11 -0
- package/dist/src/poppy/server_middleware.d.ts.map +1 -0
- package/dist/src/poppy/server_middleware.js +16 -0
- package/dist/src/poppy/server_middleware.js.map +1 -0
- package/dist/src/poppy/store.d.ts +207 -0
- package/dist/src/poppy/store.d.ts.map +1 -0
- package/dist/src/poppy/store.js +444 -0
- package/dist/src/poppy/store.js.map +1 -0
- package/dist/src/poppy-client/api.d.ts +36 -0
- package/dist/src/poppy-client/api.d.ts.map +1 -0
- package/dist/src/poppy-client/api.js +77 -0
- package/dist/src/poppy-client/api.js.map +1 -0
- package/dist/src/poppy-client/bin/poppy-agent.d.ts +3 -0
- package/dist/src/poppy-client/bin/poppy-agent.d.ts.map +1 -0
- package/dist/src/poppy-client/bin/poppy-agent.js +9 -0
- package/dist/src/poppy-client/bin/poppy-agent.js.map +1 -0
- package/dist/src/poppy-client/browser.d.ts +24 -0
- package/dist/src/poppy-client/browser.d.ts.map +1 -0
- package/dist/src/poppy-client/browser.js +83 -0
- package/dist/src/poppy-client/browser.js.map +1 -0
- package/dist/src/poppy-client/cli/main.d.ts +2 -0
- package/dist/src/poppy-client/cli/main.d.ts.map +1 -0
- package/dist/src/poppy-client/cli/main.js +776 -0
- package/dist/src/poppy-client/cli/main.js.map +1 -0
- package/dist/src/poppy-client/cli/prompt.d.ts +13 -0
- package/dist/src/poppy-client/cli/prompt.d.ts.map +1 -0
- package/dist/src/poppy-client/cli/prompt.js +50 -0
- package/dist/src/poppy-client/cli/prompt.js.map +1 -0
- package/dist/src/poppy-client/company.d.ts +87 -0
- package/dist/src/poppy-client/company.d.ts.map +1 -0
- package/dist/src/poppy-client/company.js +336 -0
- package/dist/src/poppy-client/company.js.map +1 -0
- package/dist/src/poppy-client/conversations.d.ts +89 -0
- package/dist/src/poppy-client/conversations.d.ts.map +1 -0
- package/dist/src/poppy-client/conversations.js +332 -0
- package/dist/src/poppy-client/conversations.js.map +1 -0
- package/dist/src/poppy-client/discovery.d.ts +41 -0
- package/dist/src/poppy-client/discovery.d.ts.map +1 -0
- package/dist/src/poppy-client/discovery.js +217 -0
- package/dist/src/poppy-client/discovery.js.map +1 -0
- package/dist/src/poppy-client/dpop.d.ts +19 -0
- package/dist/src/poppy-client/dpop.d.ts.map +1 -0
- package/dist/src/poppy-client/dpop.js +43 -0
- package/dist/src/poppy-client/dpop.js.map +1 -0
- package/dist/src/poppy-client/errors.d.ts +50 -0
- package/dist/src/poppy-client/errors.d.ts.map +1 -0
- package/dist/src/poppy-client/errors.js +55 -0
- package/dist/src/poppy-client/errors.js.map +1 -0
- package/dist/src/poppy-client/http.d.ts +40 -0
- package/dist/src/poppy-client/http.d.ts.map +1 -0
- package/dist/src/poppy-client/http.js +95 -0
- package/dist/src/poppy-client/http.js.map +1 -0
- package/dist/src/poppy-client/identity.d.ts +61 -0
- package/dist/src/poppy-client/identity.d.ts.map +1 -0
- package/dist/src/poppy-client/identity.js +111 -0
- package/dist/src/poppy-client/identity.js.map +1 -0
- package/dist/src/poppy-client/identity_server.d.ts +29 -0
- package/dist/src/poppy-client/identity_server.d.ts.map +1 -0
- package/dist/src/poppy-client/identity_server.js +84 -0
- package/dist/src/poppy-client/identity_server.js.map +1 -0
- package/dist/src/poppy-client/index.d.ts +19 -0
- package/dist/src/poppy-client/index.d.ts.map +1 -0
- package/dist/src/poppy-client/index.js +18 -0
- package/dist/src/poppy-client/index.js.map +1 -0
- package/dist/src/poppy-client/keys.d.ts +13 -0
- package/dist/src/poppy-client/keys.d.ts.map +1 -0
- package/dist/src/poppy-client/keys.js +31 -0
- package/dist/src/poppy-client/keys.js.map +1 -0
- package/dist/src/poppy-client/llm.d.ts +31 -0
- package/dist/src/poppy-client/llm.d.ts.map +1 -0
- package/dist/src/poppy-client/llm.js +230 -0
- package/dist/src/poppy-client/llm.js.map +1 -0
- package/dist/src/poppy-client/mcp.d.ts +16 -0
- package/dist/src/poppy-client/mcp.d.ts.map +1 -0
- package/dist/src/poppy-client/mcp.js +57 -0
- package/dist/src/poppy-client/mcp.js.map +1 -0
- package/dist/src/poppy-client/open_url.d.ts +3 -0
- package/dist/src/poppy-client/open_url.d.ts.map +1 -0
- package/dist/src/poppy-client/open_url.js +13 -0
- package/dist/src/poppy-client/open_url.js.map +1 -0
- package/dist/src/poppy-client/signin.d.ts +59 -0
- package/dist/src/poppy-client/signin.d.ts.map +1 -0
- package/dist/src/poppy-client/signin.js +210 -0
- package/dist/src/poppy-client/signin.js.map +1 -0
- package/dist/src/poppy-client/sse.d.ts +15 -0
- package/dist/src/poppy-client/sse.d.ts.map +1 -0
- package/dist/src/poppy-client/sse.js +74 -0
- package/dist/src/poppy-client/sse.js.map +1 -0
- package/dist/src/poppy-client/store.d.ts +89 -0
- package/dist/src/poppy-client/store.d.ts.map +1 -0
- package/dist/src/poppy-client/store.js +79 -0
- package/dist/src/poppy-client/store.js.map +1 -0
- package/dist/src/poppy-client/token_client.d.ts +69 -0
- package/dist/src/poppy-client/token_client.d.ts.map +1 -0
- package/dist/src/poppy-client/token_client.js +154 -0
- package/dist/src/poppy-client/token_client.js.map +1 -0
- package/dist/src/poppy-client/types.d.ts +184 -0
- package/dist/src/poppy-client/types.d.ts.map +1 -0
- package/dist/src/poppy-client/types.js +8 -0
- package/dist/src/poppy-client/types.js.map +1 -0
- package/dist/src/poppy-client/util.d.ts +42 -0
- package/dist/src/poppy-client/util.d.ts.map +1 -0
- package/dist/src/poppy-client/util.js +122 -0
- package/dist/src/poppy-client/util.js.map +1 -0
- package/dist/src/poppy-connections/config.d.ts +134 -0
- package/dist/src/poppy-connections/config.d.ts.map +1 -0
- package/dist/src/poppy-connections/config.js +44 -0
- package/dist/src/poppy-connections/config.js.map +1 -0
- package/dist/src/poppy-connections/crypto.d.ts +12 -0
- package/dist/src/poppy-connections/crypto.d.ts.map +1 -0
- package/dist/src/poppy-connections/crypto.js +36 -0
- package/dist/src/poppy-connections/crypto.js.map +1 -0
- package/dist/src/poppy-connections/http.d.ts +63 -0
- package/dist/src/poppy-connections/http.d.ts.map +1 -0
- package/dist/src/poppy-connections/http.js +217 -0
- package/dist/src/poppy-connections/http.js.map +1 -0
- package/dist/src/poppy-connections/index.d.ts +14 -0
- package/dist/src/poppy-connections/index.d.ts.map +1 -0
- package/dist/src/poppy-connections/index.js +17 -0
- package/dist/src/poppy-connections/index.js.map +1 -0
- package/dist/src/poppy-connections/resume.d.ts +46 -0
- package/dist/src/poppy-connections/resume.d.ts.map +1 -0
- package/dist/src/poppy-connections/resume.js +109 -0
- package/dist/src/poppy-connections/resume.js.map +1 -0
- package/dist/src/poppy-connections/runtime.d.ts +4 -0
- package/dist/src/poppy-connections/runtime.d.ts.map +1 -0
- package/dist/src/poppy-connections/runtime.js +9 -0
- package/dist/src/poppy-connections/runtime.js.map +1 -0
- package/dist/src/poppy-connections/server_middleware.d.ts +10 -0
- package/dist/src/poppy-connections/server_middleware.d.ts.map +1 -0
- package/dist/src/poppy-connections/server_middleware.js +14 -0
- package/dist/src/poppy-connections/server_middleware.js.map +1 -0
- package/dist/src/poppy-connections/service.d.ts +179 -0
- package/dist/src/poppy-connections/service.d.ts.map +1 -0
- package/dist/src/poppy-connections/service.js +648 -0
- package/dist/src/poppy-connections/service.js.map +1 -0
- package/dist/src/poppy-connections/store.d.ts +139 -0
- package/dist/src/poppy-connections/store.d.ts.map +1 -0
- package/dist/src/poppy-connections/store.js +260 -0
- package/dist/src/poppy-connections/store.js.map +1 -0
- package/dist/src/poppy-connections/tools.d.ts +65 -0
- package/dist/src/poppy-connections/tools.d.ts.map +1 -0
- package/dist/src/poppy-connections/tools.js +574 -0
- package/dist/src/poppy-connections/tools.js.map +1 -0
- package/dist/src/react/core/approvals/use-action-proposals.d.ts +6 -1
- package/dist/src/react/core/approvals/use-action-proposals.d.ts.map +1 -1
- package/dist/src/react/core/approvals/use-action-proposals.js +18 -3
- package/dist/src/react/core/approvals/use-action-proposals.js.map +1 -1
- package/dist/src/react/core/use-agent-chat.d.ts +6 -0
- package/dist/src/react/core/use-agent-chat.d.ts.map +1 -1
- package/dist/src/react/core/use-agent-chat.js +47 -1
- package/dist/src/react/core/use-agent-chat.js.map +1 -1
- package/dist/src/tool-presentation.d.ts +6 -0
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +1 -0
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/types.d.ts +6 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +41 -2
- package/skills/agent-governance/SKILL.md +13 -2
- package/skills/agent-personas-agents/SKILL.md +1 -1
- package/skills/agent-tools/SKILL.md +20 -3
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import type { CompanyClient } from './company.js';
|
|
3
|
+
import type { PoppyApiEntry } from './types.js';
|
|
4
|
+
export interface McpConnection {
|
|
5
|
+
client: Client;
|
|
6
|
+
api: PoppyApiEntry;
|
|
7
|
+
close(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Connects to a listed MCP server over Streamable HTTP with a Bearer Session Token issued for
|
|
11
|
+
* that server's `url` (4.3 "Bearer tokens", section 6). On `invalid_token` the token is
|
|
12
|
+
* re-minted once and the request retried; a `403` `insufficient_scope` / `sign_in_required`
|
|
13
|
+
* rejects the call with a {@link ResourceAuthError} carrying the needed `scope`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function connectMcp(company: CompanyClient, apiIndex?: number | undefined): Promise<McpConnection>;
|
|
16
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../../src/poppy-client/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAGnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,aAAa,CAAC;IACnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,aAAa,EACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAC5B,OAAO,CAAC,aAAa,CAAC,CAgDxB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
|
+
import { pickApi } from './api.js';
|
|
4
|
+
import { ResourceAuthError } from './errors.js';
|
|
5
|
+
import { wwwAuthError } from './util.js';
|
|
6
|
+
/**
|
|
7
|
+
* Connects to a listed MCP server over Streamable HTTP with a Bearer Session Token issued for
|
|
8
|
+
* that server's `url` (4.3 "Bearer tokens", section 6). On `invalid_token` the token is
|
|
9
|
+
* re-minted once and the request retried; a `403` `insufficient_scope` / `sign_in_required`
|
|
10
|
+
* rejects the call with a {@link ResourceAuthError} carrying the needed `scope`.
|
|
11
|
+
*/
|
|
12
|
+
export async function connectMcp(company, apiIndex) {
|
|
13
|
+
const api = pickApi(company, 'mcp', apiIndex);
|
|
14
|
+
// `resource` MUST be the MCP server's `url` from poppy.json (4.3).
|
|
15
|
+
const resource = api.url;
|
|
16
|
+
let token = await company.bearerFor(resource);
|
|
17
|
+
const authedFetch = async (input, init) => {
|
|
18
|
+
for (let attempt = 0;; attempt++) {
|
|
19
|
+
const headers = new Headers(init?.headers);
|
|
20
|
+
headers.set('authorization', `Bearer ${token}`);
|
|
21
|
+
const res = await company.http.fetch(input, { ...init, headers });
|
|
22
|
+
const err = wwwAuthError(res.headers.get('www-authenticate'));
|
|
23
|
+
if (res.status === 401 && attempt === 0 && (!err.error || err.error === 'invalid_token')) {
|
|
24
|
+
token = await company.bearerFor(resource, true);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
// A signed-in Bearer whose Session was signed out meanwhile (4.4): the Account Token signs
|
|
28
|
+
// it back in — or, revoked, answers invalid_grant and the client continues signed out.
|
|
29
|
+
if (res.status === 403 &&
|
|
30
|
+
attempt === 0 &&
|
|
31
|
+
err.error === 'sign_in_required' &&
|
|
32
|
+
company.accountToken) {
|
|
33
|
+
await res.body?.cancel().catch(() => { });
|
|
34
|
+
token = await company.bearerFor(resource, true);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// A tool behind a scope the user did not grant (MCP scope step-up, RFC 6750 §3.1): surface it
|
|
38
|
+
// like any other resource, so the caller can sign in again with `scope`.
|
|
39
|
+
if (res.status === 403 &&
|
|
40
|
+
(err.error === 'insufficient_scope' || err.error === 'sign_in_required')) {
|
|
41
|
+
await res.body?.cancel().catch(() => { });
|
|
42
|
+
throw new ResourceAuthError(err.error, {
|
|
43
|
+
status: 403,
|
|
44
|
+
description: err.description,
|
|
45
|
+
scope: err.scope,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return res;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const transport = new StreamableHTTPClientTransport(new URL(api.url), { fetch: authedFetch });
|
|
52
|
+
const client = new Client({ name: 'poppy-agent', version: '0.0.0' });
|
|
53
|
+
// The SDK's own types disagree under `exactOptionalPropertyTypes`; the transport is the SDK's.
|
|
54
|
+
await client.connect(transport);
|
|
55
|
+
return { client, api, close: () => client.close() };
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../../src/poppy-client/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open_url.d.ts","sourceRoot":"","sources":["../../../src/poppy-client/open_url.ts"],"names":[],"mappings":"AAEA,6FAA6F;AAC7F,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAS/C"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
/** Best-effort: opens a URL in the desktop browser. Callers always print the URL as well. */
|
|
3
|
+
export function openInBrowser(url) {
|
|
4
|
+
const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';
|
|
5
|
+
const args = process.platform === 'win32' ? ['/c', 'start', '""', url] : [url];
|
|
6
|
+
try {
|
|
7
|
+
const child = spawn(cmd, args, { stdio: 'ignore', detached: true });
|
|
8
|
+
child.on('error', () => { });
|
|
9
|
+
child.unref();
|
|
10
|
+
}
|
|
11
|
+
catch { }
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=open_url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open_url.js","sourceRoot":"","sources":["../../../src/poppy-client/open_url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,6FAA6F;AAC7F,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,GAAG,GACP,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IAC7F,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC5B,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { CompanyClient, SignInResult } from './company.js';
|
|
2
|
+
export type SignInType = 'direct' | 'device' | 'mediated';
|
|
3
|
+
/** The sign-in types this Company offers that can grant every requested scope (4.4). */
|
|
4
|
+
export declare function eligibleSignInTypes(company: CompanyClient, scope: string): SignInType[];
|
|
5
|
+
export interface PendingDirectSignIn {
|
|
6
|
+
url: string;
|
|
7
|
+
state: string;
|
|
8
|
+
codeVerifier: string;
|
|
9
|
+
redirectUri: string;
|
|
10
|
+
scope: string;
|
|
11
|
+
issuer: string;
|
|
12
|
+
}
|
|
13
|
+
/** Step 1 of 4.5: PKCE (S256) + random `state`, and the authorization URL to open. */
|
|
14
|
+
export declare function startDirectSignIn(company: CompanyClient, scope: string): Promise<PendingDirectSignIn>;
|
|
15
|
+
/**
|
|
16
|
+
* Steps 3–4 of 4.5: checks `state` and the RFC 9207 `iss` (exact match with the issuer we
|
|
17
|
+
* started with), then exchanges the code with PKCE, DPoP and `session_id`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function completeDirectSignIn(company: CompanyClient, pending: PendingDirectSignIn, callback: URLSearchParams): Promise<SignInResult>;
|
|
20
|
+
export interface DeviceSignInOptions {
|
|
21
|
+
/** Shows the link and code to the User. `device_code` is never passed here. */
|
|
22
|
+
display: (info: {
|
|
23
|
+
userCode: string;
|
|
24
|
+
verificationUri: string;
|
|
25
|
+
verificationUriComplete?: string | undefined;
|
|
26
|
+
expiresIn: number;
|
|
27
|
+
}) => void;
|
|
28
|
+
signal?: AbortSignal | undefined;
|
|
29
|
+
/** Hook for tests. */
|
|
30
|
+
sleep?: ((ms: number, signal?: AbortSignal) => Promise<void>) | undefined;
|
|
31
|
+
onPoll?: ((status: 'authorization_pending' | 'slow_down', intervalSeconds: number) => void) | undefined;
|
|
32
|
+
}
|
|
33
|
+
/** RFC 8628 device flow: start, show the code, poll every `interval`, +5s on `slow_down`. */
|
|
34
|
+
export declare function deviceSignIn(company: CompanyClient, scope: string, opts: DeviceSignInOptions): Promise<SignInResult>;
|
|
35
|
+
/**
|
|
36
|
+
* One device-code exchange (4.6), for a server that cannot hold a polling loop open (the user
|
|
37
|
+
* comes back and says "approved"): `'pending'` while the User has not decided, the sign-in when
|
|
38
|
+
* they approved. `access_denied` / `expired_token` throw.
|
|
39
|
+
*/
|
|
40
|
+
export declare function pollDeviceSignInOnce(company: CompanyClient, deviceCode: string, scope: string): Promise<SignInResult | 'pending'>;
|
|
41
|
+
export type MediatedOutcome = {
|
|
42
|
+
status: 'complete';
|
|
43
|
+
result: SignInResult;
|
|
44
|
+
} | {
|
|
45
|
+
status: 'code_required';
|
|
46
|
+
signInId: string;
|
|
47
|
+
sentTo?: string | undefined;
|
|
48
|
+
expiresAt?: string | undefined;
|
|
49
|
+
} | {
|
|
50
|
+
status: 'failed' | 'expired';
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Mediated Sign-In (4.7). Credentials go ONLY to `auth.mediated.endpoint`, with the current
|
|
54
|
+
* Session Token. Secret values are never logged or echoed by this module.
|
|
55
|
+
*/
|
|
56
|
+
export declare function mediatedSignIn(company: CompanyClient, scope: string, credentials: Record<string, string>): Promise<MediatedOutcome>;
|
|
57
|
+
/** Submits only the one-time code, to `{endpoint}/{sign_in_id}` (4.7). */
|
|
58
|
+
export declare function submitMediatedCode(company: CompanyClient, scope: string, signInId: string, code: string): Promise<MediatedOutcome>;
|
|
59
|
+
//# sourceMappingURL=signin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signin.d.ts","sourceRoot":"","sources":["../../../src/poppy-client/signin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAMhE,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE1D,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,CAOvF;AAmBD,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,sFAAsF;AACtF,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,mBAAmB,CAAC,CAkB9B;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,YAAY,CAAC,CA2BvB;AAuBD,MAAM,WAAW,mBAAmB;IAClC,+EAA+E;IAC/E,OAAO,EAAE,CAAC,IAAI,EAAE;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,EAAE,MAAM,CAAC;QACxB,uBAAuB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC7C,SAAS,EAAE,MAAM,CAAC;KACnB,KAAK,IAAI,CAAC;IACX,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,sBAAsB;IACtB,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IAC1E,MAAM,CAAC,EACH,CAAC,CAAC,MAAM,EAAE,uBAAuB,GAAG,WAAW,EAAE,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC,GAClF,SAAS,CAAC;CACf;AAED,6FAA6F;AAC7F,wBAAsB,YAAY,CAChC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,YAAY,CAAC,CAsCvB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAYnC;AAID,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GAC5C;IACE,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,GACD;IAAE,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAA;CAAE,CAAC;AA8CrC;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAAC,eAAe,CAAC,CAc1B;AAED,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,CAAC,CAG1B"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { OAuthError, PoppyError } from './errors.js';
|
|
3
|
+
import { readJson } from './http.js';
|
|
4
|
+
import { requireSecureUrl, scopeSet, sha256b64url, sleep } from './util.js';
|
|
5
|
+
/** The sign-in types this Company offers that can grant every requested scope (4.4). */
|
|
6
|
+
export function eligibleSignInTypes(company, scope) {
|
|
7
|
+
const auth = company.document.auth;
|
|
8
|
+
const wanted = [...scopeSet(scope)];
|
|
9
|
+
return ['direct', 'device', 'mediated'].filter((t) => {
|
|
10
|
+
const cfg = auth[t];
|
|
11
|
+
return cfg && wanted.every((s) => cfg.scopes.includes(s));
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function assertScopeAllowed(company, type, scope) {
|
|
15
|
+
const cfg = company.document.auth[type];
|
|
16
|
+
if (!cfg)
|
|
17
|
+
throw new PoppyError('unsupported_sign_in', `${type} sign-in is not offered`);
|
|
18
|
+
if (scopeSet(scope).size === 0) {
|
|
19
|
+
throw new PoppyError('invalid_scope', 'sign-in requests MUST include scope (4.4)');
|
|
20
|
+
}
|
|
21
|
+
const extra = [...scopeSet(scope)].filter((s) => !cfg.scopes.includes(s));
|
|
22
|
+
if (extra.length > 0) {
|
|
23
|
+
throw new PoppyError('invalid_scope', `${type} sign-in can't grant ${extra.join(', ')} (offers: ${cfg.scopes.join(' ')})`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Step 1 of 4.5: PKCE (S256) + random `state`, and the authorization URL to open. */
|
|
27
|
+
export async function startDirectSignIn(company, scope) {
|
|
28
|
+
assertScopeAllowed(company, 'direct', scope);
|
|
29
|
+
const endpoint = company.metadata.authorization_endpoint;
|
|
30
|
+
if (!endpoint)
|
|
31
|
+
throw new PoppyError('unsupported_sign_in', 'no authorization_endpoint');
|
|
32
|
+
// Make sure there is a Session for the code exchange to sign in.
|
|
33
|
+
await company.token();
|
|
34
|
+
const state = randomBytes(16).toString('base64url');
|
|
35
|
+
const codeVerifier = randomBytes(32).toString('base64url');
|
|
36
|
+
const redirectUri = company.agent.identity.redirectUri;
|
|
37
|
+
const url = new URL(endpoint);
|
|
38
|
+
url.searchParams.set('response_type', 'code');
|
|
39
|
+
url.searchParams.set('client_id', company.agent.identity.clientId);
|
|
40
|
+
url.searchParams.set('redirect_uri', redirectUri);
|
|
41
|
+
url.searchParams.set('scope', scope);
|
|
42
|
+
url.searchParams.set('state', state);
|
|
43
|
+
url.searchParams.set('code_challenge', sha256b64url(codeVerifier));
|
|
44
|
+
url.searchParams.set('code_challenge_method', 'S256');
|
|
45
|
+
return { url: url.toString(), state, codeVerifier, redirectUri, scope, issuer: company.issuer };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Steps 3–4 of 4.5: checks `state` and the RFC 9207 `iss` (exact match with the issuer we
|
|
49
|
+
* started with), then exchanges the code with PKCE, DPoP and `session_id`.
|
|
50
|
+
*/
|
|
51
|
+
export async function completeDirectSignIn(company, pending, callback) {
|
|
52
|
+
if (callback.get('state') !== pending.state) {
|
|
53
|
+
throw new PoppyError('state_mismatch', 'Direct Sign-In callback state does not match');
|
|
54
|
+
}
|
|
55
|
+
const iss = callback.get('iss');
|
|
56
|
+
if (iss !== pending.issuer) {
|
|
57
|
+
throw new PoppyError('issuer_mismatch', `Direct Sign-In callback iss "${iss ?? '(missing)'}" != "${pending.issuer}" (RFC 9207)`);
|
|
58
|
+
}
|
|
59
|
+
const error = callback.get('error');
|
|
60
|
+
if (error) {
|
|
61
|
+
throw new OAuthError(error, { description: callback.get('error_description') ?? undefined });
|
|
62
|
+
}
|
|
63
|
+
const code = callback.get('code');
|
|
64
|
+
if (!code)
|
|
65
|
+
throw new PoppyError('invalid_callback', 'callback has neither code nor error');
|
|
66
|
+
const resp = await withLiveSession(company, (sessionId) => company.tokens.authorizationCode({
|
|
67
|
+
code,
|
|
68
|
+
redirectUri: pending.redirectUri,
|
|
69
|
+
codeVerifier: pending.codeVerifier,
|
|
70
|
+
sessionId,
|
|
71
|
+
dpop: company.dpop,
|
|
72
|
+
}));
|
|
73
|
+
return company.applySignIn(resp, 'direct', pending.scope);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Runs a sign-in exchange with the current Session. The stored Session may have ended at the
|
|
77
|
+
* Company (expired, ended, the Company's data reset) — 4.2: on `invalid_session` the agent starts a
|
|
78
|
+
* new Session and the exchange is retried once with it (the code is not consumed by the refusal).
|
|
79
|
+
*/
|
|
80
|
+
async function withLiveSession(company, exchange) {
|
|
81
|
+
const sessionId = (await company.token()).sessionId;
|
|
82
|
+
try {
|
|
83
|
+
return await exchange(sessionId);
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
if (!(e instanceof OAuthError) || e.code !== 'invalid_session')
|
|
87
|
+
throw e;
|
|
88
|
+
company.agent.log('invalid_session during sign-in: starting a new Session');
|
|
89
|
+
return exchange((await company.token({ forceRenew: true })).sessionId);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** RFC 8628 device flow: start, show the code, poll every `interval`, +5s on `slow_down`. */
|
|
93
|
+
export async function deviceSignIn(company, scope, opts) {
|
|
94
|
+
assertScopeAllowed(company, 'device', scope);
|
|
95
|
+
const d = await company.tokens.deviceAuthorization(scope);
|
|
96
|
+
opts.display({
|
|
97
|
+
userCode: d.user_code,
|
|
98
|
+
verificationUri: d.verification_uri,
|
|
99
|
+
verificationUriComplete: d.verification_uri_complete,
|
|
100
|
+
expiresIn: d.expires_in,
|
|
101
|
+
});
|
|
102
|
+
const wait = opts.sleep ?? sleep;
|
|
103
|
+
let interval = typeof d.interval === 'number' && d.interval > 0 ? d.interval : 5;
|
|
104
|
+
const deadline = Date.now() + d.expires_in * 1000;
|
|
105
|
+
for (;;) {
|
|
106
|
+
await wait(interval * 1000, opts.signal);
|
|
107
|
+
if (Date.now() > deadline)
|
|
108
|
+
throw new OAuthError('expired_token');
|
|
109
|
+
try {
|
|
110
|
+
const resp = await withLiveSession(company, (sessionId) => company.tokens.deviceToken({
|
|
111
|
+
deviceCode: d.device_code,
|
|
112
|
+
sessionId,
|
|
113
|
+
dpop: company.dpop,
|
|
114
|
+
}));
|
|
115
|
+
return await company.applySignIn(resp, 'device', scope);
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
if (!(e instanceof OAuthError))
|
|
119
|
+
throw e;
|
|
120
|
+
if (e.code === 'authorization_pending') {
|
|
121
|
+
opts.onPoll?.('authorization_pending', interval);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (e.code === 'slow_down') {
|
|
125
|
+
interval += 5; // RFC 8628 section 3.5
|
|
126
|
+
opts.onPoll?.('slow_down', interval);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
throw e; // access_denied, expired_token, anything else: stop asking.
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* One device-code exchange (4.6), for a server that cannot hold a polling loop open (the user
|
|
135
|
+
* comes back and says "approved"): `'pending'` while the User has not decided, the sign-in when
|
|
136
|
+
* they approved. `access_denied` / `expired_token` throw.
|
|
137
|
+
*/
|
|
138
|
+
export async function pollDeviceSignInOnce(company, deviceCode, scope) {
|
|
139
|
+
try {
|
|
140
|
+
const resp = await withLiveSession(company, (sessionId) => company.tokens.deviceToken({ deviceCode, sessionId, dpop: company.dpop }));
|
|
141
|
+
return await company.applySignIn(resp, 'device', scope);
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
if (e instanceof OAuthError && (e.code === 'authorization_pending' || e.code === 'slow_down')) {
|
|
145
|
+
return 'pending';
|
|
146
|
+
}
|
|
147
|
+
throw e;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function mediatedRequest(company, url, body, scope) {
|
|
151
|
+
const res = await company.fetch(url, {
|
|
152
|
+
method: 'POST',
|
|
153
|
+
headers: { 'content-type': 'application/json', accept: 'application/json' },
|
|
154
|
+
body: JSON.stringify(body),
|
|
155
|
+
});
|
|
156
|
+
const json = await readJson(res);
|
|
157
|
+
if (!json || typeof json.status !== 'string') {
|
|
158
|
+
throw new PoppyError(json?.error ?? `http_${res.status}`, undefined, {
|
|
159
|
+
status: res.status,
|
|
160
|
+
description: 'mediated sign-in failed',
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
switch (json.status) {
|
|
164
|
+
case 'complete': {
|
|
165
|
+
const resp = json;
|
|
166
|
+
if (String(resp.token_type).toLowerCase() !== 'dpop') {
|
|
167
|
+
throw new OAuthError('invalid_response', { description: 'expected a DPoP Session Token' });
|
|
168
|
+
}
|
|
169
|
+
return { status: 'complete', result: await company.applySignIn(resp, 'mediated', scope) };
|
|
170
|
+
}
|
|
171
|
+
case 'code_required':
|
|
172
|
+
if (!json.sign_in_id || !/^[A-Za-z0-9_-]{1,256}$/.test(json.sign_in_id)) {
|
|
173
|
+
throw new PoppyError('invalid_response', 'code_required without a valid sign_in_id');
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
status: 'code_required',
|
|
177
|
+
signInId: json.sign_in_id,
|
|
178
|
+
sentTo: json.code?.sent_to,
|
|
179
|
+
expiresAt: json.expires_at,
|
|
180
|
+
};
|
|
181
|
+
case 'failed':
|
|
182
|
+
case 'expired':
|
|
183
|
+
return { status: json.status };
|
|
184
|
+
default:
|
|
185
|
+
throw new PoppyError('invalid_response', `unknown mediated status ${String(json.status)}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Mediated Sign-In (4.7). Credentials go ONLY to `auth.mediated.endpoint`, with the current
|
|
190
|
+
* Session Token. Secret values are never logged or echoed by this module.
|
|
191
|
+
*/
|
|
192
|
+
export async function mediatedSignIn(company, scope, credentials) {
|
|
193
|
+
assertScopeAllowed(company, 'mediated', scope);
|
|
194
|
+
const mediated = company.document.auth.mediated;
|
|
195
|
+
const endpoint = requireSecureUrl(mediated.endpoint, 'auth.mediated.endpoint', company.security);
|
|
196
|
+
const missing = mediated.fields.filter((f) => typeof credentials[f.name] !== 'string');
|
|
197
|
+
if (missing.length > 0) {
|
|
198
|
+
throw new PoppyError('missing_credentials', `missing: ${missing.map((f) => f.name).join(', ')}`);
|
|
199
|
+
}
|
|
200
|
+
const sent = {};
|
|
201
|
+
for (const f of mediated.fields)
|
|
202
|
+
sent[f.name] = credentials[f.name] ?? '';
|
|
203
|
+
return mediatedRequest(company, endpoint.toString(), { scope, credentials: sent }, scope);
|
|
204
|
+
}
|
|
205
|
+
/** Submits only the one-time code, to `{endpoint}/{sign_in_id}` (4.7). */
|
|
206
|
+
export function submitMediatedCode(company, scope, signInId, code) {
|
|
207
|
+
const base = company.document.auth.mediated.endpoint.replace(/\/+$/, '');
|
|
208
|
+
return mediatedRequest(company, `${base}/${encodeURIComponent(signInId)}`, { code }, scope);
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=signin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signin.js","sourceRoot":"","sources":["../../../src/poppy-client/signin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** One dispatched server-sent event (WHATWG HTML, "Server-sent events"). */
|
|
2
|
+
export interface SseEvent {
|
|
3
|
+
/** `message` when the stream gave no `event:` field. */
|
|
4
|
+
event: string;
|
|
5
|
+
data: string;
|
|
6
|
+
/** The `id:` field of this event, if it had one. */
|
|
7
|
+
id?: string | undefined;
|
|
8
|
+
retry?: number | undefined;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parses an SSE byte stream. Follows the WHATWG algorithm closely enough for Poppy: CRLF/CR/LF
|
|
12
|
+
* line endings, `:` comments, multi-line `data`, `id` without NUL, `retry`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseSse(stream: ReadableStream<Uint8Array>): AsyncGenerator<SseEvent>;
|
|
15
|
+
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../src/poppy-client/sse.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,WAAW,QAAQ;IACvB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAuB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,cAAc,CAAC,QAAQ,CAAC,CA6D5F"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses an SSE byte stream. Follows the WHATWG algorithm closely enough for Poppy: CRLF/CR/LF
|
|
3
|
+
* line endings, `:` comments, multi-line `data`, `id` without NUL, `retry`.
|
|
4
|
+
*/
|
|
5
|
+
export async function* parseSse(stream) {
|
|
6
|
+
const decoder = new TextDecoder();
|
|
7
|
+
let buffer = '';
|
|
8
|
+
let data = [];
|
|
9
|
+
let event = '';
|
|
10
|
+
let id;
|
|
11
|
+
let retry;
|
|
12
|
+
let sawCr = false;
|
|
13
|
+
const dispatch = () => {
|
|
14
|
+
const out = data.length > 0 ? { event: event || 'message', data: data.join('\n'), id, retry } : undefined;
|
|
15
|
+
data = [];
|
|
16
|
+
event = '';
|
|
17
|
+
id = undefined;
|
|
18
|
+
retry = undefined;
|
|
19
|
+
return out;
|
|
20
|
+
};
|
|
21
|
+
const handleLine = (line) => {
|
|
22
|
+
if (line === '')
|
|
23
|
+
return dispatch();
|
|
24
|
+
if (line.startsWith(':'))
|
|
25
|
+
return undefined;
|
|
26
|
+
const colon = line.indexOf(':');
|
|
27
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
28
|
+
let value = colon === -1 ? '' : line.slice(colon + 1);
|
|
29
|
+
if (value.startsWith(' '))
|
|
30
|
+
value = value.slice(1);
|
|
31
|
+
if (field === 'data')
|
|
32
|
+
data.push(value);
|
|
33
|
+
else if (field === 'event')
|
|
34
|
+
event = value;
|
|
35
|
+
else if (field === 'id' && !value.includes('\0'))
|
|
36
|
+
id = value;
|
|
37
|
+
else if (field === 'retry' && /^\d+$/.test(value))
|
|
38
|
+
retry = Number(value);
|
|
39
|
+
return undefined;
|
|
40
|
+
};
|
|
41
|
+
const reader = stream.getReader();
|
|
42
|
+
try {
|
|
43
|
+
for (;;) {
|
|
44
|
+
const { value, done } = await reader.read();
|
|
45
|
+
if (done)
|
|
46
|
+
break;
|
|
47
|
+
buffer += decoder.decode(value, { stream: true });
|
|
48
|
+
let start = 0;
|
|
49
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
50
|
+
const ch = buffer[i];
|
|
51
|
+
if (ch === '\n' && sawCr) {
|
|
52
|
+
sawCr = false;
|
|
53
|
+
start = i + 1;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
sawCr = false;
|
|
57
|
+
if (ch === '\r' || ch === '\n') {
|
|
58
|
+
if (ch === '\r')
|
|
59
|
+
sawCr = true;
|
|
60
|
+
const ev = handleLine(buffer.slice(start, i));
|
|
61
|
+
start = i + 1;
|
|
62
|
+
if (ev)
|
|
63
|
+
yield ev;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
buffer = buffer.slice(start);
|
|
67
|
+
}
|
|
68
|
+
// An event without its terminating blank line is discarded, per the spec.
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
reader.releaseLock();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=sse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../../src/poppy-client/sse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { StoredKey } from './keys.js';
|
|
2
|
+
export interface TokenRecord {
|
|
3
|
+
accessToken: string;
|
|
4
|
+
tokenType: string;
|
|
5
|
+
/** Epoch ms. */
|
|
6
|
+
expiresAt: number;
|
|
7
|
+
scope: string;
|
|
8
|
+
sessionId: string;
|
|
9
|
+
signedIn: boolean;
|
|
10
|
+
/** RFC 8707 resource this token was issued for, if any. */
|
|
11
|
+
resource?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface AccountTokenRecord {
|
|
14
|
+
/** The Account Token (an OAuth refresh token). A secret: never logged or shown (4.8). */
|
|
15
|
+
refreshToken: string;
|
|
16
|
+
scope: string;
|
|
17
|
+
obtainedAt: number;
|
|
18
|
+
/** Epoch ms, from `refresh_token_expires_in` when the Company sets one. */
|
|
19
|
+
expiresAt?: number | undefined;
|
|
20
|
+
/** Which sign-in type produced it. */
|
|
21
|
+
via: 'direct' | 'device' | 'mediated';
|
|
22
|
+
}
|
|
23
|
+
export interface ConversationRecord {
|
|
24
|
+
endpoint: string;
|
|
25
|
+
/** Last event handled (a cursor / Last-Event-ID). */
|
|
26
|
+
cursor?: string | undefined;
|
|
27
|
+
parentConversationId?: string | undefined;
|
|
28
|
+
createdAt: number;
|
|
29
|
+
closed?: boolean | undefined;
|
|
30
|
+
}
|
|
31
|
+
/** Everything the agent remembers about one User at one Company (keyed by issuer, 3.2). */
|
|
32
|
+
export interface CompanyState {
|
|
33
|
+
issuer: string;
|
|
34
|
+
domains: string[];
|
|
35
|
+
/** Opaque, random, per-Company User ID (4.2). Never derived from personal information. */
|
|
36
|
+
userId: string;
|
|
37
|
+
/** DPoP key for this User at this Company (4.3). Never published. */
|
|
38
|
+
dpopKey: StoredKey;
|
|
39
|
+
accountToken?: AccountTokenRecord | undefined;
|
|
40
|
+
/** Session Tokens by key: `dpop` (default) or `dpop|scope|resource` / `bearer|resource`. */
|
|
41
|
+
tokens: Record<string, TokenRecord>;
|
|
42
|
+
/** The current Session's ID. Not a credential (4.2). */
|
|
43
|
+
sessionId?: string | undefined;
|
|
44
|
+
conversations: Record<string, ConversationRecord>;
|
|
45
|
+
}
|
|
46
|
+
export interface IdentityState {
|
|
47
|
+
baseUrl: string;
|
|
48
|
+
clientName: string;
|
|
49
|
+
logoUri?: string | undefined;
|
|
50
|
+
keys: StoredKey[];
|
|
51
|
+
}
|
|
52
|
+
export interface StateFile {
|
|
53
|
+
version: 1;
|
|
54
|
+
identity?: IdentityState | undefined;
|
|
55
|
+
/** Local users ("profiles") of this agent, each with their Companies. */
|
|
56
|
+
profiles: Record<string, {
|
|
57
|
+
companies: Record<string, CompanyState>;
|
|
58
|
+
}>;
|
|
59
|
+
}
|
|
60
|
+
export declare function defaultStatePath(): string;
|
|
61
|
+
/**
|
|
62
|
+
* The local state file. It holds private keys and Account Tokens, so it is written with mode
|
|
63
|
+
* 0600 (directory 0700) and atomically (temp file + rename).
|
|
64
|
+
*/
|
|
65
|
+
export declare class StateStore {
|
|
66
|
+
#private;
|
|
67
|
+
readonly path: string;
|
|
68
|
+
data: StateFile;
|
|
69
|
+
private readonly persist?;
|
|
70
|
+
private constructor();
|
|
71
|
+
/**
|
|
72
|
+
* A state kept by the caller instead of a file — a server keeping each user's Companies in its
|
|
73
|
+
* own database. `persist` receives the whole state on every save (serialized, like the file).
|
|
74
|
+
*/
|
|
75
|
+
static memory(data?: StateFile, persist?: (data: StateFile) => Promise<void>): StateStore;
|
|
76
|
+
static open(path?: string): Promise<StateStore>;
|
|
77
|
+
/** Directory next to the state file, used for the Direct Sign-In callback relay. */
|
|
78
|
+
get dir(): string;
|
|
79
|
+
profile(name: string): {
|
|
80
|
+
companies: Record<string, CompanyState>;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Writes the state atomically (tmp file + rename). Saves are serialized: a conversation stream
|
|
84
|
+
* and the prompt can save at the same time, and two writes sharing one tmp file made the second
|
|
85
|
+
* `rename` fail with ENOENT.
|
|
86
|
+
*/
|
|
87
|
+
save(): Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/poppy-client/store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,yFAAyF;IACzF,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,sCAAsC;IACtC,GAAG,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9B;AAED,2FAA2F;AAC3F,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,0FAA0F;IAC1F,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,OAAO,EAAE,SAAS,CAAC;IACnB,YAAY,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC9C,4FAA4F;IAC5F,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACrC,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;KAAE,CAAC,CAAC;CACvE;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAIzC;AAED;;;GAGG;AACH,qBAAa,UAAU;;IAEnB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACd,IAAI,EAAE,SAAS;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAH3B,OAAO,eAIH;IAEJ;;;OAGG;IACH,MAAM,CAAC,MAAM,CACX,IAAI,GAAE,SAAwC,EAC9C,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,GAC3C,UAAU,CAGZ;IAED,OAAa,IAAI,CAAC,IAAI,SAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,CAahE;IAED,oFAAoF;IACpF,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,OAAO,CAAC,IAAI,EAAE,MAAM;mBApDkB,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;MAuDjE;IAID;;;;OAIG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAIpB;CAYF"}
|