@yuanze_dev/tracker-miniprogram 0.7.0 → 0.7.1

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 (2) hide show
  1. package/dist/index.js +1 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var __defProp=Object.defineProperty;var __defProps=Object.defineProperties;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropDescs=Object.getOwnPropertyDescriptors;var __getOwnPropNames=Object.getOwnPropertyNames;var __getOwnPropSymbols=Object.getOwnPropertySymbols;var __hasOwnProp=Object.prototype.hasOwnProperty;var __propIsEnum=Object.prototype.propertyIsEnumerable;var __pow=Math.pow;var __defNormalProp=(obj,key,value)=>key in obj?__defProp(obj,key,{enumerable:true,configurable:true,writable:true,value}):obj[key]=value;var __spreadValues=(a,b)=>{for(var prop in b||(b={}))if(__hasOwnProp.call(b,prop))__defNormalProp(a,prop,b[prop]);if(__getOwnPropSymbols)for(var prop of __getOwnPropSymbols(b)){if(__propIsEnum.call(b,prop))__defNormalProp(a,prop,b[prop])}return a};var __spreadProps=(a,b)=>__defProps(a,__getOwnPropDescs(b));var __objRest=(source,exclude)=>{var target={};for(var prop in source)if(__hasOwnProp.call(source,prop)&&exclude.indexOf(prop)<0)target[prop]=source[prop];if(source!=null&&__getOwnPropSymbols)for(var prop of __getOwnPropSymbols(source)){if(exclude.indexOf(prop)<0&&__propIsEnum.call(source,prop))target[prop]=source[prop]}return target};var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var __publicField=(obj,key,value)=>__defNormalProp(obj,typeof key!=="symbol"?key+"":key,value);var __async=(__this,__arguments,generator)=>{return new Promise((resolve,reject)=>{var fulfilled=value=>{try{step(generator.next(value))}catch(e){reject(e)}};var rejected=value=>{try{step(generator.throw(value))}catch(e){reject(e)}};var step=x=>x.done?resolve(x.value):Promise.resolve(x.value).then(fulfilled,rejected);step((generator=generator.apply(__this,__arguments)).next())})};var index_exports={};__export(index_exports,{SYSTEM_EVENTS:()=>SYSTEM_EVENTS,default:()=>index_default,enableAutoTrack:()=>enableAutoTrack,flush:()=>flush,getTracker:()=>getTracker,identify:()=>identify,init:()=>init,isSystemEvent:()=>isSystemEvent,register:()=>register,reset:()=>reset,track:()=>track,trackTap:()=>trackTap,tracker:()=>tracker,wxEnvContext:()=>wxEnvContext,wxPersistence:()=>wxPersistence,wxSender:()=>wxSender,wxStorage:()=>wxStorage});module.exports=__toCommonJS(index_exports);function uuid(){const c=globalThis.crypto;if(typeof(c==null?void 0:c.randomUUID)==="function"){try{return c.randomUUID()}catch(e){}}if(typeof(c==null?void 0:c.getRandomValues)==="function"){try{const b2=c.getRandomValues(new Uint8Array(16));return formatUuid(b2)}catch(e){}}const b=new Uint8Array(16);for(let i=0;i<16;i+=1)b[i]=Math.floor(Math.random()*256);return formatUuid(b)}function formatUuid(b){b[6]=b[6]&15|64;b[8]=b[8]&63|128;const hex=[];for(let i=0;i<16;i+=1)hex.push(b[i].toString(16).padStart(2,"0"));const s=hex.join("");return`${s.slice(0,8)}-${s.slice(8,12)}-${s.slice(12,16)}-${s.slice(16,20)}-${s.slice(20)}`}function memoryStorage(){const m=new Map;return{get:k=>{var _a;return(_a=m.get(k))!=null?_a:null},set:(k,v)=>void m.set(k,v),remove:k=>void m.delete(k)}}function webStorage(){const mem=memoryStorage();let ls=null;try{ls=typeof localStorage!=="undefined"?localStorage:null}catch(e){ls=null}if(!ls)return mem;return{get(k){try{return ls.getItem(k)}catch(e){return mem.get(k)}},set(k,v){try{ls.setItem(k,v)}catch(e){mem.set(k,v)}},remove(k){try{ls.removeItem(k)}catch(e){mem.remove(k)}}}}var STORAGE_KEYS={anonymousId:"yz_anon",userId:"yz_uid",session:"yz_session"};var SESSION_TIMEOUT_MS=30*60*1e3;var TOUCH_PERSIST_MS=60*1e3;function dayKey(ts){const d=new Date(ts);const p=n=>String(n).padStart(2,"0");return`${d.getFullYear()}-${p(d.getMonth()+1)}-${p(d.getDate())}`}var Identity=class{constructor(store,now=Date.now){__publicField(this,"store",store);__publicField(this,"now",now);__publicField(this,"anonymousId");__publicField(this,"userId");__publicField(this,"session");__publicField(this,"persistedAt");var _a;this.anonymousId=(_a=this.store.get(STORAGE_KEYS.anonymousId))!=null?_a:this.newAnonymousId();this.userId=this.store.get(STORAGE_KEYS.userId)||null;this.session=this.loadSession();this.persistedAt=this.session.lastActive}newAnonymousId(){const id=`anon_${uuid()}`;this.store.set(STORAGE_KEYS.anonymousId,id);return id}loadSession(){const raw=this.store.get(STORAGE_KEYS.session);if(raw){try{const s=JSON.parse(raw);if((s==null?void 0:s.id)&&typeof s.lastActive==="number"&&!this.expired(s,this.now()))return s}catch(e){}}return this.startSession(this.now())}expired(s,at){return at-s.lastActive>SESSION_TIMEOUT_MS||s.day!==dayKey(at)}startSession(at){const s={id:uuid(),lastActive:at,day:dayKey(at)};this.store.set(STORAGE_KEYS.session,JSON.stringify(s));this.persistedAt=at;return s}touch(){const at=this.now();if(this.expired(this.session,at)){this.session=this.startSession(at);return}this.session.lastActive=at;if(at-this.persistedAt>=TOUCH_PERSIST_MS){this.store.set(STORAGE_KEYS.session,JSON.stringify(this.session));this.persistedAt=at}}identify(userId){const id=String(userId!=null?userId:"").trim();if(!id||id===this.userId)return false;this.userId=id;this.store.set(STORAGE_KEYS.userId,id);return true}reset(){this.userId=null;this.store.remove(STORAGE_KEYS.userId);this.anonymousId=this.newAnonymousId();this.session=this.startSession(this.now())}snapshot(){var _a;return{distinctId:(_a=this.userId)!=null?_a:this.anonymousId,anonymousId:this.anonymousId,userId:this.userId,sessionId:this.session.id}}setAnonymousId(id){this.anonymousId=id;this.store.set(STORAGE_KEYS.anonymousId,id)}};var DB_NAME="yz_tracker";var STORE="queue";var DEFAULT_LIMIT=500;function openDb(dbName){return new Promise((resolve,reject)=>{const req=indexedDB.open(dbName,1);req.onupgradeneeded=()=>{const db=req.result;if(!db.objectStoreNames.contains(STORE)){db.createObjectStore(STORE,{keyPath:"eventId"}).createIndex("savedAt","savedAt")}};req.onsuccess=()=>resolve(req.result);req.onerror=()=>reject(req.error);req.onblocked=()=>reject(new Error("indexedDB blocked"))})}function indexedDbPersistence(opts={}){var _a,_b;if(typeof indexedDB==="undefined")return null;const dbName=(_a=opts.dbName)!=null?_a:DB_NAME;const limit=(_b=opts.limit)!=null?_b:DEFAULT_LIMIT;let dbPromise=null;const db=()=>{dbPromise!=null?dbPromise:dbPromise=openDb(dbName);return dbPromise};const write=fn=>__async(null,null,function*(){try{const d=yield db();const tx=d.transaction(STORE,"readwrite");fn(tx.objectStore(STORE))}catch(e){}});return{load(){return __async(this,null,function*(){try{const d=yield db();const tx=d.transaction(STORE,"readonly");const req=tx.objectStore(STORE).index("savedAt").getAll();const rows=yield new Promise((resolve,reject)=>{req.onsuccess=()=>resolve(req.result);req.onerror=()=>reject(req.error)});return rows.map(r=>r.payload)}catch(e){return[]}})},add(records){void write(store=>{for(const r of records)store.put(r);const countReq=store.count();countReq.onsuccess=()=>{const over=countReq.result-limit;if(over<=0)return;let dropped=0;const cur=store.index("savedAt").openCursor();cur.onsuccess=()=>{const c=cur.result;if(!c||dropped>=over)return;c.delete();dropped+=1;c.continue()}}})},remove(eventIds){if(!eventIds.length)return;void write(store=>{for(const id of eventIds)store.delete(id)})}}}var SDK_NAME="@yuanze_dev/tracker";var SDK_VERSION="0.7.0";var PROTOCOL_VERSION=1;var MAX_BATCH_SIZE=50;var PLATFORMS=["web","pc","flutter","ios","android","miniprogram","backend"];var MAX_BACKOFF_MS=3e4;var Tracker=class{constructor(opts){__publicField(this,"queue",[]);__publicField(this,"timer",null);__publicField(this,"superProps",{});__publicField(this,"identity");__publicField(this,"persistence");__publicField(this,"send");__publicField(this,"endpoint");__publicField(this,"writeKey");__publicField(this,"platform");__publicField(this,"appVersion");__publicField(this,"maxBatch");__publicField(this,"flushMs");__publicField(this,"maxQueueSize");__publicField(this,"flushing",false);__publicField(this,"retryCount",0);var _a,_b,_c,_d,_e,_f,_g;this.endpoint=opts.endpoint;this.writeKey=opts.writeKey;this.platform=(_a=opts.platform)==null?void 0:_a.trim().toLowerCase();this.appVersion=opts.appVersion;this.maxBatch=(_b=opts.maxBatch)!=null?_b:5;this.flushMs=(_c=opts.flushMs)!=null?_c:5e3;this.maxQueueSize=(_d=opts.maxQueueSize)!=null?_d:500;this.send=(_e=opts.sender)!=null?_e:defaultFetchSender;this.identity=new Identity((_f=opts.storage)!=null?_f:webStorage());if(opts.distinctId)this.identity.setAnonymousId(opts.distinctId);this.persistence=opts.persistence===false?null:(_g=opts.persistence)!=null?_g:indexedDbPersistence({limit:this.maxQueueSize});void this.restore();if(this.platform&&!PLATFORMS.includes(this.platform)){console.error(`[tracker] platform "${this.platform}" 不在受控端列表里,按端分析时这批数据会自成一端。可选值:${PLATFORMS.join(" / ")}(微信小程序是 miniprogram,不是 wechat)`)}if(typeof document!=="undefined"){document.addEventListener("visibilitychange",()=>{if(document.visibilityState==="hidden")this.flush(true)});if(typeof window!=="undefined"){window.addEventListener("pagehide",()=>this.flush(true))}}}restore(){return __async(this,null,function*(){if(!this.persistence)return;const saved=yield this.persistence.load();const known=new Set(this.queue.map(e=>e.eventId));const revived=saved.filter(e=>(e==null?void 0:e.eventId)&&!known.has(e.eventId));if(!revived.length)return;this.queue.unshift(...revived);this.trim();void this.flush()})}register(props){Object.assign(this.superProps,props)}identify(id){if(this.identity.identify(id))this.enqueue("$identify",{})}reset(){this.identity.reset()}getDistinctId(){return this.identity.snapshot().distinctId}getAnonymousId(){return this.identity.snapshot().anonymousId}getSessionId(){return this.identity.snapshot().sessionId}get pending(){return this.queue.length}dispose(){if(this.timer){clearTimeout(this.timer);this.timer=null}}track(name,properties){this.enqueue(name,properties!=null?properties:{})}trackUnsafe(name,properties={}){this.enqueue(name,properties)}captureAs(who,name,properties={}){this.enqueue(name,properties,who)}enqueue(name,properties,override){var _a,_b;if(!override)this.identity.touch();const who=override!=null?override:this.identity.snapshot();const raw={eventId:uuid(),eventName:name,distinctId:who.distinctId,anonymousId:who.anonymousId,userId:(_a=who.userId)!=null?_a:void 0,sessionId:who.sessionId,platform:this.platform,appVersion:this.appVersion,clientTime:new Date().toISOString(),properties:__spreadProps(__spreadValues(__spreadValues({},this.superProps),properties),{$sdk_name:SDK_NAME,$sdk_version:SDK_VERSION,$protocol_version:PROTOCOL_VERSION})};this.queue.push(raw);(_b=this.persistence)==null?void 0:_b.add([{eventId:raw.eventId,savedAt:Date.now(),payload:raw}]);this.trim();if(this.queue.length>=this.maxBatch)this.flush();else this.schedule()}trim(){var _a;const overflow=this.queue.length-this.maxQueueSize;if(overflow>0){const dropped=this.queue.splice(0,overflow);(_a=this.persistence)==null?void 0:_a.remove(dropped.map(e=>e.eventId));console.warn(`[tracker] 队列超过 ${this.maxQueueSize} 条,丢弃最旧的 ${overflow} 条`)}}schedule(delayMs=this.flushMs){if(this.timer)return;this.timer=setTimeout(()=>this.flush(),delayMs)}flush(unloading=false){return __async(this,null,function*(){var _a,_b;if(this.timer){clearTimeout(this.timer);this.timer=null}if(this.queue.length===0||this.flushing&&!unloading)return;this.flushing=true;const batch=this.queue.splice(0,Math.min(MAX_BATCH_SIZE,this.queue.length));const body=JSON.stringify({events:batch,protocolVersion:PROTOCOL_VERSION});const headers={"Content-Type":"application/json","x-write-key":this.writeKey};try{yield this.send(this.endpoint,body,headers,unloading);(_a=this.persistence)==null?void 0:_a.remove(batch.map(e=>e.eventId));this.retryCount=0}catch(err){if((err==null?void 0:err.retryable)!==false){this.queue.unshift(...batch);this.trim();this.retryCount+=1}else{console.warn("[tracker] 丢弃一批(不可重试):",err==null?void 0:err.status);(_b=this.persistence)==null?void 0:_b.remove(batch.map(e=>e.eventId));this.retryCount=0}}finally{this.flushing=false}if(this.queue.length>0&&!unloading){this.schedule(Math.min(this.flushMs*__pow(2,this.retryCount),MAX_BACKOFF_MS))}})}};var defaultFetchSender=(endpoint,body,headers,keepalive)=>__async(null,null,function*(){const res=yield fetch(endpoint,{method:"POST",headers,body,keepalive});if(!res.ok){const e=new Error(`HTTP ${res.status}`);e.status=res.status;e.retryable=res.status>=500||res.status===429;throw e}});var wxSender=(endpoint,body,headers)=>new Promise((resolve,reject)=>{wx.request({url:endpoint,method:"POST",header:headers,data:body,timeout:1e4,success:res=>{if(res.statusCode>=200&&res.statusCode<300)return resolve();const e=new Error(`HTTP ${res.statusCode}`);e.status=res.statusCode;e.retryable=res.statusCode>=500||res.statusCode===429;reject(e)},fail:err=>{const e=new Error(err.errMsg);e.retryable=true;reject(e)}})});function wxStorage(){return{get(key){try{const v=wx.getStorageSync(key);return typeof v==="string"&&v?v:null}catch(e){return null}},set(key,value){try{wx.setStorageSync(key,value)}catch(e){}},remove(key){try{wx.removeStorageSync(key)}catch(e){}}}}var QUEUE_PREFIX="yz_q_";function wxPersistence(limit=500){let known=-1;const keys=()=>{try{return wx.getStorageInfoSync().keys.filter(k=>k.startsWith(QUEUE_PREFIX))}catch(e){return[]}};const readAll=()=>{const out=[];for(const k of keys()){try{const r=wx.getStorageSync(k);if(r==null?void 0:r.eventId)out.push(r)}catch(e){}}return out.sort((a,b)=>a.savedAt-b.savedAt)};return{load(){return __async(this,null,function*(){const all=readAll();known=all.length;return all.map(r=>r.payload)})},add(records){for(const r of records){try{wx.setStorageSync(QUEUE_PREFIX+r.eventId,r)}catch(e){}}known=known<0?keys().length:known+records.length;if(known<=limit)return;const all=readAll();for(const r of all.slice(0,all.length-limit)){try{wx.removeStorageSync(QUEUE_PREFIX+r.eventId)}catch(e){}}known=Math.min(all.length,limit)},remove(eventIds){for(const id of eventIds){try{wx.removeStorageSync(QUEUE_PREFIX+id)}catch(e){}}if(known>0)known=Math.max(0,known-eventIds.length)}}}function wxEnvContext(){try{const i=wx.getSystemInfoSync();const ctx={$runtime:"miniprogram"};if(i.system)ctx.$os=i.system;if(i.model)ctx.$device_model=i.model;if(i.brand)ctx.$device_brand=i.brand;if(i.SDKVersion)ctx.$mp_sdk_version=i.SDKVersion;if(i.version)ctx.$wechat_version=i.version;return ctx}catch(e){return{$runtime:"miniprogram"}}}var SYSTEM_EVENTS=["$pageview","$pageleave","$autocapture","$identify","$experiment_exposure"];var isSystemEvent=name=>SYSTEM_EVENTS.includes(name);var instance=null;function init(options){var _b;const _a=options,{envContext=true,persist=true}=_a,rest=__objRest(_a,["envContext","persist"]);instance=new Tracker(__spreadProps(__spreadValues({},rest),{platform:"miniprogram",sender:wxSender,storage:wxStorage(),persistence:persist?wxPersistence((_b=rest.maxQueueSize)!=null?_b:500):false}));if(envContext)instance.register(wxEnvContext());return instance}function getTracker(){return instance}function ensure(){if(!instance)throw new Error("tracker 未初始化,请先在 app.js 里调用 init()");return instance}function track(name,properties={}){ensure().trackUnsafe(name,properties)}function register(props){ensure().register(props)}function identify(id){ensure().identify(id)}function reset(){ensure().reset()}function flush(){return ensure().flush()}function trackTap(e){var _a,_b;const ds=(_b=(_a=e==null?void 0:e.currentTarget)==null?void 0:_a.dataset)!=null?_b:{};const name=ds.track;if(typeof name!=="string"||!name)return;const props={};for(const k of Object.keys(ds))if(k!=="track")props[k]=ds[k];instance==null?void 0:instance.trackUnsafe(name,props)}function wrap(hooks,name,extra){const original=hooks[name];hooks[name]=function(...args){try{extra(this,args)}catch(e){}return typeof original==="function"?original.apply(this,args):void 0}}function enableAutoTrack(){if(typeof Page==="function"){const originalPage=Page;const patched=(options=>{const enteredAt=new WeakMap;const routeOf=self=>{var _a,_b;return(_b=(_a=self==null?void 0:self.route)!=null?_a:self==null?void 0:self.__route__)!=null?_b:""};wrap(options,"onShow",self=>{enteredAt.set(self,Date.now());instance==null?void 0:instance.track("$pageview",{$url:routeOf(self)})});wrap(options,"onHide",self=>{const at=enteredAt.get(self);if(at===void 0)return;enteredAt.delete(self);instance==null?void 0:instance.track("$pageleave",{$url:routeOf(self),$duration_ms:Date.now()-at})});wrap(options,"onUnload",self=>{const at=enteredAt.get(self);if(at===void 0)return;enteredAt.delete(self);instance==null?void 0:instance.track("$pageleave",{$url:routeOf(self),$duration_ms:Date.now()-at})});return originalPage(options)});Object.assign(patched,originalPage);globalThis.Page=patched}if(typeof App==="function"){const originalApp=App;const patched=(options=>{wrap(options,"onHide",()=>void(instance==null?void 0:instance.flush(true)));return originalApp(options)});Object.assign(patched,originalApp);globalThis.App=patched}}var tracker={init,getTracker,track,register,identify,reset,flush,trackTap,enableAutoTrack};var index_default=tracker;
