@authhero/cloudflare-adapter 3.0.11 → 3.1.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.
package/README.md CHANGED
@@ -676,6 +676,67 @@ curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/analytics_engin
676
676
  -d "SELECT blob3 as type, count() as count FROM authhero_logs WHERE index1 = 'tenant-123' GROUP BY blob3"
677
677
  ```
678
678
 
679
+ ## Outbox Metrics Sink (Analytics Engine)
680
+
681
+ `createAnalyticsEngineOutboxMetricsSink` turns authhero's outbox relay metrics
682
+ into Analytics Engine data points, so dead-letters and retry backoff are
683
+ queryable instead of only appearing in `console` output.
684
+
685
+ ### Setup
686
+
687
+ 1. Add a dataset binding in `wrangler.toml`:
688
+
689
+ ```toml
690
+ [[analytics_engine_datasets]]
691
+ binding = "OUTBOX_METRICS"
692
+ dataset = "authhero_outbox_metrics"
693
+ ```
694
+
695
+ 2. Pass the sink to both relay paths — `init()` (inline per-request delivery)
696
+ and `runOutboxRelay()` (the cron drain):
697
+
698
+ ```typescript
699
+ import { createAnalyticsEngineOutboxMetricsSink } from "@authhero/cloudflare-adapter";
700
+ import { init, runOutboxRelay } from "authhero";
701
+
702
+ const metrics = createAnalyticsEngineOutboxMetricsSink({
703
+ analyticsEngineBinding: env.OUTBOX_METRICS,
704
+ });
705
+
706
+ const { app } = init({ dataAdapter, outbox: { enabled: true, metrics } });
707
+
708
+ // in scheduled():
709
+ await runOutboxRelay({ dataAdapter, issuer: env.ISSUER, metrics });
710
+ ```
711
+
712
+ Without `analyticsEngineBinding` the sink is a silent no-op, so the same wiring
713
+ works in local dev and tests.
714
+
715
+ ### Data Schema
716
+
717
+ | Field | Type | Description |
718
+ | ------- | ------ | ---------------------------------------------------------------------------------------------------------------- |
719
+ | blob1 | string | metric name (`outbox_events_processed_total`, `outbox_events_dead_lettered_total`, `outbox_retry_delay_seconds`) |
720
+ | blob2 | string | tenant_id |
721
+ | blob3 | string | event_type |
722
+ | blob4 | string | source (`request` or `cron`) |
723
+ | blob5 | string | destination (delivery failures only) |
724
+ | blob6 | string | error (delivery failures only) |
725
+ | double1 | number | value — `1` for counters, retry delay in seconds for `outbox_retry_delay_seconds` |
726
+ | double2 | number | retry_count of the event |
727
+ | double3 | number | timestamp (epoch ms) |
728
+ | index1 | string | tenant_id (for efficient filtering) |
729
+
730
+ Analytics Engine samples rows under load, so weight counters by
731
+ `_sample_interval` to get true totals:
732
+
733
+ ```bash
734
+ # Dead-lettered events per tenant
735
+ curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/analytics_engine/sql" \
736
+ -H "Authorization: Bearer $API_TOKEN" \
737
+ -d "SELECT index1 as tenant, sum(double1 * _sample_interval) as dead_lettered FROM authhero_outbox_metrics WHERE blob1 = 'outbox_events_dead_lettered_total' GROUP BY index1"
738
+ ```
739
+
679
740
  ## Geo Adapter
680
741
 
681
742
  The Cloudflare Geo adapter extracts geographic location information from Cloudflare's automatic request headers. This is used to enrich authentication logs with location data.
@@ -1,23 +1,23 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require("./sync-defaults-errors-Htp1NWTq.js");let l=require("@authhero/adapter-interfaces"),u=require("@hono/zod-openapi"),d=require("hono/http-exception"),f=require("wretch");f=s(f);let p=require("wretch/middlewares");var m=u.z.object({code:u.z.number(),message:u.z.string()}),h=u.z.object({message:u.z.string()}),g=u.z.object({emails:u.z.array(u.z.string()).optional(),http_body:u.z.string().optional(),http_url:u.z.string().optional(),txt_name:u.z.string().optional(),txt_value:u.z.string().optional()}),_=u.z.object({ciphers:u.z.array(u.z.string()).optional(),early_hints:u.z.string().optional(),http2:u.z.string().optional(),min_tls_version:u.z.string().optional(),tls_1_3:u.z.string().optional()}),ee=u.z.object({id:u.z.string(),bundle_method:u.z.string().optional(),certificate_authority:u.z.string(),custom_certificate:u.z.string().optional(),custom_csr_id:u.z.string().optional(),custom_key:u.z.string().optional(),expires_on:u.z.string().optional(),hosts:u.z.array(u.z.string()).optional(),issuer:u.z.string().optional(),method:u.z.string(),serial_number:u.z.string().optional(),settings:_.optional(),signature:u.z.string().optional(),type:u.z.string(),uploaded_on:u.z.string().optional(),validation_errors:u.z.array(h).optional(),validation_records:u.z.array(g).optional(),wildcard:u.z.boolean()}),te=u.z.object({name:u.z.string(),type:u.z.string(),value:u.z.string()}),ne=u.z.object({http_body:u.z.string().optional(),http_url:u.z.string().optional()}),v=u.z.object({id:u.z.string(),ssl:ee,hostname:u.z.string(),custom_metadata:u.z.record(u.z.string(),u.z.string()).optional(),custom_origin_server:u.z.string().optional(),custom_origin_sni:u.z.string().optional(),ownership_verification:te.optional(),ownership_verification_http:ne.optional(),status:u.z.string(),verification_errors:u.z.array(u.z.string()).optional(),created_at:u.z.string()}),y=u.z.object({errors:u.z.array(m),messages:u.z.array(m),success:u.z.boolean(),result:v}),re=u.z.object({errors:u.z.array(m),messages:u.z.array(m),success:u.z.boolean(),result:u.z.array(v)});function b(e){return(0,f.default)(`https://api.cloudflare.com/client/v4/zones/${e.zoneId}`).headers({"X-Auth-Email":e.authEmail,"X-Auth-Key":e.authKey,"Content-Type":`application/json`}).middlewares([(0,p.retry)(),(0,p.dedupe)()])}function x(e){let t={},n={};if(!e)return{sslOverrides:t,rest:n};for(let[r,i]of Object.entries(e))r.startsWith(`ssl.`)?t[r.slice(4)]=i:n[r]=i;return{sslOverrides:t,rest:n}}function S(e){let t=[];if(e.ssl.validation_records)for(let n of e.ssl.validation_records)n.txt_name&&n.txt_value&&t.push({name:`txt`,record:n.txt_value,domain:n.txt_name});if(e.ownership_verification&&t.push({name:`txt`,record:e.ownership_verification.value,domain:e.ownership_verification.name}),e.ownership_verification_http?.http_body&&e.ownership_verification_http?.http_url&&t.push({name:`http`,http_body:e.ownership_verification_http.http_body,http_url:e.ownership_verification_http.http_url}),e.ssl.validation_records)for(let n of e.ssl.validation_records)n.http_body&&n.http_url&&t.push({name:`http`,http_body:n.http_body,http_url:n.http_url});let n={...e.domain_metadata||{},"ssl.method":e.ssl.method,"ssl.type":e.ssl.type,"ssl.certificate_authority":e.ssl.certificate_authority};return{custom_domain_id:e.id,domain:e.hostname,primary:e.primary,status:e.status===`active`?`ready`:`pending`,type:e.type??`auth0_managed_certs`,verification:{methods:u.z.array(l.verificationMethodsSchema).parse(t)},domain_metadata:n}}function ie(e){let t=e instanceof Error?e.message:String(e);return/duplicate/i.test(t)}async function ae(e,t,n){let r;try{r=await b(e).get(`/custom_hostnames?hostname=${encodeURIComponent(n)}`).json()}catch{return null}let i=re.safeParse(r);if(!i.success||!i.data.success)return null;let a=i.data.result.find(e=>e.hostname.toLowerCase()===n.toLowerCase());return!a||e.enterprise&&a.custom_metadata?.tenant_id!==t?null:a}function oe(e){return{create:async(t,n)=>{let{sslOverrides:r,rest:i}=x(n.domain_metadata);if(await e.customDomainAdapter.getByDomain(n.domain))throw new d.HTTPException(409,{message:`The domain ${n.domain} is already registered`});let a;try{let i=y.parse(await b(e).post({hostname:n.domain,ssl:{method:`txt`,type:`dv`,...r},custom_metadata:e.enterprise?{tenant_id:t}:void 0},`/custom_hostnames`).json());if(!i.success)throw Error(JSON.stringify(i.errors));a=i.result}catch(r){if(!ie(r))throw r;let i=await ae(e,t,n.domain);if(!i)throw r;a=i}let o=S({...a,primary:!1,type:n.type,domain_metadata:i});return await e.customDomainAdapter.create(t,{custom_domain_id:o.custom_domain_id,domain:o.domain,type:o.type,domain_metadata:n.domain_metadata}),await e.customDomainAdapter.update(t,o.custom_domain_id,{status:o.status,primary:o.primary,verification:o.verification}),o},get:async(t,n)=>{let r=await e.customDomainAdapter.get(t,n);if(!r)throw new d.HTTPException(404);let i;try{i=await b(e).get(`/custom_hostnames/${encodeURIComponent(n)}`).json()}catch(e){return console.warn(`[custom-domains] CF fetch failed for ${n} (tenant=${t}); returning stale DB row:`,e instanceof Error?e.message:e),r}let a=y.safeParse(i);if(!a.success||!a.data.success)return console.warn(`[custom-domains] CF response unparseable for ${n} (tenant=${t}); returning stale DB row.`,a.success?{cfErrors:a.data.errors}:{zodIssues:a.error.issues,body:i}),r;let{result:o}=a.data;if(e.enterprise&&o.custom_metadata?.tenant_id!==t)throw new d.HTTPException(404);let s;try{s=S({...r,...o})}catch(e){return console.warn(`[custom-domains] mapCustomDomainResponse failed for ${n} (tenant=${t}); returning stale DB row.`,e instanceof Error?e.message:e),r}if(s.status!==r.status||JSON.stringify(s.verification)!==JSON.stringify(r.verification))try{await e.customDomainAdapter.update(t,n,{status:s.status,verification:s.verification})}catch(e){console.warn(`[custom-domains] DB writeback failed for ${n} (tenant=${t}); returning merged response without DB sync.`,e instanceof Error?e.message:e)}return s},getByDomain:async t=>e.customDomainAdapter.getByDomain(t),list:async t=>e.customDomainAdapter.list(t),remove:async(t,n)=>{if(e.enterprise){let{result:r,success:i}=y.parse(await b(e).get(`/custom_hostnames/${encodeURIComponent(n)}`).json());if(!i||r.custom_metadata?.tenant_id!==t)throw new d.HTTPException(404)}let r=await b(e).delete(`/custom_hostnames/${encodeURIComponent(n)}`).res();return r.ok&&await e.customDomainAdapter.remove(t,n),r.ok},update:async(t,n,r)=>{let{sslOverrides:i}=x(r.domain_metadata),a={};if(Object.keys(i).length>0){let t;try{t=await b(e).get(`/custom_hostnames/${encodeURIComponent(n)}`).json()}catch(e){throw new d.HTTPException(503,{message:`Failed to fetch current custom hostname state: ${e instanceof Error?e.message:String(e)}`})}let r=y.safeParse(t);if(!r.success||!r.data.success)throw new d.HTTPException(503,{message:`Failed to parse current custom hostname state: ${JSON.stringify(r.success?r.data.errors:r.error.issues)}`});a.ssl={method:r.data.result.ssl.method,type:r.data.result.ssl.type,certificate_authority:r.data.result.ssl.certificate_authority,...i}}if(Object.keys(a).length>0){let t=await b(e).patch(a,`/custom_hostnames/${encodeURIComponent(n)}`).res().catch(e=>{throw new d.HTTPException(503,{message:`Failed to update custom hostname: ${e instanceof Error?e.message:String(e)}`})});if(!t.ok)throw new d.HTTPException(503,{message:await t.text()})}return e.customDomainAdapter.update(t,n,r)},uploadCertificate:async(t,n,r)=>{let i=await e.customDomainAdapter.get(t,n);if(!i)throw new d.HTTPException(404);let a=await b(e).patch({ssl:{custom_certificate:r.certificate,custom_key:r.private_key}},`/custom_hostnames/${encodeURIComponent(n)}`).json(),{result:o,errors:s,success:c}=y.parse(a);if(!c)throw new d.HTTPException(503,{message:JSON.stringify(s)});let l=S({...i,...o});return await e.customDomainAdapter.update(t,n,{status:l.status,verification:l.verification}),l}}}var se=class{config;cache=null;constructor(e){this.config=e}async getCache(){if(this.cache)return this.cache;if(typeof caches>`u`)throw Error(`caches API is not available - CloudflareCache should only be used in Cloudflare Workers`);return this.config.cacheName?this.cache=await caches.open(this.config.cacheName):this.cache=caches.default,this.cache}getKey(e){return this.config.keyPrefix?`${this.config.keyPrefix}:${e}`:e}createRequest(e){return new Request(`https://cache.internal/${this.getKey(e)}`)}async matchWithTimeout(e,t){let n=this.config.getTimeoutMs??200;return n<=0?e.match(t):new Promise(r=>{let i=setTimeout(()=>r(void 0),n);e.match(t).then(e=>{clearTimeout(i),r(e)},()=>{clearTimeout(i),r(void 0)})})}async get(e){try{let t=await this.getCache(),n=this.createRequest(e),r=await this.matchWithTimeout(t,n);if(!r)return null;let i=await r.text();if(!i)return await this.delete(e),null;let a;try{a=JSON.parse(i)}catch{return await this.delete(e),null}return a.expiresAt&&new Date(a.expiresAt)<new Date?(await this.delete(e),null):a.value}catch(t){return console.error(`CloudflareCache: get error for key ${e}:`,t),null}}async set(e,t,n){try{let r=await this.getCache(),i=n??this.config.defaultTtlSeconds,a=i!==void 0,o=a?Math.max(0,i):0,s={value:t,expiresAt:a?new Date(Date.now()+(o>0?o*1e3:-1)).toISOString():void 0,cachedAt:new Date().toISOString()},c=this.createRequest(e),l={"Content-Type":`application/json`};a&&o>0&&(l[`Cache-Control`]=`max-age=${o}`);let u=new Response(JSON.stringify(s),{headers:l});await r.put(c,u)}catch(t){console.error(`CloudflareCache: set error for key ${e}:`,t)}}async delete(e){try{let t=await this.getCache(),n=this.createRequest(e);return await t.delete(n)}catch(t){return console.error(`CloudflareCache: delete error for key ${e}:`,t),!1}}async deleteByPrefix(e){return console.warn(`CloudflareCache.deleteByPrefix() is not implemented - Cloudflare Cache API does not support prefix-based deletion`),0}async clear(){console.warn(`CloudflareCache.clear() is not implemented - Cloudflare Cache API does not support clearing all entries`)}};function ce(e={}){return new se({defaultTtlSeconds:300,keyPrefix:`authhero`,getTimeoutMs:200,...e})}var le=`useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict`,C=(e=21)=>{let t=``,n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+=le[n[e]&63];return t};async function w(e,t){let n=e.timeout||3e4,r=new AbortController,i=setTimeout(()=>r.abort(),n);try{let n=`https://api.sql.cloudflarestorage.com/api/v1/accounts/${e.accountId}/r2-sql/query/${e.warehouseName}`,i=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${e.authToken}`},body:JSON.stringify({query:t}),signal:r.signal});if(!i.ok)throw Error(`R2 SQL query failed: ${i.status} ${i.statusText}`);let a=await i.json();if(!a.success&&a.errors)throw Error(`R2 SQL error: ${a.errors.join(`, `)}`);return a.data||a.result?.data||[]}finally{clearTimeout(i)}}function T(e){return`'${e.replace(/'/g,`''`)}'`}function E(e){return`"${e.replace(/"/g,`""`)}"`}function D(e){let t=e=>{if(!e)return``;try{return JSON.parse(e)}catch{return e}};return{type:e.type,date:e.date,description:e.description,ip:e.ip,user_agent:e.user_agent,details:t(e.details),isMobile:!!e.isMobile,user_id:e.user_id,user_name:e.user_name,connection:e.connection,connection_id:e.connection_id,client_id:e.client_id,client_name:e.client_name,audience:e.audience,scope:e.scope,strategy:e.strategy,strategy_type:e.strategy_type,hostname:e.hostname,auth0_client:t(e.auth0_client),log_id:e.id,location_info:e.country_code||e.city_name||e.latitude||e.longitude||e.time_zone||e.continent_code?{country_code:e.country_code||``,city_name:e.city_name||``,latitude:e.latitude||``,longitude:e.longitude||``,time_zone:e.time_zone||``,continent_code:e.continent_code||``}:void 0}}function ue(e){return async(t,n)=>{let r=n.log_id||C(),i={...n,log_id:r};return await de(e,t,i),i}}async function de(e,t,n){let r=e=>e?JSON.stringify(e):void 0,i={id:n.log_id,tenant_id:t,type:n.type,date:n.date,description:n.description?.substring(0,256),ip:n.ip,user_agent:n.user_agent,details:r(n.details)?.substring(0,8192),isMobile:+!!n.isMobile,user_id:n.user_id,user_name:n.user_name,connection:n.connection,connection_id:n.connection_id,client_id:n.client_id,client_name:n.client_name,audience:n.audience,scope:n.scope,strategy:n.strategy,strategy_type:n.strategy_type,hostname:n.hostname,auth0_client:r(n.auth0_client),log_id:n.log_id,country_code:n.location_info?.country_code,city_name:n.location_info?.city_name,latitude:n.location_info?.latitude,longitude:n.location_info?.longitude,time_zone:n.location_info?.time_zone,continent_code:n.location_info?.continent_code};try{if(e.pipelineBinding)await e.pipelineBinding.send([i]);else if(e.pipelineEndpoint){let t=e.timeout||3e4,n=new AbortController,r=setTimeout(()=>n.abort(),t);try{let t=await fetch(e.pipelineEndpoint,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify([i]),signal:n.signal});if(!t.ok)throw Error(`Pipeline ingestion failed: ${t.status} ${t.statusText}`)}finally{clearTimeout(r)}}else throw Error(`Either pipelineEndpoint or pipelineBinding must be configured`)}catch(e){throw console.error(`Failed to send log to Pipeline:`,e),e}}function fe(e){return async(t,n)=>{let r=e.namespace||`default`,i=e.tableName||`logs`,a=await w(e,`
2
- SELECT * FROM ${E(r)}.${E(i)}
3
- WHERE tenant_id = ${T(t)}
4
- AND id = ${T(n)}
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require("./sync-defaults-errors-Htp1NWTq.js");let l=require("@authhero/adapter-interfaces"),u=require("@hono/zod-openapi"),d=require("hono/http-exception"),f=require("wretch");f=s(f);let p=require("wretch/middlewares");var m=u.z.object({code:u.z.number(),message:u.z.string()}),h=u.z.object({message:u.z.string()}),g=u.z.object({emails:u.z.array(u.z.string()).optional(),http_body:u.z.string().optional(),http_url:u.z.string().optional(),txt_name:u.z.string().optional(),txt_value:u.z.string().optional()}),_=u.z.object({ciphers:u.z.array(u.z.string()).optional(),early_hints:u.z.string().optional(),http2:u.z.string().optional(),min_tls_version:u.z.string().optional(),tls_1_3:u.z.string().optional()}),ee=u.z.object({id:u.z.string(),bundle_method:u.z.string().optional(),certificate_authority:u.z.string(),custom_certificate:u.z.string().optional(),custom_csr_id:u.z.string().optional(),custom_key:u.z.string().optional(),expires_on:u.z.string().optional(),hosts:u.z.array(u.z.string()).optional(),issuer:u.z.string().optional(),method:u.z.string(),serial_number:u.z.string().optional(),settings:_.optional(),signature:u.z.string().optional(),type:u.z.string(),uploaded_on:u.z.string().optional(),validation_errors:u.z.array(h).optional(),validation_records:u.z.array(g).optional(),wildcard:u.z.boolean()}),te=u.z.object({name:u.z.string(),type:u.z.string(),value:u.z.string()}),ne=u.z.object({http_body:u.z.string().optional(),http_url:u.z.string().optional()}),v=u.z.object({id:u.z.string(),ssl:ee,hostname:u.z.string(),custom_metadata:u.z.record(u.z.string(),u.z.string()).optional(),custom_origin_server:u.z.string().optional(),custom_origin_sni:u.z.string().optional(),ownership_verification:te.optional(),ownership_verification_http:ne.optional(),status:u.z.string(),verification_errors:u.z.array(u.z.string()).optional(),created_at:u.z.string()}),y=u.z.object({errors:u.z.array(m),messages:u.z.array(m),success:u.z.boolean(),result:v}),b=u.z.object({errors:u.z.array(m),messages:u.z.array(m),success:u.z.boolean(),result:u.z.array(v)});function x(e){return(0,f.default)(`https://api.cloudflare.com/client/v4/zones/${e.zoneId}`).headers({"X-Auth-Email":e.authEmail,"X-Auth-Key":e.authKey,"Content-Type":`application/json`}).middlewares([(0,p.retry)(),(0,p.dedupe)()])}function S(e){let t={},n={};if(!e)return{sslOverrides:t,rest:n};for(let[r,i]of Object.entries(e))r.startsWith(`ssl.`)?t[r.slice(4)]=i:n[r]=i;return{sslOverrides:t,rest:n}}function C(e){let t=[];if(e.ssl.validation_records)for(let n of e.ssl.validation_records)n.txt_name&&n.txt_value&&t.push({name:`txt`,record:n.txt_value,domain:n.txt_name});if(e.ownership_verification&&t.push({name:`txt`,record:e.ownership_verification.value,domain:e.ownership_verification.name}),e.ownership_verification_http?.http_body&&e.ownership_verification_http?.http_url&&t.push({name:`http`,http_body:e.ownership_verification_http.http_body,http_url:e.ownership_verification_http.http_url}),e.ssl.validation_records)for(let n of e.ssl.validation_records)n.http_body&&n.http_url&&t.push({name:`http`,http_body:n.http_body,http_url:n.http_url});let n={...e.domain_metadata||{},"ssl.method":e.ssl.method,"ssl.type":e.ssl.type,"ssl.certificate_authority":e.ssl.certificate_authority};return{custom_domain_id:e.id,domain:e.hostname,primary:e.primary,status:e.status===`active`?`ready`:`pending`,type:e.type??`auth0_managed_certs`,verification:{methods:u.z.array(l.verificationMethodsSchema).parse(t)},domain_metadata:n}}function re(e){let t=e instanceof Error?e.message:String(e);return/duplicate/i.test(t)}async function ie(e,t,n){let r;try{r=await x(e).get(`/custom_hostnames?hostname=${encodeURIComponent(n)}`).json()}catch{return null}let i=b.safeParse(r);if(!i.success||!i.data.success)return null;let a=i.data.result.find(e=>e.hostname.toLowerCase()===n.toLowerCase());return!a||e.enterprise&&a.custom_metadata?.tenant_id!==t?null:a}async function ae(e,t,n,r){let i=n.custom_domain_id,a;try{a=C({...n,...r})}catch(e){return console.warn(`[custom-domains] mapCustomDomainResponse failed for ${i} (tenant=${t}); keeping the stored row.`,e instanceof Error?e.message:e),{domain:n,outcome:`failed`}}if(a.status===n.status&&JSON.stringify(a.verification)===JSON.stringify(n.verification))return{domain:a,outcome:`unchanged`};try{await e.customDomainAdapter.update(t,i,{status:a.status,verification:a.verification})}catch(e){return console.warn(`[custom-domains] DB writeback failed for ${i} (tenant=${t}); returning merged response without DB sync.`,e instanceof Error?e.message:e),{domain:a,outcome:`failed`}}return{domain:a,outcome:`updated`}}function oe(e){return{create:async(t,n)=>{let{sslOverrides:r,rest:i}=S(n.domain_metadata);if(await e.customDomainAdapter.getByDomain(n.domain))throw new d.HTTPException(409,{message:`The domain ${n.domain} is already registered`});let a;try{let i=y.parse(await x(e).post({hostname:n.domain,ssl:{method:`txt`,type:`dv`,...r},custom_metadata:e.enterprise?{tenant_id:t}:void 0},`/custom_hostnames`).json());if(!i.success)throw Error(JSON.stringify(i.errors));a=i.result}catch(r){if(!re(r))throw r;let i=await ie(e,t,n.domain);if(!i)throw r;a=i}let o=C({...a,primary:!1,type:n.type,domain_metadata:i});return await e.customDomainAdapter.create(t,{custom_domain_id:o.custom_domain_id,domain:o.domain,type:o.type,domain_metadata:n.domain_metadata}),await e.customDomainAdapter.update(t,o.custom_domain_id,{status:o.status,primary:o.primary,verification:o.verification}),o},get:async(t,n)=>{let r=await e.customDomainAdapter.get(t,n);if(!r)throw new d.HTTPException(404);let i;try{i=await x(e).get(`/custom_hostnames/${encodeURIComponent(n)}`).json()}catch(e){return console.warn(`[custom-domains] CF fetch failed for ${n} (tenant=${t}); returning stale DB row:`,e instanceof Error?e.message:e),r}let a=y.safeParse(i);if(!a.success||!a.data.success)return console.warn(`[custom-domains] CF response unparseable for ${n} (tenant=${t}); returning stale DB row.`,a.success?{cfErrors:a.data.errors}:{zodIssues:a.error.issues,body:i}),r;let{result:o}=a.data;if(e.enterprise&&o.custom_metadata?.tenant_id!==t)throw new d.HTTPException(404);let{domain:s}=await ae(e,t,r,o);return s},getByDomain:async t=>e.customDomainAdapter.getByDomain(t),list:async t=>e.customDomainAdapter.list(t),remove:async(t,n)=>{if(e.enterprise){let{result:r,success:i}=y.parse(await x(e).get(`/custom_hostnames/${encodeURIComponent(n)}`).json());if(!i||r.custom_metadata?.tenant_id!==t)throw new d.HTTPException(404)}let r=await x(e).delete(`/custom_hostnames/${encodeURIComponent(n)}`).res();return r.ok&&await e.customDomainAdapter.remove(t,n),r.ok},update:async(t,n,r)=>{let{sslOverrides:i}=S(r.domain_metadata),a={};if(Object.keys(i).length>0){let t;try{t=await x(e).get(`/custom_hostnames/${encodeURIComponent(n)}`).json()}catch(e){throw new d.HTTPException(503,{message:`Failed to fetch current custom hostname state: ${e instanceof Error?e.message:String(e)}`})}let r=y.safeParse(t);if(!r.success||!r.data.success)throw new d.HTTPException(503,{message:`Failed to parse current custom hostname state: ${JSON.stringify(r.success?r.data.errors:r.error.issues)}`});a.ssl={method:r.data.result.ssl.method,type:r.data.result.ssl.type,certificate_authority:r.data.result.ssl.certificate_authority,...i}}if(Object.keys(a).length>0){let t=await x(e).patch(a,`/custom_hostnames/${encodeURIComponent(n)}`).res().catch(e=>{throw new d.HTTPException(503,{message:`Failed to update custom hostname: ${e instanceof Error?e.message:String(e)}`})});if(!t.ok)throw new d.HTTPException(503,{message:await t.text()})}return e.customDomainAdapter.update(t,n,r)},uploadCertificate:async(t,n,r)=>{let i=await e.customDomainAdapter.get(t,n);if(!i)throw new d.HTTPException(404);let a=await x(e).patch({ssl:{custom_certificate:r.certificate,custom_key:r.private_key}},`/custom_hostnames/${encodeURIComponent(n)}`).json(),{result:o,errors:s,success:c}=y.parse(a);if(!c)throw new d.HTTPException(503,{message:JSON.stringify(s)});let l=C({...i,...o});return await e.customDomainAdapter.update(t,n,{status:l.status,verification:l.verification}),l}}}var se=class{config;cache=null;constructor(e){this.config=e}async getCache(){if(this.cache)return this.cache;if(typeof caches>`u`)throw Error(`caches API is not available - CloudflareCache should only be used in Cloudflare Workers`);return this.config.cacheName?this.cache=await caches.open(this.config.cacheName):this.cache=caches.default,this.cache}getKey(e){return this.config.keyPrefix?`${this.config.keyPrefix}:${e}`:e}createRequest(e){return new Request(`https://cache.internal/${this.getKey(e)}`)}async matchWithTimeout(e,t){let n=this.config.getTimeoutMs??200;return n<=0?e.match(t):new Promise(r=>{let i=setTimeout(()=>r(void 0),n);e.match(t).then(e=>{clearTimeout(i),r(e)},()=>{clearTimeout(i),r(void 0)})})}async get(e){try{let t=await this.getCache(),n=this.createRequest(e),r=await this.matchWithTimeout(t,n);if(!r)return null;let i=await r.text();if(!i)return await this.delete(e),null;let a;try{a=JSON.parse(i)}catch{return await this.delete(e),null}return a.expiresAt&&new Date(a.expiresAt)<new Date?(await this.delete(e),null):a.value}catch(t){return console.error(`CloudflareCache: get error for key ${e}:`,t),null}}async set(e,t,n){try{let r=await this.getCache(),i=n??this.config.defaultTtlSeconds,a=i!==void 0,o=a?Math.max(0,i):0,s={value:t,expiresAt:a?new Date(Date.now()+(o>0?o*1e3:-1)).toISOString():void 0,cachedAt:new Date().toISOString()},c=this.createRequest(e),l={"Content-Type":`application/json`};a&&o>0&&(l[`Cache-Control`]=`max-age=${o}`);let u=new Response(JSON.stringify(s),{headers:l});await r.put(c,u)}catch(t){console.error(`CloudflareCache: set error for key ${e}:`,t)}}async delete(e){try{let t=await this.getCache(),n=this.createRequest(e);return await t.delete(n)}catch(t){return console.error(`CloudflareCache: delete error for key ${e}:`,t),!1}}async deleteByPrefix(e){return console.warn(`CloudflareCache.deleteByPrefix() is not implemented - Cloudflare Cache API does not support prefix-based deletion`),0}async clear(){console.warn(`CloudflareCache.clear() is not implemented - Cloudflare Cache API does not support clearing all entries`)}};function ce(e={}){return new se({defaultTtlSeconds:300,keyPrefix:`authhero`,getTimeoutMs:200,...e})}var le=`useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict`,w=(e=21)=>{let t=``,n=crypto.getRandomValues(new Uint8Array(e|=0));for(;e--;)t+=le[n[e]&63];return t};async function T(e,t){let n=e.timeout||3e4,r=new AbortController,i=setTimeout(()=>r.abort(),n);try{let n=`https://api.sql.cloudflarestorage.com/api/v1/accounts/${e.accountId}/r2-sql/query/${e.warehouseName}`,i=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${e.authToken}`},body:JSON.stringify({query:t}),signal:r.signal});if(!i.ok)throw Error(`R2 SQL query failed: ${i.status} ${i.statusText}`);let a=await i.json();if(!a.success&&a.errors)throw Error(`R2 SQL error: ${a.errors.join(`, `)}`);return a.data||a.result?.data||[]}finally{clearTimeout(i)}}function E(e){return`'${e.replace(/'/g,`''`)}'`}function D(e){return`"${e.replace(/"/g,`""`)}"`}function O(e){let t=e=>{if(!e)return``;try{return JSON.parse(e)}catch{return e}};return{type:e.type,date:e.date,description:e.description,ip:e.ip,user_agent:e.user_agent,details:t(e.details),isMobile:!!e.isMobile,user_id:e.user_id,user_name:e.user_name,connection:e.connection,connection_id:e.connection_id,client_id:e.client_id,client_name:e.client_name,audience:e.audience,scope:e.scope,strategy:e.strategy,strategy_type:e.strategy_type,hostname:e.hostname,auth0_client:t(e.auth0_client),log_id:e.id,location_info:e.country_code||e.city_name||e.latitude||e.longitude||e.time_zone||e.continent_code?{country_code:e.country_code||``,city_name:e.city_name||``,latitude:e.latitude||``,longitude:e.longitude||``,time_zone:e.time_zone||``,continent_code:e.continent_code||``}:void 0}}function ue(e){return async(t,n)=>{let r=n.log_id||w(),i={...n,log_id:r};return await de(e,t,i),i}}async function de(e,t,n){let r=e=>e?JSON.stringify(e):void 0,i={id:n.log_id,tenant_id:t,type:n.type,date:n.date,description:n.description?.substring(0,256),ip:n.ip,user_agent:n.user_agent,details:r(n.details)?.substring(0,8192),isMobile:+!!n.isMobile,user_id:n.user_id,user_name:n.user_name,connection:n.connection,connection_id:n.connection_id,client_id:n.client_id,client_name:n.client_name,audience:n.audience,scope:n.scope,strategy:n.strategy,strategy_type:n.strategy_type,hostname:n.hostname,auth0_client:r(n.auth0_client),log_id:n.log_id,country_code:n.location_info?.country_code,city_name:n.location_info?.city_name,latitude:n.location_info?.latitude,longitude:n.location_info?.longitude,time_zone:n.location_info?.time_zone,continent_code:n.location_info?.continent_code};try{if(e.pipelineBinding)await e.pipelineBinding.send([i]);else if(e.pipelineEndpoint){let t=e.timeout||3e4,n=new AbortController,r=setTimeout(()=>n.abort(),t);try{let t=await fetch(e.pipelineEndpoint,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify([i]),signal:n.signal});if(!t.ok)throw Error(`Pipeline ingestion failed: ${t.status} ${t.statusText}`)}finally{clearTimeout(r)}}else throw Error(`Either pipelineEndpoint or pipelineBinding must be configured`)}catch(e){throw console.error(`Failed to send log to Pipeline:`,e),e}}function fe(e){return async(t,n)=>{let r=e.namespace||`default`,i=e.tableName||`logs`,a=await T(e,`
2
+ SELECT * FROM ${D(r)}.${D(i)}
3
+ WHERE tenant_id = ${E(t)}
4
+ AND id = ${E(n)}
5
5
  LIMIT 1
