@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,100 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var http_transports_exports = {};
20
+ __export(http_transports_exports, {
21
+ VanaConnectHttpError: () => VanaConnectHttpError,
22
+ createVanaConnectTransports: () => createVanaConnectTransports
23
+ });
24
+ module.exports = __toCommonJS(http_transports_exports);
25
+ class VanaConnectHttpError extends Error {
26
+ constructor(message, status, code) {
27
+ super(message);
28
+ this.status = status;
29
+ this.code = code;
30
+ this.name = "VanaConnectHttpError";
31
+ }
32
+ status;
33
+ code;
34
+ }
35
+ function createVanaConnectTransports(options = {}) {
36
+ const base = (options.endpoint ?? "/api/vana").replace(/\/+$/, "");
37
+ const now = options.now ?? Date.now;
38
+ const reuseMs = options.reuseFreshAuthorizationMs ?? 6e4;
39
+ let fresh = null;
40
+ let config = null;
41
+ async function call(path, init) {
42
+ const fetchFn = options.fetch ?? globalThis.fetch;
43
+ const response = await fetchFn(`${base}/${path}`, {
44
+ credentials: "same-origin",
45
+ ...init
46
+ });
47
+ const body = await response.json().catch(() => null);
48
+ if (!response.ok) {
49
+ const code = typeof body?.error?.code === "string" ? body.error.code : void 0;
50
+ const message = typeof body?.error?.message === "string" ? body.error.message : `Vana connect route ${path} failed: ${response.status}`;
51
+ throw new VanaConnectHttpError(message, response.status, code);
52
+ }
53
+ return body;
54
+ }
55
+ function postRequest(body) {
56
+ return call("request", {
57
+ method: "POST",
58
+ headers: { "Content-Type": "application/json" },
59
+ body: JSON.stringify(body)
60
+ });
61
+ }
62
+ return {
63
+ async createRequest() {
64
+ const { request, embed } = await postRequest({});
65
+ fresh = embed ? { ...embed, at: now() } : null;
66
+ return request;
67
+ },
68
+ getStatus(requestId) {
69
+ return call(`status?requestId=${encodeURIComponent(requestId)}`);
70
+ },
71
+ readResult(requestId) {
72
+ return call(`data?requestId=${encodeURIComponent(requestId)}`);
73
+ },
74
+ async authorizeRequest(requestId) {
75
+ const cached = fresh;
76
+ fresh = null;
77
+ if (cached && cached.id === requestId && now() - cached.at < reuseMs) {
78
+ return cached.authorization;
79
+ }
80
+ const { embed } = await postRequest({ requestId });
81
+ if (!embed) {
82
+ throw new VanaConnectHttpError("The request could not be signed", 500);
83
+ }
84
+ return embed.authorization;
85
+ },
86
+ getConfig() {
87
+ config ??= call("config").catch((error) => {
88
+ config = null;
89
+ throw error;
90
+ });
91
+ return config;
92
+ }
93
+ };
94
+ }
95
+ // Annotate the CommonJS export names for ESM import in node:
96
+ 0 && (module.exports = {
97
+ VanaConnectHttpError,
98
+ createVanaConnectTransports
99
+ });
100
+ //# sourceMappingURL=http-transports.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/connect/http-transports.ts"],"sourcesContent":["/**\n * Browser transports for the routes `createVanaConnectHandler` serves.\n *\n * @remarks\n * `createVanaConnectTransports({ endpoint: \"/api/vana\" })` returns the\n * `createRequest` / `getStatus` / `readResult` / `authorizeRequest`\n * transports `createDirectConnectFlow` takes, plus `getConfig` for the sheet.\n * Any backend that implements the same wire contract works, in any language.\n *\n * @category Connect\n * @module connect/http-transports\n */\n\nimport type { RequestAuthorization } from \"./protocol\";\nimport type {\n AccessRequest,\n AccessRequestStatus,\n ApprovedDataResult,\n} from \"../direct/types\";\n\n/** Response body of `GET {endpoint}/config`. */\nexport interface VanaConnectConfig {\n /** Protocol version of the sheet the backend's SDK speaks. */\n protocolVersion: number;\n /** `\"production\"` or `\"dev\"`. */\n env: string;\n /** Registered embed client id, or `null` when the sheet is not set up. */\n clientId: string | null;\n /** Label on the sheet chrome. */\n appName: string;\n /** Vana Account origin that serves the sheet. */\n accountOrigin: string;\n}\n\n/** Response body of `POST {endpoint}/request`. */\nexport interface VanaConnectRequestResponse {\n request: AccessRequest;\n /** The sheet's read capability for `request`; `null` if it cannot be signed. */\n embed: { id: string; authorization: RequestAuthorization } | null;\n}\n\n/** Thrown when a connect route answers with a non-2xx status. */\nexport class VanaConnectHttpError extends Error {\n constructor(\n message: string,\n /** HTTP status. */\n public readonly status: number,\n /** `error.code` from the body, when present. */\n public readonly code?: string,\n ) {\n super(message);\n this.name = \"VanaConnectHttpError\";\n }\n}\n\n/** Options for {@link createVanaConnectTransports}. */\nexport interface VanaConnectTransportOptions {\n /** Base path of the handler's routes. Defaults to `\"/api/vana\"`. */\n endpoint?: string;\n /** `fetch`. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n /**\n * How long the signature returned with a fresh request is reused for the\n * sheet's first ask, in ms. Defaults to 60000. Later asks always re-sign.\n */\n reuseFreshAuthorizationMs?: number;\n /** Clock in ms. Defaults to `Date.now`. */\n now?: () => number;\n}\n\n/** The transports {@link createVanaConnectTransports} returns. */\nexport interface VanaConnectTransports<T = unknown> {\n createRequest(): Promise<AccessRequest>;\n getStatus(requestId: string): Promise<AccessRequestStatus>;\n readResult(requestId: string): Promise<ApprovedDataResult<T>>;\n authorizeRequest(requestId: string): Promise<RequestAuthorization>;\n getConfig(): Promise<VanaConnectConfig>;\n}\n\n/**\n * Create browser transports for a `createVanaConnectHandler` backend.\n *\n * @param options - Base path and `fetch`.\n * @returns Transports for `createDirectConnectFlow` / `useVanaConnect`.\n */\nexport function createVanaConnectTransports<T = unknown>(\n options: VanaConnectTransportOptions = {},\n): VanaConnectTransports<T> {\n const base = (options.endpoint ?? \"/api/vana\").replace(/\\/+$/, \"\");\n const now = options.now ?? Date.now;\n const reuseMs = options.reuseFreshAuthorizationMs ?? 60_000;\n let fresh: {\n id: string;\n authorization: RequestAuthorization;\n at: number;\n } | null = null;\n let config: Promise<VanaConnectConfig> | null = null;\n\n async function call<R>(path: string, init?: RequestInit): Promise<R> {\n const fetchFn = options.fetch ?? globalThis.fetch;\n const response = await fetchFn(`${base}/${path}`, {\n credentials: \"same-origin\",\n ...init,\n });\n const body = (await response.json().catch(() => null)) as {\n error?: { code?: unknown; message?: unknown };\n } | null;\n if (!response.ok) {\n const code =\n typeof body?.error?.code === \"string\" ? body.error.code : undefined;\n const message =\n typeof body?.error?.message === \"string\"\n ? body.error.message\n : `Vana connect route ${path} failed: ${response.status}`;\n throw new VanaConnectHttpError(message, response.status, code);\n }\n return body as R;\n }\n\n function postRequest(body: object): Promise<VanaConnectRequestResponse> {\n return call<VanaConnectRequestResponse>(\"request\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n }\n\n return {\n async createRequest() {\n const { request, embed } = await postRequest({});\n fresh = embed ? { ...embed, at: now() } : null;\n return request;\n },\n getStatus(requestId) {\n return call(`status?requestId=${encodeURIComponent(requestId)}`);\n },\n readResult(requestId) {\n return call(`data?requestId=${encodeURIComponent(requestId)}`);\n },\n async authorizeRequest(requestId) {\n const cached = fresh;\n fresh = null;\n if (cached && cached.id === requestId && now() - cached.at < reuseMs) {\n return cached.authorization;\n }\n const { embed } = await postRequest({ requestId });\n if (!embed) {\n throw new VanaConnectHttpError(\"The request could not be signed\", 500);\n }\n return embed.authorization;\n },\n getConfig() {\n config ??= call<VanaConnectConfig>(\"config\").catch((error: unknown) => {\n config = null;\n throw error;\n });\n return config;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0CO,MAAM,6BAA6B,MAAM;AAAA,EAC9C,YACE,SAEgB,QAEA,MAChB;AACA,UAAM,OAAO;AAJG;AAEA;AAGhB,SAAK,OAAO;AAAA,EACd;AAAA,EANkB;AAAA,EAEA;AAKpB;AAgCO,SAAS,4BACd,UAAuC,CAAC,GACd;AAC1B,QAAM,QAAQ,QAAQ,YAAY,aAAa,QAAQ,QAAQ,EAAE;AACjE,QAAM,MAAM,QAAQ,OAAO,KAAK;AAChC,QAAM,UAAU,QAAQ,6BAA6B;AACrD,MAAI,QAIO;AACX,MAAI,SAA4C;AAEhD,iBAAe,KAAQ,MAAc,MAAgC;AACnE,UAAM,UAAU,QAAQ,SAAS,WAAW;AAC5C,UAAM,WAAW,MAAM,QAAQ,GAAG,IAAI,IAAI,IAAI,IAAI;AAAA,MAChD,aAAa;AAAA,MACb,GAAG;AAAA,IACL,CAAC;AACD,UAAM,OAAQ,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,IAAI;AAGpD,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OACJ,OAAO,MAAM,OAAO,SAAS,WAAW,KAAK,MAAM,OAAO;AAC5D,YAAM,UACJ,OAAO,MAAM,OAAO,YAAY,WAC5B,KAAK,MAAM,UACX,sBAAsB,IAAI,YAAY,SAAS,MAAM;AAC3D,YAAM,IAAI,qBAAqB,SAAS,SAAS,QAAQ,IAAI;AAAA,IAC/D;AACA,WAAO;AAAA,EACT;AAEA,WAAS,YAAY,MAAmD;AACtE,WAAO,KAAiC,WAAW;AAAA,MACjD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,MAAM,gBAAgB;AACpB,YAAM,EAAE,SAAS,MAAM,IAAI,MAAM,YAAY,CAAC,CAAC;AAC/C,cAAQ,QAAQ,EAAE,GAAG,OAAO,IAAI,IAAI,EAAE,IAAI;AAC1C,aAAO;AAAA,IACT;AAAA,IACA,UAAU,WAAW;AACnB,aAAO,KAAK,oBAAoB,mBAAmB,SAAS,CAAC,EAAE;AAAA,IACjE;AAAA,IACA,WAAW,WAAW;AACpB,aAAO,KAAK,kBAAkB,mBAAmB,SAAS,CAAC,EAAE;AAAA,IAC/D;AAAA,IACA,MAAM,iBAAiB,WAAW;AAChC,YAAM,SAAS;AACf,cAAQ;AACR,UAAI,UAAU,OAAO,OAAO,aAAa,IAAI,IAAI,OAAO,KAAK,SAAS;AACpE,eAAO,OAAO;AAAA,MAChB;AACA,YAAM,EAAE,MAAM,IAAI,MAAM,YAAY,EAAE,UAAU,CAAC;AACjD,UAAI,CAAC,OAAO;AACV,cAAM,IAAI,qBAAqB,mCAAmC,GAAG;AAAA,MACvE;AACA,aAAO,MAAM;AAAA,IACf;AAAA,IACA,YAAY;AACV,iBAAW,KAAwB,QAAQ,EAAE,MAAM,CAAC,UAAmB;AACrE,iBAAS;AACT,cAAM;AAAA,MACR,CAAC;AACD,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Browser transports for the routes `createVanaConnectHandler` serves.
3
+ *
4
+ * @remarks
5
+ * `createVanaConnectTransports({ endpoint: "/api/vana" })` returns the
6
+ * `createRequest` / `getStatus` / `readResult` / `authorizeRequest`
7
+ * transports `createDirectConnectFlow` takes, plus `getConfig` for the sheet.
8
+ * Any backend that implements the same wire contract works, in any language.
9
+ *
10
+ * @category Connect
11
+ * @module connect/http-transports
12
+ */
13
+ import type { RequestAuthorization } from "./protocol.js";
14
+ import type { AccessRequest, AccessRequestStatus, ApprovedDataResult } from "../direct/types.js";
15
+ /** Response body of `GET {endpoint}/config`. */
16
+ export interface VanaConnectConfig {
17
+ /** Protocol version of the sheet the backend's SDK speaks. */
18
+ protocolVersion: number;
19
+ /** `"production"` or `"dev"`. */
20
+ env: string;
21
+ /** Registered embed client id, or `null` when the sheet is not set up. */
22
+ clientId: string | null;
23
+ /** Label on the sheet chrome. */
24
+ appName: string;
25
+ /** Vana Account origin that serves the sheet. */
26
+ accountOrigin: string;
27
+ }
28
+ /** Response body of `POST {endpoint}/request`. */
29
+ export interface VanaConnectRequestResponse {
30
+ request: AccessRequest;
31
+ /** The sheet's read capability for `request`; `null` if it cannot be signed. */
32
+ embed: {
33
+ id: string;
34
+ authorization: RequestAuthorization;
35
+ } | null;
36
+ }
37
+ /** Thrown when a connect route answers with a non-2xx status. */
38
+ export declare class VanaConnectHttpError extends Error {
39
+ /** HTTP status. */
40
+ readonly status: number;
41
+ /** `error.code` from the body, when present. */
42
+ readonly code?: string | undefined;
43
+ constructor(message: string,
44
+ /** HTTP status. */
45
+ status: number,
46
+ /** `error.code` from the body, when present. */
47
+ code?: string | undefined);
48
+ }
49
+ /** Options for {@link createVanaConnectTransports}. */
50
+ export interface VanaConnectTransportOptions {
51
+ /** Base path of the handler's routes. Defaults to `"/api/vana"`. */
52
+ endpoint?: string;
53
+ /** `fetch`. Defaults to `globalThis.fetch`. */
54
+ fetch?: typeof fetch;
55
+ /**
56
+ * How long the signature returned with a fresh request is reused for the
57
+ * sheet's first ask, in ms. Defaults to 60000. Later asks always re-sign.
58
+ */
59
+ reuseFreshAuthorizationMs?: number;
60
+ /** Clock in ms. Defaults to `Date.now`. */
61
+ now?: () => number;
62
+ }
63
+ /** The transports {@link createVanaConnectTransports} returns. */
64
+ export interface VanaConnectTransports<T = unknown> {
65
+ createRequest(): Promise<AccessRequest>;
66
+ getStatus(requestId: string): Promise<AccessRequestStatus>;
67
+ readResult(requestId: string): Promise<ApprovedDataResult<T>>;
68
+ authorizeRequest(requestId: string): Promise<RequestAuthorization>;
69
+ getConfig(): Promise<VanaConnectConfig>;
70
+ }
71
+ /**
72
+ * Create browser transports for a `createVanaConnectHandler` backend.
73
+ *
74
+ * @param options - Base path and `fetch`.
75
+ * @returns Transports for `createDirectConnectFlow` / `useVanaConnect`.
76
+ */
77
+ export declare function createVanaConnectTransports<T = unknown>(options?: VanaConnectTransportOptions): VanaConnectTransports<T>;
@@ -0,0 +1,75 @@
1
+ class VanaConnectHttpError extends Error {
2
+ constructor(message, status, code) {
3
+ super(message);
4
+ this.status = status;
5
+ this.code = code;
6
+ this.name = "VanaConnectHttpError";
7
+ }
8
+ status;
9
+ code;
10
+ }
11
+ function createVanaConnectTransports(options = {}) {
12
+ const base = (options.endpoint ?? "/api/vana").replace(/\/+$/, "");
13
+ const now = options.now ?? Date.now;
14
+ const reuseMs = options.reuseFreshAuthorizationMs ?? 6e4;
15
+ let fresh = null;
16
+ let config = null;
17
+ async function call(path, init) {
18
+ const fetchFn = options.fetch ?? globalThis.fetch;
19
+ const response = await fetchFn(`${base}/${path}`, {
20
+ credentials: "same-origin",
21
+ ...init
22
+ });
23
+ const body = await response.json().catch(() => null);
24
+ if (!response.ok) {
25
+ const code = typeof body?.error?.code === "string" ? body.error.code : void 0;
26
+ const message = typeof body?.error?.message === "string" ? body.error.message : `Vana connect route ${path} failed: ${response.status}`;
27
+ throw new VanaConnectHttpError(message, response.status, code);
28
+ }
29
+ return body;
30
+ }
31
+ function postRequest(body) {
32
+ return call("request", {
33
+ method: "POST",
34
+ headers: { "Content-Type": "application/json" },
35
+ body: JSON.stringify(body)
36
+ });
37
+ }
38
+ return {
39
+ async createRequest() {
40
+ const { request, embed } = await postRequest({});
41
+ fresh = embed ? { ...embed, at: now() } : null;
42
+ return request;
43
+ },
44
+ getStatus(requestId) {
45
+ return call(`status?requestId=${encodeURIComponent(requestId)}`);
46
+ },
47
+ readResult(requestId) {
48
+ return call(`data?requestId=${encodeURIComponent(requestId)}`);
49
+ },
50
+ async authorizeRequest(requestId) {
51
+ const cached = fresh;
52
+ fresh = null;
53
+ if (cached && cached.id === requestId && now() - cached.at < reuseMs) {
54
+ return cached.authorization;
55
+ }
56
+ const { embed } = await postRequest({ requestId });
57
+ if (!embed) {
58
+ throw new VanaConnectHttpError("The request could not be signed", 500);
59
+ }
60
+ return embed.authorization;
61
+ },
62
+ getConfig() {
63
+ config ??= call("config").catch((error) => {
64
+ config = null;
65
+ throw error;
66
+ });
67
+ return config;
68
+ }
69
+ };
70
+ }
71
+ export {
72
+ VanaConnectHttpError,
73
+ createVanaConnectTransports
74
+ };
75
+ //# sourceMappingURL=http-transports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/connect/http-transports.ts"],"sourcesContent":["/**\n * Browser transports for the routes `createVanaConnectHandler` serves.\n *\n * @remarks\n * `createVanaConnectTransports({ endpoint: \"/api/vana\" })` returns the\n * `createRequest` / `getStatus` / `readResult` / `authorizeRequest`\n * transports `createDirectConnectFlow` takes, plus `getConfig` for the sheet.\n * Any backend that implements the same wire contract works, in any language.\n *\n * @category Connect\n * @module connect/http-transports\n */\n\nimport type { RequestAuthorization } from \"./protocol\";\nimport type {\n AccessRequest,\n AccessRequestStatus,\n ApprovedDataResult,\n} from \"../direct/types\";\n\n/** Response body of `GET {endpoint}/config`. */\nexport interface VanaConnectConfig {\n /** Protocol version of the sheet the backend's SDK speaks. */\n protocolVersion: number;\n /** `\"production\"` or `\"dev\"`. */\n env: string;\n /** Registered embed client id, or `null` when the sheet is not set up. */\n clientId: string | null;\n /** Label on the sheet chrome. */\n appName: string;\n /** Vana Account origin that serves the sheet. */\n accountOrigin: string;\n}\n\n/** Response body of `POST {endpoint}/request`. */\nexport interface VanaConnectRequestResponse {\n request: AccessRequest;\n /** The sheet's read capability for `request`; `null` if it cannot be signed. */\n embed: { id: string; authorization: RequestAuthorization } | null;\n}\n\n/** Thrown when a connect route answers with a non-2xx status. */\nexport class VanaConnectHttpError extends Error {\n constructor(\n message: string,\n /** HTTP status. */\n public readonly status: number,\n /** `error.code` from the body, when present. */\n public readonly code?: string,\n ) {\n super(message);\n this.name = \"VanaConnectHttpError\";\n }\n}\n\n/** Options for {@link createVanaConnectTransports}. */\nexport interface VanaConnectTransportOptions {\n /** Base path of the handler's routes. Defaults to `\"/api/vana\"`. */\n endpoint?: string;\n /** `fetch`. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n /**\n * How long the signature returned with a fresh request is reused for the\n * sheet's first ask, in ms. Defaults to 60000. Later asks always re-sign.\n */\n reuseFreshAuthorizationMs?: number;\n /** Clock in ms. Defaults to `Date.now`. */\n now?: () => number;\n}\n\n/** The transports {@link createVanaConnectTransports} returns. */\nexport interface VanaConnectTransports<T = unknown> {\n createRequest(): Promise<AccessRequest>;\n getStatus(requestId: string): Promise<AccessRequestStatus>;\n readResult(requestId: string): Promise<ApprovedDataResult<T>>;\n authorizeRequest(requestId: string): Promise<RequestAuthorization>;\n getConfig(): Promise<VanaConnectConfig>;\n}\n\n/**\n * Create browser transports for a `createVanaConnectHandler` backend.\n *\n * @param options - Base path and `fetch`.\n * @returns Transports for `createDirectConnectFlow` / `useVanaConnect`.\n */\nexport function createVanaConnectTransports<T = unknown>(\n options: VanaConnectTransportOptions = {},\n): VanaConnectTransports<T> {\n const base = (options.endpoint ?? \"/api/vana\").replace(/\\/+$/, \"\");\n const now = options.now ?? Date.now;\n const reuseMs = options.reuseFreshAuthorizationMs ?? 60_000;\n let fresh: {\n id: string;\n authorization: RequestAuthorization;\n at: number;\n } | null = null;\n let config: Promise<VanaConnectConfig> | null = null;\n\n async function call<R>(path: string, init?: RequestInit): Promise<R> {\n const fetchFn = options.fetch ?? globalThis.fetch;\n const response = await fetchFn(`${base}/${path}`, {\n credentials: \"same-origin\",\n ...init,\n });\n const body = (await response.json().catch(() => null)) as {\n error?: { code?: unknown; message?: unknown };\n } | null;\n if (!response.ok) {\n const code =\n typeof body?.error?.code === \"string\" ? body.error.code : undefined;\n const message =\n typeof body?.error?.message === \"string\"\n ? body.error.message\n : `Vana connect route ${path} failed: ${response.status}`;\n throw new VanaConnectHttpError(message, response.status, code);\n }\n return body as R;\n }\n\n function postRequest(body: object): Promise<VanaConnectRequestResponse> {\n return call<VanaConnectRequestResponse>(\"request\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n }\n\n return {\n async createRequest() {\n const { request, embed } = await postRequest({});\n fresh = embed ? { ...embed, at: now() } : null;\n return request;\n },\n getStatus(requestId) {\n return call(`status?requestId=${encodeURIComponent(requestId)}`);\n },\n readResult(requestId) {\n return call(`data?requestId=${encodeURIComponent(requestId)}`);\n },\n async authorizeRequest(requestId) {\n const cached = fresh;\n fresh = null;\n if (cached && cached.id === requestId && now() - cached.at < reuseMs) {\n return cached.authorization;\n }\n const { embed } = await postRequest({ requestId });\n if (!embed) {\n throw new VanaConnectHttpError(\"The request could not be signed\", 500);\n }\n return embed.authorization;\n },\n getConfig() {\n config ??= call<VanaConnectConfig>(\"config\").catch((error: unknown) => {\n config = null;\n throw error;\n });\n return config;\n },\n };\n}\n"],"mappings":"AA0CO,MAAM,6BAA6B,MAAM;AAAA,EAC9C,YACE,SAEgB,QAEA,MAChB;AACA,UAAM,OAAO;AAJG;AAEA;AAGhB,SAAK,OAAO;AAAA,EACd;AAAA,EANkB;AAAA,EAEA;AAKpB;AAgCO,SAAS,4BACd,UAAuC,CAAC,GACd;AAC1B,QAAM,QAAQ,QAAQ,YAAY,aAAa,QAAQ,QAAQ,EAAE;AACjE,QAAM,MAAM,QAAQ,OAAO,KAAK;AAChC,QAAM,UAAU,QAAQ,6BAA6B;AACrD,MAAI,QAIO;AACX,MAAI,SAA4C;AAEhD,iBAAe,KAAQ,MAAc,MAAgC;AACnE,UAAM,UAAU,QAAQ,SAAS,WAAW;AAC5C,UAAM,WAAW,MAAM,QAAQ,GAAG,IAAI,IAAI,IAAI,IAAI;AAAA,MAChD,aAAa;AAAA,MACb,GAAG;AAAA,IACL,CAAC;AACD,UAAM,OAAQ,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,IAAI;AAGpD,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OACJ,OAAO,MAAM,OAAO,SAAS,WAAW,KAAK,MAAM,OAAO;AAC5D,YAAM,UACJ,OAAO,MAAM,OAAO,YAAY,WAC5B,KAAK,MAAM,UACX,sBAAsB,IAAI,YAAY,SAAS,MAAM;AAC3D,YAAM,IAAI,qBAAqB,SAAS,SAAS,QAAQ,IAAI;AAAA,IAC/D;AACA,WAAO;AAAA,EACT;AAEA,WAAS,YAAY,MAAmD;AACtE,WAAO,KAAiC,WAAW;AAAA,MACjD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,MAAM,gBAAgB;AACpB,YAAM,EAAE,SAAS,MAAM,IAAI,MAAM,YAAY,CAAC,CAAC;AAC/C,cAAQ,QAAQ,EAAE,GAAG,OAAO,IAAI,IAAI,EAAE,IAAI;AAC1C,aAAO;AAAA,IACT;AAAA,IACA,UAAU,WAAW;AACnB,aAAO,KAAK,oBAAoB,mBAAmB,SAAS,CAAC,EAAE;AAAA,IACjE;AAAA,IACA,WAAW,WAAW;AACpB,aAAO,KAAK,kBAAkB,mBAAmB,SAAS,CAAC,EAAE;AAAA,IAC/D;AAAA,IACA,MAAM,iBAAiB,WAAW;AAChC,YAAM,SAAS;AACf,cAAQ;AACR,UAAI,UAAU,OAAO,OAAO,aAAa,IAAI,IAAI,OAAO,KAAK,SAAS;AACpE,eAAO,OAAO;AAAA,MAChB;AACA,YAAM,EAAE,MAAM,IAAI,MAAM,YAAY,EAAE,UAAU,CAAC;AACjD,UAAI,CAAC,OAAO;AACV,cAAM,IAAI,qBAAqB,mCAAmC,GAAG;AAAA,MACvE;AACA,aAAO,MAAM;AAAA,IACf;AAAA,IACA,YAAY;AACV,iBAAW,KAAwB,QAAQ,EAAE,MAAM,CAAC,UAAmB;AACrE,iBAAS;AACT,cAAM;AAAA,MACR,CAAC;AACD,aAAO;AAAA,IACT;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var launcher_exports = {};
20
+ __export(launcher_exports, {
21
+ connect: () => connect,
22
+ open: () => open,
23
+ openConnectSheet: () => openConnectSheet
24
+ });
25
+ module.exports = __toCommonJS(launcher_exports);
26
+ var import_chrome = require("./chrome");
27
+ var import_protocol = require("./protocol");
28
+ const DEFAULT_READY_TIMEOUT_MS = 1e4;
29
+ let closeCurrent = null;
30
+ function open(options) {
31
+ const vanaOrigin = resolveTarget(options);
32
+ const display = (0, import_protocol.readConnectDisplay)(
33
+ options.display ?? import_protocol.DEFAULT_CONNECT_DISPLAY
34
+ );
35
+ if (!display) {
36
+ throw new TypeError('display must be "sheet" or "fullscreen"');
37
+ }
38
+ closeCurrent?.("replaced");
39
+ const emit = (event) => options.onEvent?.(event);
40
+ const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
41
+ const previousOverflow = document.body.style.overflow;
42
+ let closed = false;
43
+ let ready = false;
44
+ let pendingStatus = null;
45
+ let chrome = null;
46
+ const post = (message) => {
47
+ chrome?.iframe.contentWindow?.postMessage(message, vanaOrigin);
48
+ };
49
+ const close = (reason) => {
50
+ if (closed) {
51
+ return;
52
+ }
53
+ closed = true;
54
+ window.clearTimeout(readyTimer);
55
+ window.removeEventListener("message", onMessage);
56
+ document.removeEventListener("keydown", onKeyDown);
57
+ chrome?.remove();
58
+ document.body.style.overflow = previousOverflow;
59
+ previousFocus?.focus();
60
+ if (closeCurrent === close) {
61
+ closeCurrent = null;
62
+ }
63
+ emit({ reason, type: "close" });
64
+ };
65
+ const requestFromPartner = () => {
66
+ options.getRequest().then(
67
+ (request) => {
68
+ if (!closed) {
69
+ post({ request, type: "vana:request", v: import_protocol.PROTOCOL_VERSION });
70
+ }
71
+ },
72
+ () => {
73
+ if (!closed) {
74
+ emit({ code: "request_failed", type: "error" });
75
+ }
76
+ }
77
+ );
78
+ };
79
+ const handleSheetMessage = (message) => {
80
+ switch (message.type) {
81
+ case "vana:ready":
82
+ if (ready) {
83
+ return;
84
+ }
85
+ window.clearTimeout(readyTimer);
86
+ ready = true;
87
+ if (pendingStatus) {
88
+ post({
89
+ status: pendingStatus,
90
+ type: "vana:request-status",
91
+ v: import_protocol.PROTOCOL_VERSION
92
+ });
93
+ pendingStatus = null;
94
+ }
95
+ emit({ type: "ready" });
96
+ return;
97
+ case "vana:resize":
98
+ if (message.height >= import_protocol.MIN_SHEET_HEIGHT_PX) {
99
+ chrome?.setContentHeight(message.height);
100
+ }
101
+ return;
102
+ case "vana:signed-in":
103
+ emit({ type: "signed-in" });
104
+ return;
105
+ case "vana:request-needed":
106
+ requestFromPartner();
107
+ return;
108
+ case "vana:connected":
109
+ emit({
110
+ completion: message.completion,
111
+ status: message.status,
112
+ type: "connected"
113
+ });
114
+ return;
115
+ case "vana:progress":
116
+ emit({ phase: message.phase, type: "progress" });
117
+ return;
118
+ case "vana:close":
119
+ close("sheet");
120
+ return;
121
+ case "vana:error":
122
+ window.clearTimeout(readyTimer);
123
+ emit({ code: message.code, type: "error" });
124
+ return;
125
+ default:
126
+ return;
127
+ }
128
+ };
129
+ function onMessage(event) {
130
+ if (event.origin !== vanaOrigin || !chrome || event.source !== chrome.iframe.contentWindow) {
131
+ return;
132
+ }
133
+ if ((0, import_protocol.readIncompatibleVersion)(event.data) !== null) {
134
+ emit({ code: "incompatible_version", type: "error" });
135
+ close("incompatible_version");
136
+ return;
137
+ }
138
+ const message = (0, import_protocol.parseSheetMessage)(event.data);
139
+ if (message) {
140
+ handleSheetMessage(message);
141
+ }
142
+ }
143
+ function onKeyDown(event) {
144
+ if (event.key === "Escape") {
145
+ close("escape");
146
+ }
147
+ }
148
+ const handle = {
149
+ close: () => {
150
+ close("api");
151
+ },
152
+ setRequestStatus(status) {
153
+ if (!ready) {
154
+ pendingStatus = status;
155
+ return;
156
+ }
157
+ post({ status, type: "vana:request-status", v: import_protocol.PROTOCOL_VERSION });
158
+ }
159
+ };
160
+ window.addEventListener("message", onMessage);
161
+ document.addEventListener("keydown", onKeyDown);
162
+ const readyTimer = window.setTimeout(() => {
163
+ emit({ code: "frame_blocked", type: "error" });
164
+ close("frame_blocked");
165
+ }, options.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS);
166
+ checkClient(
167
+ (0, import_protocol.clientCheckUrl)({
168
+ clientId: options.clientId,
169
+ partnerOrigin: window.location.origin,
170
+ vanaOrigin
171
+ }),
172
+ () => {
173
+ if (!(closed || ready)) {
174
+ emit({ code: "origin_not_registered", type: "error" });
175
+ close("origin_not_registered");
176
+ }
177
+ }
178
+ );
179
+ chrome = (0, import_chrome.createSheetChrome)({
180
+ ariaLabel: `${options.appName} uses Vana`,
181
+ container: options.container ?? document.body,
182
+ display,
183
+ onClose: close,
184
+ src: (0, import_protocol.sheetUrl)({
185
+ clientId: options.clientId,
186
+ display,
187
+ partnerOrigin: window.location.origin,
188
+ vanaOrigin
189
+ })
190
+ });
191
+ document.body.style.overflow = "hidden";
192
+ chrome.show();
193
+ chrome.iframe.focus();
194
+ closeCurrent = close;
195
+ return handle;
196
+ }
197
+ function resolveTarget(target) {
198
+ const { env, vanaOrigin } = target;
199
+ if (env === void 0 === (vanaOrigin === void 0)) {
200
+ throw new TypeError("Pass exactly one of env and vanaOrigin");
201
+ }
202
+ if (env !== void 0) {
203
+ if (env !== "production" && env !== "dev") {
204
+ throw new TypeError('env must be "production" or "dev"');
205
+ }
206
+ return import_protocol.VANA_ACCOUNT_ORIGINS[env];
207
+ }
208
+ const origin = typeof vanaOrigin === "string" ? (0, import_protocol.normalizeOrigin)(vanaOrigin) : null;
209
+ if (!origin) {
210
+ throw new TypeError("vanaOrigin must be an http(s) origin");
211
+ }
212
+ return origin;
213
+ }
214
+ function checkClient(url, onRefused) {
215
+ if (typeof fetch !== "function") {
216
+ return;
217
+ }
218
+ fetch(url, { cache: "no-store", credentials: "omit" }).then((response) => response.ok ? response.json() : null).then((body) => {
219
+ if ((0, import_protocol.parseClientCheck)(body)?.registered === false) {
220
+ onRefused();
221
+ }
222
+ }).catch(() => void 0);
223
+ }
224
+ const openConnectSheet = open;
225
+ const connect = { open };
226
+ // Annotate the CommonJS export names for ESM import in node:
227
+ 0 && (module.exports = {
228
+ connect,
229
+ open,
230
+ openConnectSheet
231
+ });
232
+ //# sourceMappingURL=launcher.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/connect/launcher.ts"],"sourcesContent":["/**\n * Partner-side launcher for the Vana connect sheet.\n *\n * @remarks\n * `connect.open({ clientId, appName, env, getRequest, onEvent, display? })` returns\n * `{ close, setRequestStatus }`. Only launcher, chrome and message\n * protocol live here. Identity, consent and signing live in the Vana-hosted\n * iframe and Vana's servers; no token ever crosses into the partner page.\n *\n * Most apps should not call this directly: `createDirectConnectFlow` (and\n * `useVanaConnect`) with `presentation: \"sheet\"` open it and wire it to the\n * request, the status poll and the read.\n *\n * Ported from `@vana-unity/connect-embed` with two differences: the version\n * handshake (`incompatible_version`), and no default Vana origin (pass `env`\n * or `vanaOrigin`).\n *\n * `connected` means the person approved; it is not delivery. Treat the data\n * as delivered only once your backend's status poll and read say so (the\n * connect flow's `done`).\n *\n * @category Connect\n * @module connect/launcher\n */\n\nimport {\n type CloseReason,\n createSheetChrome,\n type SheetChrome,\n} from \"./chrome\";\nimport {\n type ConnectCompletion,\n type ConnectDisplay,\n type ConnectProgressPhase,\n type ConnectRequest,\n clientCheckUrl,\n DEFAULT_CONNECT_DISPLAY,\n MIN_SHEET_HEIGHT_PX,\n normalizeOrigin,\n type PartnerMessage,\n PROTOCOL_VERSION,\n parseClientCheck,\n parseSheetMessage,\n readConnectDisplay,\n readIncompatibleVersion,\n type RequestStatus,\n type SheetErrorCode,\n type SheetMessage,\n sheetUrl,\n VANA_ACCOUNT_ORIGINS,\n type VanaConnectEnv,\n} from \"./protocol\";\n\nconst DEFAULT_READY_TIMEOUT_MS = 10_000;\n\n/**\n * What the launcher reports to `onEvent`.\n *\n * @remarks\n * `connected` is approval, not delivery: data is delivered only when the\n * partner's backend reads it. The sheet sends no terminal \"delivered\" event\n * today; the connect flow settles from the status poll instead.\n */\nexport type ConnectEvent =\n | { type: \"ready\" }\n | { type: \"signed-in\" }\n | { completion: ConnectCompletion; status: \"approved\"; type: \"connected\" }\n | { phase: ConnectProgressPhase; type: \"progress\" }\n | { reason: ConnectCloseReason; type: \"close\" }\n | { code: SheetErrorCode | \"request_failed\"; type: \"error\" };\n\n/** Every close says why, so a sheet never disappears unexplained. */\nexport type ConnectCloseReason =\n | CloseReason\n | \"api\"\n | \"escape\"\n | \"frame_blocked\"\n | \"incompatible_version\"\n | \"origin_not_registered\"\n | \"replaced\"\n | \"sheet\";\n\n/**\n * Which Vana Account serves the sheet: an environment, or an exact origin\n * (resolve preview origins with `resolveVanaAccountOrigin`). Required, so a\n * dev app never silently frames production.\n */\nexport type ConnectTarget =\n | {\n /** Vana deployment; the sheet comes from `VANA_ACCOUNT_ORIGINS[env]`. */\n env: VanaConnectEnv;\n vanaOrigin?: undefined;\n }\n | {\n /** Vana Account origin. */\n vanaOrigin: string;\n env?: undefined;\n };\n\n/** Options for {@link open}, besides the {@link ConnectTarget}. */\nexport interface ConnectOpenBaseOptions {\n /** Chrome label only. Vana never trusts it; the sheet shows registered names. */\n appName: string;\n /** Registered embed client id. */\n clientId: string;\n /** Defaults to `document.body`. */\n container?: HTMLElement;\n /**\n * `sheet` (the default) is a bottom sheet over your page. `fullscreen` fills\n * this window, for a window that holds nothing else, such as a small popup\n * you opened yourself: close that window on the `close` event.\n */\n display?: ConnectDisplay;\n /**\n * Called when the sheet asks for the request (after sign-in). The partner's\n * backend creates the request or re-signs its short-lived read capability.\n */\n getRequest: () => Promise<ConnectRequest>;\n onEvent?: (event: ConnectEvent) => void;\n /**\n * CSP-blocked frames still fire `load`, so only `vana:ready` proves the\n * sheet runs. Without it by this deadline the sheet closes with\n * `frame_blocked`.\n */\n readyTimeoutMs?: number;\n}\n\n/** Options for {@link open}. */\nexport type ConnectOpenOptions = ConnectOpenBaseOptions & ConnectTarget;\n\n/** The open sheet. */\nexport interface ConnectHandle {\n /** Close the sheet; emits `close` with reason `\"api\"`. */\n close(): void;\n /** Report the request outcome the partner's backend observed. */\n setRequestStatus(status: RequestStatus): void;\n}\n\n/** Closes the open sheet, if any. One sheet at a time. */\nlet closeCurrent: ((reason: ConnectCloseReason) => void) | null = null;\n\n/**\n * Open the Vana connect sheet over the page. One sheet exists at a time;\n * opening another closes the first with reason `\"replaced\"`.\n *\n * @param options - Client id, app name, the request source and event sink.\n * @remarks\n * Alongside framing, it asks Vana (`GET /api/embed/connect/client`, no\n * credentials, no cache) whether this page's origin is registered for the\n * client id, and closes with `origin_not_registered` on a definite no. If\n * that check cannot be answered, the ready deadline decides.\n *\n * @param options - Client id, app name, Vana target, the request source and\n * event sink.\n * @returns A handle to close the sheet and report status.\n * @throws TypeError when neither (or both) of `env` and `vanaOrigin` is\n * given, `vanaOrigin` is not an http(s) origin, or `display` is not a known\n * display.\n */\nexport function open(options: ConnectOpenOptions): ConnectHandle {\n const vanaOrigin = resolveTarget(options);\n const display = readConnectDisplay(\n options.display ?? DEFAULT_CONNECT_DISPLAY,\n );\n if (!display) {\n throw new TypeError('display must be \"sheet\" or \"fullscreen\"');\n }\n closeCurrent?.(\"replaced\");\n\n const emit = (event: ConnectEvent) => options.onEvent?.(event);\n const previousFocus =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n const previousOverflow = document.body.style.overflow;\n let closed = false;\n let ready = false;\n /** Latest status reported before the sheet was ready, sent on ready. */\n let pendingStatus: RequestStatus | null = null;\n let chrome: SheetChrome | null = null;\n\n const post = (message: PartnerMessage) => {\n chrome?.iframe.contentWindow?.postMessage(message, vanaOrigin);\n };\n\n const close = (reason: ConnectCloseReason) => {\n if (closed) {\n return;\n }\n closed = true;\n window.clearTimeout(readyTimer);\n window.removeEventListener(\"message\", onMessage);\n document.removeEventListener(\"keydown\", onKeyDown);\n chrome?.remove();\n document.body.style.overflow = previousOverflow;\n previousFocus?.focus();\n if (closeCurrent === close) {\n closeCurrent = null;\n }\n emit({ reason, type: \"close\" });\n };\n\n const requestFromPartner = () => {\n options.getRequest().then(\n (request) => {\n if (!closed) {\n post({ request, type: \"vana:request\", v: PROTOCOL_VERSION });\n }\n },\n () => {\n if (!closed) {\n emit({ code: \"request_failed\", type: \"error\" });\n }\n },\n );\n };\n\n const handleSheetMessage = (message: SheetMessage) => {\n switch (message.type) {\n case \"vana:ready\":\n // A sheet that mounts twice (strict-mode dev builds) says ready twice.\n if (ready) {\n return;\n }\n window.clearTimeout(readyTimer);\n ready = true;\n if (pendingStatus) {\n post({\n status: pendingStatus,\n type: \"vana:request-status\",\n v: PROTOCOL_VERSION,\n });\n pendingStatus = null;\n }\n emit({ type: \"ready\" });\n return;\n case \"vana:resize\":\n if (message.height >= MIN_SHEET_HEIGHT_PX) {\n chrome?.setContentHeight(message.height);\n }\n return;\n case \"vana:signed-in\":\n emit({ type: \"signed-in\" });\n return;\n case \"vana:request-needed\":\n requestFromPartner();\n return;\n case \"vana:connected\":\n emit({\n completion: message.completion,\n status: message.status,\n type: \"connected\",\n });\n return;\n case \"vana:progress\":\n emit({ phase: message.phase, type: \"progress\" });\n return;\n case \"vana:close\":\n close(\"sheet\");\n return;\n case \"vana:error\":\n // The frame runs, so it is not blocked; the sheet stays open to say why.\n window.clearTimeout(readyTimer);\n emit({ code: message.code, type: \"error\" });\n return;\n default:\n return;\n }\n };\n\n function onMessage(event: MessageEvent) {\n if (\n event.origin !== vanaOrigin ||\n !chrome ||\n event.source !== chrome.iframe.contentWindow\n ) {\n return;\n }\n // A sheet at a version this launcher cannot speak is up but unusable:\n // say so, rather than waiting out the ready timeout as \"frame_blocked\".\n if (readIncompatibleVersion(event.data) !== null) {\n emit({ code: \"incompatible_version\", type: \"error\" });\n close(\"incompatible_version\");\n return;\n }\n const message = parseSheetMessage(event.data);\n if (message) {\n handleSheetMessage(message);\n }\n }\n\n function onKeyDown(event: KeyboardEvent) {\n if (event.key === \"Escape\") {\n close(\"escape\");\n }\n }\n\n const handle: ConnectHandle = {\n close: () => {\n close(\"api\");\n },\n setRequestStatus(status) {\n // Before ready the frame still holds about:blank; posting would be lost.\n if (!ready) {\n pendingStatus = status;\n return;\n }\n post({ status, type: \"vana:request-status\", v: PROTOCOL_VERSION });\n },\n };\n\n window.addEventListener(\"message\", onMessage);\n document.addEventListener(\"keydown\", onKeyDown);\n const readyTimer = window.setTimeout(() => {\n emit({ code: \"frame_blocked\", type: \"error\" });\n close(\"frame_blocked\");\n }, options.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS);\n\n checkClient(\n clientCheckUrl({\n clientId: options.clientId,\n partnerOrigin: window.location.origin,\n vanaOrigin,\n }),\n () => {\n if (!(closed || ready)) {\n emit({ code: \"origin_not_registered\", type: \"error\" });\n close(\"origin_not_registered\");\n }\n },\n );\n\n chrome = createSheetChrome({\n ariaLabel: `${options.appName} uses Vana`,\n container: options.container ?? document.body,\n display,\n onClose: close,\n src: sheetUrl({\n clientId: options.clientId,\n display,\n partnerOrigin: window.location.origin,\n vanaOrigin,\n }),\n });\n document.body.style.overflow = \"hidden\";\n chrome.show();\n chrome.iframe.focus();\n\n closeCurrent = close;\n return handle;\n}\n\nfunction resolveTarget(target: ConnectTarget): string {\n const { env, vanaOrigin } = target as {\n env?: unknown;\n vanaOrigin?: unknown;\n };\n if ((env === undefined) === (vanaOrigin === undefined)) {\n throw new TypeError(\"Pass exactly one of env and vanaOrigin\");\n }\n if (env !== undefined) {\n if (env !== \"production\" && env !== \"dev\") {\n throw new TypeError('env must be \"production\" or \"dev\"');\n }\n return VANA_ACCOUNT_ORIGINS[env];\n }\n const origin =\n typeof vanaOrigin === \"string\" ? normalizeOrigin(vanaOrigin) : null;\n if (!origin) {\n throw new TypeError(\"vanaOrigin must be an http(s) origin\");\n }\n return origin;\n}\n\n/**\n * Ask Vana whether this page may frame the sheet, alongside framing it, and\n * call `onRefused` only on a definite no. Any failure to ask leaves the ready\n * deadline to decide, so the check can only end the sheet sooner.\n */\nfunction checkClient(url: string, onRefused: () => void): void {\n if (typeof fetch !== \"function\") {\n return;\n }\n fetch(url, { cache: \"no-store\", credentials: \"omit\" })\n .then((response) => (response.ok ? response.json() : null))\n .then((body: unknown) => {\n if (parseClientCheck(body)?.registered === false) {\n onRefused();\n }\n })\n .catch(() => undefined);\n}\n\n/** Alias of {@link open}, for call sites where `open` would be ambiguous. */\nexport const openConnectSheet = open;\n\n/** Namespace form: `connect.open(...)`. */\nexport const connect = { open } as const;\n"],"mappings":"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","names":[]}