@grainql/analytics-web 1.7.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +71 -718
  2. package/dist/cjs/react/GrainProvider.d.ts +11 -0
  3. package/dist/cjs/react/GrainProvider.d.ts.map +1 -0
  4. package/dist/cjs/react/GrainProvider.js +79 -0
  5. package/dist/cjs/react/GrainProvider.js.map +1 -0
  6. package/dist/cjs/react/context.d.ts +11 -0
  7. package/dist/cjs/react/context.d.ts.map +1 -0
  8. package/dist/cjs/react/context.js +43 -0
  9. package/dist/cjs/react/context.js.map +1 -0
  10. package/dist/cjs/react/hooks/useAllConfigs.d.ts +8 -0
  11. package/dist/cjs/react/hooks/useAllConfigs.d.ts.map +1 -0
  12. package/dist/cjs/react/hooks/useAllConfigs.js +112 -0
  13. package/dist/cjs/react/hooks/useAllConfigs.js.map +1 -0
  14. package/dist/cjs/react/hooks/useConfig.d.ts +9 -0
  15. package/dist/cjs/react/hooks/useConfig.d.ts.map +1 -0
  16. package/dist/cjs/react/hooks/useConfig.js +116 -0
  17. package/dist/cjs/react/hooks/useConfig.js.map +1 -0
  18. package/dist/cjs/react/hooks/useGrainAnalytics.d.ts +6 -0
  19. package/dist/cjs/react/hooks/useGrainAnalytics.d.ts.map +1 -0
  20. package/dist/cjs/react/hooks/useGrainAnalytics.js +50 -0
  21. package/dist/cjs/react/hooks/useGrainAnalytics.js.map +1 -0
  22. package/dist/cjs/react/hooks/useTrack.d.ts +9 -0
  23. package/dist/cjs/react/hooks/useTrack.d.ts.map +1 -0
  24. package/dist/cjs/react/hooks/useTrack.js +53 -0
  25. package/dist/cjs/react/hooks/useTrack.js.map +1 -0
  26. package/dist/cjs/react/index.d.ts +36 -0
  27. package/dist/cjs/react/index.d.ts.map +1 -0
  28. package/dist/cjs/react/index.js +45 -0
  29. package/dist/cjs/react/index.js.map +1 -0
  30. package/dist/cjs/react/types.d.ts +33 -0
  31. package/dist/cjs/react/types.d.ts.map +1 -0
  32. package/dist/cjs/react/types.js +6 -0
  33. package/dist/cjs/react/types.js.map +1 -0
  34. package/dist/esm/react/GrainProvider.d.ts +11 -0
  35. package/dist/esm/react/GrainProvider.d.ts.map +1 -0
  36. package/dist/esm/react/GrainProvider.js +43 -0
  37. package/dist/esm/react/GrainProvider.js.map +1 -0
  38. package/dist/esm/react/context.d.ts +11 -0
  39. package/dist/esm/react/context.d.ts.map +1 -0
  40. package/dist/esm/react/context.js +7 -0
  41. package/dist/esm/react/context.js.map +1 -0
  42. package/dist/esm/react/hooks/useAllConfigs.d.ts +8 -0
  43. package/dist/esm/react/hooks/useAllConfigs.d.ts.map +1 -0
  44. package/dist/esm/react/hooks/useAllConfigs.js +76 -0
  45. package/dist/esm/react/hooks/useAllConfigs.js.map +1 -0
  46. package/dist/esm/react/hooks/useConfig.d.ts +9 -0
  47. package/dist/esm/react/hooks/useConfig.d.ts.map +1 -0
  48. package/dist/esm/react/hooks/useConfig.js +80 -0
  49. package/dist/esm/react/hooks/useConfig.js.map +1 -0
  50. package/dist/esm/react/hooks/useGrainAnalytics.d.ts +6 -0
  51. package/dist/esm/react/hooks/useGrainAnalytics.d.ts.map +1 -0
  52. package/dist/esm/react/hooks/useGrainAnalytics.js +14 -0
  53. package/dist/esm/react/hooks/useGrainAnalytics.js.map +1 -0
  54. package/dist/esm/react/hooks/useTrack.d.ts +9 -0
  55. package/dist/esm/react/hooks/useTrack.d.ts.map +1 -0
  56. package/dist/esm/react/hooks/useTrack.js +17 -0
  57. package/dist/esm/react/hooks/useTrack.js.map +1 -0
  58. package/dist/esm/react/index.d.ts +36 -0
  59. package/dist/esm/react/index.d.ts.map +1 -0
  60. package/dist/esm/react/index.js +37 -0
  61. package/dist/esm/react/index.js.map +1 -0
  62. package/dist/esm/react/types.d.ts +33 -0
  63. package/dist/esm/react/types.d.ts.map +1 -0
  64. package/dist/esm/react/types.js +5 -0
  65. package/dist/esm/react/types.js.map +1 -0
  66. package/dist/index.global.dev.js +1 -1
  67. package/dist/index.global.js +1 -1
  68. package/dist/react/index.d.ts +405 -0
  69. package/dist/react/index.d.ts.map +1 -0
  70. package/dist/react/index.js +1181 -0
  71. package/dist/react/index.mjs +1176 -0
  72. package/dist/react/react/GrainProvider.d.ts +11 -0
  73. package/dist/react/react/GrainProvider.d.ts.map +1 -0
  74. package/dist/react/react/GrainProvider.js +45 -0
  75. package/dist/react/react/GrainProvider.mjs +42 -0
  76. package/dist/react/react/context.d.ts +11 -0
  77. package/dist/react/react/context.d.ts.map +1 -0
  78. package/dist/react/react/context.js +9 -0
  79. package/dist/react/react/context.mjs +6 -0
  80. package/dist/react/react/hooks/useAllConfigs.d.ts +8 -0
  81. package/dist/react/react/hooks/useAllConfigs.d.ts.map +1 -0
  82. package/dist/react/react/hooks/useAllConfigs.js +78 -0
  83. package/dist/react/react/hooks/useAllConfigs.mjs +75 -0
  84. package/dist/react/react/hooks/useConfig.d.ts +9 -0
  85. package/dist/react/react/hooks/useConfig.d.ts.map +1 -0
  86. package/dist/react/react/hooks/useConfig.js +82 -0
  87. package/dist/react/react/hooks/useConfig.mjs +79 -0
  88. package/dist/react/react/hooks/useGrainAnalytics.d.ts +6 -0
  89. package/dist/react/react/hooks/useGrainAnalytics.d.ts.map +1 -0
  90. package/dist/react/react/hooks/useGrainAnalytics.js +16 -0
  91. package/dist/react/react/hooks/useGrainAnalytics.mjs +13 -0
  92. package/dist/react/react/hooks/useTrack.d.ts +9 -0
  93. package/dist/react/react/hooks/useTrack.d.ts.map +1 -0
  94. package/dist/react/react/hooks/useTrack.js +19 -0
  95. package/dist/react/react/hooks/useTrack.mjs +16 -0
  96. package/dist/react/react/index.d.ts +36 -0
  97. package/dist/react/react/index.d.ts.map +1 -0
  98. package/dist/react/react/index.js +44 -0
  99. package/dist/react/react/index.mjs +36 -0
  100. package/dist/react/react/types.d.ts +33 -0
  101. package/dist/react/react/types.d.ts.map +1 -0
  102. package/dist/react/react/types.js +5 -0
  103. package/dist/react/react/types.mjs +4 -0
  104. package/package.json +20 -2
