@easy-data/sdk 0.1.0 → 0.1.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.
- package/dist/browser/index.cjs +1 -1
- package/dist/browser/index.cjs.map +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/browser/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var a=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var m=(o,e)=>{for(var t in e)a(o,t,{get:e[t],enumerable:!0})},l=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of T(e))!h.call(o,r)&&r!==t&&a(o,r,{get:()=>e[r],enumerable:!(n=E(e,r))||n.enumerable});return o};var _=o=>l(a({},"__esModule",{value:!0}),o);var u={};m(u,{fetchEphemeralToken:()=>i});module.exports=_(u);var p=class extends Error{constructor(t,n){super(t);this.code=n;this.name="EasydataError"}};var s=class extends p{statusCode;constructor(e,t){super(e,"NETWORK_ERROR"),this.name="EasydataNetworkError",this.statusCode=t}};var c="https://api.
|
|
1
|
+
"use strict";var a=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var m=(o,e)=>{for(var t in e)a(o,t,{get:e[t],enumerable:!0})},l=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of T(e))!h.call(o,r)&&r!==t&&a(o,r,{get:()=>e[r],enumerable:!(n=E(e,r))||n.enumerable});return o};var _=o=>l(a({},"__esModule",{value:!0}),o);var u={};m(u,{fetchEphemeralToken:()=>i});module.exports=_(u);var p=class extends Error{constructor(t,n){super(t);this.code=n;this.name="EasydataError"}};var s=class extends p{statusCode;constructor(e,t){super(e,"NETWORK_ERROR"),this.name="EasydataNetworkError",this.statusCode=t}};var c="https://easydata-api.onrender.com";async function i(o){let e=o.baseUrl??c,t=await fetch(`${e}/v1/tokens/ephemeral`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o.apiKey}`}});if(!t.ok)throw new s(`Failed to fetch ephemeral token: HTTP ${t.status}`,t.status);return await t.json()}0&&(module.exports={fetchEphemeralToken});
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/browser/index.ts","../../src/errors.ts","../../src/constants.ts","../../src/browser/token.ts"],"sourcesContent":["export { fetchEphemeralToken } from \"./token\";\nexport type { FetchTokenOptions } from \"./token\";\n","export class EasydataError extends Error {\n constructor(message: string, public readonly code?: string) {\n super(message);\n this.name = \"EasydataError\";\n }\n}\n\nexport class EasydataValidationError extends EasydataError {\n constructor(message: string) {\n super(message, \"VALIDATION_ERROR\");\n this.name = \"EasydataValidationError\";\n }\n}\n\nexport class EasydataNetworkError extends EasydataError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message, \"NETWORK_ERROR\");\n this.name = \"EasydataNetworkError\";\n this.statusCode = statusCode;\n }\n}\n","export const DEFAULT_BASE_URL = \"https://api.
|
|
1
|
+
{"version":3,"sources":["../../src/browser/index.ts","../../src/errors.ts","../../src/constants.ts","../../src/browser/token.ts"],"sourcesContent":["export { fetchEphemeralToken } from \"./token\";\nexport type { FetchTokenOptions } from \"./token\";\n","export class EasydataError extends Error {\n constructor(message: string, public readonly code?: string) {\n super(message);\n this.name = \"EasydataError\";\n }\n}\n\nexport class EasydataValidationError extends EasydataError {\n constructor(message: string) {\n super(message, \"VALIDATION_ERROR\");\n this.name = \"EasydataValidationError\";\n }\n}\n\nexport class EasydataNetworkError extends EasydataError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message, \"NETWORK_ERROR\");\n this.name = \"EasydataNetworkError\";\n this.statusCode = statusCode;\n }\n}\n","export const DEFAULT_BASE_URL = \"https://easydata-api.onrender.com\";\nexport const DEFAULT_BATCH_SIZE = 10;\nexport const DEFAULT_BATCH_INTERVAL_MS = 5000;\nexport const DEFAULT_TIMEOUT_MS = 30000;\nexport const DEFAULT_MAX_RETRIES = 3;\nexport const RETRY_BASE_DELAY_MS = 500;\nexport const SDK_VERSION = \"0.1.0\";\n","import type { EphemeralToken } from \"../types\";\nimport { EasydataNetworkError } from \"../errors\";\nimport { DEFAULT_BASE_URL } from \"../constants\";\n\nexport interface FetchTokenOptions {\n baseUrl?: string;\n apiKey: string;\n}\n\nexport async function fetchEphemeralToken(\n options: FetchTokenOptions\n): Promise<EphemeralToken> {\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n const response = await fetch(`${baseUrl}/v1/tokens/ephemeral`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${options.apiKey}`,\n },\n });\n\n if (!response.ok) {\n throw new EasydataNetworkError(\n `Failed to fetch ephemeral token: HTTP ${response.status}`,\n response.status\n );\n }\n\n return (await response.json()) as EphemeralToken;\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,yBAAAE,IAAA,eAAAC,EAAAH,GCAO,IAAMI,EAAN,cAA4B,KAAM,CACvC,YAAYC,EAAiCC,EAAe,CAC1D,MAAMD,CAAO,EAD8B,UAAAC,EAE3C,KAAK,KAAO,eACd,CACF,EASO,IAAMC,EAAN,cAAmCC,CAAc,CACtC,WAEhB,YAAYC,EAAiBC,EAAqB,CAChD,MAAMD,EAAS,eAAe,EAC9B,KAAK,KAAO,uBACZ,KAAK,WAAaC,CACpB,CACF,ECtBO,IAAMC,EAAmB,oCCShC,eAAsBC,EACpBC,EACyB,CACzB,IAAMC,EAAUD,EAAQ,SAAWE,EAC7BC,EAAW,MAAM,MAAM,GAAGF,CAAO,uBAAwB,CAC7D,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,cAAe,UAAUD,EAAQ,MAAM,EACzC,CACF,CAAC,EAED,GAAI,CAACG,EAAS,GACZ,MAAM,IAAIC,EACR,yCAAyCD,EAAS,MAAM,GACxDA,EAAS,MACX,EAGF,OAAQ,MAAMA,EAAS,KAAK,CAC9B","names":["browser_exports","__export","fetchEphemeralToken","__toCommonJS","EasydataError","message","code","EasydataNetworkError","EasydataError","message","statusCode","DEFAULT_BASE_URL","fetchEphemeralToken","options","baseUrl","DEFAULT_BASE_URL","response","EasydataNetworkError"]}
|
package/dist/browser/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var s=class extends Error{constructor(e,p){super(e);this.code=p;this.name="EasydataError"}};var r=class extends s{statusCode;constructor(o,e){super(o,"NETWORK_ERROR"),this.name="EasydataNetworkError",this.statusCode=e}};var n="https://api.
|
|
1
|
+
var s=class extends Error{constructor(e,p){super(e);this.code=p;this.name="EasydataError"}};var r=class extends s{statusCode;constructor(o,e){super(o,"NETWORK_ERROR"),this.name="EasydataNetworkError",this.statusCode=e}};var n="https://easydata-api.onrender.com";async function a(t){let o=t.baseUrl??n,e=await fetch(`${o}/v1/tokens/ephemeral`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.apiKey}`}});if(!e.ok)throw new r(`Failed to fetch ephemeral token: HTTP ${e.status}`,e.status);return await e.json()}export{a as fetchEphemeralToken};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/errors.ts","../../src/constants.ts","../../src/browser/token.ts"],"sourcesContent":["export class EasydataError extends Error {\n constructor(message: string, public readonly code?: string) {\n super(message);\n this.name = \"EasydataError\";\n }\n}\n\nexport class EasydataValidationError extends EasydataError {\n constructor(message: string) {\n super(message, \"VALIDATION_ERROR\");\n this.name = \"EasydataValidationError\";\n }\n}\n\nexport class EasydataNetworkError extends EasydataError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message, \"NETWORK_ERROR\");\n this.name = \"EasydataNetworkError\";\n this.statusCode = statusCode;\n }\n}\n","export const DEFAULT_BASE_URL = \"https://api.
|
|
1
|
+
{"version":3,"sources":["../../src/errors.ts","../../src/constants.ts","../../src/browser/token.ts"],"sourcesContent":["export class EasydataError extends Error {\n constructor(message: string, public readonly code?: string) {\n super(message);\n this.name = \"EasydataError\";\n }\n}\n\nexport class EasydataValidationError extends EasydataError {\n constructor(message: string) {\n super(message, \"VALIDATION_ERROR\");\n this.name = \"EasydataValidationError\";\n }\n}\n\nexport class EasydataNetworkError extends EasydataError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message, \"NETWORK_ERROR\");\n this.name = \"EasydataNetworkError\";\n this.statusCode = statusCode;\n }\n}\n","export const DEFAULT_BASE_URL = \"https://easydata-api.onrender.com\";\nexport const DEFAULT_BATCH_SIZE = 10;\nexport const DEFAULT_BATCH_INTERVAL_MS = 5000;\nexport const DEFAULT_TIMEOUT_MS = 30000;\nexport const DEFAULT_MAX_RETRIES = 3;\nexport const RETRY_BASE_DELAY_MS = 500;\nexport const SDK_VERSION = \"0.1.0\";\n","import type { EphemeralToken } from \"../types\";\nimport { EasydataNetworkError } from \"../errors\";\nimport { DEFAULT_BASE_URL } from \"../constants\";\n\nexport interface FetchTokenOptions {\n baseUrl?: string;\n apiKey: string;\n}\n\nexport async function fetchEphemeralToken(\n options: FetchTokenOptions\n): Promise<EphemeralToken> {\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n const response = await fetch(`${baseUrl}/v1/tokens/ephemeral`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${options.apiKey}`,\n },\n });\n\n if (!response.ok) {\n throw new EasydataNetworkError(\n `Failed to fetch ephemeral token: HTTP ${response.status}`,\n response.status\n );\n }\n\n return (await response.json()) as EphemeralToken;\n}\n"],"mappings":"AAAO,IAAMA,EAAN,cAA4B,KAAM,CACvC,YAAYC,EAAiCC,EAAe,CAC1D,MAAMD,CAAO,EAD8B,UAAAC,EAE3C,KAAK,KAAO,eACd,CACF,EASO,IAAMC,EAAN,cAAmCC,CAAc,CACtC,WAEhB,YAAYC,EAAiBC,EAAqB,CAChD,MAAMD,EAAS,eAAe,EAC9B,KAAK,KAAO,uBACZ,KAAK,WAAaC,CACpB,CACF,ECtBO,IAAMC,EAAmB,oCCShC,eAAsBC,EACpBC,EACyB,CACzB,IAAMC,EAAUD,EAAQ,SAAWE,EAC7BC,EAAW,MAAM,MAAM,GAAGF,CAAO,uBAAwB,CAC7D,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,cAAe,UAAUD,EAAQ,MAAM,EACzC,CACF,CAAC,EAED,GAAI,CAACG,EAAS,GACZ,MAAM,IAAIC,EACR,yCAAyCD,EAAS,MAAM,GACxDA,EAAS,MACX,EAGF,OAAQ,MAAMA,EAAS,KAAK,CAC9B","names":["EasydataError","message","code","EasydataNetworkError","EasydataError","message","statusCode","DEFAULT_BASE_URL","fetchEphemeralToken","options","baseUrl","DEFAULT_BASE_URL","response","EasydataNetworkError"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var y=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var S=Object.prototype.hasOwnProperty;var B=(r,e)=>{for(var t in e)y(r,t,{get:e[t],enumerable:!0})},D=(r,e,t,
|
|
1
|
+
"use strict";var y=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var S=Object.prototype.hasOwnProperty;var B=(r,e)=>{for(var t in e)y(r,t,{get:e[t],enumerable:!0})},D=(r,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of P(e))!S.call(r,s)&&s!==t&&y(r,s,{get:()=>e[s],enumerable:!(o=x(e,s))||o.enumerable});return r};var M=r=>D(y({},"__esModule",{value:!0}),r);var F={};B(F,{DEFAULT_BASE_URL:()=>l,DEFAULT_BATCH_INTERVAL_MS:()=>h,DEFAULT_BATCH_SIZE:()=>d,DEFAULT_MAX_RETRIES:()=>E,DEFAULT_TIMEOUT_MS:()=>m,Easydata:()=>T,EasydataError:()=>p,EasydataNetworkError:()=>n,EasydataValidationError:()=>u,SDK_VERSION:()=>_,scrubEntry:()=>R,scrubText:()=>c});module.exports=M(F);var p=class extends Error{constructor(t,o){super(t);this.code=o;this.name="EasydataError"}},u=class extends p{constructor(e){super(e,"VALIDATION_ERROR"),this.name="EasydataValidationError"}},n=class extends p{statusCode;constructor(e,t){super(e,"NETWORK_ERROR"),this.name="EasydataNetworkError",this.statusCode=t}};var l="https://easydata-api.onrender.com",d=10,h=5e3,m=3e4,E=3;var _="0.1.0";function w(r){return r>=500||r===429}function I(r){return new Promise(e=>setTimeout(e,r))}async function A(r,e,t){let o=`${t.baseUrl}${r}`,s;for(let a=0;a<t.maxRetries;a++){let C=new AbortController,b=setTimeout(()=>C.abort(),t.timeoutMs);try{let i=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.apiKey}`,"X-Easydata-SDK":"js/0.1.0"},body:JSON.stringify(e),signal:C.signal});if(clearTimeout(b),i.ok)return await i.json();if(!w(i.status)){let v=await i.text().catch(()=>"Unknown error");throw new n(`HTTP ${i.status}: ${v}`,i.status)}s=new n(`HTTP ${i.status}`,i.status)}catch(i){if(clearTimeout(b),i instanceof n&&!w(i.statusCode??0))throw i;i instanceof DOMException&&i.name==="AbortError"?s=new n("Request timed out"):i instanceof n?s=i:s=i instanceof Error?i:new Error(String(i))}a<t.maxRetries-1&&await I(500*Math.pow(2,a))}throw s??new n("Request failed after retries")}var f=class{queue=[];timer=null;options;_isShutdown=!1;constructor(e){this.options=e,this.startTimer()}get pending(){return this.queue.length}get isShutdown(){return this._isShutdown}enqueue(e){return this._isShutdown?Promise.reject(new Error("BatchQueue has been shut down")):new Promise((t,o)=>{this.queue.push({entry:e,resolve:t,reject:o}),this.queue.length>=this.options.size&&this.flush()})}async flush(){if(this.queue.length===0)return{results:[],accepted:0,rejected:0,failed:0};let e=this.queue.splice(0),t=e.map(o=>o.entry);try{let o=await this.options.onFlush(t);for(let s=0;s<e.length;s++){let a=o.results[s];a?e[s].resolve(a):e[s].resolve({id:"unknown",status:"failed",reason:"No result returned"})}return o}catch(o){let s=o instanceof Error?o:new Error(String(o));for(let a of e)a.reject(s);return{results:[],accepted:0,rejected:0,failed:e.length}}}async shutdown(){this._isShutdown=!0,this.stopTimer(),this.queue.length>0&&await this.flush()}startTimer(){this.options.intervalMs>0&&(this.timer=setInterval(()=>{this.queue.length>0&&this.flush()},this.options.intervalMs))}stopTimer(){this.timer!==null&&(clearInterval(this.timer),this.timer=null)}};var L=[{pattern:/\b\d{3}-\d{2}-\d{4}\b/g,replacement:"[REDACTED_SSN]"},{pattern:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,replacement:"[REDACTED_EMAIL]"},{pattern:/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g,replacement:"[REDACTED_PHONE]"},{pattern:/\b(?:4\d{3}|5[1-5]\d{2}|3[47]\d{2}|6(?:011|5\d{2}))\d{8,12}\b/g,replacement:"[REDACTED_CC]"}];function c(r){let e=r;for(let{pattern:t,replacement:o}of L)t.lastIndex=0,e=e.replace(t,o);return e}function R(r){return{...r,userPrompt:c(r.userPrompt),aiResponse:c(r.aiResponse),userCorrection:c(r.userCorrection),...r.aiCorrectedResponse?{aiCorrectedResponse:c(r.aiCorrectedResponse)}:{},...r.aiInitialPrompt?{aiInitialPrompt:c(r.aiInitialPrompt)}:{}}}var g=class{constructor(e=!1){this.debug=e}info(e,...t){this.debug&&console.log(`[easydata] ${e}`,...t)}warn(e,...t){console.warn(`[easydata] ${e}`,...t)}error(e,...t){console.error(`[easydata] ${e}`,...t)}logBatchResult(e){let t=`${e.accepted} entries accepted ${e.rejected} entries rejected ${e.failed} entries failed`;e.failed>0?this.warn(t):this.info(t)}};var T=class r{config;batchQueue;logger;constructor(e){if(!e.apiKey)throw new u("apiKey is required");this.config={apiKey:e.apiKey,baseUrl:e.baseUrl??l,scrubPii:e.scrubPii??!0,timeoutMs:e.timeoutMs??3e4,maxRetries:e.maxRetries??3,debug:e.debug??!1},this.logger=new g(this.config.debug),this.batchQueue=new f({size:e.batch?.size??10,intervalMs:e.batch?.intervalMs??5e3,onFlush:t=>this.sendBatch(t)}),this.logger.info("Client initialized")}async captureCorrection(e){this.validateEntry(e);let t=this.config.scrubPii?R(e):e;return this.batchQueue.enqueue(t)}async captureCorrections(e){return Promise.all(e.map(t=>this.captureCorrection(t)))}async flush(){return this.batchQueue.flush()}async shutdown(){this.logger.info("Shutting down client"),await this.batchQueue.shutdown()}static createBrowserClient(e){return new r(e)}validateEntry(e){if(!e.userPrompt)throw new u("userPrompt is required");if(!e.aiResponse)throw new u("aiResponse is required");if(!e.userCorrection)throw new u("userCorrection is required")}toApiEntry(e){return{user_prompt:e.userPrompt,ai_response:e.aiResponse,user_correction:e.userCorrection,...e.aiCorrectedResponse&&{ai_corrected_response:e.aiCorrectedResponse},...e.aiInitialPrompt&&{system_prompt:e.aiInitialPrompt},...e.provider&&{provider:e.provider},...e.model&&{model:e.model},...e.domain&&{domain:e.domain},...e.metadata&&{metadata:e.metadata}}}async sendBatch(e){this.logger.info(`Sending batch of ${e.length} entries`);let t=e.map(s=>this.toApiEntry(s)),o=await A("/v1/corrections",{entries:t},{baseUrl:this.config.baseUrl,apiKey:this.config.apiKey,timeoutMs:this.config.timeoutMs,maxRetries:this.config.maxRetries});return this.logger.logBatchResult(o),o}};0&&(module.exports={DEFAULT_BASE_URL,DEFAULT_BATCH_INTERVAL_MS,DEFAULT_BATCH_SIZE,DEFAULT_MAX_RETRIES,DEFAULT_TIMEOUT_MS,Easydata,EasydataError,EasydataNetworkError,EasydataValidationError,SDK_VERSION,scrubEntry,scrubText});
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/constants.ts","../src/transport/http.ts","../src/transport/batch.ts","../src/pii/scrubber.ts","../src/logger.ts","../src/client.ts"],"sourcesContent":["export { Easydata } from \"./client\";\nexport {\n EasydataError,\n EasydataValidationError,\n EasydataNetworkError,\n} from \"./errors\";\nexport { scrubText, scrubEntry } from \"./pii/scrubber\";\nexport type {\n EasydataConfig,\n CorrectionEntry,\n CaptureResult,\n BatchResult,\n BatchConfig,\n Domain,\n EphemeralToken,\n} from \"./types\";\nexport {\n DEFAULT_BASE_URL,\n DEFAULT_BATCH_SIZE,\n DEFAULT_BATCH_INTERVAL_MS,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_MAX_RETRIES,\n SDK_VERSION,\n} from \"./constants\";\n","export class EasydataError extends Error {\n constructor(message: string, public readonly code?: string) {\n super(message);\n this.name = \"EasydataError\";\n }\n}\n\nexport class EasydataValidationError extends EasydataError {\n constructor(message: string) {\n super(message, \"VALIDATION_ERROR\");\n this.name = \"EasydataValidationError\";\n }\n}\n\nexport class EasydataNetworkError extends EasydataError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message, \"NETWORK_ERROR\");\n this.name = \"EasydataNetworkError\";\n this.statusCode = statusCode;\n }\n}\n","export const DEFAULT_BASE_URL = \"https://api.easydata.dev\";\nexport const DEFAULT_BATCH_SIZE = 10;\nexport const DEFAULT_BATCH_INTERVAL_MS = 5000;\nexport const DEFAULT_TIMEOUT_MS = 30000;\nexport const DEFAULT_MAX_RETRIES = 3;\nexport const RETRY_BASE_DELAY_MS = 500;\nexport const SDK_VERSION = \"0.1.0\";\n","import { EasydataNetworkError } from \"../errors\";\nimport { RETRY_BASE_DELAY_MS } from \"../constants\";\n\nexport interface HttpOptions {\n baseUrl: string;\n apiKey: string;\n timeoutMs: number;\n maxRetries: number;\n}\n\nfunction isRetryable(status: number): boolean {\n return status >= 500 || status === 429;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function httpPost<T>(\n path: string,\n body: unknown,\n options: HttpOptions\n): Promise<T> {\n const url = `${options.baseUrl}${path}`;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < options.maxRetries; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), options.timeoutMs);\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${options.apiKey}`,\n \"X-Easydata-SDK\": \"js/0.1.0\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n if (!isRetryable(response.status)) {\n const text = await response.text().catch(() => \"Unknown error\");\n throw new EasydataNetworkError(\n `HTTP ${response.status}: ${text}`,\n response.status\n );\n }\n\n lastError = new EasydataNetworkError(\n `HTTP ${response.status}`,\n response.status\n );\n } catch (err) {\n clearTimeout(timer);\n\n if (err instanceof EasydataNetworkError && !isRetryable(err.statusCode ?? 0)) {\n throw err;\n }\n\n if (err instanceof DOMException && err.name === \"AbortError\") {\n lastError = new EasydataNetworkError(\"Request timed out\");\n } else if (!(err instanceof EasydataNetworkError)) {\n lastError = err instanceof Error ? err : new Error(String(err));\n } else {\n lastError = err;\n }\n }\n\n if (attempt < options.maxRetries - 1) {\n await delay(RETRY_BASE_DELAY_MS * Math.pow(2, attempt));\n }\n }\n\n throw lastError ?? new EasydataNetworkError(\"Request failed after retries\");\n}\n","import type { CorrectionEntry, BatchResult, CaptureResult } from \"../types\";\n\nexport interface QueuedEntry {\n entry: CorrectionEntry;\n resolve: (result: CaptureResult) => void;\n reject: (error: Error) => void;\n}\n\nexport interface BatchQueueOptions {\n size: number;\n intervalMs: number;\n onFlush: (entries: CorrectionEntry[]) => Promise<BatchResult>;\n}\n\nexport class BatchQueue {\n private queue: QueuedEntry[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly options: BatchQueueOptions;\n private _isShutdown = false;\n\n constructor(options: BatchQueueOptions) {\n this.options = options;\n this.startTimer();\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n get isShutdown(): boolean {\n return this._isShutdown;\n }\n\n enqueue(entry: CorrectionEntry): Promise<CaptureResult> {\n if (this._isShutdown) {\n return Promise.reject(new Error(\"BatchQueue has been shut down\"));\n }\n\n return new Promise<CaptureResult>((resolve, reject) => {\n this.queue.push({ entry, resolve, reject });\n\n if (this.queue.length >= this.options.size) {\n void this.flush();\n }\n });\n }\n\n async flush(): Promise<BatchResult> {\n if (this.queue.length === 0) {\n return { results: [], accepted: 0, rejected: 0, failed: 0 };\n }\n\n const batch = this.queue.splice(0);\n const entries = batch.map((q) => q.entry);\n\n try {\n const result = await this.options.onFlush(entries);\n\n for (let i = 0; i < batch.length; i++) {\n const captureResult = result.results[i];\n if (captureResult) {\n batch[i].resolve(captureResult);\n } else {\n batch[i].resolve({\n id: \"unknown\",\n status: \"failed\",\n reason: \"No result returned\",\n });\n }\n }\n\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n for (const item of batch) {\n item.reject(error);\n }\n return {\n results: [],\n accepted: 0,\n rejected: 0,\n failed: batch.length,\n };\n }\n }\n\n async shutdown(): Promise<void> {\n this._isShutdown = true;\n this.stopTimer();\n if (this.queue.length > 0) {\n await this.flush();\n }\n }\n\n private startTimer(): void {\n if (this.options.intervalMs > 0) {\n this.timer = setInterval(() => {\n if (this.queue.length > 0) {\n void this.flush();\n }\n }, this.options.intervalMs);\n }\n }\n\n private stopTimer(): void {\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n","import type { CorrectionEntry } from \"../types\";\n\nconst PII_PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [\n // SSN must come before phone to avoid false positives\n {\n pattern: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g,\n replacement: \"[REDACTED_SSN]\",\n },\n {\n pattern: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/g,\n replacement: \"[REDACTED_EMAIL]\",\n },\n {\n pattern: /\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b/g,\n replacement: \"[REDACTED_PHONE]\",\n },\n {\n pattern: /\\b(?:4\\d{3}|5[1-5]\\d{2}|3[47]\\d{2}|6(?:011|5\\d{2}))\\d{8,12}\\b/g,\n replacement: \"[REDACTED_CC]\",\n },\n];\n\nexport function scrubText(text: string): string {\n let result = text;\n for (const { pattern, replacement } of PII_PATTERNS) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0;\n result = result.replace(pattern, replacement);\n }\n return result;\n}\n\nexport function scrubEntry(entry: CorrectionEntry): CorrectionEntry {\n return {\n ...entry,\n userPrompt: scrubText(entry.userPrompt),\n aiResponse: scrubText(entry.aiResponse),\n userCorrection: scrubText(entry.userCorrection),\n ...(entry.aiCorrectedResponse\n ? { aiCorrectedResponse: scrubText(entry.aiCorrectedResponse) }\n : {}),\n ...(entry.aiInitialPrompt\n ? { aiInitialPrompt: scrubText(entry.aiInitialPrompt) }\n : {}),\n };\n}\n","import type { BatchResult } from \"./types\";\n\nexport class Logger {\n constructor(private readonly debug: boolean = false) {}\n\n info(message: string, ...args: unknown[]): void {\n if (this.debug) {\n console.log(`[easydata] ${message}`, ...args);\n }\n }\n\n warn(message: string, ...args: unknown[]): void {\n console.warn(`[easydata] ${message}`, ...args);\n }\n\n error(message: string, ...args: unknown[]): void {\n console.error(`[easydata] ${message}`, ...args);\n }\n\n logBatchResult(result: BatchResult): void {\n const msg = `${result.accepted} entries accepted ${result.rejected} entries rejected ${result.failed} entries failed`;\n if (result.failed > 0) {\n this.warn(msg);\n } else {\n this.info(msg);\n }\n }\n}\n","import type {\n EasydataConfig,\n CorrectionEntry,\n CaptureResult,\n BatchResult,\n} from \"./types\";\nimport { EasydataValidationError } from \"./errors\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_BATCH_SIZE,\n DEFAULT_BATCH_INTERVAL_MS,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_MAX_RETRIES,\n} from \"./constants\";\nimport { httpPost } from \"./transport/http\";\nimport { BatchQueue } from \"./transport/batch\";\nimport { scrubEntry } from \"./pii/scrubber\";\nimport { Logger } from \"./logger\";\n\nexport class Easydata {\n private readonly config: Required<\n Pick<EasydataConfig, \"apiKey\" | \"baseUrl\" | \"scrubPii\" | \"timeoutMs\" | \"maxRetries\" | \"debug\">\n >;\n private readonly batchQueue: BatchQueue;\n private readonly logger: Logger;\n\n constructor(config: EasydataConfig) {\n if (!config.apiKey) {\n throw new EasydataValidationError(\"apiKey is required\");\n }\n\n this.config = {\n apiKey: config.apiKey,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n scrubPii: config.scrubPii ?? true,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n debug: config.debug ?? false,\n };\n\n this.logger = new Logger(this.config.debug);\n\n this.batchQueue = new BatchQueue({\n size: config.batch?.size ?? DEFAULT_BATCH_SIZE,\n intervalMs: config.batch?.intervalMs ?? DEFAULT_BATCH_INTERVAL_MS,\n onFlush: (entries) => this.sendBatch(entries),\n });\n\n this.logger.info(\"Client initialized\");\n }\n\n async captureCorrection(entry: CorrectionEntry): Promise<CaptureResult> {\n this.validateEntry(entry);\n\n const processed = this.config.scrubPii ? scrubEntry(entry) : entry;\n return this.batchQueue.enqueue(processed);\n }\n\n async captureCorrections(entries: CorrectionEntry[]): Promise<CaptureResult[]> {\n return Promise.all(entries.map((e) => this.captureCorrection(e)));\n }\n\n async flush(): Promise<BatchResult> {\n return this.batchQueue.flush();\n }\n\n async shutdown(): Promise<void> {\n this.logger.info(\"Shutting down client\");\n await this.batchQueue.shutdown();\n }\n\n static createBrowserClient(config: EasydataConfig): Easydata {\n return new Easydata(config);\n }\n\n private validateEntry(entry: CorrectionEntry): void {\n if (!entry.userPrompt) {\n throw new EasydataValidationError(\"userPrompt is required\");\n }\n if (!entry.aiResponse) {\n throw new EasydataValidationError(\"aiResponse is required\");\n }\n if (!entry.userCorrection) {\n throw new EasydataValidationError(\"userCorrection is required\");\n }\n }\n\n private toApiEntry(entry: CorrectionEntry) {\n return {\n user_prompt: entry.userPrompt,\n ai_response: entry.aiResponse,\n user_correction: entry.userCorrection,\n ...(entry.aiCorrectedResponse && { ai_corrected_response: entry.aiCorrectedResponse }),\n ...(entry.aiInitialPrompt && { system_prompt: entry.aiInitialPrompt }),\n ...(entry.provider && { provider: entry.provider }),\n ...(entry.model && { model: entry.model }),\n ...(entry.domain && { domain: entry.domain }),\n ...(entry.metadata && { metadata: entry.metadata }),\n };\n }\n\n private async sendBatch(entries: CorrectionEntry[]): Promise<BatchResult> {\n this.logger.info(`Sending batch of ${entries.length} entries`);\n\n const apiEntries = entries.map((e) => this.toApiEntry(e));\n\n const result = await httpPost<BatchResult>(\n \"/v1/corrections\",\n { entries: apiEntries },\n {\n baseUrl: this.config.baseUrl,\n apiKey: this.config.apiKey,\n timeoutMs: this.config.timeoutMs,\n maxRetries: this.config.maxRetries,\n }\n );\n\n this.logger.logBatchResult(result);\n return result;\n }\n}\n"],"mappings":"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","names":["index_exports","__export","DEFAULT_BASE_URL","DEFAULT_BATCH_INTERVAL_MS","DEFAULT_BATCH_SIZE","DEFAULT_MAX_RETRIES","DEFAULT_TIMEOUT_MS","Easydata","EasydataError","EasydataNetworkError","EasydataValidationError","SDK_VERSION","scrubEntry","scrubText","__toCommonJS","EasydataError","message","code","EasydataValidationError","EasydataNetworkError","statusCode","DEFAULT_BASE_URL","DEFAULT_BATCH_SIZE","DEFAULT_BATCH_INTERVAL_MS","DEFAULT_TIMEOUT_MS","DEFAULT_MAX_RETRIES","SDK_VERSION","isRetryable","status","delay","ms","resolve","httpPost","path","body","options","url","lastError","attempt","controller","timer","response","text","EasydataNetworkError","err","BatchQueue","options","entry","resolve","reject","batch","entries","q","result","i","captureResult","err","error","item","PII_PATTERNS","scrubText","text","result","pattern","replacement","scrubEntry","entry","Logger","debug","message","args","result","msg","Easydata","_Easydata","config","EasydataValidationError","DEFAULT_BASE_URL","Logger","BatchQueue","entries","entry","processed","scrubEntry","e","apiEntries","result","httpPost"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/constants.ts","../src/transport/http.ts","../src/transport/batch.ts","../src/pii/scrubber.ts","../src/logger.ts","../src/client.ts"],"sourcesContent":["export { Easydata } from \"./client\";\nexport {\n EasydataError,\n EasydataValidationError,\n EasydataNetworkError,\n} from \"./errors\";\nexport { scrubText, scrubEntry } from \"./pii/scrubber\";\nexport type {\n EasydataConfig,\n CorrectionEntry,\n CaptureResult,\n BatchResult,\n BatchConfig,\n Domain,\n EphemeralToken,\n} from \"./types\";\nexport {\n DEFAULT_BASE_URL,\n DEFAULT_BATCH_SIZE,\n DEFAULT_BATCH_INTERVAL_MS,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_MAX_RETRIES,\n SDK_VERSION,\n} from \"./constants\";\n","export class EasydataError extends Error {\n constructor(message: string, public readonly code?: string) {\n super(message);\n this.name = \"EasydataError\";\n }\n}\n\nexport class EasydataValidationError extends EasydataError {\n constructor(message: string) {\n super(message, \"VALIDATION_ERROR\");\n this.name = \"EasydataValidationError\";\n }\n}\n\nexport class EasydataNetworkError extends EasydataError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message, \"NETWORK_ERROR\");\n this.name = \"EasydataNetworkError\";\n this.statusCode = statusCode;\n }\n}\n","export const DEFAULT_BASE_URL = \"https://easydata-api.onrender.com\";\nexport const DEFAULT_BATCH_SIZE = 10;\nexport const DEFAULT_BATCH_INTERVAL_MS = 5000;\nexport const DEFAULT_TIMEOUT_MS = 30000;\nexport const DEFAULT_MAX_RETRIES = 3;\nexport const RETRY_BASE_DELAY_MS = 500;\nexport const SDK_VERSION = \"0.1.0\";\n","import { EasydataNetworkError } from \"../errors\";\nimport { RETRY_BASE_DELAY_MS } from \"../constants\";\n\nexport interface HttpOptions {\n baseUrl: string;\n apiKey: string;\n timeoutMs: number;\n maxRetries: number;\n}\n\nfunction isRetryable(status: number): boolean {\n return status >= 500 || status === 429;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function httpPost<T>(\n path: string,\n body: unknown,\n options: HttpOptions\n): Promise<T> {\n const url = `${options.baseUrl}${path}`;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < options.maxRetries; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), options.timeoutMs);\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${options.apiKey}`,\n \"X-Easydata-SDK\": \"js/0.1.0\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n if (!isRetryable(response.status)) {\n const text = await response.text().catch(() => \"Unknown error\");\n throw new EasydataNetworkError(\n `HTTP ${response.status}: ${text}`,\n response.status\n );\n }\n\n lastError = new EasydataNetworkError(\n `HTTP ${response.status}`,\n response.status\n );\n } catch (err) {\n clearTimeout(timer);\n\n if (err instanceof EasydataNetworkError && !isRetryable(err.statusCode ?? 0)) {\n throw err;\n }\n\n if (err instanceof DOMException && err.name === \"AbortError\") {\n lastError = new EasydataNetworkError(\"Request timed out\");\n } else if (!(err instanceof EasydataNetworkError)) {\n lastError = err instanceof Error ? err : new Error(String(err));\n } else {\n lastError = err;\n }\n }\n\n if (attempt < options.maxRetries - 1) {\n await delay(RETRY_BASE_DELAY_MS * Math.pow(2, attempt));\n }\n }\n\n throw lastError ?? new EasydataNetworkError(\"Request failed after retries\");\n}\n","import type { CorrectionEntry, BatchResult, CaptureResult } from \"../types\";\n\nexport interface QueuedEntry {\n entry: CorrectionEntry;\n resolve: (result: CaptureResult) => void;\n reject: (error: Error) => void;\n}\n\nexport interface BatchQueueOptions {\n size: number;\n intervalMs: number;\n onFlush: (entries: CorrectionEntry[]) => Promise<BatchResult>;\n}\n\nexport class BatchQueue {\n private queue: QueuedEntry[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly options: BatchQueueOptions;\n private _isShutdown = false;\n\n constructor(options: BatchQueueOptions) {\n this.options = options;\n this.startTimer();\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n get isShutdown(): boolean {\n return this._isShutdown;\n }\n\n enqueue(entry: CorrectionEntry): Promise<CaptureResult> {\n if (this._isShutdown) {\n return Promise.reject(new Error(\"BatchQueue has been shut down\"));\n }\n\n return new Promise<CaptureResult>((resolve, reject) => {\n this.queue.push({ entry, resolve, reject });\n\n if (this.queue.length >= this.options.size) {\n void this.flush();\n }\n });\n }\n\n async flush(): Promise<BatchResult> {\n if (this.queue.length === 0) {\n return { results: [], accepted: 0, rejected: 0, failed: 0 };\n }\n\n const batch = this.queue.splice(0);\n const entries = batch.map((q) => q.entry);\n\n try {\n const result = await this.options.onFlush(entries);\n\n for (let i = 0; i < batch.length; i++) {\n const captureResult = result.results[i];\n if (captureResult) {\n batch[i].resolve(captureResult);\n } else {\n batch[i].resolve({\n id: \"unknown\",\n status: \"failed\",\n reason: \"No result returned\",\n });\n }\n }\n\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n for (const item of batch) {\n item.reject(error);\n }\n return {\n results: [],\n accepted: 0,\n rejected: 0,\n failed: batch.length,\n };\n }\n }\n\n async shutdown(): Promise<void> {\n this._isShutdown = true;\n this.stopTimer();\n if (this.queue.length > 0) {\n await this.flush();\n }\n }\n\n private startTimer(): void {\n if (this.options.intervalMs > 0) {\n this.timer = setInterval(() => {\n if (this.queue.length > 0) {\n void this.flush();\n }\n }, this.options.intervalMs);\n }\n }\n\n private stopTimer(): void {\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n","import type { CorrectionEntry } from \"../types\";\n\nconst PII_PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [\n // SSN must come before phone to avoid false positives\n {\n pattern: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g,\n replacement: \"[REDACTED_SSN]\",\n },\n {\n pattern: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/g,\n replacement: \"[REDACTED_EMAIL]\",\n },\n {\n pattern: /\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b/g,\n replacement: \"[REDACTED_PHONE]\",\n },\n {\n pattern: /\\b(?:4\\d{3}|5[1-5]\\d{2}|3[47]\\d{2}|6(?:011|5\\d{2}))\\d{8,12}\\b/g,\n replacement: \"[REDACTED_CC]\",\n },\n];\n\nexport function scrubText(text: string): string {\n let result = text;\n for (const { pattern, replacement } of PII_PATTERNS) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0;\n result = result.replace(pattern, replacement);\n }\n return result;\n}\n\nexport function scrubEntry(entry: CorrectionEntry): CorrectionEntry {\n return {\n ...entry,\n userPrompt: scrubText(entry.userPrompt),\n aiResponse: scrubText(entry.aiResponse),\n userCorrection: scrubText(entry.userCorrection),\n ...(entry.aiCorrectedResponse\n ? { aiCorrectedResponse: scrubText(entry.aiCorrectedResponse) }\n : {}),\n ...(entry.aiInitialPrompt\n ? { aiInitialPrompt: scrubText(entry.aiInitialPrompt) }\n : {}),\n };\n}\n","import type { BatchResult } from \"./types\";\n\nexport class Logger {\n constructor(private readonly debug: boolean = false) {}\n\n info(message: string, ...args: unknown[]): void {\n if (this.debug) {\n console.log(`[easydata] ${message}`, ...args);\n }\n }\n\n warn(message: string, ...args: unknown[]): void {\n console.warn(`[easydata] ${message}`, ...args);\n }\n\n error(message: string, ...args: unknown[]): void {\n console.error(`[easydata] ${message}`, ...args);\n }\n\n logBatchResult(result: BatchResult): void {\n const msg = `${result.accepted} entries accepted ${result.rejected} entries rejected ${result.failed} entries failed`;\n if (result.failed > 0) {\n this.warn(msg);\n } else {\n this.info(msg);\n }\n }\n}\n","import type {\n EasydataConfig,\n CorrectionEntry,\n CaptureResult,\n BatchResult,\n} from \"./types\";\nimport { EasydataValidationError } from \"./errors\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_BATCH_SIZE,\n DEFAULT_BATCH_INTERVAL_MS,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_MAX_RETRIES,\n} from \"./constants\";\nimport { httpPost } from \"./transport/http\";\nimport { BatchQueue } from \"./transport/batch\";\nimport { scrubEntry } from \"./pii/scrubber\";\nimport { Logger } from \"./logger\";\n\nexport class Easydata {\n private readonly config: Required<\n Pick<EasydataConfig, \"apiKey\" | \"baseUrl\" | \"scrubPii\" | \"timeoutMs\" | \"maxRetries\" | \"debug\">\n >;\n private readonly batchQueue: BatchQueue;\n private readonly logger: Logger;\n\n constructor(config: EasydataConfig) {\n if (!config.apiKey) {\n throw new EasydataValidationError(\"apiKey is required\");\n }\n\n this.config = {\n apiKey: config.apiKey,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n scrubPii: config.scrubPii ?? true,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n debug: config.debug ?? false,\n };\n\n this.logger = new Logger(this.config.debug);\n\n this.batchQueue = new BatchQueue({\n size: config.batch?.size ?? DEFAULT_BATCH_SIZE,\n intervalMs: config.batch?.intervalMs ?? DEFAULT_BATCH_INTERVAL_MS,\n onFlush: (entries) => this.sendBatch(entries),\n });\n\n this.logger.info(\"Client initialized\");\n }\n\n async captureCorrection(entry: CorrectionEntry): Promise<CaptureResult> {\n this.validateEntry(entry);\n\n const processed = this.config.scrubPii ? scrubEntry(entry) : entry;\n return this.batchQueue.enqueue(processed);\n }\n\n async captureCorrections(entries: CorrectionEntry[]): Promise<CaptureResult[]> {\n return Promise.all(entries.map((e) => this.captureCorrection(e)));\n }\n\n async flush(): Promise<BatchResult> {\n return this.batchQueue.flush();\n }\n\n async shutdown(): Promise<void> {\n this.logger.info(\"Shutting down client\");\n await this.batchQueue.shutdown();\n }\n\n static createBrowserClient(config: EasydataConfig): Easydata {\n return new Easydata(config);\n }\n\n private validateEntry(entry: CorrectionEntry): void {\n if (!entry.userPrompt) {\n throw new EasydataValidationError(\"userPrompt is required\");\n }\n if (!entry.aiResponse) {\n throw new EasydataValidationError(\"aiResponse is required\");\n }\n if (!entry.userCorrection) {\n throw new EasydataValidationError(\"userCorrection is required\");\n }\n }\n\n private toApiEntry(entry: CorrectionEntry) {\n return {\n user_prompt: entry.userPrompt,\n ai_response: entry.aiResponse,\n user_correction: entry.userCorrection,\n ...(entry.aiCorrectedResponse && { ai_corrected_response: entry.aiCorrectedResponse }),\n ...(entry.aiInitialPrompt && { system_prompt: entry.aiInitialPrompt }),\n ...(entry.provider && { provider: entry.provider }),\n ...(entry.model && { model: entry.model }),\n ...(entry.domain && { domain: entry.domain }),\n ...(entry.metadata && { metadata: entry.metadata }),\n };\n }\n\n private async sendBatch(entries: CorrectionEntry[]): Promise<BatchResult> {\n this.logger.info(`Sending batch of ${entries.length} entries`);\n\n const apiEntries = entries.map((e) => this.toApiEntry(e));\n\n const result = await httpPost<BatchResult>(\n \"/v1/corrections\",\n { entries: apiEntries },\n {\n baseUrl: this.config.baseUrl,\n apiKey: this.config.apiKey,\n timeoutMs: this.config.timeoutMs,\n maxRetries: this.config.maxRetries,\n }\n );\n\n this.logger.logBatchResult(result);\n return result;\n }\n}\n"],"mappings":"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","names":["index_exports","__export","DEFAULT_BASE_URL","DEFAULT_BATCH_INTERVAL_MS","DEFAULT_BATCH_SIZE","DEFAULT_MAX_RETRIES","DEFAULT_TIMEOUT_MS","Easydata","EasydataError","EasydataNetworkError","EasydataValidationError","SDK_VERSION","scrubEntry","scrubText","__toCommonJS","EasydataError","message","code","EasydataValidationError","EasydataNetworkError","statusCode","DEFAULT_BASE_URL","DEFAULT_BATCH_SIZE","DEFAULT_BATCH_INTERVAL_MS","DEFAULT_TIMEOUT_MS","DEFAULT_MAX_RETRIES","SDK_VERSION","isRetryable","status","delay","ms","resolve","httpPost","path","body","options","url","lastError","attempt","controller","timer","response","text","EasydataNetworkError","err","BatchQueue","options","entry","resolve","reject","batch","entries","q","result","i","captureResult","err","error","item","PII_PATTERNS","scrubText","text","result","pattern","replacement","scrubEntry","entry","Logger","debug","message","args","result","msg","Easydata","_Easydata","config","EasydataValidationError","DEFAULT_BASE_URL","Logger","BatchQueue","entries","entry","processed","scrubEntry","e","apiEntries","result","httpPost"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -31,7 +31,7 @@ declare class EasydataNetworkError extends EasydataError {
|
|
|
31
31
|
declare function scrubText(text: string): string;
|
|
32
32
|
declare function scrubEntry(entry: CorrectionEntry): CorrectionEntry;
|
|
33
33
|
|
|
34
|
-
declare const DEFAULT_BASE_URL = "https://api.
|
|
34
|
+
declare const DEFAULT_BASE_URL = "https://easydata-api.onrender.com";
|
|
35
35
|
declare const DEFAULT_BATCH_SIZE = 10;
|
|
36
36
|
declare const DEFAULT_BATCH_INTERVAL_MS = 5000;
|
|
37
37
|
declare const DEFAULT_TIMEOUT_MS = 30000;
|
package/dist/index.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ declare class EasydataNetworkError extends EasydataError {
|
|
|
31
31
|
declare function scrubText(text: string): string;
|
|
32
32
|
declare function scrubEntry(entry: CorrectionEntry): CorrectionEntry;
|
|
33
33
|
|
|
34
|
-
declare const DEFAULT_BASE_URL = "https://api.
|
|
34
|
+
declare const DEFAULT_BASE_URL = "https://easydata-api.onrender.com";
|
|
35
35
|
declare const DEFAULT_BATCH_SIZE = 10;
|
|
36
36
|
declare const DEFAULT_BATCH_INTERVAL_MS = 5000;
|
|
37
37
|
declare const DEFAULT_TIMEOUT_MS = 30000;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var p=class extends Error{constructor(t,
|
|
1
|
+
var p=class extends Error{constructor(t,s){super(t);this.code=s;this.name="EasydataError"}},u=class extends p{constructor(e){super(e,"VALIDATION_ERROR"),this.name="EasydataValidationError"}},n=class extends p{statusCode;constructor(e,t){super(e,"NETWORK_ERROR"),this.name="EasydataNetworkError",this.statusCode=t}};var h="https://easydata-api.onrender.com",m=10,E=5e3,f=3e4,R=3;var A="0.1.0";function b(r){return r>=500||r===429}function x(r){return new Promise(e=>setTimeout(e,r))}async function _(r,e,t){let s=`${t.baseUrl}${r}`,i;for(let a=0;a<t.maxRetries;a++){let y=new AbortController,C=setTimeout(()=>y.abort(),t.timeoutMs);try{let o=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.apiKey}`,"X-Easydata-SDK":"js/0.1.0"},body:JSON.stringify(e),signal:y.signal});if(clearTimeout(C),o.ok)return await o.json();if(!b(o.status)){let w=await o.text().catch(()=>"Unknown error");throw new n(`HTTP ${o.status}: ${w}`,o.status)}i=new n(`HTTP ${o.status}`,o.status)}catch(o){if(clearTimeout(C),o instanceof n&&!b(o.statusCode??0))throw o;o instanceof DOMException&&o.name==="AbortError"?i=new n("Request timed out"):o instanceof n?i=o:i=o instanceof Error?o:new Error(String(o))}a<t.maxRetries-1&&await x(500*Math.pow(2,a))}throw i??new n("Request failed after retries")}var l=class{queue=[];timer=null;options;_isShutdown=!1;constructor(e){this.options=e,this.startTimer()}get pending(){return this.queue.length}get isShutdown(){return this._isShutdown}enqueue(e){return this._isShutdown?Promise.reject(new Error("BatchQueue has been shut down")):new Promise((t,s)=>{this.queue.push({entry:e,resolve:t,reject:s}),this.queue.length>=this.options.size&&this.flush()})}async flush(){if(this.queue.length===0)return{results:[],accepted:0,rejected:0,failed:0};let e=this.queue.splice(0),t=e.map(s=>s.entry);try{let s=await this.options.onFlush(t);for(let i=0;i<e.length;i++){let a=s.results[i];a?e[i].resolve(a):e[i].resolve({id:"unknown",status:"failed",reason:"No result returned"})}return s}catch(s){let i=s instanceof Error?s:new Error(String(s));for(let a of e)a.reject(i);return{results:[],accepted:0,rejected:0,failed:e.length}}}async shutdown(){this._isShutdown=!0,this.stopTimer(),this.queue.length>0&&await this.flush()}startTimer(){this.options.intervalMs>0&&(this.timer=setInterval(()=>{this.queue.length>0&&this.flush()},this.options.intervalMs))}stopTimer(){this.timer!==null&&(clearInterval(this.timer),this.timer=null)}};var P=[{pattern:/\b\d{3}-\d{2}-\d{4}\b/g,replacement:"[REDACTED_SSN]"},{pattern:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,replacement:"[REDACTED_EMAIL]"},{pattern:/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g,replacement:"[REDACTED_PHONE]"},{pattern:/\b(?:4\d{3}|5[1-5]\d{2}|3[47]\d{2}|6(?:011|5\d{2}))\d{8,12}\b/g,replacement:"[REDACTED_CC]"}];function c(r){let e=r;for(let{pattern:t,replacement:s}of P)t.lastIndex=0,e=e.replace(t,s);return e}function g(r){return{...r,userPrompt:c(r.userPrompt),aiResponse:c(r.aiResponse),userCorrection:c(r.userCorrection),...r.aiCorrectedResponse?{aiCorrectedResponse:c(r.aiCorrectedResponse)}:{},...r.aiInitialPrompt?{aiInitialPrompt:c(r.aiInitialPrompt)}:{}}}var d=class{constructor(e=!1){this.debug=e}info(e,...t){this.debug&&console.log(`[easydata] ${e}`,...t)}warn(e,...t){console.warn(`[easydata] ${e}`,...t)}error(e,...t){console.error(`[easydata] ${e}`,...t)}logBatchResult(e){let t=`${e.accepted} entries accepted ${e.rejected} entries rejected ${e.failed} entries failed`;e.failed>0?this.warn(t):this.info(t)}};var T=class r{config;batchQueue;logger;constructor(e){if(!e.apiKey)throw new u("apiKey is required");this.config={apiKey:e.apiKey,baseUrl:e.baseUrl??h,scrubPii:e.scrubPii??!0,timeoutMs:e.timeoutMs??3e4,maxRetries:e.maxRetries??3,debug:e.debug??!1},this.logger=new d(this.config.debug),this.batchQueue=new l({size:e.batch?.size??10,intervalMs:e.batch?.intervalMs??5e3,onFlush:t=>this.sendBatch(t)}),this.logger.info("Client initialized")}async captureCorrection(e){this.validateEntry(e);let t=this.config.scrubPii?g(e):e;return this.batchQueue.enqueue(t)}async captureCorrections(e){return Promise.all(e.map(t=>this.captureCorrection(t)))}async flush(){return this.batchQueue.flush()}async shutdown(){this.logger.info("Shutting down client"),await this.batchQueue.shutdown()}static createBrowserClient(e){return new r(e)}validateEntry(e){if(!e.userPrompt)throw new u("userPrompt is required");if(!e.aiResponse)throw new u("aiResponse is required");if(!e.userCorrection)throw new u("userCorrection is required")}toApiEntry(e){return{user_prompt:e.userPrompt,ai_response:e.aiResponse,user_correction:e.userCorrection,...e.aiCorrectedResponse&&{ai_corrected_response:e.aiCorrectedResponse},...e.aiInitialPrompt&&{system_prompt:e.aiInitialPrompt},...e.provider&&{provider:e.provider},...e.model&&{model:e.model},...e.domain&&{domain:e.domain},...e.metadata&&{metadata:e.metadata}}}async sendBatch(e){this.logger.info(`Sending batch of ${e.length} entries`);let t=e.map(i=>this.toApiEntry(i)),s=await _("/v1/corrections",{entries:t},{baseUrl:this.config.baseUrl,apiKey:this.config.apiKey,timeoutMs:this.config.timeoutMs,maxRetries:this.config.maxRetries});return this.logger.logBatchResult(s),s}};export{h as DEFAULT_BASE_URL,E as DEFAULT_BATCH_INTERVAL_MS,m as DEFAULT_BATCH_SIZE,R as DEFAULT_MAX_RETRIES,f as DEFAULT_TIMEOUT_MS,T as Easydata,p as EasydataError,n as EasydataNetworkError,u as EasydataValidationError,A as SDK_VERSION,g as scrubEntry,c as scrubText};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/constants.ts","../src/transport/http.ts","../src/transport/batch.ts","../src/pii/scrubber.ts","../src/logger.ts","../src/client.ts"],"sourcesContent":["export class EasydataError extends Error {\n constructor(message: string, public readonly code?: string) {\n super(message);\n this.name = \"EasydataError\";\n }\n}\n\nexport class EasydataValidationError extends EasydataError {\n constructor(message: string) {\n super(message, \"VALIDATION_ERROR\");\n this.name = \"EasydataValidationError\";\n }\n}\n\nexport class EasydataNetworkError extends EasydataError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message, \"NETWORK_ERROR\");\n this.name = \"EasydataNetworkError\";\n this.statusCode = statusCode;\n }\n}\n","export const DEFAULT_BASE_URL = \"https://api.easydata.dev\";\nexport const DEFAULT_BATCH_SIZE = 10;\nexport const DEFAULT_BATCH_INTERVAL_MS = 5000;\nexport const DEFAULT_TIMEOUT_MS = 30000;\nexport const DEFAULT_MAX_RETRIES = 3;\nexport const RETRY_BASE_DELAY_MS = 500;\nexport const SDK_VERSION = \"0.1.0\";\n","import { EasydataNetworkError } from \"../errors\";\nimport { RETRY_BASE_DELAY_MS } from \"../constants\";\n\nexport interface HttpOptions {\n baseUrl: string;\n apiKey: string;\n timeoutMs: number;\n maxRetries: number;\n}\n\nfunction isRetryable(status: number): boolean {\n return status >= 500 || status === 429;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function httpPost<T>(\n path: string,\n body: unknown,\n options: HttpOptions\n): Promise<T> {\n const url = `${options.baseUrl}${path}`;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < options.maxRetries; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), options.timeoutMs);\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${options.apiKey}`,\n \"X-Easydata-SDK\": \"js/0.1.0\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n if (!isRetryable(response.status)) {\n const text = await response.text().catch(() => \"Unknown error\");\n throw new EasydataNetworkError(\n `HTTP ${response.status}: ${text}`,\n response.status\n );\n }\n\n lastError = new EasydataNetworkError(\n `HTTP ${response.status}`,\n response.status\n );\n } catch (err) {\n clearTimeout(timer);\n\n if (err instanceof EasydataNetworkError && !isRetryable(err.statusCode ?? 0)) {\n throw err;\n }\n\n if (err instanceof DOMException && err.name === \"AbortError\") {\n lastError = new EasydataNetworkError(\"Request timed out\");\n } else if (!(err instanceof EasydataNetworkError)) {\n lastError = err instanceof Error ? err : new Error(String(err));\n } else {\n lastError = err;\n }\n }\n\n if (attempt < options.maxRetries - 1) {\n await delay(RETRY_BASE_DELAY_MS * Math.pow(2, attempt));\n }\n }\n\n throw lastError ?? new EasydataNetworkError(\"Request failed after retries\");\n}\n","import type { CorrectionEntry, BatchResult, CaptureResult } from \"../types\";\n\nexport interface QueuedEntry {\n entry: CorrectionEntry;\n resolve: (result: CaptureResult) => void;\n reject: (error: Error) => void;\n}\n\nexport interface BatchQueueOptions {\n size: number;\n intervalMs: number;\n onFlush: (entries: CorrectionEntry[]) => Promise<BatchResult>;\n}\n\nexport class BatchQueue {\n private queue: QueuedEntry[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly options: BatchQueueOptions;\n private _isShutdown = false;\n\n constructor(options: BatchQueueOptions) {\n this.options = options;\n this.startTimer();\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n get isShutdown(): boolean {\n return this._isShutdown;\n }\n\n enqueue(entry: CorrectionEntry): Promise<CaptureResult> {\n if (this._isShutdown) {\n return Promise.reject(new Error(\"BatchQueue has been shut down\"));\n }\n\n return new Promise<CaptureResult>((resolve, reject) => {\n this.queue.push({ entry, resolve, reject });\n\n if (this.queue.length >= this.options.size) {\n void this.flush();\n }\n });\n }\n\n async flush(): Promise<BatchResult> {\n if (this.queue.length === 0) {\n return { results: [], accepted: 0, rejected: 0, failed: 0 };\n }\n\n const batch = this.queue.splice(0);\n const entries = batch.map((q) => q.entry);\n\n try {\n const result = await this.options.onFlush(entries);\n\n for (let i = 0; i < batch.length; i++) {\n const captureResult = result.results[i];\n if (captureResult) {\n batch[i].resolve(captureResult);\n } else {\n batch[i].resolve({\n id: \"unknown\",\n status: \"failed\",\n reason: \"No result returned\",\n });\n }\n }\n\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n for (const item of batch) {\n item.reject(error);\n }\n return {\n results: [],\n accepted: 0,\n rejected: 0,\n failed: batch.length,\n };\n }\n }\n\n async shutdown(): Promise<void> {\n this._isShutdown = true;\n this.stopTimer();\n if (this.queue.length > 0) {\n await this.flush();\n }\n }\n\n private startTimer(): void {\n if (this.options.intervalMs > 0) {\n this.timer = setInterval(() => {\n if (this.queue.length > 0) {\n void this.flush();\n }\n }, this.options.intervalMs);\n }\n }\n\n private stopTimer(): void {\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n","import type { CorrectionEntry } from \"../types\";\n\nconst PII_PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [\n // SSN must come before phone to avoid false positives\n {\n pattern: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g,\n replacement: \"[REDACTED_SSN]\",\n },\n {\n pattern: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/g,\n replacement: \"[REDACTED_EMAIL]\",\n },\n {\n pattern: /\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b/g,\n replacement: \"[REDACTED_PHONE]\",\n },\n {\n pattern: /\\b(?:4\\d{3}|5[1-5]\\d{2}|3[47]\\d{2}|6(?:011|5\\d{2}))\\d{8,12}\\b/g,\n replacement: \"[REDACTED_CC]\",\n },\n];\n\nexport function scrubText(text: string): string {\n let result = text;\n for (const { pattern, replacement } of PII_PATTERNS) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0;\n result = result.replace(pattern, replacement);\n }\n return result;\n}\n\nexport function scrubEntry(entry: CorrectionEntry): CorrectionEntry {\n return {\n ...entry,\n userPrompt: scrubText(entry.userPrompt),\n aiResponse: scrubText(entry.aiResponse),\n userCorrection: scrubText(entry.userCorrection),\n ...(entry.aiCorrectedResponse\n ? { aiCorrectedResponse: scrubText(entry.aiCorrectedResponse) }\n : {}),\n ...(entry.aiInitialPrompt\n ? { aiInitialPrompt: scrubText(entry.aiInitialPrompt) }\n : {}),\n };\n}\n","import type { BatchResult } from \"./types\";\n\nexport class Logger {\n constructor(private readonly debug: boolean = false) {}\n\n info(message: string, ...args: unknown[]): void {\n if (this.debug) {\n console.log(`[easydata] ${message}`, ...args);\n }\n }\n\n warn(message: string, ...args: unknown[]): void {\n console.warn(`[easydata] ${message}`, ...args);\n }\n\n error(message: string, ...args: unknown[]): void {\n console.error(`[easydata] ${message}`, ...args);\n }\n\n logBatchResult(result: BatchResult): void {\n const msg = `${result.accepted} entries accepted ${result.rejected} entries rejected ${result.failed} entries failed`;\n if (result.failed > 0) {\n this.warn(msg);\n } else {\n this.info(msg);\n }\n }\n}\n","import type {\n EasydataConfig,\n CorrectionEntry,\n CaptureResult,\n BatchResult,\n} from \"./types\";\nimport { EasydataValidationError } from \"./errors\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_BATCH_SIZE,\n DEFAULT_BATCH_INTERVAL_MS,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_MAX_RETRIES,\n} from \"./constants\";\nimport { httpPost } from \"./transport/http\";\nimport { BatchQueue } from \"./transport/batch\";\nimport { scrubEntry } from \"./pii/scrubber\";\nimport { Logger } from \"./logger\";\n\nexport class Easydata {\n private readonly config: Required<\n Pick<EasydataConfig, \"apiKey\" | \"baseUrl\" | \"scrubPii\" | \"timeoutMs\" | \"maxRetries\" | \"debug\">\n >;\n private readonly batchQueue: BatchQueue;\n private readonly logger: Logger;\n\n constructor(config: EasydataConfig) {\n if (!config.apiKey) {\n throw new EasydataValidationError(\"apiKey is required\");\n }\n\n this.config = {\n apiKey: config.apiKey,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n scrubPii: config.scrubPii ?? true,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n debug: config.debug ?? false,\n };\n\n this.logger = new Logger(this.config.debug);\n\n this.batchQueue = new BatchQueue({\n size: config.batch?.size ?? DEFAULT_BATCH_SIZE,\n intervalMs: config.batch?.intervalMs ?? DEFAULT_BATCH_INTERVAL_MS,\n onFlush: (entries) => this.sendBatch(entries),\n });\n\n this.logger.info(\"Client initialized\");\n }\n\n async captureCorrection(entry: CorrectionEntry): Promise<CaptureResult> {\n this.validateEntry(entry);\n\n const processed = this.config.scrubPii ? scrubEntry(entry) : entry;\n return this.batchQueue.enqueue(processed);\n }\n\n async captureCorrections(entries: CorrectionEntry[]): Promise<CaptureResult[]> {\n return Promise.all(entries.map((e) => this.captureCorrection(e)));\n }\n\n async flush(): Promise<BatchResult> {\n return this.batchQueue.flush();\n }\n\n async shutdown(): Promise<void> {\n this.logger.info(\"Shutting down client\");\n await this.batchQueue.shutdown();\n }\n\n static createBrowserClient(config: EasydataConfig): Easydata {\n return new Easydata(config);\n }\n\n private validateEntry(entry: CorrectionEntry): void {\n if (!entry.userPrompt) {\n throw new EasydataValidationError(\"userPrompt is required\");\n }\n if (!entry.aiResponse) {\n throw new EasydataValidationError(\"aiResponse is required\");\n }\n if (!entry.userCorrection) {\n throw new EasydataValidationError(\"userCorrection is required\");\n }\n }\n\n private toApiEntry(entry: CorrectionEntry) {\n return {\n user_prompt: entry.userPrompt,\n ai_response: entry.aiResponse,\n user_correction: entry.userCorrection,\n ...(entry.aiCorrectedResponse && { ai_corrected_response: entry.aiCorrectedResponse }),\n ...(entry.aiInitialPrompt && { system_prompt: entry.aiInitialPrompt }),\n ...(entry.provider && { provider: entry.provider }),\n ...(entry.model && { model: entry.model }),\n ...(entry.domain && { domain: entry.domain }),\n ...(entry.metadata && { metadata: entry.metadata }),\n };\n }\n\n private async sendBatch(entries: CorrectionEntry[]): Promise<BatchResult> {\n this.logger.info(`Sending batch of ${entries.length} entries`);\n\n const apiEntries = entries.map((e) => this.toApiEntry(e));\n\n const result = await httpPost<BatchResult>(\n \"/v1/corrections\",\n { entries: apiEntries },\n {\n baseUrl: this.config.baseUrl,\n apiKey: this.config.apiKey,\n timeoutMs: this.config.timeoutMs,\n maxRetries: this.config.maxRetries,\n }\n );\n\n this.logger.logBatchResult(result);\n return result;\n }\n}\n"],"mappings":"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","names":["EasydataError","message","code","EasydataValidationError","EasydataNetworkError","statusCode","DEFAULT_BASE_URL","DEFAULT_BATCH_SIZE","DEFAULT_BATCH_INTERVAL_MS","DEFAULT_TIMEOUT_MS","DEFAULT_MAX_RETRIES","SDK_VERSION","isRetryable","status","delay","ms","resolve","httpPost","path","body","options","url","lastError","attempt","controller","timer","response","text","EasydataNetworkError","err","BatchQueue","options","entry","resolve","reject","batch","entries","q","result","captureResult","err","error","item","PII_PATTERNS","scrubText","text","result","pattern","replacement","scrubEntry","entry","Logger","debug","message","args","result","msg","Easydata","_Easydata","config","EasydataValidationError","DEFAULT_BASE_URL","Logger","BatchQueue","entries","entry","processed","scrubEntry","e","apiEntries","result","httpPost"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/constants.ts","../src/transport/http.ts","../src/transport/batch.ts","../src/pii/scrubber.ts","../src/logger.ts","../src/client.ts"],"sourcesContent":["export class EasydataError extends Error {\n constructor(message: string, public readonly code?: string) {\n super(message);\n this.name = \"EasydataError\";\n }\n}\n\nexport class EasydataValidationError extends EasydataError {\n constructor(message: string) {\n super(message, \"VALIDATION_ERROR\");\n this.name = \"EasydataValidationError\";\n }\n}\n\nexport class EasydataNetworkError extends EasydataError {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message, \"NETWORK_ERROR\");\n this.name = \"EasydataNetworkError\";\n this.statusCode = statusCode;\n }\n}\n","export const DEFAULT_BASE_URL = \"https://easydata-api.onrender.com\";\nexport const DEFAULT_BATCH_SIZE = 10;\nexport const DEFAULT_BATCH_INTERVAL_MS = 5000;\nexport const DEFAULT_TIMEOUT_MS = 30000;\nexport const DEFAULT_MAX_RETRIES = 3;\nexport const RETRY_BASE_DELAY_MS = 500;\nexport const SDK_VERSION = \"0.1.0\";\n","import { EasydataNetworkError } from \"../errors\";\nimport { RETRY_BASE_DELAY_MS } from \"../constants\";\n\nexport interface HttpOptions {\n baseUrl: string;\n apiKey: string;\n timeoutMs: number;\n maxRetries: number;\n}\n\nfunction isRetryable(status: number): boolean {\n return status >= 500 || status === 429;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function httpPost<T>(\n path: string,\n body: unknown,\n options: HttpOptions\n): Promise<T> {\n const url = `${options.baseUrl}${path}`;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < options.maxRetries; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), options.timeoutMs);\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${options.apiKey}`,\n \"X-Easydata-SDK\": \"js/0.1.0\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n if (!isRetryable(response.status)) {\n const text = await response.text().catch(() => \"Unknown error\");\n throw new EasydataNetworkError(\n `HTTP ${response.status}: ${text}`,\n response.status\n );\n }\n\n lastError = new EasydataNetworkError(\n `HTTP ${response.status}`,\n response.status\n );\n } catch (err) {\n clearTimeout(timer);\n\n if (err instanceof EasydataNetworkError && !isRetryable(err.statusCode ?? 0)) {\n throw err;\n }\n\n if (err instanceof DOMException && err.name === \"AbortError\") {\n lastError = new EasydataNetworkError(\"Request timed out\");\n } else if (!(err instanceof EasydataNetworkError)) {\n lastError = err instanceof Error ? err : new Error(String(err));\n } else {\n lastError = err;\n }\n }\n\n if (attempt < options.maxRetries - 1) {\n await delay(RETRY_BASE_DELAY_MS * Math.pow(2, attempt));\n }\n }\n\n throw lastError ?? new EasydataNetworkError(\"Request failed after retries\");\n}\n","import type { CorrectionEntry, BatchResult, CaptureResult } from \"../types\";\n\nexport interface QueuedEntry {\n entry: CorrectionEntry;\n resolve: (result: CaptureResult) => void;\n reject: (error: Error) => void;\n}\n\nexport interface BatchQueueOptions {\n size: number;\n intervalMs: number;\n onFlush: (entries: CorrectionEntry[]) => Promise<BatchResult>;\n}\n\nexport class BatchQueue {\n private queue: QueuedEntry[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private readonly options: BatchQueueOptions;\n private _isShutdown = false;\n\n constructor(options: BatchQueueOptions) {\n this.options = options;\n this.startTimer();\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n get isShutdown(): boolean {\n return this._isShutdown;\n }\n\n enqueue(entry: CorrectionEntry): Promise<CaptureResult> {\n if (this._isShutdown) {\n return Promise.reject(new Error(\"BatchQueue has been shut down\"));\n }\n\n return new Promise<CaptureResult>((resolve, reject) => {\n this.queue.push({ entry, resolve, reject });\n\n if (this.queue.length >= this.options.size) {\n void this.flush();\n }\n });\n }\n\n async flush(): Promise<BatchResult> {\n if (this.queue.length === 0) {\n return { results: [], accepted: 0, rejected: 0, failed: 0 };\n }\n\n const batch = this.queue.splice(0);\n const entries = batch.map((q) => q.entry);\n\n try {\n const result = await this.options.onFlush(entries);\n\n for (let i = 0; i < batch.length; i++) {\n const captureResult = result.results[i];\n if (captureResult) {\n batch[i].resolve(captureResult);\n } else {\n batch[i].resolve({\n id: \"unknown\",\n status: \"failed\",\n reason: \"No result returned\",\n });\n }\n }\n\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n for (const item of batch) {\n item.reject(error);\n }\n return {\n results: [],\n accepted: 0,\n rejected: 0,\n failed: batch.length,\n };\n }\n }\n\n async shutdown(): Promise<void> {\n this._isShutdown = true;\n this.stopTimer();\n if (this.queue.length > 0) {\n await this.flush();\n }\n }\n\n private startTimer(): void {\n if (this.options.intervalMs > 0) {\n this.timer = setInterval(() => {\n if (this.queue.length > 0) {\n void this.flush();\n }\n }, this.options.intervalMs);\n }\n }\n\n private stopTimer(): void {\n if (this.timer !== null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n","import type { CorrectionEntry } from \"../types\";\n\nconst PII_PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [\n // SSN must come before phone to avoid false positives\n {\n pattern: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g,\n replacement: \"[REDACTED_SSN]\",\n },\n {\n pattern: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/g,\n replacement: \"[REDACTED_EMAIL]\",\n },\n {\n pattern: /\\b\\d{3}[-.]?\\d{3}[-.]?\\d{4}\\b/g,\n replacement: \"[REDACTED_PHONE]\",\n },\n {\n pattern: /\\b(?:4\\d{3}|5[1-5]\\d{2}|3[47]\\d{2}|6(?:011|5\\d{2}))\\d{8,12}\\b/g,\n replacement: \"[REDACTED_CC]\",\n },\n];\n\nexport function scrubText(text: string): string {\n let result = text;\n for (const { pattern, replacement } of PII_PATTERNS) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0;\n result = result.replace(pattern, replacement);\n }\n return result;\n}\n\nexport function scrubEntry(entry: CorrectionEntry): CorrectionEntry {\n return {\n ...entry,\n userPrompt: scrubText(entry.userPrompt),\n aiResponse: scrubText(entry.aiResponse),\n userCorrection: scrubText(entry.userCorrection),\n ...(entry.aiCorrectedResponse\n ? { aiCorrectedResponse: scrubText(entry.aiCorrectedResponse) }\n : {}),\n ...(entry.aiInitialPrompt\n ? { aiInitialPrompt: scrubText(entry.aiInitialPrompt) }\n : {}),\n };\n}\n","import type { BatchResult } from \"./types\";\n\nexport class Logger {\n constructor(private readonly debug: boolean = false) {}\n\n info(message: string, ...args: unknown[]): void {\n if (this.debug) {\n console.log(`[easydata] ${message}`, ...args);\n }\n }\n\n warn(message: string, ...args: unknown[]): void {\n console.warn(`[easydata] ${message}`, ...args);\n }\n\n error(message: string, ...args: unknown[]): void {\n console.error(`[easydata] ${message}`, ...args);\n }\n\n logBatchResult(result: BatchResult): void {\n const msg = `${result.accepted} entries accepted ${result.rejected} entries rejected ${result.failed} entries failed`;\n if (result.failed > 0) {\n this.warn(msg);\n } else {\n this.info(msg);\n }\n }\n}\n","import type {\n EasydataConfig,\n CorrectionEntry,\n CaptureResult,\n BatchResult,\n} from \"./types\";\nimport { EasydataValidationError } from \"./errors\";\nimport {\n DEFAULT_BASE_URL,\n DEFAULT_BATCH_SIZE,\n DEFAULT_BATCH_INTERVAL_MS,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_MAX_RETRIES,\n} from \"./constants\";\nimport { httpPost } from \"./transport/http\";\nimport { BatchQueue } from \"./transport/batch\";\nimport { scrubEntry } from \"./pii/scrubber\";\nimport { Logger } from \"./logger\";\n\nexport class Easydata {\n private readonly config: Required<\n Pick<EasydataConfig, \"apiKey\" | \"baseUrl\" | \"scrubPii\" | \"timeoutMs\" | \"maxRetries\" | \"debug\">\n >;\n private readonly batchQueue: BatchQueue;\n private readonly logger: Logger;\n\n constructor(config: EasydataConfig) {\n if (!config.apiKey) {\n throw new EasydataValidationError(\"apiKey is required\");\n }\n\n this.config = {\n apiKey: config.apiKey,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n scrubPii: config.scrubPii ?? true,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n debug: config.debug ?? false,\n };\n\n this.logger = new Logger(this.config.debug);\n\n this.batchQueue = new BatchQueue({\n size: config.batch?.size ?? DEFAULT_BATCH_SIZE,\n intervalMs: config.batch?.intervalMs ?? DEFAULT_BATCH_INTERVAL_MS,\n onFlush: (entries) => this.sendBatch(entries),\n });\n\n this.logger.info(\"Client initialized\");\n }\n\n async captureCorrection(entry: CorrectionEntry): Promise<CaptureResult> {\n this.validateEntry(entry);\n\n const processed = this.config.scrubPii ? scrubEntry(entry) : entry;\n return this.batchQueue.enqueue(processed);\n }\n\n async captureCorrections(entries: CorrectionEntry[]): Promise<CaptureResult[]> {\n return Promise.all(entries.map((e) => this.captureCorrection(e)));\n }\n\n async flush(): Promise<BatchResult> {\n return this.batchQueue.flush();\n }\n\n async shutdown(): Promise<void> {\n this.logger.info(\"Shutting down client\");\n await this.batchQueue.shutdown();\n }\n\n static createBrowserClient(config: EasydataConfig): Easydata {\n return new Easydata(config);\n }\n\n private validateEntry(entry: CorrectionEntry): void {\n if (!entry.userPrompt) {\n throw new EasydataValidationError(\"userPrompt is required\");\n }\n if (!entry.aiResponse) {\n throw new EasydataValidationError(\"aiResponse is required\");\n }\n if (!entry.userCorrection) {\n throw new EasydataValidationError(\"userCorrection is required\");\n }\n }\n\n private toApiEntry(entry: CorrectionEntry) {\n return {\n user_prompt: entry.userPrompt,\n ai_response: entry.aiResponse,\n user_correction: entry.userCorrection,\n ...(entry.aiCorrectedResponse && { ai_corrected_response: entry.aiCorrectedResponse }),\n ...(entry.aiInitialPrompt && { system_prompt: entry.aiInitialPrompt }),\n ...(entry.provider && { provider: entry.provider }),\n ...(entry.model && { model: entry.model }),\n ...(entry.domain && { domain: entry.domain }),\n ...(entry.metadata && { metadata: entry.metadata }),\n };\n }\n\n private async sendBatch(entries: CorrectionEntry[]): Promise<BatchResult> {\n this.logger.info(`Sending batch of ${entries.length} entries`);\n\n const apiEntries = entries.map((e) => this.toApiEntry(e));\n\n const result = await httpPost<BatchResult>(\n \"/v1/corrections\",\n { entries: apiEntries },\n {\n baseUrl: this.config.baseUrl,\n apiKey: this.config.apiKey,\n timeoutMs: this.config.timeoutMs,\n maxRetries: this.config.maxRetries,\n }\n );\n\n this.logger.logBatchResult(result);\n return result;\n }\n}\n"],"mappings":"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","names":["EasydataError","message","code","EasydataValidationError","EasydataNetworkError","statusCode","DEFAULT_BASE_URL","DEFAULT_BATCH_SIZE","DEFAULT_BATCH_INTERVAL_MS","DEFAULT_TIMEOUT_MS","DEFAULT_MAX_RETRIES","SDK_VERSION","isRetryable","status","delay","ms","resolve","httpPost","path","body","options","url","lastError","attempt","controller","timer","response","text","EasydataNetworkError","err","BatchQueue","options","entry","resolve","reject","batch","entries","q","result","captureResult","err","error","item","PII_PATTERNS","scrubText","text","result","pattern","replacement","scrubEntry","entry","Logger","debug","message","args","result","msg","Easydata","_Easydata","config","EasydataValidationError","DEFAULT_BASE_URL","Logger","BatchQueue","entries","entry","processed","scrubEntry","e","apiEntries","result","httpPost"]}
|