@a2a-exposed/control-core 0.7.33 → 0.7.34

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.
@@ -9,13 +9,17 @@ export type { WakeSave, WakeSettings } from "../tenants/wake.js";
9
9
  export { MAX_WAKE_PLAIN, MAX_WAKE_SEALED, MAX_WAKE_VALUE, WAKE_SECRET_KEYS, openWakeSecrets, sealWakeSecrets, } from "../tenants/wake-secrets.js";
10
10
  export type { WakeSecretKey, WakeSecrets } from "../tenants/wake-secrets.js";
11
11
  export { RESERVED_NAMES, TENANT_NAME, tenantNameProblem } from "../tenants/reserved.js";
12
+ export { httpsOrigin, newApprovalClient } from "../tenants/approval.js";
13
+ export type { ApprovalClient } from "../tenants/approval.js";
12
14
  export { dataPlaneFromEnv, deliverOutbox, flushOutbox, pushFromRow, withOutboxLock, } from "../tenants/push.js";
13
15
  export type { DataPlane, DirectoryEntry, OutboxRow, OwnerCall, PlaneEnv, TenantPush, } from "../tenants/push.js";
14
16
  export type { ControlEnv } from "../env.js";
15
- export type { Sql, SqlStatement } from "../auth/invites.js";
17
+ export type { Sql, SqlStatement } from "./sql.js";
16
18
  export { RUN_WORKER_FIRST } from "../routing.js";
17
19
  export { routes } from "./routes.js";
18
20
  export type { CoreRoutes } from "./routes.js";
21
+ export * from "../provision/grant.js";
22
+ export * from "../provision/setup.js";
19
23
  export * from "../provision/cloudflare-api.js";
20
24
  export * from "../provision/names.js";
21
25
  export * from "../provision/statements.js";