@@ -1,3 +1,3 @@
1
- /* Grain Analytics Web SDK v1.7.4 | MIT License */
1
+ /* Grain Analytics Web SDK v2.0.0 | MIT License */
2
2
  "use strict";var Grain=(()=>{var m=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var I=(g,t)=>{for(var e in t)m(g,e,{get:t[e],enumerable:!0})},R=(g,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of v(t))!C.call(g,n)&&n!==e&&m(g,n,{get:()=>t[n],enumerable:!(r=E(t,n))||r.enumerable});return g};var w=g=>R(m({},"__esModule",{value:!0}),g);var S={};I(S,{GrainAnalytics:()=>f,createGrainAnalytics:()=>y,default:()=>P});var f=class{constructor(t){this.eventQueue=[];this.flushTimer=null;this.isDestroyed=!1;this.globalUserId=null;this.persistentAnonymousUserId=null;this.configCache=null;this.configRefreshTimer=null;this.configChangeListeners=[];this.configFetchPromise=null;this.config={apiUrl:"https://api.grainql.com",authStrategy:"NONE",batchSize:50,flushInterval:5e3,retryAttempts:3,retryDelay:1e3,maxEventsPerRequest:160,debug:!1,defaultConfigurations:{},configCacheKey:"grain_config",configRefreshInterval:3e5,enableConfigCache:!0,...t,tenantId:t.tenantId},t.userId&&(this.globalUserId=t.userId),this.validateConfig(),this.initializePersistentAnonymousUserId(),this.setupBeforeUnload(),this.startFlushTimer(),this.initializeConfigCache()}validateConfig(){if(!this.config.tenantId)throw new Error("Grain Analytics: tenantId is required");if(this.config.authStrategy==="SERVER_SIDE"&&!this.config.secretKey)throw new Error("Grain Analytics: secretKey is required for SERVER_SIDE auth strategy");if(this.config.authStrategy==="JWT"&&!this.config.authProvider)throw new Error("Grain Analytics: authProvider is required for JWT auth strategy")}generateUUID(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}generateAnonymousUserId(){return this.generateUUID()}initializePersistentAnonymousUserId(){if(typeof window>"u")return;let t=`grain_anonymous_user_id_${this.config.tenantId}`;try{let e=localStorage.getItem(t);e?(this.persistentAnonymousUserId=e,this.log("Loaded persistent anonymous user ID:",this.persistentAnonymousUserId)):(this.persistentAnonymousUserId=this.generateAnonymousUserId(),localStorage.setItem(t,this.persistentAnonymousUserId),this.log("Generated new persistent anonymous user ID:",this.persistentAnonymousUserId))}catch(e){this.log("Failed to initialize persistent anonymous user ID:",e),this.persistentAnonymousUserId=this.generateAnonymousUserId()}}getEffectiveUserId(){if(this.globalUserId)return this.globalUserId;if(this.persistentAnonymousUserId)return this.persistentAnonymousUserId;if(this.persistentAnonymousUserId=this.generateAnonymousUserId(),typeof window<"u")try{let t=`grain_anonymous_user_id_${this.config.tenantId}`;localStorage.setItem(t,this.persistentAnonymousUserId)}catch(t){this.log("Failed to persist generated anonymous user ID:",t)}return this.persistentAnonymousUserId}log(...t){this.config.debug&&console.log("[Grain Analytics]",...t)}createErrorDigest(t){let e=[...new Set(t.map(i=>i.eventName))],r=[...new Set(t.map(i=>i.userId))],n=0,s=0;return t.forEach(i=>{let o=i.properties||{};n+=Object.keys(o).length,s+=JSON.stringify(i).length}),{eventCount:t.length,totalProperties:n,totalSize:s,eventNames:e,userIds:r}}formatError(t,e,r){let n=r?this.createErrorDigest(r):{eventCount:0,totalProperties:0,totalSize:0,eventNames:[],userIds:[]},s="UNKNOWN_ERROR",i="An unknown error occurred";if(t instanceof Error)i=t.message,i.includes("fetch failed")||i.includes("network error")?s="NETWORK_ERROR":i.includes("timeout")?s="TIMEOUT_ERROR":i.includes("HTTP 4")?s="CLIENT_ERROR":i.includes("HTTP 5")?s="SERVER_ERROR":i.includes("JSON")?s="PARSE_ERROR":i.includes("auth")||i.includes("unauthorized")?s="AUTH_ERROR":i.includes("rate limit")||i.includes("429")?s="RATE_LIMIT_ERROR":s="GENERAL_ERROR";else if(typeof t=="string")i=t,s="STRING_ERROR";else if(t&&typeof t=="object"&&"status"in t){let o=t.status;s=`HTTP_${o}`,i=`HTTP ${o} error`}return{code:s,message:i,digest:n,timestamp:new Date().toISOString(),context:e,originalError:t}}logError(t){let{code:e,message:r,digest:n,timestamp:s,context:i}=t,o={"\u{1F6A8} Grain Analytics Error":{"Error Code":e,Message:r,Context:i,Timestamp:s,"Event Digest":{Events:n.eventCount,Properties:n.totalProperties,"Size (bytes)":n.totalSize,"Event Names":n.eventNames.length>0?n.eventNames.join(", "):"None","User IDs":n.userIds.length>0?n.userIds.slice(0,3).join(", ")+(n.userIds.length>3?"...":""):"None"}}};console.error("\u{1F6A8} Grain Analytics Error:",o),this.config.debug&&console.error(`[Grain Analytics] ${e}: ${r} (${i}) - Events: ${n.eventCount}, Props: ${n.totalProperties}, Size: ${n.totalSize}B`)}async safeExecute(t,e,r){try{return await t()}catch(n){let s=this.formatError(n,e,r);return this.logError(s),null}}formatEvent(t){return{eventName:t.eventName,userId:t.userId||this.getEffectiveUserId(),properties:t.properties||{}}}async getAuthHeaders(){let t={"Content-Type":"application/json"};switch(this.config.authStrategy){case"NONE":break;case"SERVER_SIDE":t.Authorization=`Chase ${this.config.secretKey}`;break;case"JWT":if(this.config.authProvider){let e=await this.config.authProvider.getToken();t.Authorization=`Bearer ${e}`}break}return t}async delay(t){return new Promise(e=>setTimeout(e,t))}isRetriableError(t){if(t instanceof Error){let e=t.message.toLowerCase();if(e.includes("fetch failed")||e==="network error"||e.includes("timeout")||e.includes("connection"))return!0}if(typeof t=="object"&&t!==null&&"status"in t){let e=t.status;return e>=500||e===429}return!1}async sendEvents(t){if(t.length===0)return;let e;for(let r=0;r<=this.config.retryAttempts;r++)try{let n=await this.getAuthHeaders(),s=`${this.config.apiUrl}/v1/events/${encodeURIComponent(this.config.tenantId)}/multi`;this.log(`Sending ${t.length} events to ${s} (attempt ${r+1})`);let i=await fetch(s,{method:"POST",headers:n,body:JSON.stringify(t)});if(!i.ok){let o=`HTTP ${i.status}`;try{let c=await i.json();c?.message&&(o=c.message)}catch{let c=await i.text();c&&(o=c)}let a=new Error(`Failed to send events: ${o}`);throw a.status=i.status,a}this.log(`Successfully sent ${t.length} events`);return}catch(n){if(e=n,r===this.config.retryAttempts){let i=this.formatError(n,`sendEvents (attempt ${r+1}/${this.config.retryAttempts+1})`,t);this.logError(i);return}if(!this.isRetriableError(n)){let i=this.formatError(n,"sendEvents (non-retriable error)",t);this.logError(i);return}let s=this.config.retryDelay*Math.pow(2,r);this.log(`Retrying in ${s}ms after error:`,n),await this.delay(s)}}async sendEventsWithBeacon(t){if(t.length!==0)try{let e=await this.getAuthHeaders(),r=`${this.config.apiUrl}/v1/events/${encodeURIComponent(this.config.tenantId)}/multi`,n=JSON.stringify({events:t});if(typeof navigator<"u"&&"sendBeacon"in navigator){let s=new Blob([n],{type:"application/json"});if(navigator.sendBeacon(r,s)){this.log(`Successfully sent ${t.length} events via beacon`);return}}await fetch(r,{method:"POST",headers:e,body:n,keepalive:!0}),this.log(`Successfully sent ${t.length} events via fetch (keepalive)`)}catch(e){let r=this.formatError(e,"sendEventsWithBeacon",t);this.logError(r)}}startFlushTimer(){this.flushTimer&&clearInterval(this.flushTimer),this.flushTimer=window.setInterval(()=>{this.eventQueue.length>0&&this.flush().catch(t=>{let e=this.formatError(t,"auto-flush");this.logError(e)})},this.config.flushInterval)}setupBeforeUnload(){if(typeof window>"u")return;let t=()=>{if(this.eventQueue.length>0){let e=[...this.eventQueue];this.eventQueue=[];let r=this.chunkEvents(e,this.config.maxEventsPerRequest);r.length>0&&this.sendEventsWithBeacon(r[0]).catch(()=>{})}};window.addEventListener("beforeunload",t),window.addEventListener("pagehide",t),document.addEventListener("visibilitychange",()=>{if(document.visibilityState==="hidden"&&this.eventQueue.length>0){let e=[...this.eventQueue];this.eventQueue=[];let r=this.chunkEvents(e,this.config.maxEventsPerRequest);r.length>0&&this.sendEventsWithBeacon(r[0]).catch(()=>{})}})}async track(t,e,r){try{if(this.isDestroyed){let o=new Error("Grain Analytics: Client has been destroyed"),a=this.formatError(o,"track (client destroyed)");this.logError(a);return}let n,s={};typeof t=="string"?(n={eventName:t,properties:e},s=r||{}):(n=t,s=e||{});let i=this.formatEvent(n);this.eventQueue.push(i),this.log(`Queued event: ${n.eventName}`,n.properties),(s.flush||this.eventQueue.length>=this.config.batchSize)&&await this.flush()}catch(n){let s=this.formatError(n,"track");this.logError(s)}}identify(t){this.log(`Identified user: ${t}`),this.globalUserId=t,this.persistentAnonymousUserId=null}setUserId(t){if(this.log(`Set global user ID: ${t}`),this.globalUserId=t,t)this.persistentAnonymousUserId=null;else if(!this.persistentAnonymousUserId&&(this.persistentAnonymousUserId=this.generateAnonymousUserId(),typeof window<"u"))try{let e=`grain_anonymous_user_id_${this.config.tenantId}`;localStorage.setItem(e,this.persistentAnonymousUserId)}catch(e){this.log("Failed to persist new anonymous user ID:",e)}}getUserId(){return this.globalUserId}getEffectiveUserIdPublic(){return this.getEffectiveUserId()}login(t){try{if(this.isDestroyed){let e=new Error("Grain Analytics: Client has been destroyed"),r=this.formatError(e,"login (client destroyed)");this.logError(r);return}t.userId&&(this.log(`Login: Setting user ID to ${t.userId}`),this.globalUserId=t.userId,this.persistentAnonymousUserId=null),t.authToken&&(this.log("Login: Setting auth token"),this.config.authStrategy==="NONE"&&(this.config.authStrategy="JWT"),this.config.authProvider={getToken:()=>t.authToken}),t.authStrategy&&(this.log(`Login: Setting auth strategy to ${t.authStrategy}`),this.config.authStrategy=t.authStrategy),this.log(`Login successful. Effective user ID: ${this.getEffectiveUserId()}`)}catch(e){let r=this.formatError(e,"login");this.logError(r)}}logout(){try{if(this.isDestroyed){let t=new Error("Grain Analytics: Client has been destroyed"),e=this.formatError(t,"logout (client destroyed)");this.logError(e);return}if(this.log("Logout: Clearing user session"),this.globalUserId=null,this.config.authStrategy="NONE",this.config.authProvider=void 0,!this.persistentAnonymousUserId&&(this.persistentAnonymousUserId=this.generateAnonymousUserId(),typeof window<"u"))try{let t=`grain_anonymous_user_id_${this.config.tenantId}`;localStorage.setItem(t,this.persistentAnonymousUserId)}catch(t){this.log("Failed to persist new anonymous user ID after logout:",t)}this.log(`Logout successful. Effective user ID: ${this.getEffectiveUserId()}`)}catch(t){let e=this.formatError(t,"logout");this.logError(e)}}async setProperty(t,e){try{if(this.isDestroyed){let o=new Error("Grain Analytics: Client has been destroyed"),a=this.formatError(o,"setProperty (client destroyed)");this.logError(a);return}let r=e?.userId||this.getEffectiveUserId(),n=Object.keys(t);if(n.length>4){let o=new Error("Grain Analytics: Maximum 4 properties allowed per request"),a=this.formatError(o,"setProperty (validation)");this.logError(a);return}if(n.length===0){let o=new Error("Grain Analytics: At least one property is required"),a=this.formatError(o,"setProperty (validation)");this.logError(a);return}let s={};for(let[o,a]of Object.entries(t))a==null?s[o]="":typeof a=="string"?s[o]=a:s[o]=JSON.stringify(a);let i={userId:r,...s};await this.sendProperties(i)}catch(r){let n=this.formatError(r,"setProperty");this.logError(n)}}async sendProperties(t){let e;for(let r=0;r<=this.config.retryAttempts;r++)try{let n=await this.getAuthHeaders(),s=`${this.config.apiUrl}/v1/events/${encodeURIComponent(this.config.tenantId)}/properties`;this.log(`Setting properties for user ${t.userId} (attempt ${r+1})`);let i=await fetch(s,{method:"POST",headers:n,body:JSON.stringify(t)});if(!i.ok){let o=`HTTP ${i.status}`;try{let c=await i.json();c?.message&&(o=c.message)}catch{let c=await i.text();c&&(o=c)}let a=new Error(`Failed to set properties: ${o}`);throw a.status=i.status,a}this.log(`Successfully set properties for user ${t.userId}`);return}catch(n){if(e=n,r===this.config.retryAttempts){let i=this.formatError(n,`sendProperties (attempt ${r+1}/${this.config.retryAttempts+1})`);this.logError(i);return}if(!this.isRetriableError(n)){let i=this.formatError(n,"sendProperties (non-retriable error)");this.logError(i);return}let s=this.config.retryDelay*Math.pow(2,r);this.log(`Retrying in ${s}ms after error:`,n),await this.delay(s)}}async trackLogin(t,e){try{return await this.track("login",t,e)}catch(r){let n=this.formatError(r,"trackLogin");this.logError(n)}}async trackSignup(t,e){try{return await this.track("signup",t,e)}catch(r){let n=this.formatError(r,"trackSignup");this.logError(n)}}async trackCheckout(t,e){try{return await this.track("checkout",t,e)}catch(r){let n=this.formatError(r,"trackCheckout");this.logError(n)}}async trackPageView(t,e){try{return await this.track("page_view",t,e)}catch(r){let n=this.formatError(r,"trackPageView");this.logError(n)}}async trackPurchase(t,e){try{return await this.track("purchase",t,e)}catch(r){let n=this.formatError(r,"trackPurchase");this.logError(n)}}async trackSearch(t,e){try{return await this.track("search",t,e)}catch(r){let n=this.formatError(r,"trackSearch");this.logError(n)}}async trackAddToCart(t,e){try{return await this.track("add_to_cart",t,e)}catch(r){let n=this.formatError(r,"trackAddToCart");this.logError(n)}}async trackRemoveFromCart(t,e){try{return await this.track("remove_from_cart",t,e)}catch(r){let n=this.formatError(r,"trackRemoveFromCart");this.logError(n)}}async flush(){try{if(this.eventQueue.length===0)return;let t=[...this.eventQueue];this.eventQueue=[];let e=this.chunkEvents(t,this.config.maxEventsPerRequest);for(let r of e)await this.sendEvents(r)}catch(t){let e=this.formatError(t,"flush");this.logError(e)}}initializeConfigCache(){if(!(!this.config.enableConfigCache||typeof window>"u"))try{let t=localStorage.getItem(this.config.configCacheKey);t&&(this.configCache=JSON.parse(t),this.log("Loaded configuration from cache:",this.configCache))}catch(t){this.log("Failed to load configuration cache:",t)}}saveConfigCache(t){if(!(!this.config.enableConfigCache||typeof window>"u"))try{localStorage.setItem(this.config.configCacheKey,JSON.stringify(t)),this.log("Saved configuration to cache:",t)}catch(e){this.log("Failed to save configuration cache:",e)}}getConfig(t){if(this.configCache?.configurations?.[t])return this.configCache.configurations[t];if(this.config.defaultConfigurations?.[t])return this.config.defaultConfigurations[t]}getAllConfigs(){let t={...this.config.defaultConfigurations};return this.configCache?.configurations&&Object.assign(t,this.configCache.configurations),t}async fetchConfig(t={}){try{if(this.isDestroyed){let o=new Error("Grain Analytics: Client has been destroyed"),a=this.formatError(o,"fetchConfig (client destroyed)");return this.logError(a),null}let e=t.userId||this.getEffectiveUserId(),r=t.immediateKeys||[],n=t.properties||{},s={userId:e,immediateKeys:r,properties:n},i;for(let o=0;o<=this.config.retryAttempts;o++)try{let a=await this.getAuthHeaders(),c=`${this.config.apiUrl}/v1/client/${encodeURIComponent(this.config.tenantId)}/config/configurations`;this.log(`Fetching configurations for user ${e} (attempt ${o+1})`);let h=await fetch(c,{method:"POST",headers:a,body:JSON.stringify(s)});if(!h.ok){let l=`HTTP ${h.status}`;try{let u=await h.json();u?.message&&(l=u.message)}catch{let u=await h.text();u&&(l=u)}let p=new Error(`Failed to fetch configurations: ${l}`);throw p.status=h.status,p}let d=await h.json();return d.configurations&&this.updateConfigCache(d,e),this.log(`Successfully fetched configurations for user ${e}:`,d),d}catch(a){if(i=a,o===this.config.retryAttempts){let h=this.formatError(a,`fetchConfig (attempt ${o+1}/${this.config.retryAttempts+1})`);return this.logError(h),null}if(!this.isRetriableError(a)){let h=this.formatError(a,"fetchConfig (non-retriable error)");return this.logError(h),null}let c=this.config.retryDelay*Math.pow(2,o);this.log(`Retrying config fetch in ${c}ms after error:`,a),await this.delay(c)}return null}catch(e){let r=this.formatError(e,"fetchConfig");return this.logError(r),null}}async getConfigAsync(t,e={}){try{if(!e.forceRefresh&&this.configCache?.configurations?.[t])return this.configCache.configurations[t];if(!e.forceRefresh&&this.config.defaultConfigurations?.[t])return this.config.defaultConfigurations[t];let r=await this.fetchConfig(e);return r?r.configurations[t]:this.config.defaultConfigurations?.[t]}catch(r){let n=this.formatError(r,"getConfigAsync");return this.logError(n),this.config.defaultConfigurations?.[t]}}async getAllConfigsAsync(t={}){try{if(!t.forceRefresh&&this.configCache?.configurations)return{...this.config.defaultConfigurations,...this.configCache.configurations};let e=await this.fetchConfig(t);return e?{...this.config.defaultConfigurations,...e.configurations}:{...this.config.defaultConfigurations}}catch(e){let r=this.formatError(e,"getAllConfigsAsync");return this.logError(r),{...this.config.defaultConfigurations}}}updateConfigCache(t,e){let r={configurations:t.configurations,snapshotId:t.snapshotId,timestamp:t.timestamp,userId:e},n=this.configCache?.configurations||{};this.configCache=r,this.saveConfigCache(r),JSON.stringify(n)!==JSON.stringify(t.configurations)&&this.notifyConfigChangeListeners(t.configurations)}addConfigChangeListener(t){this.configChangeListeners.push(t)}removeConfigChangeListener(t){let e=this.configChangeListeners.indexOf(t);e>-1&&this.configChangeListeners.splice(e,1)}notifyConfigChangeListeners(t){this.configChangeListeners.forEach(e=>{try{e(t)}catch(r){console.error("[Grain Analytics] Config change listener error:",r)}})}startConfigRefreshTimer(){this.configRefreshTimer&&clearInterval(this.configRefreshTimer),this.configRefreshTimer=window.setInterval(()=>{this.isDestroyed||this.fetchConfig().catch(t=>{let e=this.formatError(t,"auto-config refresh");this.logError(e)})},this.config.configRefreshInterval)}stopConfigRefreshTimer(){this.configRefreshTimer&&(clearInterval(this.configRefreshTimer),this.configRefreshTimer=null)}async preloadConfig(t=[],e){try{let r=this.getEffectiveUserId();this.log(`Preloading config for user: ${r}`),await this.fetchConfig({immediateKeys:t,properties:e})&&this.startConfigRefreshTimer()}catch(r){let n=this.formatError(r,"preloadConfig");this.logError(n)}}chunkEvents(t,e){let r=[];for(let n=0;n<t.length;n+=e)r.push(t.slice(n,n+e));return r}destroy(){if(this.isDestroyed=!0,this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.stopConfigRefreshTimer(),this.configChangeListeners=[],this.eventQueue.length>0){let t=[...this.eventQueue];this.eventQueue=[];let e=this.chunkEvents(t,this.config.maxEventsPerRequest);if(e.length>0){this.sendEventsWithBeacon(e[0]).catch(()=>{});for(let r=1;r<e.length;r++)this.sendEventsWithBeacon(e[r]).catch(()=>{})}}}};function y(g){return new f(g)}var P=f;typeof window<"u"&&(window.Grain={GrainAnalytics:f,createGrainAnalytics:y});return w(S);})();