6
- `);if(a.length===0)return null;let o=a[0];return o?D(o):null}}function pe(e){let t={},n=/(\w+):(?:"([^"]*)"|(\S+))/g,r;for(;(r=n.exec(e))!==null;){let e=r[1],n=r[2]===void 0?r[3]:r[2];!e||n===void 0||(t[e]=n)}return t}function me(e){let t=[];for(let[n,r]of Object.entries(e)){let e=n.replace(/[^a-zA-Z0-9_]/g,``);e&&r&&t.push(`${E(e)} = ${T(r)}`)}return t}function he(e){return async(t,n={})=>{let{page:r=0,per_page:i=50,include_totals:a=!1,sort:o,q:s}=n,c=e.namespace||`default`,l=e.tableName||`logs`,u=[`tenant_id = ${T(t)}`];if(s){let e=pe(s);u.push(...me(e))}let d=u.join(` AND `),f=`ORDER BY date DESC`;if(o&&o.sort_by){let e=o.sort_by.replace(/[^a-zA-Z0-9_]/g,``),t=o.sort_order===`asc`?`ASC`:`DESC`;f=`ORDER BY ${E(e)} ${t}`}let p=r*i,m=`LIMIT ${i} OFFSET ${p}`,h=(await w(e,`
7
- SELECT * FROM ${E(c)}.${E(l)}
6
+ `);if(a.length===0)return null;let o=a[0];return o?O(o):null}}function pe(e){let t={},n=/(\w+):(?:"([^"]*)"|(\S+))/g,r;for(;(r=n.exec(e))!==null;){let e=r[1],n=r[2]===void 0?r[3]:r[2];!e||n===void 0||(t[e]=n)}return t}function me(e){let t=[];for(let[n,r]of Object.entries(e)){let e=n.replace(/[^a-zA-Z0-9_]/g,``);e&&r&&t.push(`${D(e)} = ${E(r)}`)}return t}function he(e){return async(t,n={})=>{let{page:r=0,per_page:i=50,include_totals:a=!1,sort:o,q:s}=n,c=e.namespace||`default`,l=e.tableName||`logs`,u=[`tenant_id = ${E(t)}`];if(s){let e=pe(s);u.push(...me(e))}let d=u.join(` AND `),f=`ORDER BY date DESC`;if(o&&o.sort_by){let e=o.sort_by.replace(/[^a-zA-Z0-9_]/g,``),t=o.sort_order===`asc`?`ASC`:`DESC`;f=`ORDER BY ${D(e)} ${t}`}let p=r*i,m=`LIMIT ${i} OFFSET ${p}`,h=(await T(e,`
7
+ SELECT * FROM ${D(c)}.${D(l)}
8
8
  WHERE ${d}