@@ -0,0 +1,16 @@
1
+ export interface SqlStatement {
2
+ bind(...values: unknown[]): SqlStatement;
3
+ first<T>(): Promise<T | null>;
4
+ run(): Promise<{
5
+ meta?: {
6
+ changes?: number;
7
+ };
8
+ }>;
9
+ all<T>(): Promise<{
10
+ results: T[];
11
+ }>;
12
+ }
13
+ export interface Sql {
14
+ prepare(query: string): SqlStatement;
15
+ batch(statements: SqlStatement[]): Promise<unknown>;
16
+ }
@@ -12,7 +12,7 @@ export interface ControlEnv extends PlaneEnv {
12
12
  TENANT_DOMAIN?: string;
13
13
  /** `eu` or `fedramp`. Unset: the platform's default placement. */
14
14
  DATA_REGION?: string;
15
- DB?: import("./auth/invites.js").Sql;
15
+ DB?: import("./core/sql.js").Sql;
16
16
  AUTH_SECRET?: string;
17
17
  GITHUB_CLIENT_ID?: string;
18
18
  GITHUB_CLIENT_SECRET?: string;
@@ -35,8 +35,8 @@ export interface ControlEnv extends PlaneEnv {
35
35
  /** Same secret as the data-plane Worker. Seals wake secrets. Unset: a new key cannot be saved. */
36
36
  TENANT_SECRETS_KEY?: string;
37
37
  /**
38
- * Fine-grained token with Issues write on FEEDBACK_REPO only. A secret, not a var.
39
- * Fallback when the GitHub App below is unset. Not a GITHUB_* name: that prefix is the sign-in OAuth app.
38
+ * Fine-grained token with Issues write on FEEDBACK_REPO. A secret.
39
+ * The feedback route files an issue with this token.
40
40
  */
41
41
  FEEDBACK_GITHUB_TOKEN?: string;
42
42
  /** GitHub App id that files feedback issues. A plain var. With the private key, preferred over the token. */
@@ -0,0 +1,54 @@
1
+ import type { Sql } from "../core/sql.js";
2
+ export interface CloudflareGrantRow {
3
+ userId: string;
4
+ /** Cloudflare user id from GET /user. The account chosen on the consent screen is not in the token response. */
5
+ accountId: string;
6
+ choice: string;
7
+ host: string;
8
+ requested_scope: string;
9
+ granted_scope: string | null;
10
+ refresh_enc: string | null;
11
+ access_expires_at: string | null;
12
+ }
13
+ export type RefreshResult = {
14
+ ok: true;
15
+ accessToken: string;
16
+ scope: string;
17
+ } | {
18
+ ok: false;
19
+ error: "no_grant" | "no_refresh" | "busy" | "invalid_grant" | "uncertain" | "failed" | "unreadable";
20
+ };
21
+ /** `v1.<iv>.<ciphertext>`, or null when the secret or the token cannot be sealed. */
22
+ export declare function sealCloudflareRefresh(secret: string, userId: string, token: string): Promise<string | null>;
23
+ export declare function openCloudflareRefresh(secret: string, userId: string, sealed: string | null | undefined): Promise<string | null>;
24
+ export declare function saveCloudflareGrant(db: Sql, secret: string, input: {
25
+ userId: string;
26
+ accountId: string;
27
+ choice: string;
28
+ host: string;
29
+ requestedScope: string;
30
+ /** Token `scope` string, or null when Cloudflare omitted it. */
31
+ grantedScope: string | null;
32
+ refreshToken: string | null;
33
+ expiresIn: unknown;
34
+ now?: number;
35
+ }): Promise<void>;
36
+ export declare function readCloudflareGrant(db: Sql, userId: string): Promise<CloudflareGrantRow | null>;
37
+ export declare function deleteCloudflareGrant(db: Sql, userId: string): Promise<void>;
38
+ /**
39
+ * Exchanges the stored refresh token and replaces it with the new one.
40
+ * A 400 or 401 drops the stored token: a single-use token is already dead.
41
+ * A timeout or a network error keeps it and returns `uncertain` or `failed`.
42
+ * Do not call this twice in parallel for the same user; the second waits on
43
+ * the lock and then sees the new token, or gets `busy` if the lock is still held.
44
+ */
45
+ export declare function refreshCloudflareGrant(input: {
46
+ database: Sql;
47
+ secret: string;
48
+ clientId: string;
49
+ clientSecret: string;
50
+ userId: string;
51
+ fetchMs?: number;
52
+ now?: number;
53
+ fetchImpl?: typeof fetch;
54
+ }): Promise<RefreshResult>;
@@ -1,4 +1,4 @@
1
- import type { Sql } from "../auth/invites.js";
1
+ import type { Sql } from "../core/sql.js";
2
2
  export interface InboxRow {
3
3
  id: string;
4
4
  userId: string;
@@ -1,5 +1,5 @@
1
- import { type SetupHost } from "../auth/cloudflare-setup.js";
2
- import type { Sql } from "../auth/invites.js";
1
+ import type { Sql } from "../core/sql.js";
2
+ import { type SetupHost } from "./setup.js";
3
3
  import { hashOwnerToken, readCloudflareInbox, type InboxRow } from "./inbox-row.js";
4
4
  import { PERMISSION_WAIT } from "./permission-wait.js";
5
5
  export { hashOwnerToken, readCloudflareInbox };
@@ -1,4 +1,4 @@
1
- import type { Sql } from "../auth/invites.js";
1
+ import type { Sql } from "../core/sql.js";
2
2
  import { type InboxRow } from "./inbox-row.js";
3
3
  export type RemovalId = "address" | "worker" | "database" | "dashboard";
4
4
  export interface RemovalItem {
@@ -0,0 +1,16 @@
1
+ export interface ApprovalClient {
2
+ clientId: string;
3
+ secretHash: string;
4
+ redirectUris: string[];
5
+ clientSecret: string;
6
+ approval: Record<string, unknown>;
7
+ }
8
+ /** https origin, or "" when the value is empty, not https, or carries userinfo. */
9
+ export declare function httpsOrigin(value: string | undefined): string;
10
+ /** Confidential client for one tenant. Null when there is no https issuer or public host. */
11
+ export declare function newApprovalClient(input: {
12
+ accountId: string;
13
+ issuer: string;
14
+ publicUrl: string | null;
15
+ label?: string;
16
+ }): Promise<ApprovalClient | null>;
@@ -1,4 +1,4 @@
1
- import type { Sql } from "../auth/invites.js";
1
+ import type { Sql } from "../core/sql.js";
2
2
  import { type DataPlane } from "./push.js";
3
3
  export interface CreatedTenant {
4
4
  id: string;
@@ -1,4 +1,4 @@
1
- import type { Sql } from "../auth/invites.js";
1
+ import type { Sql } from "../core/sql.js";
2
2
  import { type DataPlane } from "./push.js";
3
3
  export type DeleteResult = {
4
4
  ok: true;
@@ -1,4 +1,4 @@
1
- import type { Sql } from "../auth/invites.js";
1
+ import type { Sql } from "../core/sql.js";
2
2
  /** Versioned copy the data-plane Durable Object stores. Older versions are ignored there. */
3
3
  export interface TenantPush {
4
4
  version: number;
@@ -1,4 +1,4 @@
1
- import type { Sql } from "../auth/invites.js";
1
+ import type { Sql } from "../core/sql.js";
2
2
  import { type DataPlane } from "./push.js";
3
3
  export type RotateResult = {
4
4
  ok: true;
@@ -1,4 +1,4 @@
1
- import type { Sql } from "../auth/invites.js";
1
+ import type { Sql } from "../core/sql.js";
2
2
  import { type DataPlane } from "./push.js";
3
3
  /** The same list the Worker renders. Claude Code is one of them. */
4
4
  export declare const WAKE_PRESETS: readonly ["grok-bot", "claude-code", "openclaw-wake", "openclaw-agent", "hermes", "generic"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a2a-exposed/control-core",
3
- "version": "0.7.33",
3
+ "version": "0.7.34",
4
4
  "description": "Tenants, Cloudflare inbox provisioning, routing, and control-plane migrations for a2a-exposed.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,38 +0,0 @@
1
- export interface SqlStatement {
2
- bind(...values: unknown[]): SqlStatement;
3
- first<T>(): Promise<T | null>;
4
- run(): Promise<{
5
- meta?: {
6
- changes?: number;
7
- };
8
- }>;
9
- all<T>(): Promise<{
10
- results: T[];
11
- }>;
12
- }
13
- export interface Sql {
14
- prepare(query: string): SqlStatement;
15
- batch(statements: SqlStatement[]): Promise<unknown>;
16
- }
17
- export declare function newInviteCode(): string;
18
- export declare function validInviteCode(code: string): boolean;
19
- export declare function hasAccount(db: Sql, email: string): Promise<boolean>;
20
- export declare function insertInvite(db: Sql, input?: {
21
- code?: string;
22
- email?: string;
23
- expiresAt?: string | null;
24
- }): Promise<string>;
25
- /** A live code. When `email` is set, a code locked to another address does not pass. */
26
- export declare function invitePending(db: Sql, code: string, email?: string): Promise<boolean>;
27
- /** SHA-256 of a magic-link token, base64url without padding. The plaintext token is not stored. */
28
- export declare function tokenHash(token: string): Promise<string>;
29
- /**
30
- * Binds an invite to a magic-link token so the emailed link works in another browser.
31
- * The row lives in `verification` under `a2a-invite:<hash>` and is not the Better Auth record
32
- * (that record's schema rejects extra fields).
33
- */
34
- export declare function rememberMagicInvite(db: Sql, token: string, code: string, email: string, ttlSeconds: number): Promise<void>;
35
- /** Reads and deletes the invite bound to this magic-link token. Empty when missing, expired, or for another email. */
36
- export declare function takeMagicInvite(db: Sql, token: string, email: string): Promise<string>;
37
- /** Marks one unused code as used. A second caller gets false. */
38
- export declare function consumeInvite(db: Sql, code: string, email: string): Promise<boolean>;