@tatchi-xyz/sdk 0.55.0 → 0.56.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.
@@ -41,9 +41,9 @@ var IframeOverlay = class {
41
41
  if (this.testOptions?.ownerTag) iframe.dataset.w3aOwner = this.testOptions.ownerTag;
42
42
  iframe.dataset.w3aOrigin = this.walletOrigin;
43
43
  try {
44
- iframe.setAttribute("allow", this.buildAllowAttr(this.walletOrigin));
44
+ iframe.setAttribute("allow", this.buildAllowAttr());
45
45
  } catch {
46
- iframe.setAttribute("allow", "publickey-credentials-get 'self'; publickey-credentials-create 'self'; clipboard-read; clipboard-write");
46
+ iframe.setAttribute("allow", "publickey-credentials-get; publickey-credentials-create; clipboard-read; clipboard-write");
47
47
  }
48
48
  iframe._svc_loaded = false;
49
49
  iframe.addEventListener("load", () => {
@@ -135,8 +135,8 @@ var IframeOverlay = class {
135
135
  } catch {}
136
136
  }
137
137
  }
138
- buildAllowAttr(walletOrigin) {
139
- return `publickey-credentials-get 'self' ${walletOrigin}; publickey-credentials-create 'self' ${walletOrigin}; clipboard-read; clipboard-write`;
138
+ buildAllowAttr() {
139
+ return "publickey-credentials-get; publickey-credentials-create; clipboard-read; clipboard-write";
140
140
  }
141
141
  };
142
142
 
@@ -1 +1 @@
1
- {"version":3,"file":"iframe-overlay.js","names":["isDevHost","getNodeEnv"],"sources":["../../../../../src/core/WalletIframe/client/iframe-overlay.ts"],"sourcesContent":["import { ensureOverlayBase, cleanupOverlayStyles } from './overlay-styles';\nimport { getNodeEnv, isDevHost } from '../shared/runtime';\n\ntype OverlayIframe = HTMLIFrameElement & { _svc_loaded?: boolean };\n\nexport type IframeOverlayOptions = {\n walletOrigin: string;\n serviceUrl: URL;\n debug?: boolean;\n testOptions?: {\n routerId?: string;\n ownerTag?: string;\n };\n};\n\nexport class IframeOverlay {\n private iframeEl: OverlayIframe | null = null;\n private readonly walletOrigin: string;\n private readonly serviceUrl: URL;\n private readonly testOptions: { routerId?: string; ownerTag?: string };\n private readonly debug: boolean;\n\n constructor(opts: IframeOverlayOptions) {\n this.walletOrigin = opts.walletOrigin;\n this.serviceUrl = opts.serviceUrl;\n this.debug = !!opts.debug;\n this.testOptions = {\n routerId: opts.testOptions?.routerId,\n ownerTag: opts.testOptions?.ownerTag,\n };\n }\n\n get element(): HTMLIFrameElement | null {\n return this.iframeEl;\n }\n\n get contentWindow(): Window | null {\n return this.iframeEl?.contentWindow || null;\n }\n\n ensureMounted(): HTMLIFrameElement {\n if (this.iframeEl) return this.iframeEl;\n\n this.removeExistingOverlaysForOrigin();\n\n const iframe = document.createElement('iframe') as OverlayIframe;\n // Hidden by default via CSS classes; higher layers toggle state using overlay-styles.\n iframe.classList.add('w3a-wallet-overlay', 'is-hidden');\n // Ensure the base overlay stylesheet is installed early so computed styles\n // (opacity/pointer-events) reflect the hidden state immediately after mount.\n try { ensureOverlayBase(iframe); } catch {}\n // Ensure no initial footprint even before stylesheet attaches\n iframe.setAttribute('width', '0');\n iframe.setAttribute('height', '0');\n iframe.setAttribute('aria-hidden', 'true');\n iframe.setAttribute('tabindex', '-1');\n // Hint higher priority fetch for the iframe document on supporting browsers\n iframe.setAttribute('loading', 'eager');\n iframe.setAttribute('fetchpriority', 'high');\n\n iframe.dataset.w3aRouterId = this.testOptions?.routerId || '';\n if (this.testOptions?.ownerTag) iframe.dataset.w3aOwner = this.testOptions.ownerTag;\n iframe.dataset.w3aOrigin = this.walletOrigin;\n\n // Delegate WebAuthn + clipboard capabilities to the wallet origin frame\n try {\n iframe.setAttribute('allow', this.buildAllowAttr(this.walletOrigin));\n } catch {\n iframe.setAttribute('allow', \"publickey-credentials-get 'self'; publickey-credentials-create 'self'; clipboard-read; clipboard-write\");\n }\n\n // Track load state to guard against races where we post before content is listening\n iframe._svc_loaded = false;\n iframe.addEventListener('load', () => { iframe._svc_loaded = true; }, { once: true });\n\n const src = this.serviceUrl.toString();\n if (this.debug) console.debug('[IframeTransport] mount: external origin', src);\n iframe.src = src;\n\n document.body.appendChild(iframe);\n if (this.debug) console.debug('[IframeTransport] mount: iframe appended');\n this.iframeEl = iframe;\n return iframe;\n }\n\n dispose(opts?: { removeIframe?: boolean }): void {\n if (!opts?.removeIframe) return;\n if (this.iframeEl) {\n try { cleanupOverlayStyles(this.iframeEl); } catch {}\n try { this.iframeEl.remove(); } catch {}\n }\n this.iframeEl = null;\n }\n\n async waitForLoad(signal?: AbortSignal): Promise<void> {\n const iframe = this.iframeEl;\n if (!iframe) return;\n if (iframe._svc_loaded) return;\n await new Promise<void>((resolve, reject) => {\n let done = false;\n const onAbort = () => {\n if (done) return;\n done = true;\n reject(new Error('Iframe load aborted'));\n };\n const finish = () => {\n if (done) return;\n done = true;\n if (signal) {\n try { signal.removeEventListener('abort', onAbort); } catch {}\n }\n resolve();\n };\n const timeout = window.setTimeout(() => {\n finish();\n }, 150);\n iframe.addEventListener('load', () => {\n clearTimeout(timeout);\n finish();\n }, { once: true });\n if (signal) {\n if (signal.aborted) {\n clearTimeout(timeout);\n onAbort();\n return;\n }\n signal.addEventListener('abort', onAbort, { once: true });\n }\n });\n }\n\n private isOverlayForOrigin(el: HTMLIFrameElement): boolean {\n const dsOrigin = (el as { dataset?: { w3aOrigin?: string } }).dataset?.w3aOrigin;\n if (dsOrigin) return dsOrigin === this.walletOrigin;\n try {\n return new URL(el.src).origin === this.walletOrigin;\n } catch {\n return false;\n }\n }\n\n private removeExistingOverlaysForOrigin(): void {\n if (typeof document === 'undefined') return;\n const existing = Array.from(document.querySelectorAll('iframe.w3a-wallet-overlay')) as HTMLIFrameElement[];\n const matches = existing.filter((el) => this.isOverlayForOrigin(el));\n if (!matches.length) return;\n\n if (isDevHost(window.location.hostname, getNodeEnv())) {\n const routerIds = matches\n .map((el) => (el as { dataset?: { w3aRouterId?: string } }).dataset?.w3aRouterId)\n .filter((v): v is string => typeof v === 'string' && v.length > 0);\n console.warn(\n `[IframeTransport] Found existing wallet overlay iframe(s) for ${this.walletOrigin}. This usually indicates multiple SDK instances. Removing old iframe(s) to avoid duplicates.`,\n { count: matches.length, routerIds }\n );\n }\n\n for (const el of matches) {\n try { cleanupOverlayStyles(el); } catch {}\n try { el.remove(); } catch {}\n }\n }\n\n private buildAllowAttr(walletOrigin: string): string {\n return `publickey-credentials-get 'self' ${walletOrigin}; publickey-credentials-create 'self' ${walletOrigin}; clipboard-read; clipboard-write`;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"iframe-overlay.js","names":["isDevHost","getNodeEnv"],"sources":["../../../../../src/core/WalletIframe/client/iframe-overlay.ts"],"sourcesContent":["import { ensureOverlayBase, cleanupOverlayStyles } from './overlay-styles';\nimport { getNodeEnv, isDevHost } from '../shared/runtime';\n\ntype OverlayIframe = HTMLIFrameElement & { _svc_loaded?: boolean };\n\nexport type IframeOverlayOptions = {\n walletOrigin: string;\n serviceUrl: URL;\n debug?: boolean;\n testOptions?: {\n routerId?: string;\n ownerTag?: string;\n };\n};\n\nexport class IframeOverlay {\n private iframeEl: OverlayIframe | null = null;\n private readonly walletOrigin: string;\n private readonly serviceUrl: URL;\n private readonly testOptions: { routerId?: string; ownerTag?: string };\n private readonly debug: boolean;\n\n constructor(opts: IframeOverlayOptions) {\n this.walletOrigin = opts.walletOrigin;\n this.serviceUrl = opts.serviceUrl;\n this.debug = !!opts.debug;\n this.testOptions = {\n routerId: opts.testOptions?.routerId,\n ownerTag: opts.testOptions?.ownerTag,\n };\n }\n\n get element(): HTMLIFrameElement | null {\n return this.iframeEl;\n }\n\n get contentWindow(): Window | null {\n return this.iframeEl?.contentWindow || null;\n }\n\n ensureMounted(): HTMLIFrameElement {\n if (this.iframeEl) return this.iframeEl;\n\n this.removeExistingOverlaysForOrigin();\n\n const iframe = document.createElement('iframe') as OverlayIframe;\n // Hidden by default via CSS classes; higher layers toggle state using overlay-styles.\n iframe.classList.add('w3a-wallet-overlay', 'is-hidden');\n // Ensure the base overlay stylesheet is installed early so computed styles\n // (opacity/pointer-events) reflect the hidden state immediately after mount.\n try { ensureOverlayBase(iframe); } catch {}\n // Ensure no initial footprint even before stylesheet attaches\n iframe.setAttribute('width', '0');\n iframe.setAttribute('height', '0');\n iframe.setAttribute('aria-hidden', 'true');\n iframe.setAttribute('tabindex', '-1');\n // Hint higher priority fetch for the iframe document on supporting browsers\n iframe.setAttribute('loading', 'eager');\n iframe.setAttribute('fetchpriority', 'high');\n\n iframe.dataset.w3aRouterId = this.testOptions?.routerId || '';\n if (this.testOptions?.ownerTag) iframe.dataset.w3aOwner = this.testOptions.ownerTag;\n iframe.dataset.w3aOrigin = this.walletOrigin;\n\n // Delegate WebAuthn + clipboard capabilities to the wallet origin frame\n try {\n iframe.setAttribute('allow', this.buildAllowAttr());\n } catch {\n iframe.setAttribute('allow', 'publickey-credentials-get; publickey-credentials-create; clipboard-read; clipboard-write');\n }\n\n // Track load state to guard against races where we post before content is listening\n iframe._svc_loaded = false;\n iframe.addEventListener('load', () => { iframe._svc_loaded = true; }, { once: true });\n\n const src = this.serviceUrl.toString();\n if (this.debug) console.debug('[IframeTransport] mount: external origin', src);\n iframe.src = src;\n\n document.body.appendChild(iframe);\n if (this.debug) console.debug('[IframeTransport] mount: iframe appended');\n this.iframeEl = iframe;\n return iframe;\n }\n\n dispose(opts?: { removeIframe?: boolean }): void {\n if (!opts?.removeIframe) return;\n if (this.iframeEl) {\n try { cleanupOverlayStyles(this.iframeEl); } catch {}\n try { this.iframeEl.remove(); } catch {}\n }\n this.iframeEl = null;\n }\n\n async waitForLoad(signal?: AbortSignal): Promise<void> {\n const iframe = this.iframeEl;\n if (!iframe) return;\n if (iframe._svc_loaded) return;\n await new Promise<void>((resolve, reject) => {\n let done = false;\n const onAbort = () => {\n if (done) return;\n done = true;\n reject(new Error('Iframe load aborted'));\n };\n const finish = () => {\n if (done) return;\n done = true;\n if (signal) {\n try { signal.removeEventListener('abort', onAbort); } catch {}\n }\n resolve();\n };\n const timeout = window.setTimeout(() => {\n finish();\n }, 150);\n iframe.addEventListener('load', () => {\n clearTimeout(timeout);\n finish();\n }, { once: true });\n if (signal) {\n if (signal.aborted) {\n clearTimeout(timeout);\n onAbort();\n return;\n }\n signal.addEventListener('abort', onAbort, { once: true });\n }\n });\n }\n\n private isOverlayForOrigin(el: HTMLIFrameElement): boolean {\n const dsOrigin = (el as { dataset?: { w3aOrigin?: string } }).dataset?.w3aOrigin;\n if (dsOrigin) return dsOrigin === this.walletOrigin;\n try {\n return new URL(el.src).origin === this.walletOrigin;\n } catch {\n return false;\n }\n }\n\n private removeExistingOverlaysForOrigin(): void {\n if (typeof document === 'undefined') return;\n const existing = Array.from(document.querySelectorAll('iframe.w3a-wallet-overlay')) as HTMLIFrameElement[];\n const matches = existing.filter((el) => this.isOverlayForOrigin(el));\n if (!matches.length) return;\n\n if (isDevHost(window.location.hostname, getNodeEnv())) {\n const routerIds = matches\n .map((el) => (el as { dataset?: { w3aRouterId?: string } }).dataset?.w3aRouterId)\n .filter((v): v is string => typeof v === 'string' && v.length > 0);\n console.warn(\n `[IframeTransport] Found existing wallet overlay iframe(s) for ${this.walletOrigin}. This usually indicates multiple SDK instances. Removing old iframe(s) to avoid duplicates.`,\n { count: matches.length, routerIds }\n );\n }\n\n for (const el of matches) {\n try { cleanupOverlayStyles(el); } catch {}\n try { el.remove(); } catch {}\n }\n }\n\n private buildAllowAttr(): string {\n return 'publickey-credentials-get; publickey-credentials-create; clipboard-read; clipboard-write';\n }\n}\n"],"mappings":";;;;AAeA,IAAa,gBAAb,MAA2B;CACzB,AAAQ,WAAiC;CACzC,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,MAA4B;AACtC,OAAK,eAAe,KAAK;AACzB,OAAK,aAAa,KAAK;AACvB,OAAK,QAAQ,CAAC,CAAC,KAAK;AACpB,OAAK,cAAc;GACjB,UAAU,KAAK,aAAa;GAC5B,UAAU,KAAK,aAAa;;;CAIhC,IAAI,UAAoC;AACtC,SAAO,KAAK;;CAGd,IAAI,gBAA+B;AACjC,SAAO,KAAK,UAAU,iBAAiB;;CAGzC,gBAAmC;AACjC,MAAI,KAAK,SAAU,QAAO,KAAK;AAE/B,OAAK;EAEL,MAAM,SAAS,SAAS,cAAc;AAEtC,SAAO,UAAU,IAAI,sBAAsB;AAG3C,MAAI;AAAE,4CAAkB;UAAiB;AAEzC,SAAO,aAAa,SAAS;AAC7B,SAAO,aAAa,UAAU;AAC9B,SAAO,aAAa,eAAe;AACnC,SAAO,aAAa,YAAY;AAEhC,SAAO,aAAa,WAAW;AAC/B,SAAO,aAAa,iBAAiB;AAErC,SAAO,QAAQ,cAAc,KAAK,aAAa,YAAY;AAC3D,MAAI,KAAK,aAAa,SAAU,QAAO,QAAQ,WAAW,KAAK,YAAY;AAC3E,SAAO,QAAQ,YAAY,KAAK;AAGhC,MAAI;AACF,UAAO,aAAa,SAAS,KAAK;UAC5B;AACN,UAAO,aAAa,SAAS;;AAI/B,SAAO,cAAc;AACrB,SAAO,iBAAiB,cAAc;AAAE,UAAO,cAAc;KAAS,EAAE,MAAM;EAE9E,MAAM,MAAM,KAAK,WAAW;AAC5B,MAAI,KAAK,MAAO,SAAQ,MAAM,4CAA4C;AAC1E,SAAO,MAAM;AAEb,WAAS,KAAK,YAAY;AAC1B,MAAI,KAAK,MAAO,SAAQ,MAAM;AAC9B,OAAK,WAAW;AAChB,SAAO;;CAGT,QAAQ,MAAyC;AAC/C,MAAI,CAAC,MAAM,aAAc;AACzB,MAAI,KAAK,UAAU;AACjB,OAAI;AAAE,gDAAqB,KAAK;WAAmB;AACnD,OAAI;AAAE,SAAK,SAAS;WAAkB;;AAExC,OAAK,WAAW;;CAGlB,MAAM,YAAY,QAAqC;EACrD,MAAM,SAAS,KAAK;AACpB,MAAI,CAAC,OAAQ;AACb,MAAI,OAAO,YAAa;AACxB,QAAM,IAAI,SAAe,SAAS,WAAW;GAC3C,IAAI,OAAO;GACX,MAAM,gBAAgB;AACpB,QAAI,KAAM;AACV,WAAO;AACP,2BAAO,IAAI,MAAM;;GAEnB,MAAM,eAAe;AACnB,QAAI,KAAM;AACV,WAAO;AACP,QAAI,OACF,KAAI;AAAE,YAAO,oBAAoB,SAAS;YAAkB;AAE9D;;GAEF,MAAM,UAAU,OAAO,iBAAiB;AACtC;MACC;AACH,UAAO,iBAAiB,cAAc;AACpC,iBAAa;AACb;MACC,EAAE,MAAM;AACX,OAAI,QAAQ;AACV,QAAI,OAAO,SAAS;AAClB,kBAAa;AACb;AACA;;AAEF,WAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM;;;;CAKxD,AAAQ,mBAAmB,IAAgC;EACzD,MAAM,WAAY,GAA4C,SAAS;AACvE,MAAI,SAAU,QAAO,aAAa,KAAK;AACvC,MAAI;AACF,UAAO,IAAI,IAAI,GAAG,KAAK,WAAW,KAAK;UACjC;AACN,UAAO;;;CAIX,AAAQ,kCAAwC;AAC9C,MAAI,OAAO,aAAa,YAAa;EACrC,MAAM,WAAW,MAAM,KAAK,SAAS,iBAAiB;EACtD,MAAM,UAAU,SAAS,QAAQ,OAAO,KAAK,mBAAmB;AAChE,MAAI,CAAC,QAAQ,OAAQ;AAErB,MAAIA,0BAAU,OAAO,SAAS,UAAUC,+BAAe;GACrD,MAAM,YAAY,QACf,KAAK,OAAQ,GAA8C,SAAS,aACpE,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS;AAClE,WAAQ,KACN,iEAAiE,KAAK,aAAa,+FACnF;IAAE,OAAO,QAAQ;IAAQ;;;AAI7B,OAAK,MAAM,MAAM,SAAS;AACxB,OAAI;AAAE,gDAAqB;WAAa;AACxC,OAAI;AAAE,OAAG;WAAkB;;;CAI/B,AAAQ,iBAAyB;AAC/B,SAAO"}
@@ -40,6 +40,15 @@ function tryFile(...candidates) {
40
40
  } catch {}
41
41
  return void 0;
42
42
  }
43
+ function ensureViteCacheDirAllowed(server) {
44
+ const config = server?.config;
45
+ const cacheDir = config?.cacheDir;
46
+ const fsConfig = config?.server?.fs;
47
+ const allow = fsConfig?.allow;
48
+ if (!cacheDir || fsConfig?.strict === false || !Array.isArray(allow)) return;
49
+ const absCacheDir = node_path.resolve(String(cacheDir));
50
+ if (!allow.some((p) => node_path.resolve(String(p)) === absCacheDir)) allow.push(absCacheDir);
51
+ }
43
52
  const WALLET_SHIM_SOURCE = "window.global ||= window; window.process ||= { env: {} };\n";
44
53
  const WALLET_SURFACE_CSS = [
45
54
  "html, body { background: transparent !important; margin:0; padding:0; }",
@@ -83,6 +92,7 @@ function tatchiServeSdk(opts = {}) {
83
92
  apply: "serve",
84
93
  enforce: "pre",
85
94
  configureServer(server) {
95
+ ensureViteCacheDirAllowed(server);
86
96
  require_offline.addOfflineExportDevRoutes(server, {
87
97
  sdkDistRoot,
88
98
  sdkBasePath: configuredBase,
@@ -156,6 +166,7 @@ function tatchiWalletService(opts = {}) {
156
166
  apply: "serve",
157
167
  enforce: "pre",
158
168
  configureServer(server) {
169
+ ensureViteCacheDirAllowed(server);
159
170
  server.middlewares.use((req, res, next) => {
160
171
  if (!req.url) return next();
161
172
  const url = req.url.split("?")[0];
@@ -190,6 +201,7 @@ function tatchiWasmMime() {
190
201
  apply: "serve",
191
202
  enforce: "pre",
192
203
  configureServer(server) {
204
+ ensureViteCacheDirAllowed(server);
193
205
  server.middlewares.use((req, res, next) => {
194
206
  if (!req.url) return next();
195
207
  const url = req.url.split("?")[0];
@@ -221,6 +233,7 @@ function tatchiHeaders(opts = {}) {
221
233
  apply: "serve",
222
234
  enforce: "pre",
223
235
  configureServer(server) {
236
+ ensureViteCacheDirAllowed(server);
224
237
  console.log("[tatchi] headers enabled", {
225
238
  walletServicePath,
226
239
  sdkBasePath,
@@ -330,6 +343,7 @@ function tatchiDevServer(options = {}) {
330
343
  apply: "serve",
331
344
  enforce: "pre",
332
345
  configureServer(server) {
346
+ ensureViteCacheDirAllowed(server);
333
347
  sdkPlugin.configureServer?.(server);
334
348
  wasmMimePlugin.configureServer?.(server);
335
349
  if (headersPlugin) headersPlugin.configureServer?.(server);
@@ -1 +1 @@
1
- {"version":3,"file":"vite.js","names":["out: string[]","toOriginOrUndefined","fs","toBasePath","resolveSdkDistRoot","resolveCoepMode","buildOfflineExportHtml","path","buildWalletServiceHtml","buildPermissionsPolicy","buildWalletCsp","fetchRorOriginsFromNear","echoCorsFromRequest","mode: Required<Web3AuthnDevOptions>['mode']","contentLines: string[]","buildExportViewerHtml"],"sources":["../../../src/plugins/vite.ts"],"sourcesContent":["// Minimal Vite dev plugin(s) to support Passkey Manager modes.\n// See docs/passkey-manager-modes.md (Vite Plugin section).\n//\n// What these plugins do:\n// - Serve SDK assets under a base path, expose a wallet service route,\n// - Add dev headers (COOP + Permissions-Policy, optional COEP/CORP), and enforce WASM MIME.\n// - IMPORTANT: Strict CSP is scoped only to wallet HTML routes (/wallet-service, /export-viewer),\n// not to the host app pages. App routes remain free to use inline styles/scripts.\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { buildPermissionsPolicy, buildWalletCsp } from './headers'\nimport { toOriginOrUndefined } from '../utils/validation'\nimport {\n addPreconnectLink,\n buildWalletServiceHtml,\n buildExportViewerHtml,\n applyCoepCorpIfNeeded,\n echoCorsFromRequest,\n fetchRorOriginsFromNear,\n toBasePath,\n resolveCoepMode,\n resolveSdkDistRoot,\n} from './plugin-utils'\nimport { addOfflineExportDevRoutes, buildOfflineExportHtml, emitOfflineExportAssets } from './offline'\nimport { setContentType } from './plugin-utils'\n\nexport type VitePlugin = {\n name: string\n apply?: 'serve' | 'build'\n enforce?: 'pre' | 'post'\n configureServer?: (server: any) => void | Promise<void>\n}\nexport type ViteLikePlugin = VitePlugin\n\nexport type Web3AuthnDevOptions = {\n mode?: 'self-contained' | 'front-only' | 'wallet-only'\n sdkDistRoot?: string\n sdkBasePath?: string\n walletServicePath?: string\n walletOrigins?: string[]\n setDevHeaders?: boolean\n enableDebugRoutes?: boolean\n /**\n * Controls Cross-Origin-Embedder-Policy (COEP) behavior in dev.\n * - 'off' (default): do not emit COEP/CORP on app pages.\n * - 'strict': emit `Cross-Origin-Embedder-Policy: require-corp`\n * and `Cross-Origin-Resource-Policy: cross-origin` on app pages.\n *\n * Tip: set `VITE_COEP_MODE=strict` in tests/CI to enable isolation automatically.\n */\n coepMode?: 'strict' | 'off'\n}\n\nexport type ServeSdkOptions = {\n sdkDistRoot?: string\n sdkBasePath?: string\n enableDebugRoutes?: boolean\n coepMode?: 'strict' | 'off'\n}\n\nexport type WalletServiceOptions = {\n walletServicePath?: string\n sdkBasePath?: string\n coepMode?: 'strict' | 'off'\n}\n\nexport type DevHeadersOptions = {\n walletOrigins?: string[]\n walletServicePath?: string\n sdkBasePath?: string\n /**\n * Optional dev-time CSP for the wallet service route.\n * - 'strict': no inline scripts/styles (mirrors production defaults)\n * - 'compatible': allows inline scripts/styles (useful for debugging)\n */\n devCSP?: 'strict' | 'compatible'\n /**\n * Controls Cross-Origin-Embedder-Policy (COEP) behavior in dev.\n * - 'off' (default): do not emit COEP/CORP headers on app pages.\n * - 'strict': emit COEP/CORP headers on app pages.\n */\n coepMode?: 'strict' | 'off'\n}\n\nfunction normalizeWalletOrigins(walletOrigins?: string[]): string[] {\n if (!Array.isArray(walletOrigins) || walletOrigins.length === 0) return []\n const out: string[] = []\n const seen = new Set<string>()\n for (const origin of walletOrigins) {\n const normalized = toOriginOrUndefined(origin)\n if (!normalized || seen.has(normalized)) continue\n seen.add(normalized)\n out.push(normalized)\n }\n return out\n}\n\nfunction parseWalletOriginsEnv(value: unknown): string[] | undefined {\n if (typeof value !== 'string') return undefined\n const raw = value.trim()\n if (!raw) return undefined\n const parts = raw.split(/[,\\s]+/).map((v) => v.trim()).filter(Boolean)\n const origins = normalizeWalletOrigins(parts)\n return origins.length ? origins : undefined\n}\n\n/**\n * Return the first candidate path that exists and is a file.\n * Helper for robust /sdk/* asset resolution on dev servers (app and wallet).\n */\nfunction tryFile(...candidates: string[]): string | undefined {\n for (const file of candidates) {\n try {\n const stat = fs.statSync(file)\n if (stat.isFile()) return file\n } catch {}\n }\n return undefined\n}\n\n// RPC helpers are provided by plugin-utils to share logic across frameworks.\n\n// Shared assets emitted/served for the wallet service bootstrap.\nconst WALLET_SHIM_SOURCE = \"window.global ||= window; window.process ||= { env: {} };\\n\"\nconst WALLET_SURFACE_CSS = [\n 'html, body { background: transparent !important; margin:0; padding:0; }',\n 'html, body { color-scheme: normal; }',\n '',\n // Class-based surface for strict CSP setups toggled by JS\n 'html.w3a-transparent, body.w3a-transparent { background: transparent !important; margin:0; padding:0; color-scheme: normal; }',\n '',\n // Minimal portal styles used by confirm-ui (no animation; child components handle transitions)\n '.w3a-portal { position: relative; z-index: 2147483647; opacity: 0; pointer-events: none; }',\n '.w3a-portal.w3a-portal--visible { opacity: 1; pointer-events: auto; }',\n '',\n // Provide baseline tokens only when the document does not declare a theme.\n // This avoids overriding :root[data-w3a-theme] values supplied by token sheet\n // or integrator-injected themes.\n ':root:not([data-w3a-theme]) {',\n ' --w3a-colors-textPrimary: #f6f7f8;',\n ' --w3a-colors-textSecondary: rgba(255,255,255,0.7);',\n ' --w3a-colors-surface: rgba(255,255,255,0.08);',\n ' --w3a-colors-surface2: rgba(255,255,255,0.06);',\n ' --w3a-colors-surface3: rgba(255,255,255,0.04);',\n ' --w3a-colors-borderPrimary: rgba(255,255,255,0.14);',\n ' --w3a-colors-borderSecondary: rgba(255,255,255,0.1);',\n ' --w3a-colors-colorBackground: #0b0c10;',\n ' /* Default viewport custom properties for width/height calculations */',\n ' --w3a-vw: 100vw;',\n ' --w3a-vh: 100vh;',\n '}',\n '',\n].join('\\n')\n\n/**\n * Tatchi SDK plugin: serve SDK assets under a stable base (default: /sdk) with optional COEP/CORP (strict mode) and permissive CORS.\n * Where it runs: both the app server and the wallet-iframe server.\n * - App server: lets host pages and Lit components load SDK CSS/JS locally.\n * - Wallet server: used by /wallet-service to load wallet-iframe-host.js and related CSS/JS.\n */\nexport function tatchiServeSdk(opts: ServeSdkOptions = {}): VitePlugin {\n const configuredBase = toBasePath(opts.sdkBasePath, '/sdk')\n const sdkDistRoot = resolveSdkDistRoot(opts.sdkDistRoot)\n const enableDebugRoutes = opts.enableDebugRoutes === true\n const coepMode = resolveCoepMode(opts.coepMode)\n const offlineHtml = buildOfflineExportHtml(configuredBase)\n\n // In dev we want both '/sdk' and a custom base to work.\n const bases = Array.from(new Set([configuredBase, toBasePath('/sdk')]))\n .sort((a, b) => b.length - a.length)\n // Prefer longest base match first (e.g., '/sdk/esm/react' before '/sdk')\n\n return {\n name: 'tatchi:serve-sdk',\n apply: 'serve',\n enforce: 'pre',\n configureServer(server) {\n // Mount Offline Export dev routes once here (includes app module + chunks)\n addOfflineExportDevRoutes(server, {\n sdkDistRoot,\n sdkBasePath: configuredBase,\n offlineHtml,\n includeAppModule: true,\n coepMode,\n })\n // Serve a tiny shim as a virtual asset to enable strict CSP (no inline scripts)\n server.middlewares.use((req: any, res: any, next: any) => {\n const url = (req.url || '').split('?')[0]\n if (url === configuredBase + '/wallet-shims.js') {\n res.statusCode = 200\n res.setHeader('Content-Type', 'application/javascript; charset=utf-8')\n // Align with SDK asset headers so COEP/CORP environments can import\n applyCoepCorpIfNeeded(res, coepMode)\n // Dev-only CORS echo (no preflight handling on this route)\n echoCorsFromRequest(res, req, { handlePreflight: false })\n res.end(WALLET_SHIM_SOURCE)\n return\n }\n if (url === configuredBase + '/wallet-service.css') {\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/css; charset=utf-8')\n // Important: provide CORP for cross‑origin CSS so COEP documents can load it\n applyCoepCorpIfNeeded(res, coepMode)\n // Dev-only CORS echo (no preflight handling on this route)\n echoCorsFromRequest(res, req, { handlePreflight: false })\n res.end(WALLET_SURFACE_CSS)\n return\n }\n next()\n })\n\n // Optional debug route to confirm resolution\n if (enableDebugRoutes) {\n server.middlewares.use('/__sdk-root', (req: any, res: any) => {\n res.setHeader('Content-Type', 'text/plain; charset=utf-8')\n res.end(sdkDistRoot)\n })\n }\n\n // Serve files under any recognized base from sdkDistRoot with fallbacks\n server.middlewares.use((req: any, res: any, next: any) => {\n if (!req.url) return next()\n const url = req.url.split('?')[0]\n\n const matchBase = bases.find((b) => url.startsWith(b + '/'))\n if (!matchBase) return next()\n\n const rel = url.slice((matchBase + '/').length)\n // Try dist/esm/sdk first (canonical), then common fallbacks\n const candidate = tryFile(\n path.join(sdkDistRoot, 'esm', 'sdk', rel),\n path.join(sdkDistRoot, rel),\n path.join(sdkDistRoot, 'esm', rel)\n )\n\n if (!candidate) {\n res.statusCode = 404\n res.setHeader('Content-Type', 'application/json; charset=utf-8')\n res.end(JSON.stringify({ error: 'SDK asset not found', path: rel }))\n return\n }\n\n setContentType(res, candidate)\n // SDK assets need COEP headers to work in wallet iframe with COEP enabled\n applyCoepCorpIfNeeded(res, coepMode)\n // Dev-only CORS echo (no preflight handling here)\n echoCorsFromRequest(res, req, { handlePreflight: false })\n const stream = fs.createReadStream(candidate)\n stream.on('error', () => next())\n stream.pipe(res)\n })\n },\n }\n}\n\n/**\n * Dev plugin: expose the wallet service HTML route (default: /wallet-service) that links only external CSS/JS.\n * Where it runs: wallet-iframe dev server (wallet origins). Used by tatchiWalletServer.\n */\nexport function tatchiWalletService(opts: WalletServiceOptions = {}): VitePlugin {\n const walletServicePath = toBasePath(opts.walletServicePath, '/wallet-service')\n const sdkBasePath = toBasePath(opts.sdkBasePath, '/sdk')\n const coepMode = resolveCoepMode(opts.coepMode)\n\n const html = buildWalletServiceHtml(sdkBasePath)\n const offlineHtml = buildOfflineExportHtml(sdkBasePath)\n const sdkDistRoot = resolveSdkDistRoot()\n\n return {\n name: 'tatchi:wallet-service',\n apply: 'serve',\n enforce: 'pre',\n configureServer(server) {\n server.middlewares.use((req: any, res: any, next: any) => {\n if (!req.url) return next()\n const url = req.url.split('?')[0]\n const isWalletRoute = url === walletServicePath || url === `${walletServicePath}/` || url === `${walletServicePath}//`\n if (isWalletRoute) {\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html; charset=utf-8')\n // Important: allow embedding this wallet HTML into COEP=require-corp apps even\n // when the wallet itself is not running with COEP enabled.\n // Without CORP, the iframe can be blocked and remain on an opaque 'null' origin,\n // causing CONNECT/READY handshake timeouts in the parent.\n res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin')\n applyCoepCorpIfNeeded(res, coepMode)\n res.end(html)\n return\n }\n next()\n })\n\n // Mount Offline Export routes here as well (no app module duplication)\n addOfflineExportDevRoutes(server, {\n sdkDistRoot,\n sdkBasePath,\n offlineHtml,\n includeAppModule: false,\n coepMode,\n })\n },\n }\n}\n\n/**\n * Dev plugin: force the correct `.wasm` MIME type (application/wasm) for any served wasm file.\n * Where it runs: both app and wallet-iframe dev servers.\n */\nexport function tatchiWasmMime(): VitePlugin {\n return {\n name: 'tatchi:wasm-mime',\n apply: 'serve',\n enforce: 'pre',\n configureServer(server) {\n server.middlewares.use((req: any, res: any, next: any) => {\n if (!req.url) return next()\n const url = req.url.split('?')[0]\n if (url.endsWith('.wasm')) {\n res.setHeader('Content-Type', 'application/wasm')\n }\n next()\n })\n },\n }\n}\n\n/**\n * Dev plugin: add Permissions-Policy (delegating WebAuthn + clipboard), COOP, optional COEP/CORP, and optional dev CSP.\n * Where it runs: both app and wallet-iframe dev servers.\n * Notes:\n * - Uses Structured Header format for Permissions-Policy (double-quoted origins).\n * - Wallet dev CSP can be toggled strict/compatible via opts.devCSP.\n */\nexport function tatchiHeaders(opts: DevHeadersOptions = {}): VitePlugin {\n const walletOrigins = normalizeWalletOrigins(\n opts.walletOrigins ?? parseWalletOriginsEnv(process.env.VITE_WALLET_ORIGIN)\n )\n const walletServicePath = toBasePath(opts.walletServicePath || process.env.VITE_WALLET_SERVICE_PATH, '/wallet-service')\n const sdkBasePath = toBasePath(opts.sdkBasePath || process.env.VITE_SDK_BASE_PATH, '/sdk')\n const devCSPMode = (opts.devCSP ?? (process.env.VITE_WALLET_DEV_CSP as 'strict' | 'compatible' | undefined))\n const coepMode = resolveCoepMode(opts.coepMode)\n\n // Build headers via shared helpers to avoid drift.\n const permissionsPolicy = buildPermissionsPolicy(walletOrigins)\n\n // Dev convenience: dynamic ROR from NEAR RPC (no relay dependency)\n // The dev server will fetch the allowlist from chain on demand when a contract id is provided.\n const rorContractId = (process.env.VITE_WEBAUTHN_CONTRACT_ID || '').toString().trim()\n const rorMethod = (process.env.VITE_ROR_METHOD || 'get_allowed_origins').toString().trim()\n const nearRpcUrl = (process.env.VITE_NEAR_RPC_URL || 'https://test.rpc.fastnear.com').toString().trim()\n // Caching is handled inside fetchRorOriginsFromNear via TTL\n\n return {\n name: 'tatchi:dev-headers',\n apply: 'serve',\n enforce: 'pre',\n configureServer(server) {\n\n console.log('[tatchi] headers enabled', {\n walletServicePath,\n sdkBasePath,\n coepMode,\n rorContractId: rorContractId || '(none)',\n nearRpcUrl\n })\n\n server.middlewares.use((req: any, res: any, next: any) => {\n const url = (req.url || '').split('?')[0] || ''\n const isWalletRoute = url === walletServicePath || url === `${walletServicePath}/` || url === `${walletServicePath}//`\n res.setHeader('Cross-Origin-Opener-Policy', isWalletRoute ? 'unsafe-none' : 'same-origin')\n if (coepMode !== 'off') {\n res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')\n res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin')\n }\n res.setHeader('Permissions-Policy', permissionsPolicy)\n // Optional dev-time CSP for the wallet service page only (app pages are unaffected)\n if (isWalletRoute && devCSPMode) {\n const mode = devCSPMode === 'strict' ? 'strict' : 'compatible'\n const walletCsp = buildWalletCsp({ mode })\n res.setHeader('Content-Security-Policy', walletCsp)\n }\n // Resource hints: help parent pages preconnect to the wallet origins early in dev\n addPreconnectLink(res, walletOrigins)\n\n // Serve /.well-known/webauthn for ROR using chain state in dev\n const isWellKnown = url === '/.well-known/webauthn' || url === '/.well-known/webauthn/'\n if (isWellKnown) {\n // Direct fetch from NEAR RPC (no relay). Caching handled inside helper.\n // Requires contract id; RPC URL falls back to a reliable public endpoint.\n if (rorContractId) {\n ;(async () => {\n try {\n const origins = await fetchRorOriginsFromNear({\n rpcUrl: nearRpcUrl,\n contractId: rorContractId,\n method: rorMethod,\n })\n res.statusCode = 200\n res.setHeader('Content-Type', 'application/json; charset=utf-8')\n res.setHeader('Cache-Control', 'max-age=60, stale-while-revalidate=600')\n res.end(JSON.stringify({ origins }))\n } catch (e) {\n console.warn('[tatchi] ROR dynamic fetch failed:', e)\n res.statusCode = 200\n res.setHeader('Content-Type', 'application/json; charset=utf-8')\n res.setHeader('Cache-Control', 'max-age=60, stale-while-revalidate=600')\n res.end(JSON.stringify({ origins: [] }))\n }\n })()\n return\n }\n // No configuration; respond with empty allowlist to avoid hard 404 in dev\n res.statusCode = 200\n res.setHeader('Content-Type', 'application/json; charset=utf-8')\n res.setHeader('Cache-Control', 'max-age=60, stale-while-revalidate=600')\n res.end(JSON.stringify({ origins: [] }))\n return\n }\n\n if (url.startsWith(`${sdkBasePath}/`)) {\n // Dev-only CORS for SDK assets served by Vite\n applyCoepCorpIfNeeded(res, coepMode)\n // Honor existing echo from SDK server; otherwise echo\n const ended = echoCorsFromRequest(res, req, { honorExistingAcaOrigin: true, handlePreflight: true })\n if (ended) return\n }\n next()\n })\n },\n }\n}\n\n/**\n * Dev plugin (composed): convenience entry that wires SDK server, WASM MIME, optional headers,\n * and (in wallet modes) the wallet service route.\n * Where it runs:\n * - App server: mode 'front-only' (or 'self-contained' when serving wallet pages on the same origin).\n * - Wallet-iframe server: modes 'wallet-only' or 'self-contained'.\n */\n/**\n * Compose dev plugins for serving SDK assets, wallet service HTML and dev headers.\n * External-facing entry for configuring either the app or wallet-iframe dev server.\n */\nfunction tatchiDevServer(options: Web3AuthnDevOptions = {}): VitePlugin {\n const mode: Required<Web3AuthnDevOptions>['mode'] = options.mode || 'self-contained'\n const sdkBasePath = toBasePath(options.sdkBasePath || process.env.VITE_SDK_BASE_PATH, '/sdk')\n const walletServicePath = toBasePath(options.walletServicePath || process.env.VITE_WALLET_SERVICE_PATH, '/wallet-service')\n const walletOrigins = normalizeWalletOrigins(\n options.walletOrigins ?? parseWalletOriginsEnv(process.env.VITE_WALLET_ORIGIN)\n )\n const setDevHeaders = options.setDevHeaders !== false // default true\n const enableDebugRoutes = options.enableDebugRoutes === true\n const sdkDistRoot = resolveSdkDistRoot(options.sdkDistRoot)\n const coepMode = resolveCoepMode(options.coepMode)\n\n // Build the sub-plugins to keep logic small and testable\n const sdkPlugin = tatchiServeSdk({ sdkBasePath, sdkDistRoot, enableDebugRoutes, coepMode })\n const walletPlugin = tatchiWalletService({ walletServicePath, sdkBasePath, coepMode })\n const wasmMimePlugin = tatchiWasmMime()\n // Flip wallet CSP to strict by default in dev. Consumers can override via\n // VITE_WALLET_DEV_CSP or by composing tatchiHeaders directly.\n const headersPlugin = setDevHeaders\n ? tatchiHeaders({ walletOrigins, walletServicePath, sdkBasePath, devCSP: 'strict', coepMode })\n : undefined\n\n return {\n name: 'tatchi:dev',\n apply: 'serve',\n enforce: 'pre',\n configureServer(server) {\n // Always add WASM MIME + SDK server\n sdkPlugin.configureServer?.(server)\n wasmMimePlugin.configureServer?.(server)\n if (headersPlugin) headersPlugin.configureServer?.(server)\n\n // Mode-specific wallet service route\n if (mode === 'self-contained' || mode === 'wallet-only') {\n walletPlugin.configureServer?.(server)\n }\n },\n }\n}\n\n// === Build-time helper: emit Cloudflare Pages/Netlify _headers ===\n// This plugin writes a _headers file into Vite's outDir with COOP and optional COEP and a\n// Permissions-Policy delegating WebAuthn to the configured wallet origins.\n// It is a no-op if a _headers file already exists (to avoid overriding app settings).\n/**\n * Build-time plugin: writes a Cloudflare Pages/Netlify-compatible `_headers` file into Vite's `outDir`.\n * Adds COOP + Permissions-Policy and optional COEP/CORP (configurable via coepMode) delegating WebAuthn to the configured wallet origins.\n * Where it runs: build for either the app or a static wallet host (not used in dev).\n * Notes: no-ops if `_headers` already exists in `outDir` (to avoid overriding platform config).\n */\nexport function tatchiBuildHeaders(opts: { walletOrigins?: string[], cors?: { accessControlAllowOrigin?: string }, coepMode?: 'strict' | 'off' } = {}): VitePlugin {\n const walletOrigins = normalizeWalletOrigins(\n opts.walletOrigins ?? parseWalletOriginsEnv(process.env.VITE_WALLET_ORIGIN)\n )\n const walletServicePath = toBasePath(process.env.VITE_WALLET_SERVICE_PATH, '/wallet-service')\n const sdkBasePath = toBasePath(process.env.VITE_SDK_BASE_PATH, '/sdk')\n const coepMode = resolveCoepMode(opts.coepMode)\n\n // Build headers via shared helpers to avoid drift between frameworks\n const permissionsPolicy = buildPermissionsPolicy(walletOrigins)\n const walletCsp = buildWalletCsp({ mode: 'strict' })\n\n let outDir = 'dist'\n\n // We intentionally return a broader shape than VitePlugin; cast at the end\n const plugin = {\n name: 'tatchi:build-headers',\n apply: 'build' as const,\n enforce: 'post' as const,\n // Capture the resolved outDir\n configResolved(config: any) {\n outDir = (config?.build?.outDir as string) || outDir\n },\n generateBundle() {\n try {\n const hdrPath = path.join(outDir, '_headers')\n if (fs.existsSync(hdrPath)) {\n // Do not override existing headers; leave a note in build logs\n console.warn('[tatchi] _headers already exists in outDir; skipping auto-emission')\n } else {\n // Strict CSP is emitted only for wallet HTML routes; not for app pages.\n const contentLines: string[] = [\n '/*',\n ' Cross-Origin-Opener-Policy: same-origin',\n ...(coepMode === 'off'\n ? []\n : [\n ' Cross-Origin-Embedder-Policy: require-corp',\n ' Cross-Origin-Resource-Policy: cross-origin',\n ]),\n ` Permissions-Policy: ${permissionsPolicy}`,\n '',\n `${walletServicePath}`,\n ' Cross-Origin-Opener-Policy: unsafe-none',\n // Always allow COEP=require-corp apps to embed wallet HTML, even when\n // the wallet host itself is not using COEP.\n ' Cross-Origin-Resource-Policy: cross-origin',\n ` Permissions-Policy: ${permissionsPolicy}`,\n ` Content-Security-Policy: ${walletCsp}`,\n `${walletServicePath}/`,\n ' Cross-Origin-Opener-Policy: unsafe-none',\n ' Cross-Origin-Resource-Policy: cross-origin',\n ` Permissions-Policy: ${permissionsPolicy}`,\n ` Content-Security-Policy: ${walletCsp}`,\n '/export-viewer',\n ' Cross-Origin-Opener-Policy: unsafe-none',\n ' Cross-Origin-Resource-Policy: cross-origin',\n ` Permissions-Policy: ${permissionsPolicy}`,\n '/export-viewer/',\n ' Cross-Origin-Opener-Policy: unsafe-none',\n ' Cross-Origin-Resource-Policy: cross-origin',\n ` Permissions-Policy: ${permissionsPolicy}`,\n // Offline export cache policy (no-cache for HTML/SW; immutable for other assets)\n '/offline-export',\n ' Cache-Control: no-cache',\n '/offline-export/',\n ' Cache-Control: no-cache',\n '/offline-export/index.html',\n ' Cache-Control: no-cache',\n '/offline-export/sw.js',\n ' Cache-Control: no-cache',\n '/offline-export/precache.manifest.json',\n ' Cache-Control: no-cache',\n '/offline-export/manifest.webmanifest',\n ' Cache-Control: no-cache',\n '/offline-export/offline-export-app.js',\n ' Cache-Control: no-cache',\n '/offline-export/*',\n ' Cache-Control: public, max-age=31536000, immutable',\n ]\n // Optional: emit CORS headers when explicitly configured via plugin option.\n // Prefer a single source of truth (platform or plugin), not both.\n const configuredAcaOrigin = (opts.cors && typeof opts.cors.accessControlAllowOrigin === 'string'\n ? opts.cors.accessControlAllowOrigin.trim()\n : undefined) as string | undefined;\n if (configuredAcaOrigin) {\n contentLines.push(\n `${sdkBasePath}/*`,\n ` Access-Control-Allow-Origin: ${configuredAcaOrigin}`,\n )\n }\n const content = contentLines.join('\\n') + '\\n'\n fs.mkdirSync(outDir, { recursive: true })\n fs.writeFileSync(hdrPath, content, 'utf-8')\n console.log('[tatchi] emitted _headers with COOP' + (coepMode === 'off' ? '' : '/COEP/CORP') + ' + Permissions-Policy' + (configuredAcaOrigin ? ' + CORS' : ''))\n }\n\n const sdkDir = path.join(outDir, sdkBasePath.replace(/^\\//, ''))\n try { fs.mkdirSync(sdkDir, { recursive: true }) } catch {}\n const shimPath = path.join(sdkDir, 'wallet-shims.js')\n if (!fs.existsSync(shimPath)) {\n fs.writeFileSync(shimPath, WALLET_SHIM_SOURCE, 'utf-8')\n }\n const cssPath = path.join(sdkDir, 'wallet-service.css')\n if (!fs.existsSync(cssPath)) {\n fs.writeFileSync(cssPath, WALLET_SURFACE_CSS, 'utf-8')\n }\n\n // Emit minimal wallet-service/index.html if the app hasn't provided one\n const walletRel = walletServicePath.replace(/^\\//, '')\n const wsDir = path.join(outDir, walletRel)\n const wsHtml = path.join(wsDir, 'index.html')\n if (!fs.existsSync(wsHtml)) {\n fs.mkdirSync(wsDir, { recursive: true })\n fs.writeFileSync(wsHtml, buildWalletServiceHtml(sdkBasePath), 'utf-8')\n console.log(`[tatchi] emitted ${path.posix.join('/', walletRel, 'index.html')} (minimal wallet service)`)\n }\n\n // Emit minimal export viewer HTML for production\n const evDir = path.join(outDir, 'export-viewer')\n const evHtml = path.join(evDir, 'index.html')\n if (!fs.existsSync(evHtml)) {\n fs.mkdirSync(evDir, { recursive: true })\n fs.writeFileSync(evHtml, buildExportViewerHtml(sdkBasePath), 'utf-8')\n console.log('[tatchi] emitted /export-viewer/index.html (minimal export viewer)')\n }\n\n // Emit offline-export assets (SW, workers, app, HTML, manifest, precache) via helper\n try {\n const sdkDistRoot = resolveSdkDistRoot()\n emitOfflineExportAssets({ outDir, sdkBasePath, sdkDistRoot })\n } catch (e) {\n console.warn('[tatchi] failed to emit offline-export assets:', e)\n }\n } catch (e) {\n console.warn('[tatchi] failed to emit _headers:', e)\n }\n },\n }\n\n return plugin as unknown as VitePlugin\n}\n\n// Small test helpers to keep unit tests decoupled from Vite server implementation\nexport function computeDevPermissionsPolicy(walletOrigins?: string[]): string {\n return buildPermissionsPolicy(walletOrigins)\n}\n\nexport function computeDevWalletCsp(mode: 'strict' | 'compatible' = 'strict'): string {\n return buildWalletCsp({ mode })\n}\n\nexport function tatchiWalletServer(options: Omit<Web3AuthnDevOptions, 'mode'> = {}): VitePlugin {\n return tatchiDevServer({ ...options, mode: 'wallet-only' })\n}\n\nexport function tatchiAppServer(options: Omit<Web3AuthnDevOptions, 'mode'> = {}): VitePlugin {\n return tatchiDevServer({ ...options, mode: 'front-only' })\n}\n\n/**\n * Convenience wrapper: app origin helper that combines dev-time headers with optional\n * build-time headers emission for static hosts.\n *\n * Dev-time (serve): applies COOP + Permissions-Policy, plus optional COEP/CORP, via tatchiAppServer.\n * Build-time (build): when `emitHeaders` is true, writes a Cloudflare Pages/Netlify\n * `_headers` file into Vite's `outDir` via tatchiBuildHeaders, scoping strict CSP to\n * wallet HTML routes only.\n * - Emits: `COOP: same-origin`, `Permissions-Policy: …`, and (when `coepMode === 'strict'`) `COEP: require-corp` + `CORP: cross-origin`.\n * - No-op if a `_headers` file already exists in `outDir` (avoids clobbering CI/platform rules).\n *\n * Notes\n * - Keeps production header emission opt-in to avoid surprising overrides when apps\n * already manage headers via custom servers or platform rules.\n * - Returns a plugin array for ergonomics; Vite accepts arrays in the `plugins` list.\n */\nexport function tatchiApp(options: Omit<Web3AuthnDevOptions, 'mode'> & { emitHeaders?: boolean } = {}): any[] /* Vite Plugin[] */ {\n const { emitHeaders, ...devOpts } = options\n const walletOrigins = normalizeWalletOrigins(\n devOpts.walletOrigins ?? parseWalletOriginsEnv(process.env.VITE_WALLET_ORIGIN)\n )\n const app = tatchiAppServer(devOpts)\n // Build-time emission is opt-in and will no-op if `_headers` already exists.\n const hdr = emitHeaders ? tatchiBuildHeaders({ walletOrigins, coepMode: devOpts.coepMode }) : undefined\n return [app, hdr].filter(Boolean) as any[]\n}\n\n/**\n * Convenience wrapper: wallet origins helper that combines dev-time wallet server\n * with optional build-time headers emission for static hosts.\n *\n * Dev-time (serve): serves `/wallet-service` and `/sdk/*` plus headers via tatchiWalletServer.\n * Build-time (build): when `emitHeaders` is true, writes a Cloudflare Pages/Netlify\n * `_headers` file into Vite's `outDir` via tatchiBuildHeaders, scoping strict CSP to\n * wallet HTML routes only.\n * - Emits: `COOP: same-origin` (wallet HTML routes use `unsafe-none`), `Permissions-Policy: …`, and (when `coepMode === 'strict'`) `COEP: require-corp` + `CORP: cross-origin`.\n * - No-op if a `_headers` file already exists in `outDir` (avoids clobbering CI/platform rules).\n *\n * Notes\n * - Keeps production header emission opt-in to avoid overriding platform/server configs.\n * - Returns a plugin array for ergonomics; Vite accepts arrays in the `plugins` list.\n */\nexport function tatchiWallet(options: Omit<Web3AuthnDevOptions, 'mode'> & { emitHeaders?: boolean } = {}): any[] /* Vite Plugin[] */ {\n const { emitHeaders, ...devOpts } = options\n const walletOrigins = normalizeWalletOrigins(\n devOpts.walletOrigins ?? parseWalletOriginsEnv(process.env.VITE_WALLET_ORIGIN)\n )\n const wallet = tatchiWalletServer(devOpts)\n // Build-time emission is opt-in and will no-op if `_headers` already exists.\n const hdr = emitHeaders ? tatchiBuildHeaders({ walletOrigins, coepMode: devOpts.coepMode }) : undefined\n return [wallet, hdr].filter(Boolean) as any[]\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"vite.js","names":["out: string[]","toOriginOrUndefined","fs","path","toBasePath","resolveSdkDistRoot","resolveCoepMode","buildOfflineExportHtml","buildWalletServiceHtml","buildPermissionsPolicy","buildWalletCsp","fetchRorOriginsFromNear","echoCorsFromRequest","mode: Required<Web3AuthnDevOptions>['mode']","contentLines: string[]","buildExportViewerHtml"],"sources":["../../../src/plugins/vite.ts"],"sourcesContent":["// Minimal Vite dev plugin(s) to support Passkey Manager modes.\n// See docs/passkey-manager-modes.md (Vite Plugin section).\n//\n// What these plugins do:\n// - Serve SDK assets under a base path, expose a wallet service route,\n// - Add dev headers (COOP + Permissions-Policy, optional COEP/CORP), and enforce WASM MIME.\n// - IMPORTANT: Strict CSP is scoped only to wallet HTML routes (/wallet-service, /export-viewer),\n// not to the host app pages. App routes remain free to use inline styles/scripts.\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { buildPermissionsPolicy, buildWalletCsp } from './headers'\nimport { toOriginOrUndefined } from '../utils/validation'\nimport {\n addPreconnectLink,\n buildWalletServiceHtml,\n buildExportViewerHtml,\n applyCoepCorpIfNeeded,\n echoCorsFromRequest,\n fetchRorOriginsFromNear,\n toBasePath,\n resolveCoepMode,\n resolveSdkDistRoot,\n} from './plugin-utils'\nimport { addOfflineExportDevRoutes, buildOfflineExportHtml, emitOfflineExportAssets } from './offline'\nimport { setContentType } from './plugin-utils'\n\nexport type VitePlugin = {\n name: string\n apply?: 'serve' | 'build'\n enforce?: 'pre' | 'post'\n configureServer?: (server: any) => void | Promise<void>\n}\nexport type ViteLikePlugin = VitePlugin\n\nexport type Web3AuthnDevOptions = {\n mode?: 'self-contained' | 'front-only' | 'wallet-only'\n sdkDistRoot?: string\n sdkBasePath?: string\n walletServicePath?: string\n walletOrigins?: string[]\n setDevHeaders?: boolean\n enableDebugRoutes?: boolean\n /**\n * Controls Cross-Origin-Embedder-Policy (COEP) behavior in dev.\n * - 'off' (default): do not emit COEP/CORP on app pages.\n * - 'strict': emit `Cross-Origin-Embedder-Policy: require-corp`\n * and `Cross-Origin-Resource-Policy: cross-origin` on app pages.\n *\n * Tip: set `VITE_COEP_MODE=strict` in tests/CI to enable isolation automatically.\n */\n coepMode?: 'strict' | 'off'\n}\n\nexport type ServeSdkOptions = {\n sdkDistRoot?: string\n sdkBasePath?: string\n enableDebugRoutes?: boolean\n coepMode?: 'strict' | 'off'\n}\n\nexport type WalletServiceOptions = {\n walletServicePath?: string\n sdkBasePath?: string\n coepMode?: 'strict' | 'off'\n}\n\nexport type DevHeadersOptions = {\n walletOrigins?: string[]\n walletServicePath?: string\n sdkBasePath?: string\n /**\n * Optional dev-time CSP for the wallet service route.\n * - 'strict': no inline scripts/styles (mirrors production defaults)\n * - 'compatible': allows inline scripts/styles (useful for debugging)\n */\n devCSP?: 'strict' | 'compatible'\n /**\n * Controls Cross-Origin-Embedder-Policy (COEP) behavior in dev.\n * - 'off' (default): do not emit COEP/CORP headers on app pages.\n * - 'strict': emit COEP/CORP headers on app pages.\n */\n coepMode?: 'strict' | 'off'\n}\n\nfunction normalizeWalletOrigins(walletOrigins?: string[]): string[] {\n if (!Array.isArray(walletOrigins) || walletOrigins.length === 0) return []\n const out: string[] = []\n const seen = new Set<string>()\n for (const origin of walletOrigins) {\n const normalized = toOriginOrUndefined(origin)\n if (!normalized || seen.has(normalized)) continue\n seen.add(normalized)\n out.push(normalized)\n }\n return out\n}\n\nfunction parseWalletOriginsEnv(value: unknown): string[] | undefined {\n if (typeof value !== 'string') return undefined\n const raw = value.trim()\n if (!raw) return undefined\n const parts = raw.split(/[,\\s]+/).map((v) => v.trim()).filter(Boolean)\n const origins = normalizeWalletOrigins(parts)\n return origins.length ? origins : undefined\n}\n\n/**\n * Return the first candidate path that exists and is a file.\n * Helper for robust /sdk/* asset resolution on dev servers (app and wallet).\n */\nfunction tryFile(...candidates: string[]): string | undefined {\n for (const file of candidates) {\n try {\n const stat = fs.statSync(file)\n if (stat.isFile()) return file\n } catch {}\n }\n return undefined\n}\n\n// Dev convenience: allow Vite's cacheDir so `/@fs/.../deps/*.js` dynamic imports can load under `server.fs.strict`.\nfunction ensureViteCacheDirAllowed(server: any): void {\n const config = server?.config\n const cacheDir = config?.cacheDir\n const fsConfig = config?.server?.fs\n const allow = fsConfig?.allow\n if (!cacheDir || fsConfig?.strict === false || !Array.isArray(allow)) return\n\n const absCacheDir = path.resolve(String(cacheDir))\n if (!allow.some((p: any) => path.resolve(String(p)) === absCacheDir)) {\n allow.push(absCacheDir)\n }\n}\n\n// Shared assets emitted/served for the wallet service bootstrap.\nconst WALLET_SHIM_SOURCE = \"window.global ||= window; window.process ||= { env: {} };\\n\"\nconst WALLET_SURFACE_CSS = [\n 'html, body { background: transparent !important; margin:0; padding:0; }',\n 'html, body { color-scheme: normal; }',\n '',\n // Class-based surface for strict CSP setups toggled by JS\n 'html.w3a-transparent, body.w3a-transparent { background: transparent !important; margin:0; padding:0; color-scheme: normal; }',\n '',\n // Minimal portal styles used by confirm-ui (no animation; child components handle transitions)\n '.w3a-portal { position: relative; z-index: 2147483647; opacity: 0; pointer-events: none; }',\n '.w3a-portal.w3a-portal--visible { opacity: 1; pointer-events: auto; }',\n '',\n // Provide baseline tokens only when the document does not declare a theme.\n // This avoids overriding :root[data-w3a-theme] values supplied by token sheet\n // or integrator-injected themes.\n ':root:not([data-w3a-theme]) {',\n ' --w3a-colors-textPrimary: #f6f7f8;',\n ' --w3a-colors-textSecondary: rgba(255,255,255,0.7);',\n ' --w3a-colors-surface: rgba(255,255,255,0.08);',\n ' --w3a-colors-surface2: rgba(255,255,255,0.06);',\n ' --w3a-colors-surface3: rgba(255,255,255,0.04);',\n ' --w3a-colors-borderPrimary: rgba(255,255,255,0.14);',\n ' --w3a-colors-borderSecondary: rgba(255,255,255,0.1);',\n ' --w3a-colors-colorBackground: #0b0c10;',\n ' /* Default viewport custom properties for width/height calculations */',\n ' --w3a-vw: 100vw;',\n ' --w3a-vh: 100vh;',\n '}',\n '',\n].join('\\n')\n\n/**\n * Tatchi SDK plugin: serve SDK assets under a stable base (default: /sdk) with optional COEP/CORP (strict mode) and permissive CORS.\n * Where it runs: both the app server and the wallet-iframe server.\n * - App server: lets host pages and Lit components load SDK CSS/JS locally.\n * - Wallet server: used by /wallet-service to load wallet-iframe-host.js and related CSS/JS.\n */\nexport function tatchiServeSdk(opts: ServeSdkOptions = {}): VitePlugin {\n const configuredBase = toBasePath(opts.sdkBasePath, '/sdk')\n const sdkDistRoot = resolveSdkDistRoot(opts.sdkDistRoot)\n const enableDebugRoutes = opts.enableDebugRoutes === true\n const coepMode = resolveCoepMode(opts.coepMode)\n const offlineHtml = buildOfflineExportHtml(configuredBase)\n\n // In dev we want both '/sdk' and a custom base to work.\n const bases = Array.from(new Set([configuredBase, toBasePath('/sdk')]))\n .sort((a, b) => b.length - a.length)\n // Prefer longest base match first (e.g., '/sdk/esm/react' before '/sdk')\n\n return {\n name: 'tatchi:serve-sdk',\n apply: 'serve',\n enforce: 'pre',\n configureServer(server) {\n ensureViteCacheDirAllowed(server)\n\n // Mount Offline Export dev routes once here (includes app module + chunks)\n addOfflineExportDevRoutes(server, {\n sdkDistRoot,\n sdkBasePath: configuredBase,\n offlineHtml,\n includeAppModule: true,\n coepMode,\n })\n // Serve a tiny shim as a virtual asset to enable strict CSP (no inline scripts)\n server.middlewares.use((req: any, res: any, next: any) => {\n const url = (req.url || '').split('?')[0]\n if (url === configuredBase + '/wallet-shims.js') {\n res.statusCode = 200\n res.setHeader('Content-Type', 'application/javascript; charset=utf-8')\n // Align with SDK asset headers so COEP/CORP environments can import\n applyCoepCorpIfNeeded(res, coepMode)\n // Dev-only CORS echo (no preflight handling on this route)\n echoCorsFromRequest(res, req, { handlePreflight: false })\n res.end(WALLET_SHIM_SOURCE)\n return\n }\n if (url === configuredBase + '/wallet-service.css') {\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/css; charset=utf-8')\n // Important: provide CORP for cross‑origin CSS so COEP documents can load it\n applyCoepCorpIfNeeded(res, coepMode)\n // Dev-only CORS echo (no preflight handling on this route)\n echoCorsFromRequest(res, req, { handlePreflight: false })\n res.end(WALLET_SURFACE_CSS)\n return\n }\n next()\n })\n\n // Optional debug route to confirm resolution\n if (enableDebugRoutes) {\n server.middlewares.use('/__sdk-root', (req: any, res: any) => {\n res.setHeader('Content-Type', 'text/plain; charset=utf-8')\n res.end(sdkDistRoot)\n })\n }\n\n // Serve files under any recognized base from sdkDistRoot with fallbacks\n server.middlewares.use((req: any, res: any, next: any) => {\n if (!req.url) return next()\n const url = req.url.split('?')[0]\n\n const matchBase = bases.find((b) => url.startsWith(b + '/'))\n if (!matchBase) return next()\n\n const rel = url.slice((matchBase + '/').length)\n // Try dist/esm/sdk first (canonical), then common fallbacks\n const candidate = tryFile(\n path.join(sdkDistRoot, 'esm', 'sdk', rel),\n path.join(sdkDistRoot, rel),\n path.join(sdkDistRoot, 'esm', rel)\n )\n\n if (!candidate) {\n res.statusCode = 404\n res.setHeader('Content-Type', 'application/json; charset=utf-8')\n res.end(JSON.stringify({ error: 'SDK asset not found', path: rel }))\n return\n }\n\n setContentType(res, candidate)\n // SDK assets need COEP headers to work in wallet iframe with COEP enabled\n applyCoepCorpIfNeeded(res, coepMode)\n // Dev-only CORS echo (no preflight handling here)\n echoCorsFromRequest(res, req, { handlePreflight: false })\n const stream = fs.createReadStream(candidate)\n stream.on('error', () => next())\n stream.pipe(res)\n })\n },\n }\n}\n\n/**\n * Dev plugin: expose the wallet service HTML route (default: /wallet-service) that links only external CSS/JS.\n * Where it runs: wallet-iframe dev server (wallet origins). Used by tatchiWalletServer.\n */\nexport function tatchiWalletService(opts: WalletServiceOptions = {}): VitePlugin {\n const walletServicePath = toBasePath(opts.walletServicePath, '/wallet-service')\n const sdkBasePath = toBasePath(opts.sdkBasePath, '/sdk')\n const coepMode = resolveCoepMode(opts.coepMode)\n\n const html = buildWalletServiceHtml(sdkBasePath)\n const offlineHtml = buildOfflineExportHtml(sdkBasePath)\n const sdkDistRoot = resolveSdkDistRoot()\n\n return {\n name: 'tatchi:wallet-service',\n apply: 'serve',\n enforce: 'pre',\n configureServer(server) {\n ensureViteCacheDirAllowed(server)\n\n server.middlewares.use((req: any, res: any, next: any) => {\n if (!req.url) return next()\n const url = req.url.split('?')[0]\n const isWalletRoute = url === walletServicePath || url === `${walletServicePath}/` || url === `${walletServicePath}//`\n if (isWalletRoute) {\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html; charset=utf-8')\n // Important: allow embedding this wallet HTML into COEP=require-corp apps even\n // when the wallet itself is not running with COEP enabled.\n // Without CORP, the iframe can be blocked and remain on an opaque 'null' origin,\n // causing CONNECT/READY handshake timeouts in the parent.\n res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin')\n applyCoepCorpIfNeeded(res, coepMode)\n res.end(html)\n return\n }\n next()\n })\n\n // Mount Offline Export routes here as well (no app module duplication)\n addOfflineExportDevRoutes(server, {\n sdkDistRoot,\n sdkBasePath,\n offlineHtml,\n includeAppModule: false,\n coepMode,\n })\n },\n }\n}\n\n/**\n * Dev plugin: force the correct `.wasm` MIME type (application/wasm) for any served wasm file.\n * Where it runs: both app and wallet-iframe dev servers.\n */\nexport function tatchiWasmMime(): VitePlugin {\n return {\n name: 'tatchi:wasm-mime',\n apply: 'serve',\n enforce: 'pre',\n configureServer(server) {\n ensureViteCacheDirAllowed(server)\n\n server.middlewares.use((req: any, res: any, next: any) => {\n if (!req.url) return next()\n const url = req.url.split('?')[0]\n if (url.endsWith('.wasm')) {\n res.setHeader('Content-Type', 'application/wasm')\n }\n next()\n })\n },\n }\n}\n\n/**\n * Dev plugin: add Permissions-Policy (delegating WebAuthn + clipboard), COOP, optional COEP/CORP, and optional dev CSP.\n * Where it runs: both app and wallet-iframe dev servers.\n * Notes:\n * - Uses Structured Header format for Permissions-Policy (double-quoted origins).\n * - Wallet dev CSP can be toggled strict/compatible via opts.devCSP.\n */\nexport function tatchiHeaders(opts: DevHeadersOptions = {}): VitePlugin {\n const walletOrigins = normalizeWalletOrigins(\n opts.walletOrigins ?? parseWalletOriginsEnv(process.env.VITE_WALLET_ORIGIN)\n )\n const walletServicePath = toBasePath(opts.walletServicePath || process.env.VITE_WALLET_SERVICE_PATH, '/wallet-service')\n const sdkBasePath = toBasePath(opts.sdkBasePath || process.env.VITE_SDK_BASE_PATH, '/sdk')\n const devCSPMode = (opts.devCSP ?? (process.env.VITE_WALLET_DEV_CSP as 'strict' | 'compatible' | undefined))\n const coepMode = resolveCoepMode(opts.coepMode)\n\n // Build headers via shared helpers to avoid drift.\n const permissionsPolicy = buildPermissionsPolicy(walletOrigins)\n\n // Dev convenience: dynamic ROR from NEAR RPC (no relay dependency)\n // The dev server will fetch the allowlist from chain on demand when a contract id is provided.\n const rorContractId = (process.env.VITE_WEBAUTHN_CONTRACT_ID || '').toString().trim()\n const rorMethod = (process.env.VITE_ROR_METHOD || 'get_allowed_origins').toString().trim()\n const nearRpcUrl = (process.env.VITE_NEAR_RPC_URL || 'https://test.rpc.fastnear.com').toString().trim()\n // Caching is handled inside fetchRorOriginsFromNear via TTL\n\n return {\n name: 'tatchi:dev-headers',\n apply: 'serve',\n enforce: 'pre',\n configureServer(server) {\n ensureViteCacheDirAllowed(server)\n\n console.log('[tatchi] headers enabled', {\n walletServicePath,\n sdkBasePath,\n coepMode,\n rorContractId: rorContractId || '(none)',\n nearRpcUrl\n })\n\n server.middlewares.use((req: any, res: any, next: any) => {\n const url = (req.url || '').split('?')[0] || ''\n const isWalletRoute = url === walletServicePath || url === `${walletServicePath}/` || url === `${walletServicePath}//`\n res.setHeader('Cross-Origin-Opener-Policy', isWalletRoute ? 'unsafe-none' : 'same-origin')\n if (coepMode !== 'off') {\n res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')\n res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin')\n }\n res.setHeader('Permissions-Policy', permissionsPolicy)\n // Optional dev-time CSP for the wallet service page only (app pages are unaffected)\n if (isWalletRoute && devCSPMode) {\n const mode = devCSPMode === 'strict' ? 'strict' : 'compatible'\n const walletCsp = buildWalletCsp({ mode })\n res.setHeader('Content-Security-Policy', walletCsp)\n }\n // Resource hints: help parent pages preconnect to the wallet origins early in dev\n addPreconnectLink(res, walletOrigins)\n\n // Serve /.well-known/webauthn for ROR using chain state in dev\n const isWellKnown = url === '/.well-known/webauthn' || url === '/.well-known/webauthn/'\n if (isWellKnown) {\n // Direct fetch from NEAR RPC (no relay). Caching handled inside helper.\n // Requires contract id; RPC URL falls back to a reliable public endpoint.\n if (rorContractId) {\n ;(async () => {\n try {\n const origins = await fetchRorOriginsFromNear({\n rpcUrl: nearRpcUrl,\n contractId: rorContractId,\n method: rorMethod,\n })\n res.statusCode = 200\n res.setHeader('Content-Type', 'application/json; charset=utf-8')\n res.setHeader('Cache-Control', 'max-age=60, stale-while-revalidate=600')\n res.end(JSON.stringify({ origins }))\n } catch (e) {\n console.warn('[tatchi] ROR dynamic fetch failed:', e)\n res.statusCode = 200\n res.setHeader('Content-Type', 'application/json; charset=utf-8')\n res.setHeader('Cache-Control', 'max-age=60, stale-while-revalidate=600')\n res.end(JSON.stringify({ origins: [] }))\n }\n })()\n return\n }\n // No configuration; respond with empty allowlist to avoid hard 404 in dev\n res.statusCode = 200\n res.setHeader('Content-Type', 'application/json; charset=utf-8')\n res.setHeader('Cache-Control', 'max-age=60, stale-while-revalidate=600')\n res.end(JSON.stringify({ origins: [] }))\n return\n }\n\n if (url.startsWith(`${sdkBasePath}/`)) {\n // Dev-only CORS for SDK assets served by Vite\n applyCoepCorpIfNeeded(res, coepMode)\n // Honor existing echo from SDK server; otherwise echo\n const ended = echoCorsFromRequest(res, req, { honorExistingAcaOrigin: true, handlePreflight: true })\n if (ended) return\n }\n next()\n })\n },\n }\n}\n\n/**\n * Dev plugin (composed): convenience entry that wires SDK server, WASM MIME, optional headers,\n * and (in wallet modes) the wallet service route.\n * Where it runs:\n * - App server: mode 'front-only' (or 'self-contained' when serving wallet pages on the same origin).\n * - Wallet-iframe server: modes 'wallet-only' or 'self-contained'.\n */\n/**\n * Compose dev plugins for serving SDK assets, wallet service HTML and dev headers.\n * External-facing entry for configuring either the app or wallet-iframe dev server.\n */\nfunction tatchiDevServer(options: Web3AuthnDevOptions = {}): VitePlugin {\n const mode: Required<Web3AuthnDevOptions>['mode'] = options.mode || 'self-contained'\n const sdkBasePath = toBasePath(options.sdkBasePath || process.env.VITE_SDK_BASE_PATH, '/sdk')\n const walletServicePath = toBasePath(options.walletServicePath || process.env.VITE_WALLET_SERVICE_PATH, '/wallet-service')\n const walletOrigins = normalizeWalletOrigins(\n options.walletOrigins ?? parseWalletOriginsEnv(process.env.VITE_WALLET_ORIGIN)\n )\n const setDevHeaders = options.setDevHeaders !== false // default true\n const enableDebugRoutes = options.enableDebugRoutes === true\n const sdkDistRoot = resolveSdkDistRoot(options.sdkDistRoot)\n const coepMode = resolveCoepMode(options.coepMode)\n\n // Build the sub-plugins to keep logic small and testable\n const sdkPlugin = tatchiServeSdk({ sdkBasePath, sdkDistRoot, enableDebugRoutes, coepMode })\n const walletPlugin = tatchiWalletService({ walletServicePath, sdkBasePath, coepMode })\n const wasmMimePlugin = tatchiWasmMime()\n // Flip wallet CSP to strict by default in dev. Consumers can override via\n // VITE_WALLET_DEV_CSP or by composing tatchiHeaders directly.\n const headersPlugin = setDevHeaders\n ? tatchiHeaders({ walletOrigins, walletServicePath, sdkBasePath, devCSP: 'strict', coepMode })\n : undefined\n\n return {\n name: 'tatchi:dev',\n apply: 'serve',\n enforce: 'pre',\n configureServer(server) {\n ensureViteCacheDirAllowed(server)\n\n // Always add WASM MIME + SDK server\n sdkPlugin.configureServer?.(server)\n wasmMimePlugin.configureServer?.(server)\n if (headersPlugin) headersPlugin.configureServer?.(server)\n\n // Mode-specific wallet service route\n if (mode === 'self-contained' || mode === 'wallet-only') {\n walletPlugin.configureServer?.(server)\n }\n },\n }\n}\n\n// === Build-time helper: emit Cloudflare Pages/Netlify _headers ===\n// This plugin writes a _headers file into Vite's outDir with COOP and optional COEP and a\n// Permissions-Policy delegating WebAuthn to the configured wallet origins.\n// It is a no-op if a _headers file already exists (to avoid overriding app settings).\n/**\n * Build-time plugin: writes a Cloudflare Pages/Netlify-compatible `_headers` file into Vite's `outDir`.\n * Adds COOP + Permissions-Policy and optional COEP/CORP (configurable via coepMode) delegating WebAuthn to the configured wallet origins.\n * Where it runs: build for either the app or a static wallet host (not used in dev).\n * Notes: no-ops if `_headers` already exists in `outDir` (to avoid overriding platform config).\n */\nexport function tatchiBuildHeaders(opts: { walletOrigins?: string[], cors?: { accessControlAllowOrigin?: string }, coepMode?: 'strict' | 'off' } = {}): VitePlugin {\n const walletOrigins = normalizeWalletOrigins(\n opts.walletOrigins ?? parseWalletOriginsEnv(process.env.VITE_WALLET_ORIGIN)\n )\n const walletServicePath = toBasePath(process.env.VITE_WALLET_SERVICE_PATH, '/wallet-service')\n const sdkBasePath = toBasePath(process.env.VITE_SDK_BASE_PATH, '/sdk')\n const coepMode = resolveCoepMode(opts.coepMode)\n\n // Build headers via shared helpers to avoid drift between frameworks\n const permissionsPolicy = buildPermissionsPolicy(walletOrigins)\n const walletCsp = buildWalletCsp({ mode: 'strict' })\n\n let outDir = 'dist'\n\n // We intentionally return a broader shape than VitePlugin; cast at the end\n const plugin = {\n name: 'tatchi:build-headers',\n apply: 'build' as const,\n enforce: 'post' as const,\n // Capture the resolved outDir\n configResolved(config: any) {\n outDir = (config?.build?.outDir as string) || outDir\n },\n generateBundle() {\n try {\n const hdrPath = path.join(outDir, '_headers')\n if (fs.existsSync(hdrPath)) {\n // Do not override existing headers; leave a note in build logs\n console.warn('[tatchi] _headers already exists in outDir; skipping auto-emission')\n } else {\n // Strict CSP is emitted only for wallet HTML routes; not for app pages.\n const contentLines: string[] = [\n '/*',\n ' Cross-Origin-Opener-Policy: same-origin',\n ...(coepMode === 'off'\n ? []\n : [\n ' Cross-Origin-Embedder-Policy: require-corp',\n ' Cross-Origin-Resource-Policy: cross-origin',\n ]),\n ` Permissions-Policy: ${permissionsPolicy}`,\n '',\n `${walletServicePath}`,\n ' Cross-Origin-Opener-Policy: unsafe-none',\n // Always allow COEP=require-corp apps to embed wallet HTML, even when\n // the wallet host itself is not using COEP.\n ' Cross-Origin-Resource-Policy: cross-origin',\n ` Permissions-Policy: ${permissionsPolicy}`,\n ` Content-Security-Policy: ${walletCsp}`,\n `${walletServicePath}/`,\n ' Cross-Origin-Opener-Policy: unsafe-none',\n ' Cross-Origin-Resource-Policy: cross-origin',\n ` Permissions-Policy: ${permissionsPolicy}`,\n ` Content-Security-Policy: ${walletCsp}`,\n '/export-viewer',\n ' Cross-Origin-Opener-Policy: unsafe-none',\n ' Cross-Origin-Resource-Policy: cross-origin',\n ` Permissions-Policy: ${permissionsPolicy}`,\n '/export-viewer/',\n ' Cross-Origin-Opener-Policy: unsafe-none',\n ' Cross-Origin-Resource-Policy: cross-origin',\n ` Permissions-Policy: ${permissionsPolicy}`,\n // Offline export cache policy (no-cache for HTML/SW; immutable for other assets)\n '/offline-export',\n ' Cache-Control: no-cache',\n '/offline-export/',\n ' Cache-Control: no-cache',\n '/offline-export/index.html',\n ' Cache-Control: no-cache',\n '/offline-export/sw.js',\n ' Cache-Control: no-cache',\n '/offline-export/precache.manifest.json',\n ' Cache-Control: no-cache',\n '/offline-export/manifest.webmanifest',\n ' Cache-Control: no-cache',\n '/offline-export/offline-export-app.js',\n ' Cache-Control: no-cache',\n '/offline-export/*',\n ' Cache-Control: public, max-age=31536000, immutable',\n ]\n // Optional: emit CORS headers when explicitly configured via plugin option.\n // Prefer a single source of truth (platform or plugin), not both.\n const configuredAcaOrigin = (opts.cors && typeof opts.cors.accessControlAllowOrigin === 'string'\n ? opts.cors.accessControlAllowOrigin.trim()\n : undefined) as string | undefined;\n if (configuredAcaOrigin) {\n contentLines.push(\n `${sdkBasePath}/*`,\n ` Access-Control-Allow-Origin: ${configuredAcaOrigin}`,\n )\n }\n const content = contentLines.join('\\n') + '\\n'\n fs.mkdirSync(outDir, { recursive: true })\n fs.writeFileSync(hdrPath, content, 'utf-8')\n console.log('[tatchi] emitted _headers with COOP' + (coepMode === 'off' ? '' : '/COEP/CORP') + ' + Permissions-Policy' + (configuredAcaOrigin ? ' + CORS' : ''))\n }\n\n const sdkDir = path.join(outDir, sdkBasePath.replace(/^\\//, ''))\n try { fs.mkdirSync(sdkDir, { recursive: true }) } catch {}\n const shimPath = path.join(sdkDir, 'wallet-shims.js')\n if (!fs.existsSync(shimPath)) {\n fs.writeFileSync(shimPath, WALLET_SHIM_SOURCE, 'utf-8')\n }\n const cssPath = path.join(sdkDir, 'wallet-service.css')\n if (!fs.existsSync(cssPath)) {\n fs.writeFileSync(cssPath, WALLET_SURFACE_CSS, 'utf-8')\n }\n\n // Emit minimal wallet-service/index.html if the app hasn't provided one\n const walletRel = walletServicePath.replace(/^\\//, '')\n const wsDir = path.join(outDir, walletRel)\n const wsHtml = path.join(wsDir, 'index.html')\n if (!fs.existsSync(wsHtml)) {\n fs.mkdirSync(wsDir, { recursive: true })\n fs.writeFileSync(wsHtml, buildWalletServiceHtml(sdkBasePath), 'utf-8')\n console.log(`[tatchi] emitted ${path.posix.join('/', walletRel, 'index.html')} (minimal wallet service)`)\n }\n\n // Emit minimal export viewer HTML for production\n const evDir = path.join(outDir, 'export-viewer')\n const evHtml = path.join(evDir, 'index.html')\n if (!fs.existsSync(evHtml)) {\n fs.mkdirSync(evDir, { recursive: true })\n fs.writeFileSync(evHtml, buildExportViewerHtml(sdkBasePath), 'utf-8')\n console.log('[tatchi] emitted /export-viewer/index.html (minimal export viewer)')\n }\n\n // Emit offline-export assets (SW, workers, app, HTML, manifest, precache) via helper\n try {\n const sdkDistRoot = resolveSdkDistRoot()\n emitOfflineExportAssets({ outDir, sdkBasePath, sdkDistRoot })\n } catch (e) {\n console.warn('[tatchi] failed to emit offline-export assets:', e)\n }\n } catch (e) {\n console.warn('[tatchi] failed to emit _headers:', e)\n }\n },\n }\n\n return plugin as unknown as VitePlugin\n}\n\n// Small test helpers to keep unit tests decoupled from Vite server implementation\nexport function computeDevPermissionsPolicy(walletOrigins?: string[]): string {\n return buildPermissionsPolicy(walletOrigins)\n}\n\nexport function computeDevWalletCsp(mode: 'strict' | 'compatible' = 'strict'): string {\n return buildWalletCsp({ mode })\n}\n\nexport function tatchiWalletServer(options: Omit<Web3AuthnDevOptions, 'mode'> = {}): VitePlugin {\n return tatchiDevServer({ ...options, mode: 'wallet-only' })\n}\n\nexport function tatchiAppServer(options: Omit<Web3AuthnDevOptions, 'mode'> = {}): VitePlugin {\n return tatchiDevServer({ ...options, mode: 'front-only' })\n}\n\n/**\n * Convenience wrapper: app origin helper that combines dev-time headers with optional\n * build-time headers emission for static hosts.\n *\n * Dev-time (serve): applies COOP + Permissions-Policy, plus optional COEP/CORP, via tatchiAppServer.\n * Build-time (build): when `emitHeaders` is true, writes a Cloudflare Pages/Netlify\n * `_headers` file into Vite's `outDir` via tatchiBuildHeaders, scoping strict CSP to\n * wallet HTML routes only.\n * - Emits: `COOP: same-origin`, `Permissions-Policy: …`, and (when `coepMode === 'strict'`) `COEP: require-corp` + `CORP: cross-origin`.\n * - No-op if a `_headers` file already exists in `outDir` (avoids clobbering CI/platform rules).\n *\n * Notes\n * - Keeps production header emission opt-in to avoid surprising overrides when apps\n * already manage headers via custom servers or platform rules.\n * - Returns a plugin array for ergonomics; Vite accepts arrays in the `plugins` list.\n */\nexport function tatchiApp(options: Omit<Web3AuthnDevOptions, 'mode'> & { emitHeaders?: boolean } = {}): any[] /* Vite Plugin[] */ {\n const { emitHeaders, ...devOpts } = options\n const walletOrigins = normalizeWalletOrigins(\n devOpts.walletOrigins ?? parseWalletOriginsEnv(process.env.VITE_WALLET_ORIGIN)\n )\n const app = tatchiAppServer(devOpts)\n // Build-time emission is opt-in and will no-op if `_headers` already exists.\n const hdr = emitHeaders ? tatchiBuildHeaders({ walletOrigins, coepMode: devOpts.coepMode }) : undefined\n return [app, hdr].filter(Boolean) as any[]\n}\n\n/**\n * Convenience wrapper: wallet origins helper that combines dev-time wallet server\n * with optional build-time headers emission for static hosts.\n *\n * Dev-time (serve): serves `/wallet-service` and `/sdk/*` plus headers via tatchiWalletServer.\n * Build-time (build): when `emitHeaders` is true, writes a Cloudflare Pages/Netlify\n * `_headers` file into Vite's `outDir` via tatchiBuildHeaders, scoping strict CSP to\n * wallet HTML routes only.\n * - Emits: `COOP: same-origin` (wallet HTML routes use `unsafe-none`), `Permissions-Policy: …`, and (when `coepMode === 'strict'`) `COEP: require-corp` + `CORP: cross-origin`.\n * - No-op if a `_headers` file already exists in `outDir` (avoids clobbering CI/platform rules).\n *\n * Notes\n * - Keeps production header emission opt-in to avoid overriding platform/server configs.\n * - Returns a plugin array for ergonomics; Vite accepts arrays in the `plugins` list.\n */\nexport function tatchiWallet(options: Omit<Web3AuthnDevOptions, 'mode'> & { emitHeaders?: boolean } = {}): any[] /* Vite Plugin[] */ {\n const { emitHeaders, ...devOpts } = options\n const walletOrigins = normalizeWalletOrigins(\n devOpts.walletOrigins ?? parseWalletOriginsEnv(process.env.VITE_WALLET_ORIGIN)\n )\n const wallet = tatchiWalletServer(devOpts)\n // Build-time emission is opt-in and will no-op if `_headers` already exists.\n const hdr = emitHeaders ? tatchiBuildHeaders({ walletOrigins, coepMode: devOpts.coepMode }) : undefined\n return [wallet, hdr].filter(Boolean) as any[]\n}\n"],"mappings":"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"}