9
9
  ${f}
10
10
  ${m}
11
- `)).map(D);if(!a)return{logs:h,start:0,limit:0,length:0};let g=(await w(e,`
12
- SELECT COUNT(*) as count FROM ${E(c)}.${E(l)}
11
+ `)).map(O);if(!a)return{logs:h,start:0,limit:0,length:0};let g=(await T(e,`
12
+ SELECT COUNT(*) as count FROM ${D(c)}.${D(l)}
13
13
  WHERE ${d}
14
- `))[0]?.count||0;return{logs:h,start:p,limit:i,length:Number(g)}}}function ge(){return{async getDaily(){throw Error(`Stats queries are not supported by R2 SQL logs adapter. Use Analytics Engine or Kysely adapter instead.`)},async getActiveUsers(){throw Error(`Stats queries are not supported by R2 SQL logs adapter. Use Analytics Engine or Kysely adapter instead.`)}}}function O(e){let t=!!e.pipelineEndpoint,n=!!e.pipelineBinding;if(!t&&!n)throw Error(`R2 SQL logs adapter requires one of: "pipelineEndpoint" or "pipelineBinding"`);if(!e.authToken)throw Error(`R2 SQL logs adapter requires "authToken" configuration`);if(!e.warehouseName)throw Error(`R2 SQL logs adapter requires "warehouseName" configuration`);return{create:ue(e),list:he(e),get:fe(e)}}async function k(e,t){let n=e.timeout||3e4,r=new AbortController,i=setTimeout(()=>r.abort(),n);try{let n=`https://api.cloudflare.com/client/v4/accounts/${e.accountId}/analytics_engine/sql`,i=await fetch(n,{method:`POST`,headers:{"Content-Type":`text/plain`,Authorization:`Bearer ${e.apiToken}`},body:t,signal:r.signal});if(!i.ok){let e=await i.text();throw Error(`Analytics Engine query failed: ${i.status} ${i.statusText} - ${e}`)}let a=await i.json();if(!a.success&&a.errors&&a.errors.length>0)throw Error(`Analytics Engine error: ${a.errors.map(e=>e.message).join(`, `)}`);return a.data||[]}finally{clearTimeout(i)}}function A(e){return`'${e.replace(/'/g,`''`).replace(/\\/g,`\\\\`)}'`}function j(e){return`"${e.replace(/"/g,`""`)}"`}function M(e){let t=e=>{if(e)try{return JSON.parse(e)}catch{return}},n=e.double2||e.timestamp,r=n?new Date(n).toISOString():``;return{log_id:e.blob1,type:e.blob3,date:r,description:e.blob4,ip:e.blob5,user_agent:e.blob6,user_id:e.blob7,user_name:e.blob8,connection:e.blob9,connection_id:e.blob10,client_id:e.blob11,client_name:e.blob12,audience:e.blob13,scope:e.blob14,strategy:e.blob15,strategy_type:e.blob16,hostname:e.blob17,details:t(e.blob18),auth0_client:t(e.blob19),location_info:t(e.blob20),isMobile:e.double1===1}}function N(e){return async(t,n)=>{let r=n.log_id||C(),i={...n,log_id:r};return P(e,t,i),i}}function P(e,t,n){if(!e.analyticsEngineBinding){console.error(`Analytics Engine binding not configured`);return}let r=e=>e==null?``:typeof e==`string`?e:JSON.stringify(e),i=(e,t=1024)=>e.substring(0,t);try{e.analyticsEngineBinding.writeDataPoint({blobs:[i(n.log_id),i(t),i(n.type||``),i(n.description||``),i(n.ip||``),i(n.user_agent||``),i(n.user_id||``),i(n.user_name||``),i(n.connection||``),i(n.connection_id||``),i(n.client_id||``),i(n.client_name||``),i(n.audience||``),i(n.scope||``),i(n.strategy||``),i(n.strategy_type||``),i(n.hostname||``),i(r(n.details)),i(r(n.auth0_client)),i(r(n.location_info))],doubles:[+!!n.isMobile,new Date(n.date).getTime()],indexes:[t.substring(0,96)]})}catch(e){console.error(`Failed to write log to Analytics Engine:`,e)}}function F(e){return async(t,n)=>{let r=await k(e,`
14
+ `))[0]?.count||0;return{logs:h,start:p,limit:i,length:Number(g)}}}function ge(){return{async getDaily(){throw Error(`Stats queries are not supported by R2 SQL logs adapter. Use Analytics Engine or Kysely adapter instead.`)},async getActiveUsers(){throw Error(`Stats queries are not supported by R2 SQL logs adapter. Use Analytics Engine or Kysely adapter instead.`)}}}function _e(e){let t=!!e.pipelineEndpoint,n=!!e.pipelineBinding;if(!t&&!n)throw Error(`R2 SQL logs adapter requires one of: "pipelineEndpoint" or "pipelineBinding"`);if(!e.authToken)throw Error(`R2 SQL logs adapter requires "authToken" configuration`);if(!e.warehouseName)throw Error(`R2 SQL logs adapter requires "warehouseName" configuration`);return{create:ue(e),list:he(e),get:fe(e)}}async function k(e,t){let n=e.timeout||3e4,r=new AbortController,i=setTimeout(()=>r.abort(),n);try{let n=`https://api.cloudflare.com/client/v4/accounts/${e.accountId}/analytics_engine/sql`,i=await fetch(n,{method:`POST`,headers:{"Content-Type":`text/plain`,Authorization:`Bearer ${e.apiToken}`},body:t,signal:r.signal});if(!i.ok){let e=await i.text();throw Error(`Analytics Engine query failed: ${i.status} ${i.statusText} - ${e}`)}let a=await i.json();if(!a.success&&a.errors&&a.errors.length>0)throw Error(`Analytics Engine error: ${a.errors.map(e=>e.message).join(`, `)}`);return a.data||[]}finally{clearTimeout(i)}}function A(e){return`'${e.replace(/'/g,`''`).replace(/\\/g,`\\\\`)}'`}function j(e){return`"${e.replace(/"/g,`""`)}"`}function M(e){let t=e=>{if(e)try{return JSON.parse(e)}catch{return}},n=e.double2||e.timestamp,r=n?new Date(n).toISOString():``;return{log_id:e.blob1,type:e.blob3,date:r,description:e.blob4,ip:e.blob5,user_agent:e.blob6,user_id:e.blob7,user_name:e.blob8,connection:e.blob9,connection_id:e.blob10,client_id:e.blob11,client_name:e.blob12,audience:e.blob13,scope:e.blob14,strategy:e.blob15,strategy_type:e.blob16,hostname:e.blob17,details:t(e.blob18),auth0_client:t(e.blob19),location_info:t(e.blob20),isMobile:e.double1===1}}function ve(e){return async(t,n)=>{let r=n.log_id||w(),i={...n,log_id:r};return ye(e,t,i),i}}function ye(e,t,n){if(!e.analyticsEngineBinding){console.error(`Analytics Engine binding not configured`);return}let r=e=>e==null?``:typeof e==`string`?e:JSON.stringify(e),i=(e,t=1024)=>e.substring(0,t);try{e.analyticsEngineBinding.writeDataPoint({blobs:[i(n.log_id),i(t),i(n.type||``),i(n.description||``),i(n.ip||``),i(n.user_agent||``),i(n.user_id||``),i(n.user_name||``),i(n.connection||``),i(n.connection_id||``),i(n.client_id||``),i(n.client_name||``),i(n.audience||``),i(n.scope||``),i(n.strategy||``),i(n.strategy_type||``),i(n.hostname||``),i(r(n.details)),i(r(n.auth0_client)),i(r(n.location_info))],doubles:[+!!n.isMobile,new Date(n.date).getTime()],indexes:[t.substring(0,96)]})}catch(e){console.error(`Failed to write log to Analytics Engine:`,e)}}function be(e){return async(t,n)=>{let r=await k(e,`
15
15
  SELECT *
