@opendatalabs/vana-sdk 4.4.0 → 4.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.
Files changed (106) hide show
  1. package/README.md +176 -0
  2. package/dist/connect/account-origin.cjs +72 -0
  3. package/dist/connect/account-origin.cjs.map +1 -0
  4. package/dist/connect/account-origin.d.ts +92 -0
  5. package/dist/connect/account-origin.js +47 -0
  6. package/dist/connect/account-origin.js.map +1 -0
  7. package/dist/connect/account-origin.test.d.ts +1 -0
  8. package/dist/connect/chrome.cjs +284 -0
  9. package/dist/connect/chrome.cjs.map +1 -0
  10. package/dist/connect/chrome.d.ts +42 -0
  11. package/dist/connect/chrome.js +256 -0
  12. package/dist/connect/chrome.js.map +1 -0
  13. package/dist/connect/http-transports.cjs +100 -0
  14. package/dist/connect/http-transports.cjs.map +1 -0
  15. package/dist/connect/http-transports.d.ts +77 -0
  16. package/dist/connect/http-transports.js +75 -0
  17. package/dist/connect/http-transports.js.map +1 -0
  18. package/dist/connect/http-transports.test.d.ts +1 -0
  19. package/dist/connect/launcher.cjs +232 -0
  20. package/dist/connect/launcher.cjs.map +1 -0
  21. package/dist/connect/launcher.d.ts +129 -0
  22. package/dist/connect/launcher.js +220 -0
  23. package/dist/connect/launcher.js.map +1 -0
  24. package/dist/connect/launcher.test.d.ts +1 -0
  25. package/dist/connect/protocol.cjs +259 -0
  26. package/dist/connect/protocol.cjs.map +1 -0
  27. package/dist/connect/protocol.d.ts +331 -0
  28. package/dist/connect/protocol.js +215 -0
  29. package/dist/connect/protocol.js.map +1 -0
  30. package/dist/connect/protocol.test.d.ts +1 -0
  31. package/dist/connect.cjs +55 -0
  32. package/dist/connect.cjs.map +1 -0
  33. package/dist/connect.d.ts +35 -0
  34. package/dist/connect.js +34 -0
  35. package/dist/connect.js.map +1 -0
  36. package/dist/direct/connect-flow-sheet.test.d.ts +1 -0
  37. package/dist/direct/connect-flow.cjs +211 -1
  38. package/dist/direct/connect-flow.cjs.map +1 -1
  39. package/dist/direct/connect-flow.d.ts +75 -0
  40. package/dist/direct/connect-flow.js +213 -1
  41. package/dist/direct/connect-flow.js.map +1 -1
  42. package/dist/direct/connect-handler.cjs +493 -0
  43. package/dist/direct/connect-handler.cjs.map +1 -0
  44. package/dist/direct/connect-handler.d.ts +246 -0
  45. package/dist/direct/connect-handler.js +476 -0
  46. package/dist/direct/connect-handler.js.map +1 -0
  47. package/dist/direct/connect-handler.test.d.ts +1 -0
  48. package/dist/direct/controller.cjs +86 -17
  49. package/dist/direct/controller.cjs.map +1 -1
  50. package/dist/direct/controller.d.ts +101 -6
  51. package/dist/direct/controller.js +86 -16
  52. package/dist/direct/controller.js.map +1 -1
  53. package/dist/direct/endpoints.cjs +5 -2
  54. package/dist/direct/endpoints.cjs.map +1 -1
  55. package/dist/direct/endpoints.js +5 -2
  56. package/dist/direct/endpoints.js.map +1 -1
  57. package/dist/direct/request-authorization.cjs +65 -0
  58. package/dist/direct/request-authorization.cjs.map +1 -0
  59. package/dist/direct/request-authorization.d.ts +65 -0
  60. package/dist/direct/request-authorization.js +39 -0
  61. package/dist/direct/request-authorization.js.map +1 -0
  62. package/dist/direct/request-authorization.test.d.ts +1 -0
  63. package/dist/direct/types.cjs.map +1 -1
  64. package/dist/direct/types.d.ts +6 -0
  65. package/dist/direct/types.js.map +1 -1
  66. package/dist/direct/use-direct-vana-connect.cjs +18 -1
  67. package/dist/direct/use-direct-vana-connect.cjs.map +1 -1
  68. package/dist/direct/use-direct-vana-connect.js +18 -1
  69. package/dist/direct/use-direct-vana-connect.js.map +1 -1
  70. package/dist/direct/use-vana-connect.cjs +84 -0
  71. package/dist/direct/use-vana-connect.cjs.map +1 -0
  72. package/dist/direct/use-vana-connect.d.ts +59 -0
  73. package/dist/direct/use-vana-connect.js +64 -0
  74. package/dist/direct/use-vana-connect.js.map +1 -0
  75. package/dist/direct/use-vana-connect.test.d.ts +1 -0
  76. package/dist/index.browser.d.ts +1 -0
  77. package/dist/index.browser.js +104 -0
  78. package/dist/index.browser.js.map +4 -4
  79. package/dist/index.node.cjs +112 -0
  80. package/dist/index.node.cjs.map +3 -3
  81. package/dist/index.node.d.ts +1 -0
  82. package/dist/index.node.js +104 -0
  83. package/dist/index.node.js.map +4 -4
  84. package/dist/protocol/fixtures/pdpp-scope-keys.json +133 -0
  85. package/dist/protocol/pdpp-scopes.cjs +134 -0
  86. package/dist/protocol/pdpp-scopes.cjs.map +1 -0
  87. package/dist/protocol/pdpp-scopes.d.ts +123 -0
  88. package/dist/protocol/pdpp-scopes.js +103 -0
  89. package/dist/protocol/pdpp-scopes.js.map +1 -0
  90. package/dist/protocol/pdpp-scopes.test.d.ts +1 -0
  91. package/dist/protocol/scopes.cjs +17 -0
  92. package/dist/protocol/scopes.cjs.map +1 -1
  93. package/dist/protocol/scopes.d.ts +1 -0
  94. package/dist/protocol/scopes.js +18 -0
  95. package/dist/protocol/scopes.js.map +1 -1
  96. package/dist/react.cjs +10 -2
  97. package/dist/react.cjs.map +1 -1
  98. package/dist/react.d.ts +4 -1
  99. package/dist/react.js +11 -1
  100. package/dist/react.js.map +1 -1
  101. package/dist/server.cjs +61 -2
  102. package/dist/server.cjs.map +1 -1
  103. package/dist/server.d.ts +16 -4
  104. package/dist/server.js +67 -3
  105. package/dist/server.js.map +1 -1
  106. package/package.json +11 -1
