@schematichq/schematic-js 0.1.1 → 0.1.3

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.
@@ -1,2 +1,2 @@
1
- "use strict";(()=>{var p,f=new Uint8Array(16);function y(){if(!p&&(p=typeof crypto<"u"&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!p))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return p(f)}var i=[];for(let t=0;t<256;++t)i.push((t+256).toString(16).slice(1));function m(t,e=0){return i[t[e+0]]+i[t[e+1]]+i[t[e+2]]+i[t[e+3]]+"-"+i[t[e+4]]+i[t[e+5]]+"-"+i[t[e+6]]+i[t[e+7]]+"-"+i[t[e+8]]+i[t[e+9]]+"-"+i[t[e+10]]+i[t[e+11]]+i[t[e+12]]+i[t[e+13]]+i[t[e+14]]+i[t[e+15]]}var k=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),l={randomUUID:k};function S(t,e,n){if(l.randomUUID&&!e&&!t)return l.randomUUID();t=t||{};let o=t.random||(t.rng||y)();if(o[6]=o[6]&15|64,o[8]=o[8]&63|128,e){n=n||0;for(let r=0;r<16;++r)e[n+r]=o[r];return e}return m(o)}var d=S;var v="schematicId";var u=class{apiKey;conn=null;context={};eventQueue;storage;useWebSocket=!1;values={};flagListener;constructor(e,n){this.apiKey=e,this.eventQueue=[],this.useWebSocket=n?.useWebSocket??!1,this.flagListener=n?.flagListener,n?.storage?this.storage=n.storage:typeof localStorage<"u"&&(this.storage=localStorage),typeof window<"u"&&window.addEventListener("beforeunload",()=>{this.flushEventQueue()})}checkFlag=async e=>{let{fallback:n=!1,key:o}=e,r=e.context||this.context;if(this.useWebSocket){let s=this.values[h(r)]??{};return typeof s[o]>"u"?n:s[o]}let a=`https://api.schematichq.com/flags/${o}/check`;return fetch(a,{method:"POST",headers:{"X-Schematic-Api-Key":this.apiKey,"Content-Type":"application/json;charset=UTF-8"},body:JSON.stringify(r)}).then(s=>{if(!s.ok)throw new Error("Network response was not ok");return s.json()}).then(s=>s.data.value).catch(s=>(console.error("There was a problem with the fetch operation:",s),n))};checkFlags=async e=>{e=e||this.context;let n="https://api.schematichq.com/flags/check",o=JSON.stringify(e);return fetch(n,{method:"POST",headers:{"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:o}).then(r=>{if(!r.ok)throw new Error("Network response was not ok");return r.json()}).then(r=>(r?.data?.flags??[]).reduce((a,s)=>(a[s.flag]=s.value,a),{})).catch(r=>(console.error("There was a problem with the fetch operation:",r),!1))};cleanup=()=>{this.conn&&this.conn.close()};identify=e=>{this.handleEvent("identify",e)};setContext=e=>this.useWebSocket?new Promise(n=>{this.wsConnect().then(()=>{this.wsSendMessage(e),n()})}):(this.context=e,Promise.resolve());track=e=>{this.handleEvent("track",e)};flushEventQueue=()=>{for(;this.eventQueue.length>0;){let e=this.eventQueue.shift();e&&this.sendEvent(e)}};getAnonymousId=()=>{if(!this.storage)return d();let e=this.storage.getItem(v);if(typeof e<"u")return e;let n=d();return this.storage.setItem(v,n),n};handleEvent=(e,n)=>{let o={api_key:this.apiKey,body:n,sent_at:new Date().toISOString(),tracker_event_id:d(),tracker_user_id:this.getAnonymousId(),type:e};typeof document<"u"&&document.hidden?this.storeEvent(o):this.sendEvent(o)};sendEvent=e=>{let n="https://c.schematichq.com/e",o=JSON.stringify(e);fetch(n,{method:"POST",headers:{"Content-Type":"application/json;charset=UTF-8"},body:o}).then(r=>{if(!r.ok)throw new Error(`Network response was not ok: ${r.statusText}`)}).catch(r=>{console.error("There was a problem with the fetch operation:",r)})};storeEvent=e=>{this.eventQueue.push(e)};wsConnect=()=>new Promise(e=>{this.conn&&e();let n="wss://api.schematichq.com/flags/bootstrap",o=new WebSocket(n);this.conn=o,o.onopen=()=>{e()},o.onclose=()=>{this.conn=null}});wsSendMessage=e=>new Promise((n,o)=>{if(h(e)==h(this.context)&&n(),this.context=e,!this.conn){o("Not connected");return}if(this.conn.readyState===WebSocket.OPEN){let r=!1;this.conn.onmessage=a=>{let s=JSON.parse(a.data);this.values[h(e)]=(s.flags??[]).reduce((c,g)=>(c[g.flag]=g.value,c),{}),this.flagListener&&this.flagListener(this.values[h(e)]),r||(r=!0,n())},this.conn.onerror=a=>{console.error("Schematic websocket error: ",a)},this.conn.send(JSON.stringify({apiKey:this.apiKey,data:e}))}else this.conn.readyState===WebSocket.CONNECTING?this.conn.onopen=()=>{this.wsSendMessage(e)}:o("Not connected")})};function h(t){let e=Object.keys(t).reduce((n,o)=>{let a=Object.keys(t[o]||{}).sort().reduce((s,c)=>(s[c]=t[o][c],s),{});return n[o]=a,n},{});return JSON.stringify(e)}window.Schematic=u;})();
1
+ "use strict";(()=>{var p,m=new Uint8Array(16);function u(){if(!p&&(p=typeof crypto<"u"&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!p))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return p(m)}var s=[];for(let n=0;n<256;++n)s.push((n+256).toString(16).slice(1));function v(n,e=0){return s[n[e+0]]+s[n[e+1]]+s[n[e+2]]+s[n[e+3]]+"-"+s[n[e+4]]+s[n[e+5]]+"-"+s[n[e+6]]+s[n[e+7]]+"-"+s[n[e+8]]+s[n[e+9]]+"-"+s[n[e+10]]+s[n[e+11]]+s[n[e+12]]+s[n[e+13]]+s[n[e+14]]+s[n[e+15]]}var k=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),y={randomUUID:k};function S(n,e,t){if(y.randomUUID&&!e&&!n)return y.randomUUID();n=n||{};let r=n.random||(n.rng||u)();if(r[6]=r[6]&15|64,r[8]=r[8]&63|128,e){t=t||0;for(let o=0;o<16;++o)e[t+o]=r[o];return e}return v(r)}var d=S;var f="schematicId";var l=class{apiKey;apiUrl="api.schematichq.com";eventUrl="c.schematichq.com";conn=null;context={};eventQueue;storage;useWebSocket=!1;values={};flagListener;constructor(e,t){this.apiKey=e,this.eventQueue=[],this.useWebSocket=t?.useWebSocket??!1,this.flagListener=t?.flagListener,t?.storage?this.storage=t.storage:typeof localStorage<"u"&&(this.storage=localStorage),t?.apiUrl!==void 0&&(this.apiUrl=t.apiUrl),t?.eventUrl!==void 0&&(this.eventUrl=t.eventUrl),typeof window<"u"&&window.addEventListener("beforeunload",()=>{this.flushEventQueue()})}checkFlag=async e=>{let{fallback:t=!1,key:r}=e,o=e.context||this.context;if(this.useWebSocket){let i=this.values[h(o)]??{};return typeof i[r]>"u"?t:i[r]}let a=this.getUrl(this.apiUrl,`flags/${r}/check`);return fetch(a,{method:"POST",headers:{"X-Schematic-Api-Key":this.apiKey,"Content-Type":"application/json;charset=UTF-8"},body:JSON.stringify(o)}).then(i=>{if(!i.ok)throw new Error("Network response was not ok");return i.json()}).then(i=>i.data.value).catch(i=>(console.error("There was a problem with the fetch operation:",i),t))};checkFlags=async e=>{e=e||this.context;let t=this.getUrl(this.apiUrl,"flags/check"),r=JSON.stringify(e);return fetch(t,{method:"POST",headers:{"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:r}).then(o=>{if(!o.ok)throw new Error("Network response was not ok");return o.json()}).then(o=>(o?.data?.flags??[]).reduce((a,i)=>(a[i.flag]=i.value,a),{})).catch(o=>(console.error("There was a problem with the fetch operation:",o),!1))};cleanup=()=>{this.conn&&this.conn.close()};identify=e=>{this.handleEvent("identify",e)};setContext=e=>this.useWebSocket?new Promise(t=>{this.wsConnect().then(()=>{this.wsSendMessage(e),t()})}):(this.context=e,Promise.resolve());track=e=>{this.handleEvent("track",e)};getUrl=(e,t,r)=>{let o="http";return r==="ws"&&(o="ws"),typeof window>"u"||window.location.protocol==="https:"?`${o}s://${e}/${t}`:`${o}://${e}/${t}`};flushEventQueue=()=>{for(;this.eventQueue.length>0;){let e=this.eventQueue.shift();e&&this.sendEvent(e)}};getAnonymousId=()=>{if(!this.storage)return d();let e=this.storage.getItem(f);if(typeof e<"u")return e;let t=d();return this.storage.setItem(f,t),t};handleEvent=(e,t)=>{let r={api_key:this.apiKey,body:t,sent_at:new Date().toISOString(),tracker_event_id:d(),tracker_user_id:this.getAnonymousId(),type:e};typeof document<"u"&&document.hidden?this.storeEvent(r):this.sendEvent(r)};sendEvent=e=>{let t=this.getUrl(this.apiUrl,"e"),r=JSON.stringify(e);fetch(t,{method:"POST",headers:{"Content-Type":"application/json;charset=UTF-8"},body:r}).then(o=>{if(!o.ok)throw new Error(`Network response was not ok: ${o.statusText}`)}).catch(o=>{console.error("There was a problem with the fetch operation:",o)})};storeEvent=e=>{this.eventQueue.push(e)};wsConnect=()=>new Promise(e=>{this.conn&&e();let t=this.getUrl(this.apiUrl,"flags/bootstrap","ws"),r=new WebSocket(t);this.conn=r,r.onopen=()=>{e()},r.onclose=()=>{this.conn=null}});wsSendMessage=e=>new Promise((t,r)=>{if(h(e)==h(this.context)&&t(),this.context=e,!this.conn){r("Not connected");return}if(this.conn.readyState===WebSocket.OPEN){let o=!1;this.conn.onmessage=a=>{let i=JSON.parse(a.data);this.values[h(e)]=(i.flags??[]).reduce((c,g)=>(c[g.flag]=g.value,c),{}),this.flagListener&&this.flagListener(this.values[h(e)]),o||(o=!0,t())},this.conn.onerror=a=>{console.error("Schematic websocket error: ",a)},this.conn.send(JSON.stringify({apiKey:this.apiKey,data:e}))}else this.conn.readyState===WebSocket.CONNECTING?this.conn.onopen=()=>{this.wsSendMessage(e)}:r("Not connected")})};function h(n){let e=Object.keys(n).reduce((t,r)=>{let a=Object.keys(n[r]||{}).sort().reduce((i,c)=>(i[c]=n[r][c],i),{});return t[r]=a,t},{});return JSON.stringify(e)}window.Schematic=l;})();
2
2
  /* @preserve */
@@ -76,6 +76,8 @@ var v4_default = v4;
76
76
  var anonymousIdKey = "schematicId";
77
77
  var Schematic = class {
78
78
  apiKey;
79
+ apiUrl = "api.schematichq.com";
80
+ eventUrl = "c.schematichq.com";
79
81
  conn = null;
80
82
  context = {};
81
83
  eventQueue;
@@ -93,6 +95,12 @@ var Schematic = class {
93
95
  } else if (typeof localStorage !== "undefined") {
94
96
  this.storage = localStorage;
95
97
  }
98
+ if (options?.apiUrl !== void 0) {
99
+ this.apiUrl = options.apiUrl;
100
+ }
101
+ if (options?.eventUrl !== void 0) {
102
+ this.eventUrl = options.eventUrl;
103
+ }
96
104
  if (typeof window !== "undefined") {
97
105
  window.addEventListener("beforeunload", () => {
98
106
  this.flushEventQueue();
@@ -106,7 +114,7 @@ var Schematic = class {
106
114
  const contextVals = this.values[contextString(context)] ?? {};
107
115
  return typeof contextVals[key] === "undefined" ? fallback : contextVals[key];
108
116
  }
109
- const requestUrl = `https://api.schematichq.com/flags/${key}/check`;
117
+ const requestUrl = this.getUrl(this.apiUrl, `flags/${key}/check`);
110
118
  return fetch(requestUrl, {
111
119
  method: "POST",
112
120
  headers: {
@@ -129,7 +137,7 @@ var Schematic = class {
129
137
  // Make a REST API call to fetch all flag values for a given context
130
138
  checkFlags = async (context) => {
131
139
  context = context || this.context;
132
- const requestUrl = "https://api.schematichq.com/flags/check";
140
+ const requestUrl = this.getUrl(this.apiUrl, "flags/check");
133
141
  const requestBody = JSON.stringify(context);
134
142
  return fetch(requestUrl, {
135
143
  method: "POST",
@@ -185,6 +193,16 @@ var Schematic = class {
185
193
  track = (body) => {
186
194
  this.handleEvent("track", body);
187
195
  };
196
+ getUrl = (domain, path, urlType) => {
197
+ let scheme = "http";
198
+ if (urlType === "ws") {
199
+ scheme = "ws";
200
+ }
201
+ if (typeof window === "undefined" || window.location.protocol === "https:") {
202
+ return `${scheme}s://${domain}/${path}`;
203
+ }
204
+ return `${scheme}://${domain}/${path}`;
205
+ };
188
206
  flushEventQueue = () => {
189
207
  while (this.eventQueue.length > 0) {
190
208
  const event = this.eventQueue.shift();
@@ -221,7 +239,7 @@ var Schematic = class {
221
239
  }
222
240
  };
223
241
  sendEvent = (event) => {
224
- const captureUrl = "https://c.schematichq.com/e";
242
+ const captureUrl = this.getUrl(this.apiUrl, "e");
225
243
  const payload = JSON.stringify(event);
226
244
  fetch(captureUrl, {
227
245
  method: "POST",
@@ -247,7 +265,7 @@ var Schematic = class {
247
265
  if (this.conn) {
248
266
  resolve();
249
267
  }
250
- const wsUrl = "wss://api.schematichq.com/flags/bootstrap";
268
+ const wsUrl = this.getUrl(this.apiUrl, "flags/bootstrap", "ws");
251
269
  const webSocket = new WebSocket(wsUrl);
252
270
  this.conn = webSocket;
253
271
  webSocket.onopen = () => {
@@ -53,6 +53,8 @@ export declare type Keys = Record<string, string>;
53
53
 
54
54
  export declare class Schematic {
55
55
  private apiKey;
56
+ private apiUrl;
57
+ private eventUrl;
56
58
  private conn;
57
59
  private context;
58
60
  private eventQueue;
@@ -67,6 +69,7 @@ export declare class Schematic {
67
69
  identify: (body: EventBodyIdentify) => void;
68
70
  setContext: (context: SchematicContext) => Promise<void>;
69
71
  track: (body: EventBodyTrack) => void;
72
+ private getUrl;
70
73
  private flushEventQueue;
71
74
  private getAnonymousId;
72
75
  private handleEvent;
@@ -82,6 +85,8 @@ export declare type SchematicContext = {
82
85
  };
83
86
 
84
87
  declare type SchematicOptions = {
88
+ apiUrl?: string;
89
+ eventUrl?: string;
85
90
  flagListener?: (values: Record<string, boolean>) => void;
86
91
  storage?: StoragePersister;
87
92
  useWebSocket?: boolean;
@@ -50,6 +50,8 @@ var v4_default = v4;
50
50
  var anonymousIdKey = "schematicId";
51
51
  var Schematic = class {
52
52
  apiKey;
53
+ apiUrl = "api.schematichq.com";
54
+ eventUrl = "c.schematichq.com";
53
55
  conn = null;
54
56
  context = {};
55
57
  eventQueue;
@@ -67,6 +69,12 @@ var Schematic = class {
67
69
  } else if (typeof localStorage !== "undefined") {
68
70
  this.storage = localStorage;
69
71
  }
72
+ if (options?.apiUrl !== void 0) {
73
+ this.apiUrl = options.apiUrl;
74
+ }
75
+ if (options?.eventUrl !== void 0) {
76
+ this.eventUrl = options.eventUrl;
77
+ }
70
78
  if (typeof window !== "undefined") {
71
79
  window.addEventListener("beforeunload", () => {
72
80
  this.flushEventQueue();
@@ -80,7 +88,7 @@ var Schematic = class {
80
88
  const contextVals = this.values[contextString(context)] ?? {};
81
89
  return typeof contextVals[key] === "undefined" ? fallback : contextVals[key];
82
90
  }
83
- const requestUrl = `https://api.schematichq.com/flags/${key}/check`;
91
+ const requestUrl = this.getUrl(this.apiUrl, `flags/${key}/check`);
84
92
  return fetch(requestUrl, {
85
93
  method: "POST",
86
94
  headers: {
@@ -103,7 +111,7 @@ var Schematic = class {
103
111
  // Make a REST API call to fetch all flag values for a given context
104
112
  checkFlags = async (context) => {
105
113
  context = context || this.context;
106
- const requestUrl = "https://api.schematichq.com/flags/check";
114
+ const requestUrl = this.getUrl(this.apiUrl, "flags/check");
107
115
  const requestBody = JSON.stringify(context);
108
116
  return fetch(requestUrl, {
109
117
  method: "POST",
@@ -159,6 +167,16 @@ var Schematic = class {
159
167
  track = (body) => {
160
168
  this.handleEvent("track", body);
161
169
  };
170
+ getUrl = (domain, path, urlType) => {
171
+ let scheme = "http";
172
+ if (urlType === "ws") {
173
+ scheme = "ws";
174
+ }
175
+ if (typeof window === "undefined" || window.location.protocol === "https:") {
176
+ return `${scheme}s://${domain}/${path}`;
177
+ }
178
+ return `${scheme}://${domain}/${path}`;
179
+ };
162
180
  flushEventQueue = () => {
163
181
  while (this.eventQueue.length > 0) {
164
182
  const event = this.eventQueue.shift();
@@ -195,7 +213,7 @@ var Schematic = class {
195
213
  }
196
214
  };
197
215
  sendEvent = (event) => {
198
- const captureUrl = "https://c.schematichq.com/e";
216
+ const captureUrl = this.getUrl(this.apiUrl, "e");
199
217
  const payload = JSON.stringify(event);
200
218
  fetch(captureUrl, {
201
219
  method: "POST",
@@ -221,7 +239,7 @@ var Schematic = class {
221
239
  if (this.conn) {
222
240
  resolve();
223
241
  }
224
- const wsUrl = "wss://api.schematichq.com/flags/bootstrap";
242
+ const wsUrl = this.getUrl(this.apiUrl, "flags/bootstrap", "ws");
225
243
  const webSocket = new WebSocket(wsUrl);
226
244
  this.conn = webSocket;
227
245
  webSocket.onopen = () => {
package/package.json CHANGED
@@ -4,12 +4,12 @@
4
4
  "module": "dist/schematic.esm.js",
5
5
  "author": "Ben Papillon <ben@schematichq.com>",
6
6
  "dependencies": {
7
- "@types/uuid": "^9.0.2",
8
7
  "uuid": "^9.0.0"
9
8
  },
10
9
  "devDependencies": {
11
10
  "@microsoft/api-extractor": "^7.38.3",
12
11
  "@types/jest": "^29.5.11",
12
+ "@types/uuid": "^9.0.2",
13
13
  "@typescript-eslint/eslint-plugin": "^6.13.2",
14
14
  "@typescript-eslint/parser": "^6.13.2",
15
15
  "esbuild": "^0.19.9",
@@ -36,13 +36,13 @@
36
36
  "scripts": {
37
37
  "build": "npx tsc && yarn clean && yarn build:browser && yarn build:cjs && yarn build:esm && yarn build:types",
38
38
  "build:browser": "npx esbuild src/browser.ts --bundle --minify --outfile=dist/schematic.browser.js --platform=browser",
39
- "build:cjs": "npx esbuild src/index.ts --bundle --format=cjs --outfile=dist/schematic.cjs.js --platform=neutral",
40
- "build:esm": "npx esbuild src/index.ts --bundle --format=esm --outfile=dist/schematic.esm.js --platform=neutral",
39
+ "build:cjs": "npx esbuild src/index.ts --bundle --format=cjs --outfile=dist/schematic.cjs.js",
40
+ "build:esm": "npx esbuild src/index.ts --bundle --format=esm --outfile=dist/schematic.esm.js",
41
41
  "build:types": "npx tsc && npx api-extractor run",
42
42
  "clean": "rm -rf dist",
43
43
  "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --fix",
44
44
  "test": "jest --config jest.config.js"
45
45
  },
46
46
  "types": "dist/schematic.d.ts",
47
- "version": "0.1.1"
47
+ "version": "0.1.3"
48
48
  }