16
16
  FROM ${j(e.dataset||`authhero_logs`)}
17
17
  WHERE index1 = ${A(t)}
18
18
  AND blob1 = ${A(n)}
19
19
  LIMIT 1
20
- `);return r.length===0||!r[0]?null:M(r[0])}}function I(e){return e.replace(/\\([\\"+\-!(){}[\]^~*?:/&|])/g,`$1`)}function L(e){let t=[],n=``,r=!1;for(let i=0;i<e.length;i++){let a=e[i];a===`"`?(r=!r,n+=a):a===` `&&!r?(n.trim()&&t.push(n.trim()),n=``):n+=a}return n.trim()&&t.push(n.trim()),t}function R(e){let t=e;return t.startsWith(`"`)&&t.endsWith(`"`)&&t.length>1&&(t=t.slice(1,-1)),I(t)}function _e(e){let t={},n=[];for(let r of L(e)){if(r===`OR`||r===`AND`)continue;let e=r.match(/^(\w+):([\s\S]*)$/);if(e){let n=e[1],r=R(e[2]);t[n]||(t[n]=[]),t[n].push(r)}else{let e=R(r);e&&n.push(e)}}return{fields:t,terms:n}}function z(e){return{log_id:`blob1`,tenant_id:`blob2`,type:`blob3`,description:`blob4`,ip:`blob5`,user_agent:`blob6`,user_id:`blob7`,user_name:`blob8`,connection:`blob9`,connection_id:`blob10`,client_id:`blob11`,client_name:`blob12`,audience:`blob13`,scope:`blob14`,strategy:`blob15`,strategy_type:`blob16`,hostname:`blob17`}[e]||null}function ve(e){let t=[];for(let[n,r]of Object.entries(e)){let e=r.filter(e=>e!==``);if(e.length===0)continue;if(n===`success`){let n=[],r=new Set;for(let t of e)r.has(t)||(r.add(t),t===`true`?n.push(`blob3 LIKE 's%'`):t===`false`&&n.push(`blob3 LIKE 'f%'`));n.length>0&&t.push(`(${n.join(` OR `)})`);continue}let i=z(n);if(i)if(e.length===1)t.push(`${i} = ${A(e[0])}`);else{let n=e.map(e=>A(e)).join(`, `);t.push(`${i} IN (${n})`)}}return t}function ye(e){return e.filter(e=>e!==``).map(e=>{let t=A(e),n=A(`%${e}%`);return`(blob7 = ${t} OR blob5 LIKE ${n} OR blob4 LIKE ${n})`})}function be(e){return e===`date`?`double2`:z(e)||`timestamp`}function xe(e){return async(t,n={})=>{let{page:r=0,per_page:i=50,include_totals:a=!1,sort:o,q:s,from_date:c,to_date:l}=n,u=e.dataset||`authhero_logs`,d=[`index1 = ${A(t)}`];if(s){let{fields:e,terms:t}=_e(s);d.push(...ve(e)),d.push(...ye(t))}typeof c==`number`&&Number.isFinite(c)&&d.push(`double2 >= ${Math.floor(c)*1e3}`),typeof l==`number`&&Number.isFinite(l)&&d.push(`double2 <= ${Math.floor(l)*1e3}`);let f=d.join(` AND `),p=`ORDER BY timestamp DESC`;o&&o.sort_by&&(p=`ORDER BY ${be(o.sort_by)} ${o.sort_order===`asc`?`ASC`:`DESC`}`);let m=r*i,h=`LIMIT ${i} OFFSET ${m}`,g=(await k(e,`
20
+ `);return r.length===0||!r[0]?null:M(r[0])}}function N(e){let t=e;return t.startsWith(`"`)&&t.endsWith(`"`)&&t.length>1&&(t=t.slice(1,-1)),(0,l.unescapeLuceneValue)(t)}function xe(e){let t={},n=[];for(let r of(0,l.tokenizeLuceneQuery)(e)){if(r===`OR`||r===`AND`)continue;let e=r.match(/^(\w+):([\s\S]*)$/);if(e){let n=e[1],r=N(e[2]);t[n]||(t[n]=[]),t[n].push(r)}else{let e=N(r);e&&n.push(e)}}return{fields:t,terms:n}}function P(e){return{log_id:`blob1`,tenant_id:`blob2`,type:`blob3`,description:`blob4`,ip:`blob5`,user_agent:`blob6`,user_id:`blob7`,user_name:`blob8`,connection:`blob9`,connection_id:`blob10`,client_id:`blob11`,client_name:`blob12`,audience:`blob13`,scope:`blob14`,strategy:`blob15`,strategy_type:`blob16`,hostname:`blob17`}[e]||null}function Se(e){let t=[];for(let[n,r]of Object.entries(e)){let e=r.filter(e=>e!==``);if(e.length===0)continue;if(n===`success`){let n=[],r=new Set;for(let t of e)r.has(t)||(r.add(t),t===`true`?n.push(`blob3 LIKE 's%'`):t===`false`&&n.push(`blob3 LIKE 'f%'`));n.length>0&&t.push(`(${n.join(` OR `)})`);continue}let i=P(n);if(i)if(e.length===1)t.push(`${i} = ${A(e[0])}`);else{let n=e.map(e=>A(e)).join(`, `);t.push(`${i} IN (${n})`)}}return t}function Ce(e){return e.filter(e=>e!==``).map(e=>{let t=A(e),n=A(`%${e}%`);return`(blob7 = ${t} OR blob5 LIKE ${n} OR blob4 LIKE ${n})`})}function we(e){return e===`date`?`double2`:P(e)||`timestamp`}function Te(e){return async(t,n={})=>{let{page:r=0,per_page:i=50,include_totals:a=!1,sort:o,q:s,from_date:c,to_date:l}=n,u=e.dataset||`authhero_logs`,d=[`index1 = ${A(t)}`];if(s){let{fields:e,terms:t}=xe(s);d.push(...Se(e)),d.push(...Ce(t))}typeof c==`number`&&Number.isFinite(c)&&d.push(`double2 >= ${Math.floor(c)*1e3}`),typeof l==`number`&&Number.isFinite(l)&&d.push(`double2 <= ${Math.floor(l)*1e3}`);let f=d.join(` AND `),p=`ORDER BY timestamp DESC`;o&&o.sort_by&&(p=`ORDER BY ${we(o.sort_by)} ${o.sort_order===`asc`?`ASC`:`DESC`}`);let m=r*i,h=`LIMIT ${i} OFFSET ${m}`,g=(await k(e,`
21
21
  SELECT *
22
22
  FROM ${j(u)}
23
23
  WHERE ${f}