@@ -0,0 +1,246 @@
1
+ /**
2
+ * One Fetch-API handler for every backend route the connect flow needs.
3
+ *
4
+ * @remarks
5
+ * `createVanaConnectHandler` answers four routes under one base path. The
6
+ * action is the last path segment, so mount it as a catch-all
7
+ * (`app/api/vana/[action]/route.ts` in Next.js, or `app.use("/api/vana",
8
+ * toNodeHandler(handler))` in Express):
9
+ *
10
+ * | Route | Does |
11
+ * | ----------------------------- | ---------------------------------------------------- |
12
+ * | `GET config` | Sheet config: client id, app name, Account origin. |
13
+ * | `POST request` | Create a request bound to this browser, or re-sign one it already holds. Returns `{ request, embed }`. |
14
+ * | `GET status?requestId=` | Status of a bound request. |
15
+ * | `GET data?requestId=` | Read the approved data of a bound request. |
16
+ *
17
+ * Binding: a created request is bound to the browser by an HttpOnly,
18
+ * `SameSite=Lax` cookie carrying an HMAC-SHA256 tag, keyed by a secret
19
+ * derived from the app key with HKDF. The handler signs, reports and reads
20
+ * only requests bound to the calling browser (and, with `session`, to the
21
+ * app's own signed-in user). See `src/connect/WIRE_CONTRACT.md` for the
22
+ * wire contract a non-JS backend implements instead.
23
+ *
24
+ * What a request asks for is the controller's: its PDPP `grants` (each
25
+ * stream requested as `pdpp.<source>.<stream>`) and legacy `scopes`. The
26
+ * browser never chooses; `POST request` reports the scopes it sent.
27
+ *
28
+ * Creating a request is rate limited (`rateLimit`; by default in memory,
29
+ * per client IP and per session, which is not production-grade). In
30
+ * production, require a signed-in user with `session` and put a shared
31
+ * limiter in front of `POST request`.
32
+ *
33
+ * @category Direct
34
+ * @module direct/connect-handler
35
+ */
36
+ import { type DirectDataController } from "./controller.js";
37
+ import type { VanaConnectConfig } from "../connect/http-transports.js";
38
+ export type { VanaConnectConfig };
39
+ /** The create input the handler forwards, minus what it sets itself. */
40
+ export type VanaConnectCreateOptions = Omit<Parameters<DirectDataController["createAccessRequest"]>[0], "returnUrl">;
41
+ /** What a {@link VanaConnectRateLimit} decides. */
42
+ export type VanaConnectRateLimitDecision = {
43
+ ok: true;
44
+ } | {
45
+ ok: false;
46
+ /** Sent as `Retry-After`, in whole seconds. */
47
+ retryAfterSeconds?: number;
48
+ };
49
+ /**
50
+ * Decide whether one `POST request` that creates a request may proceed.
51
+ *
52
+ * @remarks
53
+ * Called after the origin and `session` checks and before the controller
54
+ * creates anything. `session` is the hash of the app's session id when
55
+ * `session` is configured. Re-signing a request the browser already holds is
56
+ * not rate limited: it creates nothing and needs a valid binding.
57
+ */
58
+ export type VanaConnectRateLimit = (input: {
59
+ request: Request;
60
+ session?: string;
61
+ }) => VanaConnectRateLimitDecision | Promise<VanaConnectRateLimitDecision>;
62
+ /** Options for {@link createMemoryRateLimit}. */
63
+ export interface MemoryRateLimitOptions {
64
+ /** Creates allowed per key per window. Defaults to 10. */
65
+ max?: number;
66
+ /** Window length in ms. Defaults to 60000. */
67
+ windowMs?: number;
68
+ /**
69
+ * The caller's IP. Defaults to {@link defaultClientIp}, which trusts proxy
70
+ * headers; behind anything else, supply the address your platform vouches
71
+ * for.
72
+ */
73
+ clientIp?: (request: Request) => string | null;
74
+ /** Keys kept before the oldest are dropped. Defaults to 10000. */
75
+ maxKeys?: number;
76
+ /** Clock in ms. Defaults to `Date.now`. */
77
+ now?: () => number;
78
+ }
79
+ /**
80
+ * The caller's IP as the default rate limit sees it.
81
+ *
82
+ * @remarks
83
+ * `CF-Connecting-IP`, then `X-Real-IP`, then the last `X-Forwarded-For`
84
+ * hop (the one your proxy appended), then the socket address when the
85
+ * request came through {@link toNodeHandler}. Headers are only as honest as
86
+ * the proxy in front of you: without one, a client can set them.
87
+ *
88
+ * @param request - The incoming request.
89
+ * @returns An IP string, or `null` when nothing names one.
90
+ */
91
+ export declare function defaultClientIp(request: Request): string | null;
92
+ /**
93
+ * An in-memory, fixed-window rate limit per client IP and per session.
94
+ *
95
+ * @remarks
96
+ * The default for `createVanaConnectHandler`. Not production-grade: each
97
+ * server instance (and each serverless cold start) counts on its own, and
98
+ * the IP comes from headers a client can forge without a trusted proxy.
99
+ * In production, require `session` and pass a `rateLimit` backed by a
100
+ * shared store (Redis, your platform's limiter).
101
+ *
102
+ * @param options - Limit, window, IP source and memory bound.
103
+ * @returns A {@link VanaConnectRateLimit}.
104
+ */
105
+ export declare function createMemoryRateLimit(options?: MemoryRateLimitOptions): VanaConnectRateLimit;
106
+ /** Options for {@link createVanaConnectHandler}. */
107
+ export interface VanaConnectHandlerOptions {
108
+ /**
109
+ * The app's controller; it holds the key and talks to Vana. It must
110
+ * implement the connect methods (`authorizeRequestRead`, `getEndpoints`,
111
+ * `getEnv`, and `deriveSecret` unless `bindingSecret` is set), as every
112
+ * `createDirectDataController` controller does.
113
+ */
114
+ controller: DirectDataController;
115
+ /**
116
+ * Absolute URL Vana returns the person to after approving in a tab. Its
117
+ * origin is also the only `Origin` accepted on `POST` (see
118
+ * {@link VanaConnectHandlerOptions.allowedOrigins}).
119
+ */
120
+ returnUrl: string;
121
+ /**
122
+ * The embed client id Vana Account registered for this app's origin. Without
123
+ * it `GET config` reports `clientId: null` and the browser cannot open the
124
+ * sheet (it falls back to a tab).
125
+ */
126
+ clientId?: string;
127
+ /** Label on the sheet chrome. Defaults to the controller's app name. */
128
+ appName?: string;
129
+ /**
130
+ * Bind requests to the app's own signed-in user too. Return a stable user or
131
+ * session id, or `null` to refuse with `401`. Only a hash of it is stored.
132
+ *
133
+ * @remarks
134
+ * Recommended for production. Without it, anyone who can load your page
135
+ * can create requests on your app's behalf; the browser binding only stops
136
+ * them reading someone else's.
137
+ */
138
+ session?: (request: Request) => string | null | Promise<string | null>;
139
+ /**
140
+ * Extra create input per request (questions, owner, ...). Called on each
141
+ * create.
142
+ */
143
+ createOptions?: (request: Request) => VanaConnectCreateOptions | Promise<VanaConnectCreateOptions>;
144
+ /**
145
+ * Custom read for `GET data`. Defaults to
146
+ * `controller.readApprovedData({ requestId })`. The result is sent as JSON.
147
+ */
148
+ read?: (input: {
149
+ controller: DirectDataController;
150
+ requestId: string;
151
+ request: Request;
152
+ }) => Promise<unknown>;
153
+ /**
154
+ * Origins accepted on `POST`. Defaults to the origin of `returnUrl`. A
155
+ * request without an `Origin` header (a non-browser client) is accepted.
156
+ */
157
+ allowedOrigins?: string[];
158
+ /**
159
+ * Secret for the binding cookie. Defaults to a key derived from the app key
160
+ * with HKDF-SHA256 (`controller.deriveSecret`). Set it to rotate bindings
161
+ * independently of the app key.
162
+ */
163
+ bindingSecret?: string;
164
+ /**
165
+ * Rate limit for creating requests. Defaults to
166
+ * {@link createMemoryRateLimit}() (10 per minute per IP and per session,
167
+ * in memory, not production-grade). Pass your own shared limiter in
168
+ * production, or `false` when one already sits in front of this route.
169
+ * A refusal answers `429 rate_limited` with `Retry-After`.
170
+ */
171
+ rateLimit?: VanaConnectRateLimit | false;
172
+ /** Cookie `Path`. Defaults to `/`. */
173
+ cookiePath?: string;
174
+ /** Clock in ms. Defaults to `Date.now`. */
175
+ now?: () => number;
176
+ }
177
+ /** A Fetch-API request handler. */
178
+ export type VanaConnectHandler = (request: Request) => Promise<Response>;
179
+ /** Error codes in a handler error body: `{ error: { code, message } }`. */
180
+ export type VanaConnectErrorCode = "not_found" | "method_not_allowed" | "invalid_request" | "forbidden_origin" | "unauthenticated" | "request_not_bound" | "not_approved" | "scope_not_approved" | "payment_required" | "personal_server_error" | "rate_limited" | "internal_error";
181
+ /** HKDF `info` the default binding key is derived with. */
182
+ export declare const CONNECT_BINDING_KEY_PURPOSE = "vana-sdk/connect/request-binding/v1";
183
+ /** Cookie name binding one request to the browser. */
184
+ export declare function connectBindingCookieName(requestId: string): string;
185
+ /**
186
+ * Create the connect handler.
187
+ *
188
+ * @example
189
+ * ```typescript
190
+ * // app/api/vana/[action]/route.ts
191
+ * import { createVanaConnectHandler } from "@opendatalabs/vana-sdk/server";
192
+ * // createDirectDataController({ grants: [{ source_id, streams }], ... })
193
+ * import { vana } from "@/lib/vana";
194
+ *
195
+ * const handler = createVanaConnectHandler({
196
+ * controller: vana,
197
+ * returnUrl: `${process.env.APP_URL}/connect/return`,
198
+ * clientId: "my-app",
199
+ * });
200
+ * export { handler as GET, handler as POST };
201
+ * ```
202
+ *
203
+ * @param options - Controller, return URL, sheet client id and hooks.
204
+ * @returns A `(request: Request) => Promise<Response>` handler.
205
+ * @throws {@link DirectConfigError} when `returnUrl` is not an absolute URL,
206
+ * or the controller lacks a connect method it needs.
207
+ */
208
+ export declare function createVanaConnectHandler(options: VanaConnectHandlerOptions): VanaConnectHandler;
209
+ /** The parts of a Node `IncomingMessage` {@link toNodeHandler} reads. */
210
+ export interface NodeRequestLike {
211
+ method?: string;
212
+ url?: string;
213
+ /** Express sets this to the URL before mount-path stripping. */
214
+ originalUrl?: string;
215
+ headers: Record<string, string | string[] | undefined>;
216
+ /** A body already parsed by middleware (Express `json()`), if any. */
217
+ body?: unknown;
218
+ socket?: {
219
+ encrypted?: boolean;
220
+ remoteAddress?: string;
221
+ };
222
+ [Symbol.asyncIterator](): AsyncIterator<Uint8Array | string>;
223
+ }
224
+ /** The parts of a Node `ServerResponse` {@link toNodeHandler} writes. */
225
+ export interface NodeResponseLike {
226
+ statusCode: number;
227
+ setHeader(name: string, value: string | string[]): unknown;
228
+ end(chunk?: Uint8Array | string): unknown;
229
+ }
230
+ /** Options for {@link toNodeHandler}. */
231
+ export interface ToNodeHandlerOptions {
232
+ /**
233
+ * Public origin of the app (`https://app.example`). Defaults to the
234
+ * request's `Host` header and `X-Forwarded-Proto` (or the socket's TLS).
235
+ */
236
+ origin?: string;
237
+ }
238
+ /**
239
+ * Adapt a Fetch-API handler to Node's `(req, res)` (http, Express, Fastify's
240
+ * raw mode).
241
+ *
242
+ * @param handler - A handler such as {@link createVanaConnectHandler}'s.
243
+ * @param options - Public origin override.
244
+ * @returns A `(req, res) => Promise<void>` listener.
245
+ */
246
+ export declare function toNodeHandler(handler: VanaConnectHandler, options?: ToNodeHandlerOptions): (req: NodeRequestLike, res: NodeResponseLike) => Promise<void>;