3
3
  //# sourceMappingURL=index.global.js.map
@@ -0,0 +1,405 @@
1
+ /**
2
+ * Grain Analytics Web SDK
3
+ * A lightweight, dependency-free TypeScript SDK for sending analytics events to Grain's REST API
4
+ */
5
+ export interface GrainEvent {
6
+ eventName: string;
7
+ userId?: string;
8
+ properties?: Record<string, unknown>;
9
+ timestamp?: Date;
10
+ }
11
+ export interface EventPayload {
12
+ eventName: string;
13
+ userId: string;
14
+ properties: Record<string, unknown>;
15
+ }
16
+ export type AuthStrategy = 'NONE' | 'SERVER_SIDE' | 'JWT';
17
+ export interface AuthProvider {
18
+ getToken(): Promise<string> | string;
19
+ }
20
+ export interface GrainConfig {
21
+ tenantId: string;
22
+ apiUrl?: string;
23
+ authStrategy?: AuthStrategy;
24
+ secretKey?: string;
25
+ authProvider?: AuthProvider;
26
+ userId?: string;
27
+ batchSize?: number;
28
+ flushInterval?: number;
29
+ retryAttempts?: number;
30
+ retryDelay?: number;
31
+ maxEventsPerRequest?: number;
32
+ debug?: boolean;
33
+ defaultConfigurations?: Record<string, string>;
34
+ configCacheKey?: string;
35
+ configRefreshInterval?: number;
36
+ enableConfigCache?: boolean;
37
+ }
38
+ export interface SendEventOptions {
39
+ flush?: boolean;
40
+ }
41
+ export interface SetPropertyOptions {
42
+ userId?: string;
43
+ }
44
+ export interface LoginOptions {
45
+ userId?: string;
46
+ authToken?: string;
47
+ authStrategy?: AuthStrategy;
48
+ }
49
+ export interface PropertyPayload {
50
+ userId: string;
51
+ [key: string]: string;
52
+ }
53
+ export interface RemoteConfigRequest {
54
+ userId: string;
55
+ immediateKeys: string[];
56
+ properties?: Record<string, string>;
57
+ }
58
+ export interface RemoteConfigResponse {
59
+ userId: string;
60
+ snapshotId: string;
61
+ configurations: Record<string, string>;
62
+ isFinal: boolean;
63
+ qualifiedSegments: string[];
64
+ qualifiedRuleSets: string[];
65
+ timestamp: string;
66
+ isFromCache: boolean;
67
+ }
68
+ export interface RemoteConfigOptions {
69
+ immediateKeys?: string[];
70
+ properties?: Record<string, string>;
71
+ userId?: string;
72
+ forceRefresh?: boolean;
73
+ }
74
+ export interface RemoteConfigCache {
75
+ configurations: Record<string, string>;
76
+ snapshotId: string;
77
+ timestamp: string;
78
+ userId: string;
79
+ }
80
+ export type ConfigChangeListener = (configurations: Record<string, string>) => void;
81
+ export interface LoginEventProperties extends Record<string, unknown> {
82
+ method?: string;
83
+ success?: boolean;
84
+ errorMessage?: string;
85
+ loginAttempt?: number;
86
+ rememberMe?: boolean;
87
+ twoFactorEnabled?: boolean;
88
+ }
89
+ export interface SignupEventProperties extends Record<string, unknown> {
90
+ method?: string;
91
+ source?: string;
92
+ plan?: string;
93
+ success?: boolean;
94
+ errorMessage?: string;
95
+ }
96
+ export interface CheckoutEventProperties extends Record<string, unknown> {
97
+ orderId?: string;
98
+ total?: number;
99
+ currency?: string;
100
+ items?: Array<{
101
+ id: string;
102
+ name: string;
103
+ price: number;
104
+ quantity: number;
105
+ }>;
106
+ paymentMethod?: string;
107
+ success?: boolean;
108
+ errorMessage?: string;
109
+ couponCode?: string;
110
+ discount?: number;
111
+ }
112
+ export interface PageViewEventProperties extends Record<string, unknown> {
113
+ page?: string;
114
+ title?: string;
115
+ referrer?: string;
116
+ url?: string;
117
+ userAgent?: string;
118
+ screenResolution?: string;
119
+ viewportSize?: string;
120
+ }
121
+ export interface PurchaseEventProperties extends Record<string, unknown> {
122
+ orderId?: string;
123
+ total?: number;
124
+ currency?: string;
125
+ items?: Array<{
126
+ id: string;
127
+ name: string;
128
+ price: number;
129
+ quantity: number;
130
+ category?: string;
131
+ }>;
132
+ paymentMethod?: string;
133
+ shippingMethod?: string;
134
+ tax?: number;
135
+ shipping?: number;
136
+ discount?: number;
137
+ couponCode?: string;
138
+ }
139
+ export interface SearchEventProperties extends Record<string, unknown> {
140
+ query?: string;
141
+ results?: number;
142
+ filters?: Record<string, unknown>;
143
+ sortBy?: string;
144
+ category?: string;
145
+ success?: boolean;
146
+ }
147
+ export interface AddToCartEventProperties extends Record<string, unknown> {
148
+ itemId?: string;
149
+ itemName?: string;
150
+ price?: number;
151
+ quantity?: number;
152
+ currency?: string;
153
+ category?: string;
154
+ variant?: string;
155
+ }
156
+ export interface RemoveFromCartEventProperties extends Record<string, unknown> {
157
+ itemId?: string;
158
+ itemName?: string;
159
+ price?: number;
160
+ quantity?: number;
161
+ currency?: string;
162
+ category?: string;
163
+ variant?: string;
164
+ }
165
+ export interface ErrorDigest {
166
+ eventCount: number;
167
+ totalProperties: number;
168
+ totalSize: number;
169
+ eventNames: string[];
170
+ userIds: string[];
171
+ }
172
+ export interface FormattedError {
173
+ code: string;
174
+ message: string;
175
+ digest: ErrorDigest;
176
+ timestamp: string;
177
+ context: string;
178
+ originalError?: unknown;
179
+ }
180
+ export declare class GrainAnalytics {
181
+ private config;
182
+ private eventQueue;
183
+ private flushTimer;
184
+ private isDestroyed;
185
+ private globalUserId;
186
+ private persistentAnonymousUserId;
187
+ private configCache;
188
+ private configRefreshTimer;
189
+ private configChangeListeners;
190
+ private configFetchPromise;
191
+ constructor(config: GrainConfig);
192
+ private validateConfig;
193
+ /**
194
+ * Generate a UUID v4 string
195
+ */
196
+ private generateUUID;
197
+ /**
198
+ * Generate a proper UUIDv4 identifier for anonymous user ID
199
+ */
200
+ private generateAnonymousUserId;
201
+ /**
202
+ * Initialize persistent anonymous user ID from localStorage or create new one
203
+ */
204
+ private initializePersistentAnonymousUserId;
205
+ /**
206
+ * Get the effective user ID (global userId or persistent anonymous ID)
207
+ */
208
+ private getEffectiveUserId;
209
+ private log;
210
+ /**
211
+ * Create error digest from events
212
+ */
213
+ private createErrorDigest;
214
+ /**
215
+ * Format error with beautiful structure
216
+ */
217
+ private formatError;
218
+ /**
219
+ * Log formatted error gracefully
220
+ */
221
+ private logError;
222
+ /**
223
+ * Safely execute a function with error handling
224
+ */
225
+ private safeExecute;
226
+ private formatEvent;
227
+ private getAuthHeaders;
228
+ private delay;
229
+ private isRetriableError;
230
+ private sendEvents;
231
+ private sendEventsWithBeacon;
232
+ private startFlushTimer;
233
+ private setupBeforeUnload;
234
+ /**
235
+ * Track an analytics event
236
+ */
237
+ track(eventName: string, properties?: Record<string, unknown>, options?: SendEventOptions): Promise<void>;
238
+ track(event: GrainEvent, options?: SendEventOptions): Promise<void>;
239
+ /**
240
+ * Identify a user (sets userId for subsequent events)
241
+ */
242
+ identify(userId: string): void;
243
+ /**
244
+ * Set global user ID for all subsequent events
245
+ */
246
+ setUserId(userId: string | null): void;
247
+ /**
248
+ * Get current global user ID
249
+ */
250
+ getUserId(): string | null;
251
+ /**
252
+ * Get current effective user ID (global userId or persistent anonymous ID)
253
+ */
254
+ getEffectiveUserIdPublic(): string;
255
+ /**
256
+ * Login with auth token or userId on the fly
257
+ *
258
+ * @example
259
+ * // Login with userId only
260
+ * client.login({ userId: 'user123' });
261
+ *
262
+ * // Login with auth token (automatically sets authStrategy to JWT)
263
+ * client.login({ authToken: 'jwt-token-here' });
264
+ *
265
+ * // Login with both userId and auth token
266
+ * client.login({ userId: 'user123', authToken: 'jwt-token-here' });
267
+ *
268
+ * // Override auth strategy
269
+ * client.login({ userId: 'user123', authStrategy: 'SERVER_SIDE' });
270
+ */
271
+ login(options: LoginOptions): void;
272
+ /**
273
+ * Logout and clear user session, fall back to UUIDv4 identifier
274
+ *
275
+ * @example
276
+ * // Logout user and return to anonymous mode
277
+ * client.logout();
278
+ *
279
+ * // After logout, events will use the persistent UUIDv4 identifier
280
+ * client.track('page_view', { page: 'home' });
281
+ */
282
+ logout(): void;
283
+ /**
284
+ * Set user properties
285
+ */
286
+ setProperty(properties: Record<string, unknown>, options?: SetPropertyOptions): Promise<void>;
287
+ /**
288
+ * Send properties to the API
289
+ */
290
+ private sendProperties;
291
+ /**
292
+ * Track user login event
293
+ */
294
+ trackLogin(properties?: LoginEventProperties, options?: SendEventOptions): Promise<void>;
295
+ /**
296
+ * Track user signup event
297
+ */
298
+ trackSignup(properties?: SignupEventProperties, options?: SendEventOptions): Promise<void>;
299
+ /**
300
+ * Track checkout event
301
+ */
302
+ trackCheckout(properties?: CheckoutEventProperties, options?: SendEventOptions): Promise<void>;
303
+ /**
304
+ * Track page view event
305
+ */
306
+ trackPageView(properties?: PageViewEventProperties, options?: SendEventOptions): Promise<void>;
307
+ /**
308
+ * Track purchase event
309
+ */
310
+ trackPurchase(properties?: PurchaseEventProperties, options?: SendEventOptions): Promise<void>;
311
+ /**
312
+ * Track search event
313
+ */
314
+ trackSearch(properties?: SearchEventProperties, options?: SendEventOptions): Promise<void>;
315
+ /**
316
+ * Track add to cart event
317
+ */
318
+ trackAddToCart(properties?: AddToCartEventProperties, options?: SendEventOptions): Promise<void>;
319
+ /**
320
+ * Track remove from cart event
321
+ */
322
+ trackRemoveFromCart(properties?: RemoveFromCartEventProperties, options?: SendEventOptions): Promise<void>;
323
+ /**
324
+ * Manually flush all queued events
325
+ */
326
+ flush(): Promise<void>;
327
+ /**
328
+ * Initialize configuration cache from localStorage
329
+ */
330
+ private initializeConfigCache;
331
+ /**
332
+ * Save configuration cache to localStorage
333
+ */
334
+ private saveConfigCache;
335
+ /**
336
+ * Get configuration value with fallback to defaults
337
+ */
338
+ getConfig(key: string): string | undefined;
339
+ /**
340
+ * Get all configurations with fallback to defaults
341
+ */
342
+ getAllConfigs(): Record<string, string>;
343
+ /**
344
+ * Fetch configurations from API
345
+ */
346
+ fetchConfig(options?: RemoteConfigOptions): Promise<RemoteConfigResponse | null>;
347
+ /**
348
+ * Get configuration asynchronously (cache-first with fallback to API)
349
+ */
350
+ getConfigAsync(key: string, options?: RemoteConfigOptions): Promise<string | undefined>;
351
+ /**
352
+ * Get all configurations asynchronously (cache-first with fallback to API)
353
+ */
354
+ getAllConfigsAsync(options?: RemoteConfigOptions): Promise<Record<string, string>>;
355
+ /**
356
+ * Update configuration cache and notify listeners
357
+ */
358
+ private updateConfigCache;
359
+ /**
360
+ * Add configuration change listener
361
+ */
362
+ addConfigChangeListener(listener: ConfigChangeListener): void;
363
+ /**
364
+ * Remove configuration change listener
365
+ */
366
+ removeConfigChangeListener(listener: ConfigChangeListener): void;
367
+ /**
368
+ * Notify all configuration change listeners
369
+ */
370
+ private notifyConfigChangeListeners;
371
+ /**
372
+ * Start automatic configuration refresh timer
373
+ */
374
+ private startConfigRefreshTimer;
375
+ /**
376
+ * Stop automatic configuration refresh timer
377
+ */
378
+ private stopConfigRefreshTimer;
379
+ /**
380
+ * Preload configurations for immediate access
381
+ */
382
+ preloadConfig(immediateKeys?: string[], properties?: Record<string, string>): Promise<void>;
383
+ /**
384
+ * Split events array into chunks of specified size
385
+ */
386
+ private chunkEvents;
387
+ /**
388
+ * Destroy the client and clean up resources
389
+ */
390
+ destroy(): void;
391
+ }
392
+ /**
393
+ * Create a new Grain Analytics client
394
+ */
395
+ export declare function createGrainAnalytics(config: GrainConfig): GrainAnalytics;
396
+ export default GrainAnalytics;
397
+ declare global {
398
+ interface Window {
399
+ Grain?: {
400
+ GrainAnalytics: typeof GrainAnalytics;
401
+ createGrainAnalytics: typeof createGrainAnalytics;
402
+ };
403
+ }
404
+ }
405
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,KAAK,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAGD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;AAGpF,MAAM,WAAW,oBAAqB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAsB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAwB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAwB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAwB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAsB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,wBAAyB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,6BAA8B,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAiBD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,yBAAyB,CAAuB;IAExD,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,qBAAqB,CAA8B;IAC3D,OAAO,CAAC,kBAAkB,CAA8C;gBAE5D,MAAM,EAAE,WAAW;IA+B/B,OAAO,CAAC,cAAc;IActB;;OAEG;IACH,OAAO,CAAC,YAAY;IAapB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAI/B;;OAEG;IACH,OAAO,CAAC,mCAAmC;IAuB3C;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,GAAG;IAMX;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsBzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAwDnB;;OAEG;IACH,OAAO,CAAC,QAAQ;IA2BhB;;OAEG;YACW,WAAW;IAczB,OAAO,CAAC,WAAW;YAQL,cAAc;YAsBd,KAAK;IAInB,OAAO,CAAC,gBAAgB;YAmBV,UAAU;YAgEV,oBAAoB;IAoClC,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,iBAAiB;IA0CzB;;OAEG;IACG,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IACzG,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA2CzE;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO9B;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAyBtC;;OAEG;IACH,SAAS,IAAI,MAAM,GAAG,IAAI;IAI1B;;OAEG;IACH,wBAAwB,IAAI,MAAM;IAIlC;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IA4ClC;;;;;;;;;OASG;IACH,MAAM,IAAI,IAAI;IAwCd;;OAEG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmDnG;;OAEG;YACW,cAAc;IAgE5B;;OAEG;IACG,UAAU,CAAC,UAAU,CAAC,EAAE,oBAAoB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9F;;OAEG;IACG,WAAW,CAAC,UAAU,CAAC,EAAE,qBAAqB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAShG;;OAEG;IACG,aAAa,CAAC,UAAU,CAAC,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IASpG;;OAEG;IACG,aAAa,CAAC,UAAU,CAAC,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IASpG;;OAEG;IACG,aAAa,CAAC,UAAU,CAAC,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IASpG;;OAEG;IACG,WAAW,CAAC,UAAU,CAAC,EAAE,qBAAqB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAShG;;OAEG;IACG,cAAc,CAAC,UAAU,CAAC,EAAE,wBAAwB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAStG;;OAEG;IACG,mBAAmB,CAAC,UAAU,CAAC,EAAE,6BAA6B,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAShH;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB5B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;OAEG;IACH,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAc1C;;OAEG;IACH,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAUvC;;OAEG;IACG,WAAW,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IA8F1F;;OAEG;IACG,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IA4BjG;;OAEG;IACG,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAuB5F;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAkBzB;;OAEG;IACH,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAI7D;;OAEG;IACH,0BAA0B,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAOhE;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAUnC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAgB/B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAO9B;;OAEG;IACG,aAAa,CAAC,aAAa,GAAE,MAAM,EAAO,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBrG;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,IAAI,IAAI;CAoChB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,cAAc,CAExE;AAGD,eAAe,cAAc,CAAC;AAG9B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,KAAK,CAAC,EAAE;YACN,cAAc,EAAE,OAAO,cAAc,CAAC;YACtC,oBAAoB,EAAE,OAAO,oBAAoB,CAAC;SACnD,CAAC;KACH;CACF"}