@@ -27,12 +27,12 @@ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{val
27
27
  SELECT count() as count
28
28
  FROM ${j(u)}
29
29
  WHERE ${f}
30
- `;try{let t=(await k(e,_))[0]?.count||0;return{logs:g,start:m,limit:i,length:Number(t)}}catch{return{logs:g,start:m,limit:i,length:g.length}}}}var B=[`s`],Se=[`pwd_leak`];function V(e){return`${e.slice(0,4)}-${e.slice(4,6)}-${e.slice(6,8)}`}function H(e){return e.toISOString().split(`T`)[0]}function Ce(e){let t=e.dataset||`authhero_logs`;return{async getDaily(n,r={}){let{from:i,to:a}=r,o=new Date,s=new Date(o);s.setDate(s.getDate()-30);let c=i?V(i):H(s),l=a?V(a):H(o),u=new Date(`${c}T00:00:00Z`).getTime(),d=new Date(`${l}T23:59:59.999Z`).getTime();return(await k(e,`
30
+ `;try{let t=(await k(e,_))[0]?.count||0;return{logs:g,start:m,limit:i,length:Number(t)}}catch{return{logs:g,start:m,limit:i,length:g.length}}}}var F=[`s`],Ee=[`pwd_leak`];function I(e){return/^\d{8}$/.test(e)?`${e.slice(0,4)}-${e.slice(4,6)}-${e.slice(6,8)}`:e}function L(e){return e.toISOString().split(`T`)[0]}function R(e,t){let n=new Date(`${e}T${t===`end`?`23:59:59.999`:`00:00:00.000`}Z`).getTime();if(Number.isNaN(n))return NaN;let r=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);if(!r)return n;let i=new Date(n);return i.getUTCFullYear()!==Number(r[1])||i.getUTCMonth()+1!==Number(r[2])||i.getUTCDate()!==Number(r[3])?NaN:n}function z(e){let t=e.dataset||`authhero_logs`;return{async getDaily(n,r={}){let{from:i,to:a}=r,o=new Date,s=new Date(o);s.setDate(s.getDate()-30);let c=i?I(i):L(s),l=a?I(a):L(o),u=R(c,`start`),d=R(l,`end`);if(Number.isNaN(u)||Number.isNaN(d))throw Error(`Invalid stats date range: from='${c}' to='${l}'`);return(await k(e,`
31
31
  SELECT
32
32
  toDate(toDateTime(double2 / 1000)) AS date,
33
- SUM(CASE WHEN blob3 IN (${B.map(e=>A(e)).join(`, `)}) THEN 1 ELSE 0 END) AS logins,
33
+ SUM(CASE WHEN blob3 IN (${F.map(e=>A(e)).join(`, `)}) THEN 1 ELSE 0 END) AS logins,
34
34
  SUM(CASE WHEN blob3 = 'ss' THEN 1 ELSE 0 END) AS signups,
35
- SUM(CASE WHEN blob3 IN (${Se.map(e=>A(e)).join(`, `)}) THEN 1 ELSE 0 END) AS leaked_passwords,
35
+ SUM(CASE WHEN blob3 IN (${Ee.map(e=>A(e)).join(`, `)}) THEN 1 ELSE 0 END) AS leaked_passwords,
36
36
  MIN(double2) AS first_event,
37
37
  MAX(double2) AS last_event
38
38
  FROM "${t}"
@@ -41,7 +41,7 @@ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{val
41
41
  AND double2 <= ${d}
42
42
  GROUP BY date
43
43
  ORDER BY date ASC
44
- `)).map(e=>({date:String(e.date),logins:Number(e.logins)||0,signups:Number(e.signups)||0,leaked_passwords:Number(e.leaked_passwords)||0,created_at:e.first_event?new Date(Number(e.first_event)).toISOString():new Date().toISOString(),updated_at:e.last_event?new Date(Number(e.last_event)).toISOString():new Date().toISOString()}))},async getActiveUsers(n){let r=new Date;r.setDate(r.getDate()-30);let i=r.getTime(),a=B.map(e=>A(e)).join(`, `),o=(await k(e,`
44
+ `)).map(e=>({date:String(e.date),logins:Number(e.logins)||0,signups:Number(e.signups)||0,leaked_passwords:Number(e.leaked_passwords)||0,created_at:e.first_event?new Date(Number(e.first_event)).toISOString():new Date().toISOString(),updated_at:e.last_event?new Date(Number(e.last_event)).toISOString():new Date().toISOString()}))},async getActiveUsers(n){let r=new Date;r.setDate(r.getDate()-30);let i=r.getTime(),a=F.map(e=>A(e)).join(`, `),o=(await k(e,`
45
45
  SELECT COUNT(DISTINCT blob7) AS count
46
46
  FROM "${t}"
47
47
  WHERE index1 = ${A(n)}
@@ -49,21 +49,21 @@ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{val
49
49
  AND blob3 IN (${a})
50
50
  AND blob7 IS NOT NULL
51
51
  AND blob7 != ''
52
- `))[0];return o&&o.count!==void 0&&Number(o.count)||0}}}var we={"active-users":[`s`,`seacft`],logins:[`s`,`f`,`fp`],signups:[`ss`,`fs`],"refresh-tokens":[`seacft`,`fertft`],sessions:[`slo`],logouts:[`slo`,`flo`],"password-changes":[`scp`,`fcp`,`scpr`,`fcpr`],"password-migrations":[`spm`],mfa:[`gd_auth_succeed`,`gd_auth_failed`,`gd_auth_rejected`],"email-verifications":[`sv`,`fv`,`svr`,`fvr`],"codes-sent":[`cls`,`cs`]},Te={connection:`blob9`,client_id:`blob11`,user_type:`blob16`,event:`blob3`},Ee={connection:`blob9`,client_id:`blob11`,user_type:`blob16`,user_id:`blob7`},De={"active-users":{expr:`count(DISTINCT blob7)`,alias:`active_users`,type:`UInt64`},logins:{expr:`count()`,alias:`logins`,type:`UInt64`},signups:{expr:`count()`,alias:`signups`,type:`UInt64`},"refresh-tokens":{expr:`count()`,alias:`refresh_tokens`,type:`UInt64`},sessions:{expr:`count()`,alias:`sessions`,type:`UInt64`},logouts:{expr:`count()`,alias:`logouts`,type:`UInt64`},"password-changes":{expr:`count()`,alias:`password_changes`,type:`UInt64`},"password-migrations":{expr:`count()`,alias:`password_migrations`,type:`UInt64`},mfa:{expr:`count()`,alias:`mfa`,type:`UInt64`},"email-verifications":{expr:`count()`,alias:`email_verifications`,type:`UInt64`},"codes-sent":{expr:`count()`,alias:`codes_sent`,type:`UInt64`}};function Oe(e,t){let n=`toDateTime(intDiv(double2, 1000), ${A(t)})`;switch(e){case`hour`:return`toStartOfHour(${n})`;case`week`:return`toStartOfWeek(${n})`;case`month`:return`toStartOfMonth(${n})`;default:return`toStartOfDay(${n})`}}function ke(e){return e===`hour`?`DateTime`:`Date`}function Ae(e,t,n){let r=new Date(e.from).getTime(),i=new Date(e.to).getTime(),a=n.map(e=>A(e)).join(`, `),o=[`index1 = ${A(t)}`,`double2 >= ${r}`,`double2 < ${i}`,`blob3 IN (${a})`];for(let[t,n]of Object.entries(Ee)){let r=e.filters[t];if(r&&r.length>0){let e=r.map(e=>A(e)).join(`, `);o.push(`${n} IN (${e})`)}}return o.join(` AND `)}function je(e,t,n){if(e.order_by){let t=e.order_by.startsWith(`-`);return`${j(t?e.order_by.slice(1):e.order_by)} ${t?`DESC`:`ASC`}`}return t.length>0&&t[0]===`time`?`${j(`time`)} ASC`:`${j(n)} DESC`}function U(e){let t=e.dataset||`authhero_logs`;return{async query(n,r,i){let a=we[r],o=De[r],s=[],c=[];for(let e of i.group_by)if(e===`time`){let e=Oe(i.interval,i.tz);s.push(`${e} AS ${j(`time`)}`),c.push({name:`time`,type:ke(i.interval)})}else{let t=Te[e];s.push(`${t} AS ${j(e)}`),c.push({name:e,type:`String`})}c.push({name:o.alias,type:o.type});let l=[...s,`${o.expr} AS ${j(o.alias)}`],u=i.group_by.length?`GROUP BY ${i.group_by.map(e=>j(e===`time`?`time`:e)).join(`, `)}`:``,d=je(i,i.group_by.map(e=>e===`time`?`time`:e),o.alias),f=`
52
+ `))[0];return o&&o.count!==void 0&&Number(o.count)||0}}}var De={"active-users":[`s`,`seacft`],logins:[`s`,`f`,`fp`],signups:[`ss`,`fs`],"refresh-tokens":[`seacft`,`fertft`],sessions:[`slo`],logouts:[`slo`,`flo`],"password-changes":[`scp`,`fcp`,`scpr`,`fcpr`],"password-migrations":[`spm`],mfa:[`gd_auth_succeed`,`gd_auth_failed`,`gd_auth_rejected`],"email-verifications":[`sv`,`fv`,`svr`,`fvr`],"codes-sent":[`cls`,`cs`]},Oe={connection:`blob9`,client_id:`blob11`,user_type:`blob16`,event:`blob3`},ke={connection:`blob9`,client_id:`blob11`,user_type:`blob16`,user_id:`blob7`},Ae={"active-users":{expr:`count(DISTINCT blob7)`,alias:`active_users`,type:`UInt64`},logins:{expr:`count()`,alias:`logins`,type:`UInt64`},signups:{expr:`count()`,alias:`signups`,type:`UInt64`},"refresh-tokens":{expr:`count()`,alias:`refresh_tokens`,type:`UInt64`},sessions:{expr:`count()`,alias:`sessions`,type:`UInt64`},logouts:{expr:`count()`,alias:`logouts`,type:`UInt64`},"password-changes":{expr:`count()`,alias:`password_changes`,type:`UInt64`},"password-migrations":{expr:`count()`,alias:`password_migrations`,type:`UInt64`},mfa:{expr:`count()`,alias:`mfa`,type:`UInt64`},"email-verifications":{expr:`count()`,alias:`email_verifications`,type:`UInt64`},"codes-sent":{expr:`count()`,alias:`codes_sent`,type:`UInt64`}};function je(e,t){let n=`toDateTime(intDiv(double2, 1000), ${A(t)})`;switch(e){case`hour`:return`toStartOfHour(${n})`;case`week`:return`toStartOfWeek(${n})`;case`month`:return`toStartOfMonth(${n})`;default:return`toStartOfDay(${n})`}}function Me(e){return e===`hour`?`DateTime`:`Date`}function Ne(e,t,n){let r=new Date(e.from).getTime(),i=new Date(e.to).getTime(),a=n.map(e=>A(e)).join(`, `),o=[`index1 = ${A(t)}`,`double2 >= ${r}`,`double2 < ${i}`,`blob3 IN (${a})`];for(let[t,n]of Object.entries(ke)){let r=e.filters[t];if(r&&r.length>0){let e=r.map(e=>A(e)).join(`, `);o.push(`${n} IN (${e})`)}}return o.join(` AND `)}function Pe(e,t,n){if(e.order_by){let t=e.order_by.startsWith(`-`);return`${j(t?e.order_by.slice(1):e.order_by)} ${t?`DESC`:`ASC`}`}return t.length>0&&t[0]===`time`?`${j(`time`)} ASC`:`${j(n)} DESC`}function B(e){let t=e.dataset||`authhero_logs`;return{async query(n,r,i){let a=De[r],o=Ae[r],s=[],c=[];for(let e of i.group_by)if(e===`time`){let e=je(i.interval,i.tz);s.push(`${e} AS ${j(`time`)}`),c.push({name:`time`,type:Me(i.interval)})}else{let t=Oe[e];s.push(`${t} AS ${j(e)}`),c.push({name:e,type:`String`})}c.push({name:o.alias,type:o.type});let l=[...s,`${o.expr} AS ${j(o.alias)}`],u=i.group_by.length?`GROUP BY ${i.group_by.map(e=>j(e===`time`?`time`:e)).join(`, `)}`:``,d=Pe(i,i.group_by.map(e=>e===`time`?`time`:e),o.alias),f=`
53
53
  SELECT ${l.join(`, `)}
54
54
  FROM ${j(t)}
55
- WHERE ${Ae(i,n,a)}
55
+ WHERE ${Ne(i,n,a)}
56
56
  ${u}
57
57
  ORDER BY ${d}
58
58
  LIMIT ${Math.max(0,i.limit)} OFFSET ${Math.max(0,i.offset)}
59
59
  FORMAT JSON
60
- `,p=`https://api.cloudflare.com/client/v4/accounts/${e.accountId}/analytics_engine/sql`,m=e.timeout||3e4,h=new AbortController,g=setTimeout(()=>h.abort(),m),_=Date.now();try{let t=await fetch(p,{method:`POST`,headers:{"Content-Type":`text/plain`,Authorization:`Bearer ${e.apiToken}`},body:f,signal:h.signal});if(!t.ok){let e=await t.text();throw Error(`Analytics Engine query failed: ${t.status} ${t.statusText} - ${e}`)}let n=await t.json();if(n.success===!1&&n.errors?.length)throw Error(`Analytics Engine error: ${n.errors.map(e=>e.message).join(`, `)}`);let r=n.data??[];return{meta:n.meta??c,data:r,rows:n.rows??r.length,rows_before_limit_at_least:n.rows_before_limit_at_least??r.length,statistics:{elapsed:(Date.now()-_)/1e3}}}finally{clearTimeout(g)}}}}function W(e){return e.analyticsEngineBinding||console.warn(`Analytics Engine: No binding configured. Logs will not be written to Analytics Engine.`),(!e.accountId||!e.apiToken)&&console.warn(`Analytics Engine: accountId and apiToken are required for querying logs via SQL API.`),{create:N(e),list:xe(e),get:F(e)}}var Me=`authhero_action_executions`,Ne=1024,Pe=`[truncated]`;function G(e){if(!(typeof e!=`string`||e.length===0))try{return JSON.parse(e)}catch{return}}function Fe(e){let t=l.actionExecutionStatusSchema.safeParse(e);return t.success?t.data:`unspecified`}function K(e,t=Ne){return e.length<=t?e:`${e.substring(0,t-11)}${Pe}`}function q(e){return e==null?``:JSON.stringify(e)}function Ie(e){let t=typeof e.blob6==`string`&&e.blob6.length>0?e.blob6:typeof e.double1==`number`?new Date(e.double1).toISOString():``,n=typeof e.blob7==`string`&&e.blob7.length>0?e.blob7:t;return{id:typeof e.blob1==`string`?e.blob1:``,tenant_id:typeof e.index1==`string`?e.index1:``,trigger_id:typeof e.blob2==`string`?e.blob2:``,status:Fe(e.blob3),results:G(e.blob4)??[],logs:G(e.blob5),created_at:t,updated_at:n}}function Le(e){return async(t,n)=>{let r=Date.now(),i=new Date(r).toISOString(),a={id:n.id,tenant_id:t,trigger_id:n.trigger_id,status:n.status,results:n.results,logs:n.logs,created_at:i,updated_at:i};return Re(e,t,a,r),a}}function Re(e,t,n,r){if(!e.analyticsEngineBinding){console.error(`Analytics Engine action_executions binding not configured; skipping write`);return}try{e.analyticsEngineBinding.writeDataPoint({blobs:[K(n.id),K(n.trigger_id),K(n.status),K(q(n.results)),K(q(n.logs)),K(n.created_at),K(n.updated_at)],doubles:[r],indexes:[t.substring(0,96)]})}catch(e){console.error(`Failed to write action_execution to Analytics Engine:`,e)}}function ze(e){return async(t,n)=>{let r=await k(e,`
60
+ `,p=`https://api.cloudflare.com/client/v4/accounts/${e.accountId}/analytics_engine/sql`,m=e.timeout||3e4,h=new AbortController,g=setTimeout(()=>h.abort(),m),_=Date.now();try{let t=await fetch(p,{method:`POST`,headers:{"Content-Type":`text/plain`,Authorization:`Bearer ${e.apiToken}`},body:f,signal:h.signal});if(!t.ok){let e=await t.text();throw Error(`Analytics Engine query failed: ${t.status} ${t.statusText} - ${e}`)}let n=await t.json();if(n.success===!1&&n.errors?.length)throw Error(`Analytics Engine error: ${n.errors.map(e=>e.message).join(`, `)}`);let r=n.data??[];return{meta:n.meta??c,data:r,rows:n.rows??r.length,rows_before_limit_at_least:n.rows_before_limit_at_least??r.length,statistics:{elapsed:(Date.now()-_)/1e3}}}finally{clearTimeout(g)}}}}function V(e){return e.analyticsEngineBinding||console.warn(`Analytics Engine: No binding configured. Logs will not be written to Analytics Engine.`),(!e.accountId||!e.apiToken)&&console.warn(`Analytics Engine: accountId and apiToken are required for querying logs via SQL API.`),{create:ve(e),list:Te(e),get:be(e)}}var Fe=`authhero_action_executions`,Ie=1024,Le=`[truncated]`;function H(e){if(!(typeof e!=`string`||e.length===0))try{return JSON.parse(e)}catch{return}}function Re(e){let t=l.actionExecutionStatusSchema.safeParse(e);return t.success?t.data:`unspecified`}function U(e,t=Ie){return e.length<=t?e:`${e.substring(0,t-11)}${Le}`}function W(e){return e==null?``:JSON.stringify(e)}function ze(e){let t=typeof e.blob6==`string`&&e.blob6.length>0?e.blob6:typeof e.double1==`number`?new Date(e.double1).toISOString():``,n=typeof e.blob7==`string`&&e.blob7.length>0?e.blob7:t;return{id:typeof e.blob1==`string`?e.blob1:``,tenant_id:typeof e.index1==`string`?e.index1:``,trigger_id:typeof e.blob2==`string`?e.blob2:``,status:Re(e.blob3),results:H(e.blob4)??[],logs:H(e.blob5),created_at:t,updated_at:n}}function Be(e){return async(t,n)=>{let r=Date.now(),i=new Date(r).toISOString(),a={id:n.id,tenant_id:t,trigger_id:n.trigger_id,status:n.status,results:n.results,logs:n.logs,created_at:i,updated_at:i};return Ve(e,t,a,r),a}}function Ve(e,t,n,r){if(!e.analyticsEngineBinding){console.error(`Analytics Engine action_executions binding not configured; skipping write`);return}try{e.analyticsEngineBinding.writeDataPoint({blobs:[U(n.id),U(n.trigger_id),U(n.status),U(W(n.results)),U(W(n.logs)),U(n.created_at),U(n.updated_at)],doubles:[r],indexes:[t.substring(0,96)]})}catch(e){console.error(`Failed to write action_execution to Analytics Engine:`,e)}}function He(e){return async(t,n)=>{let r=await k(e,`
61
61
  SELECT *
62
- FROM ${j(e.dataset||Me)}
62
+ FROM ${j(e.dataset||Fe)}
63
63
  WHERE index1 = ${A(t)}
64
64
  AND blob1 = ${A(n)}
65
65
  LIMIT 1
66
- `);return r.length===0||!r[0]?null:Ie(r[0])}}function J(e){return e.analyticsEngineBinding||console.warn(`Analytics Engine: No action_executions binding configured. Executions will not be written.`),(!e.accountId||!e.apiToken)&&console.warn(`Analytics Engine: accountId and apiToken are required to read action_executions via the SQL API.`),{create:Le(e),get:ze(e)}}function Be(){return{async getGeoInfo(e){try{let t=e[`cf-ipcountry`],n=e[`cf-ipcity`],r=e[`cf-iplatitude`],i=e[`cf-iplongitude`],a=e[`cf-timezone`],o=e[`cf-ipcontinent`];return t?{country_code:t,city_name:n||``,latitude:r||``,longitude:i||``,time_zone:a||``,continent_code:o||``}:null}catch(e){return console.warn(`Failed to get geo info from Cloudflare headers:`,e),null}}}}var Ve=class{bindings;constructor(e){this.bindings=e}async consume(e,t){let n=this.bindings[e];if(!n)return{allowed:!0};try{let{success:e}=await n.limit({key:t});return{allowed:e}}catch(t){return console.error(`CloudflareRateLimit: limit() error for scope ${e}:`,t),{allowed:!0}}}};function Y(e){if(e&&Object.keys(e).some(t=>e[t]))return new Ve(e)}function X(e){return`// Auto-generated AuthHero code hook worker
66
+ `);return r.length===0||!r[0]?null:ze(r[0])}}function G(e){return e.analyticsEngineBinding||console.warn(`Analytics Engine: No action_executions binding configured. Executions will not be written.`),(!e.accountId||!e.apiToken)&&console.warn(`Analytics Engine: accountId and apiToken are required to read action_executions via the SQL API.`),{create:Be(e),get:He(e)}}function Ue(){return{async getGeoInfo(e){try{let t=e[`cf-ipcountry`],n=e[`cf-ipcity`],r=e[`cf-iplatitude`],i=e[`cf-iplongitude`],a=e[`cf-timezone`],o=e[`cf-ipcontinent`];return t?{country_code:t,city_name:n||``,latitude:r||``,longitude:i||``,time_zone:a||``,continent_code:o||``}:null}catch(e){return console.warn(`Failed to get geo info from Cloudflare headers:`,e),null}}}}var We=class{bindings;constructor(e){this.bindings=e}async consume(e,t){let n=this.bindings[e];if(!n)return{allowed:!0};try{let{success:e}=await n.limit({key:t});return{allowed:e}}catch(t){return console.error(`CloudflareRateLimit: limit() error for scope ${e}:`,t),{allowed:!0}}}};function K(e){if(e&&Object.keys(e).some(t=>e[t]))return new We(e)}var Ge=5,Ke=1e3,q=50;async function qe(e,t={}){let n=Math.trunc(t.perPage??q),r=Number.isFinite(n)?Math.min(Ke,Math.max(Ge,n)):q,i=t.maxPages??200,a={scanned:0,matched:0,updated:0,unknown:0,mismatched:0,errors:0};for(let t=1;t<=i;t++){let n;try{n=await x(e).get(`/custom_hostnames?page=${t}&per_page=${r}`).json()}catch(n){return console.warn(`[custom-domains] sync failed to list page ${t} of zone ${e.zoneId}; stopping the sweep:`,n instanceof Error?n.message:n),a.errors++,a}let i=b.safeParse(n);if(!i.success||!i.data.success)return console.warn(`[custom-domains] sync got an unparseable listing for page ${t} of zone ${e.zoneId}; stopping the sweep.`,i.success?{cfErrors:i.data.errors}:{zodIssues:i.error.issues}),a.errors++,a;let o=i.data.result;for(let t of o){a.scanned++;try{let n=await e.customDomainAdapter.getByDomain(t.hostname);if(!n){a.unknown++;continue}if(e.enterprise&&t.custom_metadata?.tenant_id!==n.tenant_id){console.warn(`[custom-domains] sync skipping ${t.hostname}: zone says tenant=${t.custom_metadata?.tenant_id}, database says tenant=${n.tenant_id}.`),a.mismatched++;continue}if(n.custom_domain_id!==t.id){console.warn(`[custom-domains] sync skipping ${t.hostname} (tenant=${n.tenant_id}): stored id ${n.custom_domain_id} no longer matches the zone's ${t.id}.`),a.mismatched++;continue}a.matched++;let{outcome:r}=await ae(e,n.tenant_id,n,t);r===`updated`?a.updated++:r===`failed`&&a.errors++}catch(e){console.warn(`[custom-domains] sync failed for ${t.hostname}:`,e instanceof Error?e.message:e),a.errors++}}if(o.length<r)return a}return console.warn(`[custom-domains] sync hit the ${i}-page limit for zone ${e.zoneId}; the tail of the zone was not swept.`),a}function J(e){return`// Auto-generated AuthHero code hook worker
67
67
 
68
68
  const fnNames = {
69
69
  "post-user-login": "onExecutePostLogin",
@@ -150,9 +150,9 @@ export default {
150
150
  }
151
151
  },
152
152
  };
153
- `}var Z=class{config;constructor(e){this.config=e}async execute(e){let t=Date.now();if(!e.hookCodeId)return{success:!1,error:`DispatchNamespaceCodeExecutor requires hookCodeId`,durationMs:Date.now()-t,apiCalls:[]};let n=`hook-${e.hookCodeId}`,r=JSON.stringify({triggerId:e.triggerId,event:e.event});try{let i;if(this.config.dispatcher)i=await this.config.dispatcher.get(n,{},{limits:{cpuMs:e.cpuLimitMs??5e3}}).fetch(new Request(`https://hook.internal/execute`,{method:`POST`,headers:{"Content-Type":`application/json`},body:r}));else if(this.config.dispatchUrl)i=await fetch(`${this.config.dispatchUrl}/${n}`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.config.apiToken}`},body:r});else return{success:!1,error:`No dispatcher binding or dispatchUrl configured`,durationMs:Date.now()-t,apiCalls:[]};if(!i.ok){let e=await i.text();return{success:!1,error:`Worker invocation failed (${i.status}): ${e}`,durationMs:Date.now()-t,apiCalls:[]}}return{...await i.json(),durationMs:Date.now()-t}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e),durationMs:Date.now()-t,apiCalls:[]}}}async deploy(e,t){let n=`hook-${e}`,r=X(t),i=`https://api.cloudflare.com/client/v4/accounts/${this.config.accountId}/workers/dispatch/namespaces/${this.config.dispatchNamespace}/scripts/${n}`,a=JSON.stringify({main_module:`index.js`,compatibility_date:this.config.compatibilityDate??`2024-11-20`}),o=new FormData;o.append(`metadata`,new Blob([a],{type:`application/json`})),o.append(`index.js`,new Blob([r],{type:`application/javascript+module`}),`index.js`);let s=await fetch(i,{method:`PUT`,headers:{Authorization:`Bearer ${this.config.apiToken}`},body:o});if(!s.ok){let e=await s.text();throw Error(`Failed to deploy hook worker ${n}: ${s.status} ${e}`)}}async remove(e){let t=`hook-${e}`,n=`https://api.cloudflare.com/client/v4/accounts/${this.config.accountId}/workers/dispatch/namespaces/${this.config.dispatchNamespace}/scripts/${t}`,r=await fetch(n,{method:`DELETE`,headers:{Authorization:`Bearer ${this.config.apiToken}`}});if(!r.ok&&r.status!==404){let e=await r.text();throw Error(`Failed to remove hook worker ${t}: ${r.status} ${e}`)}}},He=Z,Ue={"post-user-login":`onExecutePostLogin`,"credentials-exchange":`onExecuteCredentialsExchange`,"pre-user-registration":`onExecutePreUserRegistration`,"post-user-registration":`onExecutePostUserRegistration`},We=l.TRIGGER_API_SHAPES;async function Ge(e){let t=new TextEncoder().encode(e),n=await crypto.subtle.digest(`SHA-256`,t),r=new Uint8Array(n),i=``;for(let e of r)i+=e.toString(16).padStart(2,`0`);return i}function Ke(e){return`
154
- const TRIGGER_FN_NAMES = ${JSON.stringify(Ue)};
155
- const API_SHAPES = ${JSON.stringify(We)};
153
+ `}var Y=class{config;constructor(e){this.config=e}async execute(e){let t=Date.now();if(!e.hookCodeId)return{success:!1,error:`DispatchNamespaceCodeExecutor requires hookCodeId`,durationMs:Date.now()-t,apiCalls:[]};let n=`hook-${e.hookCodeId}`,r=JSON.stringify({triggerId:e.triggerId,event:e.event});try{let i;if(this.config.dispatcher)i=await this.config.dispatcher.get(n,{},{limits:{cpuMs:e.cpuLimitMs??5e3}}).fetch(new Request(`https://hook.internal/execute`,{method:`POST`,headers:{"Content-Type":`application/json`},body:r}));else if(this.config.dispatchUrl)i=await fetch(`${this.config.dispatchUrl}/${n}`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${this.config.apiToken}`},body:r});else return{success:!1,error:`No dispatcher binding or dispatchUrl configured`,durationMs:Date.now()-t,apiCalls:[]};if(!i.ok){let e=await i.text();return{success:!1,error:`Worker invocation failed (${i.status}): ${e}`,durationMs:Date.now()-t,apiCalls:[]}}return{...await i.json(),durationMs:Date.now()-t}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e),durationMs:Date.now()-t,apiCalls:[]}}}async deploy(e,t){let n=`hook-${e}`,r=J(t),i=`https://api.cloudflare.com/client/v4/accounts/${this.config.accountId}/workers/dispatch/namespaces/${this.config.dispatchNamespace}/scripts/${n}`,a=JSON.stringify({main_module:`index.js`,compatibility_date:this.config.compatibilityDate??`2024-11-20`}),o=new FormData;o.append(`metadata`,new Blob([a],{type:`application/json`})),o.append(`index.js`,new Blob([r],{type:`application/javascript+module`}),`index.js`);let s=await fetch(i,{method:`PUT`,headers:{Authorization:`Bearer ${this.config.apiToken}`},body:o});if(!s.ok){let e=await s.text();throw Error(`Failed to deploy hook worker ${n}: ${s.status} ${e}`)}}async remove(e){let t=`hook-${e}`,n=`https://api.cloudflare.com/client/v4/accounts/${this.config.accountId}/workers/dispatch/namespaces/${this.config.dispatchNamespace}/scripts/${t}`,r=await fetch(n,{method:`DELETE`,headers:{Authorization:`Bearer ${this.config.apiToken}`}});if(!r.ok&&r.status!==404){let e=await r.text();throw Error(`Failed to remove hook worker ${t}: ${r.status} ${e}`)}}},Je=Y,Ye={"post-user-login":`onExecutePostLogin`,"credentials-exchange":`onExecuteCredentialsExchange`,"pre-user-registration":`onExecutePreUserRegistration`,"post-user-registration":`onExecutePostUserRegistration`},Xe=l.TRIGGER_API_SHAPES;async function Ze(e){let t=new TextEncoder().encode(e),n=await crypto.subtle.digest(`SHA-256`,t),r=new Uint8Array(n),i=``;for(let e of r)i+=e.toString(16).padStart(2,`0`);return i}function Qe(e){return`
154
+ const TRIGGER_FN_NAMES = ${JSON.stringify(Ye)};
155
+ const API_SHAPES = ${JSON.stringify(Xe)};
156
156
  const MAX_LOG_ENTRIES = 50;
157
157
  const MAX_LOG_LENGTH = 500;
158
158
 
@@ -250,4 +250,4 @@ export default {
250
250
  }
251
251
  },
252
252
  };
