@opendatalabs/vana-sdk 3.8.1 → 3.8.3
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/dist/direct/connect-flow.cjs +58 -8
- package/dist/direct/connect-flow.cjs.map +1 -1
- package/dist/direct/connect-flow.d.ts +34 -2
- package/dist/direct/connect-flow.js +58 -8
- package/dist/direct/connect-flow.js.map +1 -1
- package/dist/direct/use-direct-vana-connect.cjs +2 -2
- package/dist/direct/use-direct-vana-connect.cjs.map +1 -1
- package/dist/direct/use-direct-vana-connect.js +2 -2
- package/dist/direct/use-direct-vana-connect.js.map +1 -1
- package/dist/index.browser.js +6 -3
- package/dist/index.browser.js.map +2 -2
- package/dist/index.node.cjs +6 -3
- package/dist/index.node.cjs.map +2 -2
- package/dist/index.node.js +6 -3
- package/dist/index.node.js.map +2 -2
- package/dist/protocol/scopes.cjs +6 -3
- package/dist/protocol/scopes.cjs.map +1 -1
- package/dist/protocol/scopes.js +6 -3
- package/dist/protocol/scopes.js.map +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +14 -4
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/protocol/scopes.cjs
CHANGED
|
@@ -26,14 +26,17 @@ __export(scopes_exports, {
|
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(scopes_exports);
|
|
28
28
|
var import_zod = require("zod");
|
|
29
|
-
const
|
|
29
|
+
const SOURCE_RE = /^[a-z0-9][a-z0-9_]*$/;
|
|
30
|
+
const TAIL_SEGMENT_RE = /^[a-zA-Z0-9][a-zA-Z0-9_]*$/;
|
|
30
31
|
const ScopeSchema = import_zod.z.string().refine(
|
|
31
32
|
(scope) => {
|
|
32
33
|
const parts = scope.split(".");
|
|
33
|
-
|
|
34
|
+
if (parts.length < 2 || parts.length > 3) return false;
|
|
35
|
+
const [source, ...tail] = parts;
|
|
36
|
+
return SOURCE_RE.test(source) && tail.every((part) => TAIL_SEGMENT_RE.test(part));
|
|
34
37
|
},
|
|
35
38
|
{
|
|
36
|
-
message: "Scope must be {source}.{category}[.{subcategory}]
|
|
39
|
+
message: "Scope must be {source}.{category}[.{subcategory}]; source lowercase, tail may keep the historical camelCase form (e.g. spotify.savedTracks)"
|
|
37
40
|
}
|
|
38
41
|
);
|
|
39
42
|
function parseScope(scope) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/protocol/scopes.ts"],"sourcesContent":["import { z } from \"zod\";\n\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/protocol/scopes.ts"],"sourcesContent":["import { z } from \"zod\";\n\n// The source_id (first segment) must stay lowercase. Tail segments may keep\n// the historical camelCase form the contract-freeze spec explicitly preserves\n// (e.g. spotify.savedTracks, youtube.playlistItems) — the chain never validates\n// scope strings, so the SDK must not be stricter than the protocol.\nconst SOURCE_RE = /^[a-z0-9][a-z0-9_]*$/;\nconst TAIL_SEGMENT_RE = /^[a-zA-Z0-9][a-zA-Z0-9_]*$/;\n\nexport const ScopeSchema = z.string().refine(\n (scope) => {\n const parts = scope.split(\".\");\n if (parts.length < 2 || parts.length > 3) return false;\n const [source, ...tail] = parts;\n return (\n SOURCE_RE.test(source) && tail.every((part) => TAIL_SEGMENT_RE.test(part))\n );\n },\n {\n message:\n \"Scope must be {source}.{category}[.{subcategory}]; source lowercase, tail may keep the historical camelCase form (e.g. spotify.savedTracks)\",\n },\n);\n\nexport type Scope = z.infer<typeof ScopeSchema>;\n\nexport interface ParsedScope {\n source: string;\n category: string;\n subcategory?: string;\n raw: string;\n}\n\nexport function parseScope(scope: string): ParsedScope {\n const validated = ScopeSchema.parse(scope);\n const parts = validated.split(\".\");\n return {\n source: parts[0],\n category: parts[1],\n subcategory: parts[2],\n raw: validated,\n };\n}\n\nexport function scopeToPathSegments(scope: string): string[] {\n const parsed = parseScope(scope);\n const segments = [parsed.source, parsed.category];\n if (parsed.subcategory) {\n segments.push(parsed.subcategory);\n }\n return segments;\n}\n\nexport function scopeMatchesPattern(\n requestedScope: string,\n grantPattern: string,\n): boolean {\n if (grantPattern === \"*\") return true;\n\n if (grantPattern.endsWith(\".*\")) {\n const prefix = grantPattern.slice(0, -1);\n return requestedScope.startsWith(prefix);\n }\n\n return requestedScope === grantPattern;\n}\n\nexport function scopeCoveredByGrant(\n requestedScope: string,\n grantedScopes: string[],\n): boolean {\n return grantedScopes.some((pattern) =>\n scopeMatchesPattern(requestedScope, pattern),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAkB;AAMlB,MAAM,YAAY;AAClB,MAAM,kBAAkB;AAEjB,MAAM,cAAc,aAAE,OAAO,EAAE;AAAA,EACpC,CAAC,UAAU;AACT,UAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,QAAI,MAAM,SAAS,KAAK,MAAM,SAAS,EAAG,QAAO;AACjD,UAAM,CAAC,QAAQ,GAAG,IAAI,IAAI;AAC1B,WACE,UAAU,KAAK,MAAM,KAAK,KAAK,MAAM,CAAC,SAAS,gBAAgB,KAAK,IAAI,CAAC;AAAA,EAE7E;AAAA,EACA;AAAA,IACE,SACE;AAAA,EACJ;AACF;AAWO,SAAS,WAAW,OAA4B;AACrD,QAAM,YAAY,YAAY,MAAM,KAAK;AACzC,QAAM,QAAQ,UAAU,MAAM,GAAG;AACjC,SAAO;AAAA,IACL,QAAQ,MAAM,CAAC;AAAA,IACf,UAAU,MAAM,CAAC;AAAA,IACjB,aAAa,MAAM,CAAC;AAAA,IACpB,KAAK;AAAA,EACP;AACF;AAEO,SAAS,oBAAoB,OAAyB;AAC3D,QAAM,SAAS,WAAW,KAAK;AAC/B,QAAM,WAAW,CAAC,OAAO,QAAQ,OAAO,QAAQ;AAChD,MAAI,OAAO,aAAa;AACtB,aAAS,KAAK,OAAO,WAAW;AAAA,EAClC;AACA,SAAO;AACT;AAEO,SAAS,oBACd,gBACA,cACS;AACT,MAAI,iBAAiB,IAAK,QAAO;AAEjC,MAAI,aAAa,SAAS,IAAI,GAAG;AAC/B,UAAM,SAAS,aAAa,MAAM,GAAG,EAAE;AACvC,WAAO,eAAe,WAAW,MAAM;AAAA,EACzC;AAEA,SAAO,mBAAmB;AAC5B;AAEO,SAAS,oBACd,gBACA,eACS;AACT,SAAO,cAAc;AAAA,IAAK,CAAC,YACzB,oBAAoB,gBAAgB,OAAO;AAAA,EAC7C;AACF;","names":[]}
|
package/dist/protocol/scopes.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
const
|
|
2
|
+
const SOURCE_RE = /^[a-z0-9][a-z0-9_]*$/;
|
|
3
|
+
const TAIL_SEGMENT_RE = /^[a-zA-Z0-9][a-zA-Z0-9_]*$/;
|
|
3
4
|
const ScopeSchema = z.string().refine(
|
|
4
5
|
(scope) => {
|
|
5
6
|
const parts = scope.split(".");
|
|
6
|
-
|
|
7
|
+
if (parts.length < 2 || parts.length > 3) return false;
|
|
8
|
+
const [source, ...tail] = parts;
|
|
9
|
+
return SOURCE_RE.test(source) && tail.every((part) => TAIL_SEGMENT_RE.test(part));
|
|
7
10
|
},
|
|
8
11
|
{
|
|
9
|
-
message: "Scope must be {source}.{category}[.{subcategory}]
|
|
12
|
+
message: "Scope must be {source}.{category}[.{subcategory}]; source lowercase, tail may keep the historical camelCase form (e.g. spotify.savedTracks)"
|
|
10
13
|
}
|
|
11
14
|
);
|
|
12
15
|
function parseScope(scope) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/protocol/scopes.ts"],"sourcesContent":["import { z } from \"zod\";\n\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/protocol/scopes.ts"],"sourcesContent":["import { z } from \"zod\";\n\n// The source_id (first segment) must stay lowercase. Tail segments may keep\n// the historical camelCase form the contract-freeze spec explicitly preserves\n// (e.g. spotify.savedTracks, youtube.playlistItems) — the chain never validates\n// scope strings, so the SDK must not be stricter than the protocol.\nconst SOURCE_RE = /^[a-z0-9][a-z0-9_]*$/;\nconst TAIL_SEGMENT_RE = /^[a-zA-Z0-9][a-zA-Z0-9_]*$/;\n\nexport const ScopeSchema = z.string().refine(\n (scope) => {\n const parts = scope.split(\".\");\n if (parts.length < 2 || parts.length > 3) return false;\n const [source, ...tail] = parts;\n return (\n SOURCE_RE.test(source) && tail.every((part) => TAIL_SEGMENT_RE.test(part))\n );\n },\n {\n message:\n \"Scope must be {source}.{category}[.{subcategory}]; source lowercase, tail may keep the historical camelCase form (e.g. spotify.savedTracks)\",\n },\n);\n\nexport type Scope = z.infer<typeof ScopeSchema>;\n\nexport interface ParsedScope {\n source: string;\n category: string;\n subcategory?: string;\n raw: string;\n}\n\nexport function parseScope(scope: string): ParsedScope {\n const validated = ScopeSchema.parse(scope);\n const parts = validated.split(\".\");\n return {\n source: parts[0],\n category: parts[1],\n subcategory: parts[2],\n raw: validated,\n };\n}\n\nexport function scopeToPathSegments(scope: string): string[] {\n const parsed = parseScope(scope);\n const segments = [parsed.source, parsed.category];\n if (parsed.subcategory) {\n segments.push(parsed.subcategory);\n }\n return segments;\n}\n\nexport function scopeMatchesPattern(\n requestedScope: string,\n grantPattern: string,\n): boolean {\n if (grantPattern === \"*\") return true;\n\n if (grantPattern.endsWith(\".*\")) {\n const prefix = grantPattern.slice(0, -1);\n return requestedScope.startsWith(prefix);\n }\n\n return requestedScope === grantPattern;\n}\n\nexport function scopeCoveredByGrant(\n requestedScope: string,\n grantedScopes: string[],\n): boolean {\n return grantedScopes.some((pattern) =>\n scopeMatchesPattern(requestedScope, pattern),\n );\n}\n"],"mappings":"AAAA,SAAS,SAAS;AAMlB,MAAM,YAAY;AAClB,MAAM,kBAAkB;AAEjB,MAAM,cAAc,EAAE,OAAO,EAAE;AAAA,EACpC,CAAC,UAAU;AACT,UAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,QAAI,MAAM,SAAS,KAAK,MAAM,SAAS,EAAG,QAAO;AACjD,UAAM,CAAC,QAAQ,GAAG,IAAI,IAAI;AAC1B,WACE,UAAU,KAAK,MAAM,KAAK,KAAK,MAAM,CAAC,SAAS,gBAAgB,KAAK,IAAI,CAAC;AAAA,EAE7E;AAAA,EACA;AAAA,IACE,SACE;AAAA,EACJ;AACF;AAWO,SAAS,WAAW,OAA4B;AACrD,QAAM,YAAY,YAAY,MAAM,KAAK;AACzC,QAAM,QAAQ,UAAU,MAAM,GAAG;AACjC,SAAO;AAAA,IACL,QAAQ,MAAM,CAAC;AAAA,IACf,UAAU,MAAM,CAAC;AAAA,IACjB,aAAa,MAAM,CAAC;AAAA,IACpB,KAAK;AAAA,EACP;AACF;AAEO,SAAS,oBAAoB,OAAyB;AAC3D,QAAM,SAAS,WAAW,KAAK;AAC/B,QAAM,WAAW,CAAC,OAAO,QAAQ,OAAO,QAAQ;AAChD,MAAI,OAAO,aAAa;AACtB,aAAS,KAAK,OAAO,WAAW;AAAA,EAClC;AACA,SAAO;AACT;AAEO,SAAS,oBACd,gBACA,cACS;AACT,MAAI,iBAAiB,IAAK,QAAO;AAEjC,MAAI,aAAa,SAAS,IAAI,GAAG;AAC/B,UAAM,SAAS,aAAa,MAAM,GAAG,EAAE;AACvC,WAAO,eAAe,WAAW,MAAM;AAAA,EACzC;AAEA,SAAO,mBAAmB;AAC5B;AAEO,SAAS,oBACd,gBACA,eACS;AACT,SAAO,cAAc;AAAA,IAAK,CAAC,YACzB,oBAAoB,gBAAgB,OAAO;AAAA,EAC7C;AACF;","names":[]}
|
package/dist/react.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react.ts"],"sourcesContent":["/**\n * React entry point for the Vana SDK direct Data Portability flow.\n *\n * @remarks\n * Exposes {@link useDirectVanaConnect} (and the underlying framework-agnostic\n * connect-flow store) for browser apps. This entry point is browser-safe and\n * imports nothing Node-only. `react` is a peer dependency.\n *\n * @example\n * ```tsx\n * \"use client\";\n * import { useDirectVanaConnect } from \"@opendatalabs/vana-sdk/react\";\n *\n * export function ConnectNotesButton() {\n * const connect = useDirectVanaConnect({\n * createRequest: () => fetch(\"/api/vana/request\", { method: \"POST\" }).then((r) => r.json()),\n * getStatus: (id) => fetch(`/api/vana/status?requestId=${id}`).then((r) => r.json()),\n * readResult: (id) => fetch(`/api/vana/data?requestId=${id}`).then((r) => r.json()),\n * });\n * return (\n * <button disabled={
|
|
1
|
+
{"version":3,"sources":["../src/react.ts"],"sourcesContent":["/**\n * React entry point for the Vana SDK direct Data Portability flow.\n *\n * @remarks\n * Exposes {@link useDirectVanaConnect} (and the underlying framework-agnostic\n * connect-flow store) for browser apps. This entry point is browser-safe and\n * imports nothing Node-only. `react` is a peer dependency.\n *\n * @example\n * ```tsx\n * \"use client\";\n * import { useDirectVanaConnect } from \"@opendatalabs/vana-sdk/react\";\n *\n * export function ConnectNotesButton() {\n * const connect = useDirectVanaConnect({\n * createRequest: () => fetch(\"/api/vana/request\", { method: \"POST\" }).then((r) => r.json()),\n * getStatus: (id) => fetch(`/api/vana/status?requestId=${id}`).then((r) => r.json()),\n * readResult: (id) => fetch(`/api/vana/data?requestId=${id}`).then((r) => r.json()),\n * });\n * const { state, start } = connect;\n * return (\n * <div>\n * <button disabled={state.type !== \"idle\"} onClick={start} type=\"button\">\n * {state.type === \"idle\" ? \"Connect Apple Notes\" : \"Connecting...\"}\n * </button>\n * {state.type === \"awaiting_approval\" && (\n * // Fallback link: if the browser blocked the approval popup, the user\n * // can still open it manually instead of the flow silently hanging.\n * <a href={state.request.approvalUrl} target=\"_blank\" rel=\"noreferrer\">\n * {state.popupBlocked ? \"Popup blocked — open approval\" : \"Open approval\"}\n * </a>\n * )}\n * </div>\n * );\n * }\n * ```\n *\n * @category Direct\n * @module react\n */\n\nexport {\n useDirectVanaConnect,\n type UseDirectVanaConnectOptions,\n type UseDirectVanaConnectResult,\n} from \"./direct/use-direct-vana-connect\";\n\n// Framework-agnostic store (usable without React).\nexport {\n createDirectConnectFlow,\n type ConnectWindow,\n type DirectConnectFlow,\n type DirectConnectState,\n type DirectConnectOptions,\n type DirectConnectTransports,\n} from \"./direct/connect-flow\";\n\n// Shared types useful when typing the transports.\nexport type {\n AccessRequest,\n AccessRequestStatus,\n AccessRequestStatusValue,\n ApprovedDataResult,\n} from \"./direct/types\";\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCA,qCAIO;AAGP,0BAOO;","names":[]}
|
package/dist/react.d.ts
CHANGED
|
@@ -17,10 +17,20 @@
|
|
|
17
17
|
* getStatus: (id) => fetch(`/api/vana/status?requestId=${id}`).then((r) => r.json()),
|
|
18
18
|
* readResult: (id) => fetch(`/api/vana/data?requestId=${id}`).then((r) => r.json()),
|
|
19
19
|
* });
|
|
20
|
+
* const { state, start } = connect;
|
|
20
21
|
* return (
|
|
21
|
-
* <
|
|
22
|
-
* {
|
|
23
|
-
*
|
|
22
|
+
* <div>
|
|
23
|
+
* <button disabled={state.type !== "idle"} onClick={start} type="button">
|
|
24
|
+
* {state.type === "idle" ? "Connect Apple Notes" : "Connecting..."}
|
|
25
|
+
* </button>
|
|
26
|
+
* {state.type === "awaiting_approval" && (
|
|
27
|
+
* // Fallback link: if the browser blocked the approval popup, the user
|
|
28
|
+
* // can still open it manually instead of the flow silently hanging.
|
|
29
|
+
* <a href={state.request.approvalUrl} target="_blank" rel="noreferrer">
|
|
30
|
+
* {state.popupBlocked ? "Popup blocked — open approval" : "Open approval"}
|
|
31
|
+
* </a>
|
|
32
|
+
* )}
|
|
33
|
+
* </div>
|
|
24
34
|
* );
|
|
25
35
|
* }
|
|
26
36
|
* ```
|
|
@@ -29,5 +39,5 @@
|
|
|
29
39
|
* @module react
|
|
30
40
|
*/
|
|
31
41
|
export { useDirectVanaConnect, type UseDirectVanaConnectOptions, type UseDirectVanaConnectResult, } from "./direct/use-direct-vana-connect";
|
|
32
|
-
export { createDirectConnectFlow, type DirectConnectFlow, type DirectConnectState, type DirectConnectOptions, type DirectConnectTransports, } from "./direct/connect-flow";
|
|
42
|
+
export { createDirectConnectFlow, type ConnectWindow, type DirectConnectFlow, type DirectConnectState, type DirectConnectOptions, type DirectConnectTransports, } from "./direct/connect-flow";
|
|
33
43
|
export type { AccessRequest, AccessRequestStatus, AccessRequestStatusValue, ApprovedDataResult, } from "./direct/types";
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react.ts"],"sourcesContent":["/**\n * React entry point for the Vana SDK direct Data Portability flow.\n *\n * @remarks\n * Exposes {@link useDirectVanaConnect} (and the underlying framework-agnostic\n * connect-flow store) for browser apps. This entry point is browser-safe and\n * imports nothing Node-only. `react` is a peer dependency.\n *\n * @example\n * ```tsx\n * \"use client\";\n * import { useDirectVanaConnect } from \"@opendatalabs/vana-sdk/react\";\n *\n * export function ConnectNotesButton() {\n * const connect = useDirectVanaConnect({\n * createRequest: () => fetch(\"/api/vana/request\", { method: \"POST\" }).then((r) => r.json()),\n * getStatus: (id) => fetch(`/api/vana/status?requestId=${id}`).then((r) => r.json()),\n * readResult: (id) => fetch(`/api/vana/data?requestId=${id}`).then((r) => r.json()),\n * });\n * return (\n * <button disabled={
|
|
1
|
+
{"version":3,"sources":["../src/react.ts"],"sourcesContent":["/**\n * React entry point for the Vana SDK direct Data Portability flow.\n *\n * @remarks\n * Exposes {@link useDirectVanaConnect} (and the underlying framework-agnostic\n * connect-flow store) for browser apps. This entry point is browser-safe and\n * imports nothing Node-only. `react` is a peer dependency.\n *\n * @example\n * ```tsx\n * \"use client\";\n * import { useDirectVanaConnect } from \"@opendatalabs/vana-sdk/react\";\n *\n * export function ConnectNotesButton() {\n * const connect = useDirectVanaConnect({\n * createRequest: () => fetch(\"/api/vana/request\", { method: \"POST\" }).then((r) => r.json()),\n * getStatus: (id) => fetch(`/api/vana/status?requestId=${id}`).then((r) => r.json()),\n * readResult: (id) => fetch(`/api/vana/data?requestId=${id}`).then((r) => r.json()),\n * });\n * const { state, start } = connect;\n * return (\n * <div>\n * <button disabled={state.type !== \"idle\"} onClick={start} type=\"button\">\n * {state.type === \"idle\" ? \"Connect Apple Notes\" : \"Connecting...\"}\n * </button>\n * {state.type === \"awaiting_approval\" && (\n * // Fallback link: if the browser blocked the approval popup, the user\n * // can still open it manually instead of the flow silently hanging.\n * <a href={state.request.approvalUrl} target=\"_blank\" rel=\"noreferrer\">\n * {state.popupBlocked ? \"Popup blocked — open approval\" : \"Open approval\"}\n * </a>\n * )}\n * </div>\n * );\n * }\n * ```\n *\n * @category Direct\n * @module react\n */\n\nexport {\n useDirectVanaConnect,\n type UseDirectVanaConnectOptions,\n type UseDirectVanaConnectResult,\n} from \"./direct/use-direct-vana-connect\";\n\n// Framework-agnostic store (usable without React).\nexport {\n createDirectConnectFlow,\n type ConnectWindow,\n type DirectConnectFlow,\n type DirectConnectState,\n type DirectConnectOptions,\n type DirectConnectTransports,\n} from \"./direct/connect-flow\";\n\n// Shared types useful when typing the transports.\nexport type {\n AccessRequest,\n AccessRequestStatus,\n AccessRequestStatusValue,\n ApprovedDataResult,\n} from \"./direct/types\";\n"],"mappings":"AAyCA;AAAA,EACE;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,OAMK;","names":[]}
|