1
+ "use strict";var __defProp=Object.defineProperty;var __defProps=Object.defineProperties;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropDescs=Object.getOwnPropertyDescriptors;var __getOwnPropNames=Object.getOwnPropertyNames;var __getOwnPropSymbols=Object.getOwnPropertySymbols;var __hasOwnProp=Object.prototype.hasOwnProperty;var __propIsEnum=Object.prototype.propertyIsEnumerable;var __pow=Math.pow;var __defNormalProp=(obj,key,value)=>key in obj?__defProp(obj,key,{enumerable:true,configurable:true,writable:true,value}):obj[key]=value;var __spreadValues=(a,b)=>{for(var prop in b||(b={}))if(__hasOwnProp.call(b,prop))__defNormalProp(a,prop,b[prop]);if(__getOwnPropSymbols)for(var prop of __getOwnPropSymbols(b)){if(__propIsEnum.call(b,prop))__defNormalProp(a,prop,b[prop])}return a};var __spreadProps=(a,b)=>__defProps(a,__getOwnPropDescs(b));var __objRest=(source,exclude)=>{var target={};for(var prop in source)if(__hasOwnProp.call(source,prop)&&exclude.indexOf(prop)<0)target[prop]=source[prop];if(source!=null&&__getOwnPropSymbols)for(var prop of __getOwnPropSymbols(source)){if(exclude.indexOf(prop)<0&&__propIsEnum.call(source,prop))target[prop]=source[prop]}return target};var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var __publicField=(obj,key,value)=>__defNormalProp(obj,typeof key!=="symbol"?key+"":key,value);var __async=(__this,__arguments,generator)=>{return new Promise((resolve,reject)=>{var fulfilled=value=>{try{step(generator.next(value))}catch(e){reject(e)}};var rejected=value=>{try{step(generator.throw(value))}catch(e){reject(e)}};var step=x=>x.done?resolve(x.value):Promise.resolve(x.value).then(fulfilled,rejected);step((generator=generator.apply(__this,__arguments)).next())})};var index_exports={};__export(index_exports,{SYSTEM_EVENTS:()=>SYSTEM_EVENTS,default:()=>index_default,enableAutoTrack:()=>enableAutoTrack,flush:()=>flush,getTracker:()=>getTracker,identify:()=>identify,init:()=>init,isSystemEvent:()=>isSystemEvent,register:()=>register,reset:()=>reset,track:()=>track,trackTap:()=>trackTap,tracker:()=>tracker,wxEnvContext:()=>wxEnvContext,wxPersistence:()=>wxPersistence,wxSender:()=>wxSender,wxStorage:()=>wxStorage});module.exports=__toCommonJS(index_exports);function uuid(){const c=globalThis.crypto;if(typeof(c==null?void 0:c.randomUUID)==="function"){try{return c.randomUUID()}catch(e){}}if(typeof(c==null?void 0:c.getRandomValues)==="function"){try{const b2=c.getRandomValues(new Uint8Array(16));return formatUuid(b2)}catch(e){}}const b=new Uint8Array(16);for(let i=0;i<16;i+=1)b[i]=Math.floor(Math.random()*256);return formatUuid(b)}function formatUuid(b){b[6]=b[6]&15|64;b[8]=b[8]&63|128;const hex=[];for(let i=0;i<16;i+=1)hex.push(b[i].toString(16).padStart(2,"0"));const s=hex.join("");return`${s.slice(0,8)}-${s.slice(8,12)}-${s.slice(12,16)}-${s.slice(16,20)}-${s.slice(20)}`}function memoryStorage(){const m=new Map;return{get:k=>{var _a;return(_a=m.get(k))!=null?_a:null},set:(k,v)=>void m.set(k,v),remove:k=>void m.delete(k)}}function webStorage(){const mem=memoryStorage();let ls=null;try{ls=typeof localStorage!=="undefined"?localStorage:null}catch(e){ls=null}if(!ls)return mem;return{get(k){try{return ls.getItem(k)}catch(e){return mem.get(k)}},set(k,v){try{ls.setItem(k,v)}catch(e){mem.set(k,v)}},remove(k){try{ls.removeItem(k)}catch(e){mem.remove(k)}}}}var STORAGE_KEYS={anonymousId:"yz_anon",userId:"yz_uid",session:"yz_session"};var SESSION_TIMEOUT_MS=30*60*1e3;var TOUCH_PERSIST_MS=60*1e3;function dayKey(ts){const d=new Date(ts);const p=n=>String(n).padStart(2,"0");return`${d.getFullYear()}-${p(d.getMonth()+1)}-${p(d.getDate())}`}var Identity=class{constructor(store,now=Date.now){__publicField(this,"store",store);__publicField(this,"now",now);__publicField(this,"anonymousId");__publicField(this,"userId");__publicField(this,"session");__publicField(this,"persistedAt");var _a;this.anonymousId=(_a=this.store.get(STORAGE_KEYS.anonymousId))!=null?_a:this.newAnonymousId();this.userId=this.store.get(STORAGE_KEYS.userId)||null;this.session=this.loadSession();this.persistedAt=this.session.lastActive}newAnonymousId(){const id=`anon_${uuid()}`;this.store.set(STORAGE_KEYS.anonymousId,id);return id}loadSession(){const raw=this.store.get(STORAGE_KEYS.session);if(raw){try{const s=JSON.parse(raw);if((s==null?void 0:s.id)&&typeof s.lastActive==="number"&&!this.expired(s,this.now()))return s}catch(e){}}return this.startSession(this.now())}expired(s,at){return at-s.lastActive>SESSION_TIMEOUT_MS||s.day!==dayKey(at)}startSession(at){const s={id:uuid(),lastActive:at,day:dayKey(at)};this.store.set(STORAGE_KEYS.session,JSON.stringify(s));this.persistedAt=at;return s}touch(){const at=this.now();if(this.expired(this.session,at)){this.session=this.startSession(at);return}this.session.lastActive=at;if(at-this.persistedAt>=TOUCH_PERSIST_MS){this.store.set(STORAGE_KEYS.session,JSON.stringify(this.session));this.persistedAt=at}}identify(userId){const id=String(userId!=null?userId:"").trim();if(!id||id===this.userId)return false;this.userId=id;this.store.set(STORAGE_KEYS.userId,id);return true}reset(){this.userId=null;this.store.remove(STORAGE_KEYS.userId);this.anonymousId=this.newAnonymousId();this.session=this.startSession(this.now())}snapshot(){var _a;return{distinctId:(_a=this.userId)!=null?_a:this.anonymousId,anonymousId:this.anonymousId,userId:this.userId,sessionId:this.session.id}}setAnonymousId(id){this.anonymousId=id;this.store.set(STORAGE_KEYS.anonymousId,id)}};var DB_NAME="yz_tracker";var STORE="queue";var DEFAULT_LIMIT=500;function openDb(dbName){return new Promise((resolve,reject)=>{const req=indexedDB.open(dbName,1);req.onupgradeneeded=()=>{const db=req.result;if(!db.objectStoreNames.contains(STORE)){db.createObjectStore(STORE,{keyPath:"eventId"}).createIndex("savedAt","savedAt")}};req.onsuccess=()=>resolve(req.result);req.onerror=()=>reject(req.error);req.onblocked=()=>reject(new Error("indexedDB blocked"))})}function indexedDbPersistence(opts={}){var _a,_b;if(typeof indexedDB==="undefined")return null;const dbName=(_a=opts.dbName)!=null?_a:DB_NAME;const limit=(_b=opts.limit)!=null?_b:DEFAULT_LIMIT;let dbPromise=null;const db=()=>{dbPromise!=null?dbPromise:dbPromise=openDb(dbName);return dbPromise};const write=fn=>__async(null,null,function*(){try{const d=yield db();const tx=d.transaction(STORE,"readwrite");fn(tx.objectStore(STORE))}catch(e){}});return{load(){return __async(this,null,function*(){try{const d=yield db();const tx=d.transaction(STORE,"readonly");const req=tx.objectStore(STORE).index("savedAt").getAll();const rows=yield new Promise((resolve,reject)=>{req.onsuccess=()=>resolve(req.result);req.onerror=()=>reject(req.error)});return rows.map(r=>r.payload)}catch(e){return[]}})},add(records){void write(store=>{for(const r of records)store.put(r);const countReq=store.count();countReq.onsuccess=()=>{const over=countReq.result-limit;if(over<=0)return;let dropped=0;const cur=store.index("savedAt").openCursor();cur.onsuccess=()=>{const c=cur.result;if(!c||dropped>=over)return;c.delete();dropped+=1;c.continue()}}})},remove(eventIds){if(!eventIds.length)return;void write(store=>{for(const id of eventIds)store.delete(id)})}}}var SDK_NAME="@yuanze_dev/tracker";var SDK_VERSION="0.7.1";var PROTOCOL_VERSION=1;var MAX_BATCH_SIZE=50;var PLATFORMS=["web","pc","flutter","ios","android","miniprogram","backend"];var MAX_BACKOFF_MS=3e4;var Tracker=class{constructor(opts){__publicField(this,"queue",[]);__publicField(this,"timer",null);__publicField(this,"superProps",{});__publicField(this,"identity");__publicField(this,"persistence");__publicField(this,"send");__publicField(this,"endpoint");__publicField(this,"writeKey");__publicField(this,"platform");__publicField(this,"appVersion");__publicField(this,"maxBatch");__publicField(this,"flushMs");__publicField(this,"maxQueueSize");__publicField(this,"flushing",false);__publicField(this,"retryCount",0);var _a,_b,_c,_d,_e,_f,_g;this.endpoint=opts.endpoint;this.writeKey=opts.writeKey;this.platform=(_a=opts.platform)==null?void 0:_a.trim().toLowerCase();this.appVersion=opts.appVersion;this.maxBatch=(_b=opts.maxBatch)!=null?_b:5;this.flushMs=(_c=opts.flushMs)!=null?_c:5e3;this.maxQueueSize=(_d=opts.maxQueueSize)!=null?_d:500;this.send=(_e=opts.sender)!=null?_e:defaultFetchSender;this.identity=new Identity((_f=opts.storage)!=null?_f:webStorage());if(opts.distinctId)this.identity.setAnonymousId(opts.distinctId);this.persistence=opts.persistence===false?null:(_g=opts.persistence)!=null?_g:indexedDbPersistence({limit:this.maxQueueSize});void this.restore();if(this.platform&&!PLATFORMS.includes(this.platform)){console.error(`[tracker] platform "${this.platform}" 不在受控端列表里,按端分析时这批数据会自成一端。可选值:${PLATFORMS.join(" / ")}(微信小程序是 miniprogram,不是 wechat)`)}if(typeof document!=="undefined"){document.addEventListener("visibilitychange",()=>{if(document.visibilityState==="hidden")this.flush(true)});if(typeof window!=="undefined"){window.addEventListener("pagehide",()=>this.flush(true))}}}restore(){return __async(this,null,function*(){if(!this.persistence)return;const saved=yield this.persistence.load();const known=new Set(this.queue.map(e=>e.eventId));const revived=saved.filter(e=>(e==null?void 0:e.eventId)&&!known.has(e.eventId));if(!revived.length)return;this.queue.unshift(...revived);this.trim();void this.flush()})}register(props){Object.assign(this.superProps,props)}identify(id){if(this.identity.identify(id))this.enqueue("$identify",{})}reset(){this.identity.reset()}getDistinctId(){return this.identity.snapshot().distinctId}getAnonymousId(){return this.identity.snapshot().anonymousId}getSessionId(){return this.identity.snapshot().sessionId}get pending(){return this.queue.length}dispose(){if(this.timer){clearTimeout(this.timer);this.timer=null}}track(name,properties){this.enqueue(name,properties!=null?properties:{})}trackUnsafe(name,properties={}){this.enqueue(name,properties)}captureAs(who,name,properties={}){this.enqueue(name,properties,who)}enqueue(name,properties,override){var _a,_b;if(!override)this.identity.touch();const who=override!=null?override:this.identity.snapshot();const raw={eventId:uuid(),eventName:name,distinctId:who.distinctId,anonymousId:who.anonymousId,userId:(_a=who.userId)!=null?_a:void 0,sessionId:who.sessionId,platform:this.platform,appVersion:this.appVersion,clientTime:new Date().toISOString(),properties:__spreadProps(__spreadValues(__spreadValues({},this.superProps),properties),{$sdk_name:SDK_NAME,$sdk_version:SDK_VERSION,$protocol_version:PROTOCOL_VERSION})};this.queue.push(raw);(_b=this.persistence)==null?void 0:_b.add([{eventId:raw.eventId,savedAt:Date.now(),payload:raw}]);this.trim();if(this.queue.length>=this.maxBatch)this.flush();else this.schedule()}trim(){var _a;const overflow=this.queue.length-this.maxQueueSize;if(overflow>0){const dropped=this.queue.splice(0,overflow);(_a=this.persistence)==null?void 0:_a.remove(dropped.map(e=>e.eventId));console.warn(`[tracker] 队列超过 ${this.maxQueueSize} 条,丢弃最旧的 ${overflow} 条`)}}schedule(delayMs=this.flushMs){if(this.timer)return;this.timer=setTimeout(()=>this.flush(),delayMs)}flush(unloading=false){return __async(this,null,function*(){var _a,_b;if(this.timer){clearTimeout(this.timer);this.timer=null}if(this.queue.length===0||this.flushing&&!unloading)return;this.flushing=true;const batch=this.queue.splice(0,Math.min(MAX_BATCH_SIZE,this.queue.length));const body=JSON.stringify({events:batch,protocolVersion:PROTOCOL_VERSION});const headers={"Content-Type":"application/json","x-write-key":this.writeKey};try{yield this.send(this.endpoint,body,headers,unloading);(_a=this.persistence)==null?void 0:_a.remove(batch.map(e=>e.eventId));this.retryCount=0}catch(err){if((err==null?void 0:err.retryable)!==false){this.queue.unshift(...batch);this.trim();this.retryCount+=1}else{console.warn("[tracker] 丢弃一批(不可重试):",err==null?void 0:err.status);(_b=this.persistence)==null?void 0:_b.remove(batch.map(e=>e.eventId));this.retryCount=0}}finally{this.flushing=false}if(this.queue.length>0&&!unloading){this.schedule(Math.min(this.flushMs*__pow(2,this.retryCount),MAX_BACKOFF_MS))}})}};var defaultFetchSender=(endpoint,body,headers,keepalive)=>__async(null,null,function*(){const res=yield fetch(endpoint,{method:"POST",headers,body,keepalive});if(!res.ok){const e=new Error(`HTTP ${res.status}`);e.status=res.status;e.retryable=res.status>=500||res.status===429;throw e}});function coerceDatasetValue(raw){if(raw===void 0)return void 0;if(raw==="true")return true;if(raw==="false")return false;if(raw==="")return raw;const n=Number(raw);return Number.isFinite(n)&&String(n)===raw?n:raw}var wxSender=(endpoint,body,headers)=>new Promise((resolve,reject)=>{wx.request({url:endpoint,method:"POST",header:headers,data:body,timeout:1e4,success:res=>{if(res.statusCode>=200&&res.statusCode<300)return resolve();const e=new Error(`HTTP ${res.statusCode}`);e.status=res.statusCode;e.retryable=res.statusCode>=500||res.statusCode===429;reject(e)},fail:err=>{const e=new Error(err.errMsg);e.retryable=true;reject(e)}})});function wxStorage(){return{get(key){try{const v=wx.getStorageSync(key);return typeof v==="string"&&v?v:null}catch(e){return null}},set(key,value){try{wx.setStorageSync(key,value)}catch(e){}},remove(key){try{wx.removeStorageSync(key)}catch(e){}}}}var QUEUE_PREFIX="yz_q_";function wxPersistence(limit=500){let known=-1;const keys=()=>{try{return wx.getStorageInfoSync().keys.filter(k=>k.startsWith(QUEUE_PREFIX))}catch(e){return[]}};const readAll=()=>{const out=[];for(const k of keys()){try{const r=wx.getStorageSync(k);if(r==null?void 0:r.eventId)out.push(r)}catch(e){}}return out.sort((a,b)=>a.savedAt-b.savedAt)};return{load(){return __async(this,null,function*(){const all=readAll();known=all.length;return all.map(r=>r.payload)})},add(records){for(const r of records){try{wx.setStorageSync(QUEUE_PREFIX+r.eventId,r)}catch(e){}}known=known<0?keys().length:known+records.length;if(known<=limit)return;const all=readAll();for(const r of all.slice(0,all.length-limit)){try{wx.removeStorageSync(QUEUE_PREFIX+r.eventId)}catch(e){}}known=Math.min(all.length,limit)},remove(eventIds){for(const id of eventIds){try{wx.removeStorageSync(QUEUE_PREFIX+id)}catch(e){}}if(known>0)known=Math.max(0,known-eventIds.length)}}}function wxEnvContext(){try{const i=wx.getSystemInfoSync();const ctx={$runtime:"miniprogram"};if(i.system)ctx.$os=i.system;if(i.model)ctx.$device_model=i.model;if(i.brand)ctx.$device_brand=i.brand;if(i.SDKVersion)ctx.$mp_sdk_version=i.SDKVersion;if(i.version)ctx.$wechat_version=i.version;return ctx}catch(e){return{$runtime:"miniprogram"}}}var SYSTEM_EVENTS=["$pageview","$pageleave","$autocapture","$identify","$experiment_exposure"];var isSystemEvent=name=>SYSTEM_EVENTS.includes(name);var instance=null;function init(options){var _b;const _a=options,{envContext=true,persist=true}=_a,rest=__objRest(_a,["envContext","persist"]);instance=new Tracker(__spreadProps(__spreadValues({},rest),{platform:"miniprogram",sender:wxSender,storage:wxStorage(),persistence:persist?wxPersistence((_b=rest.maxQueueSize)!=null?_b:500):false}));if(envContext)instance.register(wxEnvContext());return instance}function getTracker(){return instance}function ensure(){if(!instance)throw new Error("tracker 未初始化,请先在 app.js 里调用 init()");return instance}function track(name,properties={}){ensure().trackUnsafe(name,properties)}function register(props){ensure().register(props)}function identify(id){ensure().identify(id)}function reset(){ensure().reset()}function flush(){return ensure().flush()}function trackTap(e){var _a,_b;const ds=(_b=(_a=e==null?void 0:e.currentTarget)==null?void 0:_a.dataset)!=null?_b:{};const name=ds.track;if(typeof name!=="string"||!name)return;const props={};for(const k of Object.keys(ds)){if(k==="track")continue;const v=ds[k];props[k]=typeof v==="string"?coerceDatasetValue(v):v}instance==null?void 0:instance.trackUnsafe(name,props)}function wrap(hooks,name,extra){const original=hooks[name];hooks[name]=function(...args){try{extra(this,args)}catch(e){}return typeof original==="function"?original.apply(this,args):void 0}}function enableAutoTrack(){if(typeof Page==="function"){const originalPage=Page;const patched=(options=>{const enteredAt=new WeakMap;const routeOf=self=>{var _a,_b;return(_b=(_a=self==null?void 0:self.route)!=null?_a:self==null?void 0:self.__route__)!=null?_b:""};wrap(options,"onShow",self=>{enteredAt.set(self,Date.now());instance==null?void 0:instance.track("$pageview",{$url:routeOf(self)})});wrap(options,"onHide",self=>{const at=enteredAt.get(self);if(at===void 0)return;enteredAt.delete(self);instance==null?void 0:instance.track("$pageleave",{$url:routeOf(self),$duration_ms:Date.now()-at})});wrap(options,"onUnload",self=>{const at=enteredAt.get(self);if(at===void 0)return;enteredAt.delete(self);instance==null?void 0:instance.track("$pageleave",{$url:routeOf(self),$duration_ms:Date.now()-at})});return originalPage(options)});Object.assign(patched,originalPage);globalThis.Page=patched}if(typeof App==="function"){const originalApp=App;const patched=(options=>{wrap(options,"onHide",()=>void(instance==null?void 0:instance.flush(true)));return originalApp(options)});Object.assign(patched,originalApp);globalThis.App=patched}}var tracker={init,getTracker,track,register,identify,reset,flush,trackTap,enableAutoTrack};var index_default=tracker;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuanze_dev/tracker-miniprogram",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "原则数据埋点 SDK · 微信小程序",
5
5
  "license": "UNLICENSED",
6
6
  "main": "./dist/index.js",