253
- `}var qe=class{loader;compatibilityDate;constructor(e){this.loader=e.loader,this.compatibilityDate=e.compatibilityDate||`2025-01-01`}async execute(e){let t=Date.now();try{let t=Ke(e.code),n={compatibilityDate:this.compatibilityDate,mainModule:`hook.js`,modules:{"hook.js":t}},r=e.hookCodeId?`${e.hookCodeId}-${await Ge(e.code)}`:null;return await(await(r?this.loader.get(r,async()=>n):this.loader.load(n)).getEntrypoint().fetch(new Request(`https://hook/execute`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({event:e.event,triggerId:e.triggerId})}))).json()}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e),durationMs:Date.now()-t,apiCalls:[]}}}};function Je(e){let t=c.n(e);return{async onProvision(e){let{scriptName:n,databaseName:r}=t.names(e),{databaseVersion:i,bundleConfiguration:a,workerVersion:o}=t.validate(),{id:s,created:c}=await t.findOrCreateDatabase(r);return await t.applyMigrations(s,c),await t.uploadScript(n,s),await t.uploadSecrets(n,e),{d1DatabaseId:s,scriptName:n,d1Name:r,bundleConfiguration:a,workerVersion:o,databaseVersion:i}},async onDeprovision(e){await t.deprovision(e)}}}function Ye(e){return e.deployment_type===`wfp`}var Q=2048;function $(e){let t;if(e instanceof Error)t=e.message;else try{t=String(e)}catch{t=Object.prototype.toString.call(e)}return t.slice(0,Q)}function Xe(e){let{provisioner:t,tenants:n,syncDefaults:r}=e,i=e.shouldProvision??Ye,a=e.logger;async function o(e,t){try{await n.update(e,{provisioning_state:`failed`,provisioning_error:$(t),provisioning_state_changed_at:new Date().toISOString()})}catch(t){a?.warn(`Failed to write provisioning_state="failed" for tenant ${e}:`,t)}}async function s(e,i){let s=async(t,n,r)=>{if(i)try{await i(t,n,r)}catch(n){a?.warn(`Failed to report provisioning step "${t}" for tenant ${e}:`,n)}};await s(`provision-resources`,`started`);let l;try{l=await t.onProvision(e)}catch(t){throw await s(`provision-resources`,`failed`,{message:$(t)}),await o(e,t),t}let u={d1_database_id:l.d1DatabaseId,worker_script_name:l.scriptName,bundle_configuration:l.bundleConfiguration,worker_version:l.workerVersion,database_version:l.databaseVersion};await s(`provision-resources`,`succeeded`,{...u});try{if(r){await s(`seed-defaults`,`started`);try{let t=c.t(await r(e));if(t.length>0)throw Error(`sync-defaults seed reported ${t.length} error(s): ${t.join(`; `)}`);await s(`seed-defaults`,`succeeded`)}catch(e){throw await s(`seed-defaults`,`failed`,{message:$(e)}),e}}await n.update(e,{...u,provisioning_state:`ready`,provisioning_error:void 0,provisioning_state_changed_at:new Date().toISOString()})}catch(t){try{await n.update(e,{...u,provisioning_state:`failed`,provisioning_error:$(t),provisioning_state_changed_at:new Date().toISOString()})}catch(t){a?.warn(`Failed to write provisioning_state="failed" for tenant ${e}:`,t)}throw t}}return{async onProvision(e,t){let r=await n.get(e);r&&i(r)&&await s(e,t)},async onUpgrade(e,t){let r=await n.get(e);if(!r)throw Error(`Cannot upgrade tenant "${e}": not found.`);if(!i(r))throw Error(`Cannot upgrade tenant "${e}": not a WFP-provisioned tenant.`);try{await n.update(e,{provisioning_state:`pending`,provisioning_error:void 0,provisioning_state_changed_at:new Date().toISOString()})}catch(t){a?.warn(`Failed to write provisioning_state="pending" for tenant ${e}:`,t)}await s(e,t)},async onDeprovision(e){let r=await n.get(e);r&&!i(r)||await t.onDeprovision(e)}}}var Ze=`DISPATCHER`,Qe=`tenant-{tenant_id}-auth`,$e=[`/u/widget/`];function et(e){return typeof e==`object`&&!!e&&`get`in e&&typeof Reflect.get(e,`get`)==`function`}function tt(e,t){return e.replace(/\{tenant_id\}/g,t)}function nt(e){let{tenants:t,controlPlaneTenantId:n,dispatcherBinding:r=Ze,scriptNameTemplate:i=Qe,resolveTenantId:a=e=>e.req.header(`tenant-id`),localPaths:o=$e}=e;return async(e,s)=>{if(o.length>0){let t=e.req.path;if(o.some(e=>t.startsWith(e)))return s()}let c=await a(e);if(!c||c===n)return s();let l=await t.get(c);if(!l||l.deployment_type!==`wfp`||l.provisioning_state&&l.provisioning_state!==`ready`)return s();let u=Reflect.get(e.env??{},r);if(!et(u))return s();let d=tt(i,c),f;try{f=await u.get(d).fetch(e.req.raw)}catch(t){let n=t instanceof Error?t.message:String(t),r=/not\s*found|no\s*such|does not exist/i.test(n),i=r?`wfp_worker_not_found`:`wfp_dispatch_failed`;return console.error(`[wfp-forward] ${i} tenant=${c} script=${d}: ${n}`),e.header(`X-Authhero-Error`,i),e.header(`X-Wfp-Tenant`,c),e.json({error:i,detail:r?`Tenant '${c}' is marked ready but its worker '${d}' is not deployed in the dispatch namespace.`:`The worker for tenant '${c}' could not be reached.`,tenant_id:c},r?503:502)}if(f.status>=500){let e=f.headers.get(`X-Authhero-Error`);console.error(`[wfp-forward] tenant worker ${f.status}${e?` (${e})`:``} tenant=${c} script=${d}`)}let p=Reflect.get(f,`webSocket`);if(f.status===101||p!=null)return f;let m=new Response(f.body,f);return m.headers.set(`X-Wfp-Tenant`,c),m}}function rt(e){let t={customDomains:oe(e),cache:ce({...e.cacheName&&{cacheName:e.cacheName},...e.defaultTtlSeconds!==void 0&&{defaultTtlSeconds:e.defaultTtlSeconds},...e.keyPrefix&&{keyPrefix:e.keyPrefix}}),geo:Be()};e.r2SqlLogs?t.logs=O(e.r2SqlLogs):e.analyticsEngineLogs&&(t.logs=W(e.analyticsEngineLogs)),e.analyticsEngineLogs&&(t.analytics=U(e.analyticsEngineLogs)),e.analyticsEngineActionExecutions&&(t.actionExecutions=J(e.analyticsEngineActionExecutions));let n=Y(e.rateLimitBindings);return n&&(t.rateLimit=n),t}exports.CloudflareApiClient=c.i,exports.CloudflareApiError=c.a,exports.CloudflareCodeExecutor=He,exports.DispatchNamespaceCodeExecutor=Z,exports.WorkerLoaderCodeExecutor=qe,exports.createAnalyticsEngineActionExecutionsAdapter=J,exports.createAnalyticsEngineAnalyticsAdapter=U,exports.createAnalyticsEngineLogsAdapter=W,exports.createAnalyticsEngineStatsAdapter=Ce,exports.createCloudflareRateLimitAdapter=Y,exports.createCloudflareWfpD1Provisioner=Je,exports.createR2SQLLogsAdapter=O,exports.createR2SQLStatsAdapter=ge,exports.createWfpForwardMiddleware=nt,exports.createWfpProvisionerSteps=c.n,exports.createWfpTenantProvisioningHook=Xe,exports.default=rt,exports.generateWorkerScript=X;
253
+ `}var $e=class{loader;compatibilityDate;constructor(e){this.loader=e.loader,this.compatibilityDate=e.compatibilityDate||`2025-01-01`}async execute(e){let t=Date.now();try{let t=Qe(e.code),n={compatibilityDate:this.compatibilityDate,mainModule:`hook.js`,modules:{"hook.js":t}},r=e.hookCodeId?`${e.hookCodeId}-${await Ze(e.code)}`:null;return await(await(r?this.loader.get(r,async()=>n):this.loader.load(n)).getEntrypoint().fetch(new Request(`https://hook/execute`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({event:e.event,triggerId:e.triggerId})}))).json()}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e),durationMs:Date.now()-t,apiCalls:[]}}}},X=new TextEncoder;function Z(e,t){if(X.encode(e).length<=t)return e;let n=0,r=``;for(let i of e){let e=X.encode(i).length;if(n+e>t)break;n+=e,r+=i}return r}var Q=(e,t=1024)=>Z(e,t);function et(e){let t=e.analyticsEngineBinding;return e=>{if(t)try{t.writeDataPoint({blobs:[Q(e.name),Q(e.tenantId),Q(e.eventType),Q(e.source),Q(e.destination??``),Q(e.error??``)],doubles:[e.value,e.retryCount??0,Date.now()],indexes:[Z(e.tenantId,96)]})}catch(e){console.error(`Failed to write outbox metric to Analytics Engine:`,e)}}}function tt(e){let t=c.n(e);return{async onProvision(e){let{scriptName:n,databaseName:r}=t.names(e),{databaseVersion:i,bundleConfiguration:a,workerVersion:o}=t.validate(),{id:s,created:c}=await t.findOrCreateDatabase(r);return await t.applyMigrations(s,c),await t.uploadScript(n,s),await t.uploadSecrets(n,e),{d1DatabaseId:s,scriptName:n,d1Name:r,bundleConfiguration:a,workerVersion:o,databaseVersion:i}},async onDeprovision(e){await t.deprovision(e)}}}function nt(e){return e.deployment_type===`wfp`}var rt=2048;function $(e){let t;if(e instanceof Error)t=e.message;else try{t=String(e)}catch{t=Object.prototype.toString.call(e)}return t.slice(0,rt)}function it(e){let{provisioner:t,tenants:n,syncDefaults:r}=e,i=e.shouldProvision??nt,a=e.logger;async function o(e,t){try{await n.update(e,{provisioning_state:`failed`,provisioning_error:$(t),provisioning_state_changed_at:new Date().toISOString()})}catch(t){a?.warn(`Failed to write provisioning_state="failed" for tenant ${e}:`,t)}}async function s(e,i){let s=async(t,n,r)=>{if(i)try{await i(t,n,r)}catch(n){a?.warn(`Failed to report provisioning step "${t}" for tenant ${e}:`,n)}};await s(`provision-resources`,`started`);let l;try{l=await t.onProvision(e)}catch(t){throw await s(`provision-resources`,`failed`,{message:$(t)}),await o(e,t),t}let u={d1_database_id:l.d1DatabaseId,worker_script_name:l.scriptName,bundle_configuration:l.bundleConfiguration,worker_version:l.workerVersion,database_version:l.databaseVersion};await s(`provision-resources`,`succeeded`,{...u});try{if(r){await s(`seed-defaults`,`started`);try{let t=c.t(await r(e));if(t.length>0)throw Error(`sync-defaults seed reported ${t.length} error(s): ${t.join(`; `)}`);await s(`seed-defaults`,`succeeded`)}catch(e){throw await s(`seed-defaults`,`failed`,{message:$(e)}),e}}await n.update(e,{...u,provisioning_state:`ready`,provisioning_error:void 0,provisioning_state_changed_at:new Date().toISOString()})}catch(t){try{await n.update(e,{...u,provisioning_state:`failed`,provisioning_error:$(t),provisioning_state_changed_at:new Date().toISOString()})}catch(t){a?.warn(`Failed to write provisioning_state="failed" for tenant ${e}:`,t)}throw t}}return{async onProvision(e,t){let r=await n.get(e);r&&i(r)&&await s(e,t)},async onUpgrade(e,t){let r=await n.get(e);if(!r)throw Error(`Cannot upgrade tenant "${e}": not found.`);if(!i(r))throw Error(`Cannot upgrade tenant "${e}": not a WFP-provisioned tenant.`);try{await n.update(e,{provisioning_state:`pending`,provisioning_error:void 0,provisioning_state_changed_at:new Date().toISOString()})}catch(t){a?.warn(`Failed to write provisioning_state="pending" for tenant ${e}:`,t)}await s(e,t)},async onDeprovision(e){let r=await n.get(e);r&&!i(r)||await t.onDeprovision(e)}}}var at=`DISPATCHER`,ot=`tenant-{tenant_id}-auth`,st=[`/u/widget/`];function ct(e){return typeof e==`object`&&!!e&&`get`in e&&typeof Reflect.get(e,`get`)==`function`}function lt(e,t){return e.replace(/\{tenant_id\}/g,t)}function ut(e){let{tenants:t,controlPlaneTenantId:n,dispatcherBinding:r=at,scriptNameTemplate:i=ot,resolveTenantId:a=e=>e.req.header(`tenant-id`),localPaths:o=st}=e;return async(e,s)=>{if(o.length>0){let t=e.req.path;if(o.some(e=>t.startsWith(e)))return s()}let c=await a(e);if(!c||c===n)return s();let l=await t.get(c);if(!l||l.deployment_type!==`wfp`||l.provisioning_state&&l.provisioning_state!==`ready`)return s();let u=Reflect.get(e.env??{},r);if(!ct(u))return s();let d=lt(i,c),f;try{f=await u.get(d).fetch(e.req.raw)}catch(t){let n=t instanceof Error?t.message:String(t),r=/not\s*found|no\s*such|does not exist/i.test(n),i=r?`wfp_worker_not_found`:`wfp_dispatch_failed`;return console.error(`[wfp-forward] ${i} tenant=${c} script=${d}: ${n}`),e.header(`X-Authhero-Error`,i),e.header(`X-Wfp-Tenant`,c),e.json({error:i,detail:r?`Tenant '${c}' is marked ready but its worker '${d}' is not deployed in the dispatch namespace.`:`The worker for tenant '${c}' could not be reached.`,tenant_id:c},r?503:502)}if(f.status>=500){let e=f.headers.get(`X-Authhero-Error`);console.error(`[wfp-forward] tenant worker ${f.status}${e?` (${e})`:``} tenant=${c} script=${d}`)}let p=Reflect.get(f,`webSocket`);if(f.status===101||p!=null)return f;let m=new Response(f.body,f);return m.headers.set(`X-Wfp-Tenant`,c),m}}function dt(e){let t={customDomains:oe(e),cache:ce({...e.cacheName&&{cacheName:e.cacheName},...e.defaultTtlSeconds!==void 0&&{defaultTtlSeconds:e.defaultTtlSeconds},...e.keyPrefix&&{keyPrefix:e.keyPrefix}}),geo:Ue()};e.r2SqlLogs?t.logs=_e(e.r2SqlLogs):e.analyticsEngineLogs&&(t.logs=V(e.analyticsEngineLogs)),e.analyticsEngineLogs&&(t.analytics=B(e.analyticsEngineLogs),t.stats=z(e.analyticsEngineLogs)),e.analyticsEngineActionExecutions&&(t.actionExecutions=G(e.analyticsEngineActionExecutions));let n=K(e.rateLimitBindings);return n&&(t.rateLimit=n),t}exports.CloudflareApiClient=c.i,exports.CloudflareApiError=c.a,exports.CloudflareCodeExecutor=Je,exports.DispatchNamespaceCodeExecutor=Y,exports.WorkerLoaderCodeExecutor=$e,exports.createAnalyticsEngineActionExecutionsAdapter=G,exports.createAnalyticsEngineAnalyticsAdapter=B,exports.createAnalyticsEngineLogsAdapter=V,exports.createAnalyticsEngineOutboxMetricsSink=et,exports.createAnalyticsEngineStatsAdapter=z,exports.createCloudflareRateLimitAdapter=K,exports.createCloudflareWfpD1Provisioner=tt,exports.createR2SQLLogsAdapter=_e,exports.createR2SQLStatsAdapter=ge,exports.createWfpForwardMiddleware=ut,exports.createWfpProvisionerSteps=c.n,exports.createWfpTenantProvisioningHook=it,exports.default=dt,exports.generateWorkerScript=J,exports.syncCustomDomains=qe;
@@ -336,6 +336,84 @@ interface CloudflareConfig {
336
336
  rateLimitBindings?: CloudflareRateLimitBindings;
337
337
  }
338
338
 
339
+ interface SyncCustomDomainsOptions {
340
+ /**
341
+ * Hostnames fetched per Cloudflare API call. Cloudflare accepts 5 to 1000
342
+ * (its own default is 20); values outside that are clamped rather than
343
+ * rejected, since a cron should not die on a config typo. Defaults to 50.
344
+ */
345
+ perPage?: number;
346
+ /**
347
+ * Safety stop, in pages. A zone larger than `perPage * maxPages` is swept
348
+ * partially rather than looping forever on a paginating API that never
349
+ * reports a short page. Default 200 (10 000 hostnames at the default size).
350
+ */
351
+ maxPages?: number;
352
+ }
353
+ interface SyncCustomDomainsResult {
354
+ /** Hostnames returned by Cloudflare across every page. */
355
+ scanned: number;
356
+ /** Hostnames that matched a stored custom-domain row. */
357
+ matched: number;
358
+ /** Rows whose `status` or `verification` actually changed. */
359
+ updated: number;
360
+ /**
361
+ * Hostnames in the zone with no stored row. Expected to be 0 in a zone
362
+ * AuthHero owns exclusively; a non-zero count means either a hostname
363
+ * registered outside AuthHero or a `create` that died between the Cloudflare
364
+ * call and the DB write.
365
+ */
366
+ unknown: number;
367
+ /**
368
+ * Stored rows whose `custom_domain_id` no longer matches the hostname's id
369
+ * at the edge — the hostname was deleted and re-registered behind our back.
370
+ * Left untouched: adopting the new id would rewrite a primary key that
371
+ * `proxy_routes` and the KV host blobs point at.
372
+ */
373
+ mismatched: number;
374
+ /**
375
+ * Hostnames that could not be reconciled — a throw, or a merge/writeback
376
+ * that failed without throwing. Each one is logged. A sweep reporting
377
+ * `updated: 0` is only healthy when this is 0 too.
378
+ */
379
+ errors: number;
380
+ }
381
+ /**
382
+ * Reconcile every custom hostname in the Cloudflare zone against the stored
383
+ * custom-domain rows.
384
+ *
385
+ * Without this, `status` and `verification` only ever refresh when someone
386
+ * reads a single domain by id (`get()`): `list()` and `getByDomain()` are
387
+ * deliberately DB-only so they stay fast and survive a Cloudflare outage. A
388
+ * hostname that finishes validation at the edge therefore stays `pending` in
389
+ * the database until a human happens to open its detail page. This closes that
390
+ * gap on a schedule.
391
+ *
392
+ * Enumerates Cloudflare-first — one paginated list call per 50 hostnames,
393
+ * rather than one request per stored domain — then resolves each hostname's
394
+ * tenant through `getByDomain`, which every adapter indexes because it is the
395
+ * request-routing path.
396
+ *
397
+ * One hostname's failure never aborts the sweep, and the result is returned
398
+ * rather than thrown: a cron that dies halfway leaves the rest of the zone
399
+ * stale until the next run.
400
+ *
401
+ * Deletion is deliberately out of scope. A hostname removed at the edge simply
402
+ * stops appearing in the listing, and "absent from a page I may have failed to
403
+ * fetch" is not evidence a domain is gone — removals go through `remove()`.
404
+ *
405
+ * @example
406
+ * ```ts
407
+ * export default {
408
+ * async scheduled(event, env) {
409
+ * const config = buildCloudflareConfig(env);
410
+ * console.log("custom domain sync", await syncCustomDomains(config));
411
+ * },
412
+ * };
413
+ * ```
414
+ */
415
+ declare function syncCustomDomains(config: CloudflareConfig, options?: SyncCustomDomainsOptions): Promise<SyncCustomDomainsResult>;
416
+
339
417
  /**
340
418
  * Cloudflare Workers for Platforms dispatch namespace binding type.
341
419
  * This is the type of `env.DISPATCHER` when configured in wrangler.toml:
@@ -509,6 +587,67 @@ declare class WorkerLoaderCodeExecutor implements CodeExecutor {
509
587
  }): Promise<CodeExecutionResult>;
510
588
  }
511
589
 
590
+ /**
591
+ * One metric emission from the authhero outbox relay.
592
+ *
593
+ * Structurally identical to authhero's `OutboxMetric`. It is redeclared here
594
+ * so this adapter keeps working without `authhero` installed — it is only an
595
+ * optional peer dependency of this package.
596
+ */
597
+ interface OutboxMetricRecord {
598
+ /**
599
+ * `outbox_events_processed_total`, `outbox_events_dead_lettered_total` or
600
+ * `outbox_retry_delay_seconds`.
601
+ */
602
+ name: string;
603
+ /** Counter increment, or the observed retry delay in seconds. */
604
+ value: number;
605
+ tenantId: string;
606
+ eventType: string;
607
+ source: "request" | "cron";
608
+ destination?: string;
609
+ error?: string;
610
+ retryCount?: number;
611
+ }
612
+ interface AnalyticsEngineOutboxMetricsConfig {
613
+ /**
614
+ * Cloudflare Analytics Engine dataset binding (e.g. `env.OUTBOX_METRICS`).
615
+ * When absent the sink is a no-op, so the same wiring works locally.
616
+ */
617
+ analyticsEngineBinding?: AnalyticsEngineDataset;
618
+ }
619
+ /**
620
+ * Create an Analytics Engine sink for outbox relay metrics.
621
+ *
622
+ * Pass the returned function to `init({ outbox: { metrics } })` and to
623
+ * `runOutboxRelay({ metrics })` so both the inline per-request relay and the
624
+ * cron drain report to the same dataset. Rows are indexed by tenant, matching
625
+ * `createAnalyticsEngineLogsAdapter`.
626
+ *
627
+ * Column layout:
628
+ * - blob1 `name`, blob2 `tenant_id`, blob3 `event_type`, blob4 `source`,
629
+ * blob5 `destination`, blob6 `error`
630
+ * - double1 `value`, double2 `retry_count`, double3 `timestamp` (ms)
631
+ * - index1 `tenant_id`
632
+ *
633
+ * @example
634
+ * ```typescript
635
+ * // wrangler.toml:
636
+ * // [[analytics_engine_datasets]]
637
+ * // binding = "OUTBOX_METRICS"
638
+ * // dataset = "authhero_outbox_metrics"
639
+ *
640
+ * import { createAnalyticsEngineOutboxMetricsSink } from "@authhero/cloudflare-adapter";
641
+ *
642
+ * const metrics = createAnalyticsEngineOutboxMetricsSink({
643
+ * analyticsEngineBinding: env.OUTBOX_METRICS,
644
+ * });
645
+ *
646
+ * const app = init({ dataAdapter, outbox: { enabled: true, metrics } });
647
+ * ```
648
+ */
649
+ declare function createAnalyticsEngineOutboxMetricsSink(config: AnalyticsEngineOutboxMetricsConfig): (metric: OutboxMetricRecord) => void;
650
+
512
651
  /**
513
652
  * Thin Cloudflare REST API client for the WFP+D1 provisioner.
514
653
  *
@@ -1067,11 +1206,12 @@ interface CloudflareAdapters {
1067
1206
  cache: CacheAdapter;
1068
1207
  logs?: LogsDataAdapter;
1069
1208
  analytics?: AnalyticsAdapter;
1209
+ stats?: StatsAdapter;
1070
1210
  geo?: GeoAdapter;
1071
1211
  rateLimit?: RateLimitAdapter;
1072
1212
  actionExecutions?: ActionExecutionsAdapter;
1073
1213
  }
1074
1214
  declare function createAdapters(config: CloudflareConfig): CloudflareAdapters;
1075
1215
 
1076
- export { CloudflareApiClient, CloudflareApiError, CloudflareCodeExecutor, DispatchNamespaceCodeExecutor, WorkerLoaderCodeExecutor, createAnalyticsEngineActionExecutionsAdapter, createAnalyticsEngineAnalyticsAdapter, createAnalyticsEngineLogsAdapter, createAnalyticsEngineStatsAdapter, createCloudflareRateLimitAdapter, createCloudflareWfpD1Provisioner, createR2SQLLogsAdapter, createR2SQLStatsAdapter, createWfpForwardMiddleware, createWfpProvisionerSteps, createWfpTenantProvisioningHook, createAdapters as default, generateWorkerScript };
1077
- export type { AnalyticsEngineActionExecutionsAdapterConfig, AnalyticsEngineDataset, AnalyticsEngineLogsAdapterConfig, CfApiClientOptions, CloudflareAdapters, CloudflareCodeExecutorConfig, CloudflareConfig, CloudflareRateLimitBinding, CloudflareRateLimitBindings, CloudflareWfpD1Provisioner, CloudflareWfpD1ProvisionerOptions, D1Database, D1QueryResult, DispatchNamespace, DispatchNamespaceCodeExecutorConfig, ProvisionResult, ProvisionerMigration, R2SQLLogsAdapterConfig, ScriptBinding, ScriptUploadOptions, TenantProvisionNames, TenantProvisionerSteps, TenantSecretsResolver, WfpForwardOptions, WfpProvisionerSteps, WfpTenantProvisioningHook, WfpTenantProvisioningHookOptions, WorkerCode, WorkerLoader, WorkerLoaderCodeExecutorOptions, WorkerStub };
1216
+ export { CloudflareApiClient, CloudflareApiError, CloudflareCodeExecutor, DispatchNamespaceCodeExecutor, WorkerLoaderCodeExecutor, createAnalyticsEngineActionExecutionsAdapter, createAnalyticsEngineAnalyticsAdapter, createAnalyticsEngineLogsAdapter, createAnalyticsEngineOutboxMetricsSink, createAnalyticsEngineStatsAdapter, createCloudflareRateLimitAdapter, createCloudflareWfpD1Provisioner, createR2SQLLogsAdapter, createR2SQLStatsAdapter, createWfpForwardMiddleware, createWfpProvisionerSteps, createWfpTenantProvisioningHook, createAdapters as default, generateWorkerScript, syncCustomDomains };
1217
+ export type { AnalyticsEngineActionExecutionsAdapterConfig, AnalyticsEngineDataset, AnalyticsEngineLogsAdapterConfig, AnalyticsEngineOutboxMetricsConfig, CfApiClientOptions, CloudflareAdapters, CloudflareCodeExecutorConfig, CloudflareConfig, CloudflareRateLimitBinding, CloudflareRateLimitBindings, CloudflareWfpD1Provisioner, CloudflareWfpD1ProvisionerOptions, D1Database, D1QueryResult, DispatchNamespace, DispatchNamespaceCodeExecutorConfig, OutboxMetricRecord, ProvisionResult, ProvisionerMigration, R2SQLLogsAdapterConfig, ScriptBinding, ScriptUploadOptions, SyncCustomDomainsOptions, SyncCustomDomainsResult, TenantProvisionNames, TenantProvisionerSteps, TenantSecretsResolver, WfpForwardOptions, WfpProvisionerSteps, WfpTenantProvisioningHook, WfpTenantProvisioningHookOptions, WorkerCode, WorkerLoader, WorkerLoaderCodeExecutorOptions, WorkerStub };