@schematichq/schematic-vue 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1692 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ RuleType: () => RuleType,
24
+ Schematic: () => Schematic,
25
+ SchematicPlugin: () => SchematicPlugin,
26
+ UsagePeriod: () => UsagePeriod,
27
+ useSchematic: () => useSchematic,
28
+ useSchematicClient: () => useSchematicClient,
29
+ useSchematicContext: () => useSchematicContext,
30
+ useSchematicEntitlement: () => useSchematicEntitlement,
31
+ useSchematicEvents: () => useSchematicEvents,
32
+ useSchematicFlag: () => useSchematicFlag,
33
+ useSchematicIsPending: () => useSchematicIsPending
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // node_modules/@schematichq/schematic-js/dist/schematic.esm.js
38
+ var __create = Object.create;
39
+ var __defProp2 = Object.defineProperty;
40
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
41
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
42
+ var __getProtoOf = Object.getPrototypeOf;
43
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
44
+ var __commonJS = (cb, mod) => function __require() {
45
+ return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
46
+ };
47
+ var __copyProps2 = (to, from, except, desc) => {
48
+ if (from && typeof from === "object" || typeof from === "function") {
49
+ for (let key of __getOwnPropNames2(from))
50
+ if (!__hasOwnProp2.call(to, key) && key !== except)
51
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
52
+ }
53
+ return to;
54
+ };
55
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps2(
56
+ // If the importer is in node compatibility mode or this is not an ESM
57
+ // file that has been converted to a CommonJS file using a Babel-
58
+ // compatible transform (i.e. "__esModule" has not been set), then set
59
+ // "default" to the CommonJS "module.exports" for node compatibility.
60
+ isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
61
+ mod
62
+ ));
63
+ var require_browser_polyfill = __commonJS({
64
+ "node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
65
+ (function(self2) {
66
+ var irrelevant = (function(exports2) {
67
+ var g = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || // eslint-disable-next-line no-undef
68
+ typeof global !== "undefined" && global || {};
69
+ var support = {
70
+ searchParams: "URLSearchParams" in g,
71
+ iterable: "Symbol" in g && "iterator" in Symbol,
72
+ blob: "FileReader" in g && "Blob" in g && (function() {
73
+ try {
74
+ new Blob();
75
+ return true;
76
+ } catch (e) {
77
+ return false;
78
+ }
79
+ })(),
80
+ formData: "FormData" in g,
81
+ arrayBuffer: "ArrayBuffer" in g
82
+ };
83
+ function isDataView(obj) {
84
+ return obj && DataView.prototype.isPrototypeOf(obj);
85
+ }
86
+ if (support.arrayBuffer) {
87
+ var viewClasses = [
88
+ "[object Int8Array]",
89
+ "[object Uint8Array]",
90
+ "[object Uint8ClampedArray]",
91
+ "[object Int16Array]",
92
+ "[object Uint16Array]",
93
+ "[object Int32Array]",
94
+ "[object Uint32Array]",
95
+ "[object Float32Array]",
96
+ "[object Float64Array]"
97
+ ];
98
+ var isArrayBufferView = ArrayBuffer.isView || function(obj) {
99
+ return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
100
+ };
101
+ }
102
+ function normalizeName(name) {
103
+ if (typeof name !== "string") {
104
+ name = String(name);
105
+ }
106
+ if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === "") {
107
+ throw new TypeError('Invalid character in header field name: "' + name + '"');
108
+ }
109
+ return name.toLowerCase();
110
+ }
111
+ function normalizeValue(value) {
112
+ if (typeof value !== "string") {
113
+ value = String(value);
114
+ }
115
+ return value;
116
+ }
117
+ function iteratorFor(items) {
118
+ var iterator = {
119
+ next: function() {
120
+ var value = items.shift();
121
+ return { done: value === void 0, value };
122
+ }
123
+ };
124
+ if (support.iterable) {
125
+ iterator[Symbol.iterator] = function() {
126
+ return iterator;
127
+ };
128
+ }
129
+ return iterator;
130
+ }
131
+ function Headers(headers) {
132
+ this.map = {};
133
+ if (headers instanceof Headers) {
134
+ headers.forEach(function(value, name) {
135
+ this.append(name, value);
136
+ }, this);
137
+ } else if (Array.isArray(headers)) {
138
+ headers.forEach(function(header) {
139
+ if (header.length != 2) {
140
+ throw new TypeError("Headers constructor: expected name/value pair to be length 2, found" + header.length);
141
+ }
142
+ this.append(header[0], header[1]);
143
+ }, this);
144
+ } else if (headers) {
145
+ Object.getOwnPropertyNames(headers).forEach(function(name) {
146
+ this.append(name, headers[name]);
147
+ }, this);
148
+ }
149
+ }
150
+ Headers.prototype.append = function(name, value) {
151
+ name = normalizeName(name);
152
+ value = normalizeValue(value);
153
+ var oldValue = this.map[name];
154
+ this.map[name] = oldValue ? oldValue + ", " + value : value;
155
+ };
156
+ Headers.prototype["delete"] = function(name) {
157
+ delete this.map[normalizeName(name)];
158
+ };
159
+ Headers.prototype.get = function(name) {
160
+ name = normalizeName(name);
161
+ return this.has(name) ? this.map[name] : null;
162
+ };
163
+ Headers.prototype.has = function(name) {
164
+ return this.map.hasOwnProperty(normalizeName(name));
165
+ };
166
+ Headers.prototype.set = function(name, value) {
167
+ this.map[normalizeName(name)] = normalizeValue(value);
168
+ };
169
+ Headers.prototype.forEach = function(callback, thisArg) {
170
+ for (var name in this.map) {
171
+ if (this.map.hasOwnProperty(name)) {
172
+ callback.call(thisArg, this.map[name], name, this);
173
+ }
174
+ }
175
+ };
176
+ Headers.prototype.keys = function() {
177
+ var items = [];
178
+ this.forEach(function(value, name) {
179
+ items.push(name);
180
+ });
181
+ return iteratorFor(items);
182
+ };
183
+ Headers.prototype.values = function() {
184
+ var items = [];
185
+ this.forEach(function(value) {
186
+ items.push(value);
187
+ });
188
+ return iteratorFor(items);
189
+ };
190
+ Headers.prototype.entries = function() {
191
+ var items = [];
192
+ this.forEach(function(value, name) {
193
+ items.push([name, value]);
194
+ });
195
+ return iteratorFor(items);
196
+ };
197
+ if (support.iterable) {
198
+ Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
199
+ }
200
+ function consumed(body) {
201
+ if (body._noBody) return;
202
+ if (body.bodyUsed) {
203
+ return Promise.reject(new TypeError("Already read"));
204
+ }
205
+ body.bodyUsed = true;
206
+ }
207
+ function fileReaderReady(reader) {
208
+ return new Promise(function(resolve, reject) {
209
+ reader.onload = function() {
210
+ resolve(reader.result);
211
+ };
212
+ reader.onerror = function() {
213
+ reject(reader.error);
214
+ };
215
+ });
216
+ }
217
+ function readBlobAsArrayBuffer(blob) {
218
+ var reader = new FileReader();
219
+ var promise = fileReaderReady(reader);
220
+ reader.readAsArrayBuffer(blob);
221
+ return promise;
222
+ }
223
+ function readBlobAsText(blob) {
224
+ var reader = new FileReader();
225
+ var promise = fileReaderReady(reader);
226
+ var match = /charset=([A-Za-z0-9_-]+)/.exec(blob.type);
227
+ var encoding = match ? match[1] : "utf-8";
228
+ reader.readAsText(blob, encoding);
229
+ return promise;
230
+ }
231
+ function readArrayBufferAsText(buf) {
232
+ var view = new Uint8Array(buf);
233
+ var chars = new Array(view.length);
234
+ for (var i = 0; i < view.length; i++) {
235
+ chars[i] = String.fromCharCode(view[i]);
236
+ }
237
+ return chars.join("");
238
+ }
239
+ function bufferClone(buf) {
240
+ if (buf.slice) {
241
+ return buf.slice(0);
242
+ } else {
243
+ var view = new Uint8Array(buf.byteLength);
244
+ view.set(new Uint8Array(buf));
245
+ return view.buffer;
246
+ }
247
+ }
248
+ function Body() {
249
+ this.bodyUsed = false;
250
+ this._initBody = function(body) {
251
+ this.bodyUsed = this.bodyUsed;
252
+ this._bodyInit = body;
253
+ if (!body) {
254
+ this._noBody = true;
255
+ this._bodyText = "";
256
+ } else if (typeof body === "string") {
257
+ this._bodyText = body;
258
+ } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
259
+ this._bodyBlob = body;
260
+ } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
261
+ this._bodyFormData = body;
262
+ } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
263
+ this._bodyText = body.toString();
264
+ } else if (support.arrayBuffer && support.blob && isDataView(body)) {
265
+ this._bodyArrayBuffer = bufferClone(body.buffer);
266
+ this._bodyInit = new Blob([this._bodyArrayBuffer]);
267
+ } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
268
+ this._bodyArrayBuffer = bufferClone(body);
269
+ } else {
270
+ this._bodyText = body = Object.prototype.toString.call(body);
271
+ }
272
+ if (!this.headers.get("content-type")) {
273
+ if (typeof body === "string") {
274
+ this.headers.set("content-type", "text/plain;charset=UTF-8");
275
+ } else if (this._bodyBlob && this._bodyBlob.type) {
276
+ this.headers.set("content-type", this._bodyBlob.type);
277
+ } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
278
+ this.headers.set("content-type", "application/x-www-form-urlencoded;charset=UTF-8");
279
+ }
280
+ }
281
+ };
282
+ if (support.blob) {
283
+ this.blob = function() {
284
+ var rejected = consumed(this);
285
+ if (rejected) {
286
+ return rejected;
287
+ }
288
+ if (this._bodyBlob) {
289
+ return Promise.resolve(this._bodyBlob);
290
+ } else if (this._bodyArrayBuffer) {
291
+ return Promise.resolve(new Blob([this._bodyArrayBuffer]));
292
+ } else if (this._bodyFormData) {
293
+ throw new Error("could not read FormData body as blob");
294
+ } else {
295
+ return Promise.resolve(new Blob([this._bodyText]));
296
+ }
297
+ };
298
+ }
299
+ this.arrayBuffer = function() {
300
+ if (this._bodyArrayBuffer) {
301
+ var isConsumed = consumed(this);
302
+ if (isConsumed) {
303
+ return isConsumed;
304
+ } else if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
305
+ return Promise.resolve(
306
+ this._bodyArrayBuffer.buffer.slice(
307
+ this._bodyArrayBuffer.byteOffset,
308
+ this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength
309
+ )
310
+ );
311
+ } else {
312
+ return Promise.resolve(this._bodyArrayBuffer);
313
+ }
314
+ } else if (support.blob) {
315
+ return this.blob().then(readBlobAsArrayBuffer);
316
+ } else {
317
+ throw new Error("could not read as ArrayBuffer");
318
+ }
319
+ };
320
+ this.text = function() {
321
+ var rejected = consumed(this);
322
+ if (rejected) {
323
+ return rejected;
324
+ }
325
+ if (this._bodyBlob) {
326
+ return readBlobAsText(this._bodyBlob);
327
+ } else if (this._bodyArrayBuffer) {
328
+ return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
329
+ } else if (this._bodyFormData) {
330
+ throw new Error("could not read FormData body as text");
331
+ } else {
332
+ return Promise.resolve(this._bodyText);
333
+ }
334
+ };
335
+ if (support.formData) {
336
+ this.formData = function() {
337
+ return this.text().then(decode);
338
+ };
339
+ }
340
+ this.json = function() {
341
+ return this.text().then(JSON.parse);
342
+ };
343
+ return this;
344
+ }
345
+ var methods = ["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"];
346
+ function normalizeMethod(method) {
347
+ var upcased = method.toUpperCase();
348
+ return methods.indexOf(upcased) > -1 ? upcased : method;
349
+ }
350
+ function Request(input, options) {
351
+ if (!(this instanceof Request)) {
352
+ throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
353
+ }
354
+ options = options || {};
355
+ var body = options.body;
356
+ if (input instanceof Request) {
357
+ if (input.bodyUsed) {
358
+ throw new TypeError("Already read");
359
+ }
360
+ this.url = input.url;
361
+ this.credentials = input.credentials;
362
+ if (!options.headers) {
363
+ this.headers = new Headers(input.headers);
364
+ }
365
+ this.method = input.method;
366
+ this.mode = input.mode;
367
+ this.signal = input.signal;
368
+ if (!body && input._bodyInit != null) {
369
+ body = input._bodyInit;
370
+ input.bodyUsed = true;
371
+ }
372
+ } else {
373
+ this.url = String(input);
374
+ }
375
+ this.credentials = options.credentials || this.credentials || "same-origin";
376
+ if (options.headers || !this.headers) {
377
+ this.headers = new Headers(options.headers);
378
+ }
379
+ this.method = normalizeMethod(options.method || this.method || "GET");
380
+ this.mode = options.mode || this.mode || null;
381
+ this.signal = options.signal || this.signal || (function() {
382
+ if ("AbortController" in g) {
383
+ var ctrl = new AbortController();
384
+ return ctrl.signal;
385
+ }
386
+ })();
387
+ this.referrer = null;
388
+ if ((this.method === "GET" || this.method === "HEAD") && body) {
389
+ throw new TypeError("Body not allowed for GET or HEAD requests");
390
+ }
391
+ this._initBody(body);
392
+ if (this.method === "GET" || this.method === "HEAD") {
393
+ if (options.cache === "no-store" || options.cache === "no-cache") {
394
+ var reParamSearch = /([?&])_=[^&]*/;
395
+ if (reParamSearch.test(this.url)) {
396
+ this.url = this.url.replace(reParamSearch, "$1_=" + (/* @__PURE__ */ new Date()).getTime());
397
+ } else {
398
+ var reQueryString = /\?/;
399
+ this.url += (reQueryString.test(this.url) ? "&" : "?") + "_=" + (/* @__PURE__ */ new Date()).getTime();
400
+ }
401
+ }
402
+ }
403
+ }
404
+ Request.prototype.clone = function() {
405
+ return new Request(this, { body: this._bodyInit });
406
+ };
407
+ function decode(body) {
408
+ var form = new FormData();
409
+ body.trim().split("&").forEach(function(bytes) {
410
+ if (bytes) {
411
+ var split = bytes.split("=");
412
+ var name = split.shift().replace(/\+/g, " ");
413
+ var value = split.join("=").replace(/\+/g, " ");
414
+ form.append(decodeURIComponent(name), decodeURIComponent(value));
415
+ }
416
+ });
417
+ return form;
418
+ }
419
+ function parseHeaders(rawHeaders) {
420
+ var headers = new Headers();
421
+ var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, " ");
422
+ preProcessedHeaders.split("\r").map(function(header) {
423
+ return header.indexOf("\n") === 0 ? header.substr(1, header.length) : header;
424
+ }).forEach(function(line) {
425
+ var parts = line.split(":");
426
+ var key = parts.shift().trim();
427
+ if (key) {
428
+ var value = parts.join(":").trim();
429
+ try {
430
+ headers.append(key, value);
431
+ } catch (error) {
432
+ console.warn("Response " + error.message);
433
+ }
434
+ }
435
+ });
436
+ return headers;
437
+ }
438
+ Body.call(Request.prototype);
439
+ function Response(bodyInit, options) {
440
+ if (!(this instanceof Response)) {
441
+ throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
442
+ }
443
+ if (!options) {
444
+ options = {};
445
+ }
446
+ this.type = "default";
447
+ this.status = options.status === void 0 ? 200 : options.status;
448
+ if (this.status < 200 || this.status > 599) {
449
+ throw new RangeError("Failed to construct 'Response': The status provided (0) is outside the range [200, 599].");
450
+ }
451
+ this.ok = this.status >= 200 && this.status < 300;
452
+ this.statusText = options.statusText === void 0 ? "" : "" + options.statusText;
453
+ this.headers = new Headers(options.headers);
454
+ this.url = options.url || "";
455
+ this._initBody(bodyInit);
456
+ }
457
+ Body.call(Response.prototype);
458
+ Response.prototype.clone = function() {
459
+ return new Response(this._bodyInit, {
460
+ status: this.status,
461
+ statusText: this.statusText,
462
+ headers: new Headers(this.headers),
463
+ url: this.url
464
+ });
465
+ };
466
+ Response.error = function() {
467
+ var response = new Response(null, { status: 200, statusText: "" });
468
+ response.ok = false;
469
+ response.status = 0;
470
+ response.type = "error";
471
+ return response;
472
+ };
473
+ var redirectStatuses = [301, 302, 303, 307, 308];
474
+ Response.redirect = function(url, status) {
475
+ if (redirectStatuses.indexOf(status) === -1) {
476
+ throw new RangeError("Invalid status code");
477
+ }
478
+ return new Response(null, { status, headers: { location: url } });
479
+ };
480
+ exports2.DOMException = g.DOMException;
481
+ try {
482
+ new exports2.DOMException();
483
+ } catch (err) {
484
+ exports2.DOMException = function(message, name) {
485
+ this.message = message;
486
+ this.name = name;
487
+ var error = Error(message);
488
+ this.stack = error.stack;
489
+ };
490
+ exports2.DOMException.prototype = Object.create(Error.prototype);
491
+ exports2.DOMException.prototype.constructor = exports2.DOMException;
492
+ }
493
+ function fetch2(input, init) {
494
+ return new Promise(function(resolve, reject) {
495
+ var request = new Request(input, init);
496
+ if (request.signal && request.signal.aborted) {
497
+ return reject(new exports2.DOMException("Aborted", "AbortError"));
498
+ }
499
+ var xhr = new XMLHttpRequest();
500
+ function abortXhr() {
501
+ xhr.abort();
502
+ }
503
+ xhr.onload = function() {
504
+ var options = {
505
+ statusText: xhr.statusText,
506
+ headers: parseHeaders(xhr.getAllResponseHeaders() || "")
507
+ };
508
+ if (request.url.indexOf("file://") === 0 && (xhr.status < 200 || xhr.status > 599)) {
509
+ options.status = 200;
510
+ } else {
511
+ options.status = xhr.status;
512
+ }
513
+ options.url = "responseURL" in xhr ? xhr.responseURL : options.headers.get("X-Request-URL");
514
+ var body = "response" in xhr ? xhr.response : xhr.responseText;
515
+ setTimeout(function() {
516
+ resolve(new Response(body, options));
517
+ }, 0);
518
+ };
519
+ xhr.onerror = function() {
520
+ setTimeout(function() {
521
+ reject(new TypeError("Network request failed"));
522
+ }, 0);
523
+ };
524
+ xhr.ontimeout = function() {
525
+ setTimeout(function() {
526
+ reject(new TypeError("Network request timed out"));
527
+ }, 0);
528
+ };
529
+ xhr.onabort = function() {
530
+ setTimeout(function() {
531
+ reject(new exports2.DOMException("Aborted", "AbortError"));
532
+ }, 0);
533
+ };
534
+ function fixUrl(url) {
535
+ try {
536
+ return url === "" && g.location.href ? g.location.href : url;
537
+ } catch (e) {
538
+ return url;
539
+ }
540
+ }
541
+ xhr.open(request.method, fixUrl(request.url), true);
542
+ if (request.credentials === "include") {
543
+ xhr.withCredentials = true;
544
+ } else if (request.credentials === "omit") {
545
+ xhr.withCredentials = false;
546
+ }
547
+ if ("responseType" in xhr) {
548
+ if (support.blob) {
549
+ xhr.responseType = "blob";
550
+ } else if (support.arrayBuffer) {
551
+ xhr.responseType = "arraybuffer";
552
+ }
553
+ }
554
+ if (init && typeof init.headers === "object" && !(init.headers instanceof Headers || g.Headers && init.headers instanceof g.Headers)) {
555
+ var names = [];
556
+ Object.getOwnPropertyNames(init.headers).forEach(function(name) {
557
+ names.push(normalizeName(name));
558
+ xhr.setRequestHeader(name, normalizeValue(init.headers[name]));
559
+ });
560
+ request.headers.forEach(function(value, name) {
561
+ if (names.indexOf(name) === -1) {
562
+ xhr.setRequestHeader(name, value);
563
+ }
564
+ });
565
+ } else {
566
+ request.headers.forEach(function(value, name) {
567
+ xhr.setRequestHeader(name, value);
568
+ });
569
+ }
570
+ if (request.signal) {
571
+ request.signal.addEventListener("abort", abortXhr);
572
+ xhr.onreadystatechange = function() {
573
+ if (xhr.readyState === 4) {
574
+ request.signal.removeEventListener("abort", abortXhr);
575
+ }
576
+ };
577
+ }
578
+ xhr.send(typeof request._bodyInit === "undefined" ? null : request._bodyInit);
579
+ });
580
+ }
581
+ fetch2.polyfill = true;
582
+ if (!g.fetch) {
583
+ g.fetch = fetch2;
584
+ g.Headers = Headers;
585
+ g.Request = Request;
586
+ g.Response = Response;
587
+ }
588
+ exports2.Headers = Headers;
589
+ exports2.Request = Request;
590
+ exports2.Response = Response;
591
+ exports2.fetch = fetch2;
592
+ return exports2;
593
+ })({});
594
+ })(typeof self !== "undefined" ? self : exports);
595
+ }
596
+ });
597
+ var byteToHex = [];
598
+ for (let i = 0; i < 256; ++i) {
599
+ byteToHex.push((i + 256).toString(16).slice(1));
600
+ }
601
+ function unsafeStringify(arr, offset = 0) {
602
+ return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
603
+ }
604
+ var getRandomValues;
605
+ var rnds8 = new Uint8Array(16);
606
+ function rng() {
607
+ if (!getRandomValues) {
608
+ if (typeof crypto === "undefined" || !crypto.getRandomValues) {
609
+ throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
610
+ }
611
+ getRandomValues = crypto.getRandomValues.bind(crypto);
612
+ }
613
+ return getRandomValues(rnds8);
614
+ }
615
+ var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
616
+ var native_default = { randomUUID };
617
+ function _v4(options, buf, offset) {
618
+ options = options || {};
619
+ const rnds = options.random ?? options.rng?.() ?? rng();
620
+ if (rnds.length < 16) {
621
+ throw new Error("Random bytes length must be >= 16");
622
+ }
623
+ rnds[6] = rnds[6] & 15 | 64;
624
+ rnds[8] = rnds[8] & 63 | 128;
625
+ if (buf) {
626
+ offset = offset || 0;
627
+ if (offset < 0 || offset + 16 > buf.length) {
628
+ throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
629
+ }
630
+ for (let i = 0; i < 16; ++i) {
631
+ buf[offset + i] = rnds[i];
632
+ }
633
+ return buf;
634
+ }
635
+ return unsafeStringify(rnds);
636
+ }
637
+ function v4(options, buf, offset) {
638
+ if (native_default.randomUUID && !buf && !options) {
639
+ return native_default.randomUUID();
640
+ }
641
+ return _v4(options, buf, offset);
642
+ }
643
+ var v4_default = v4;
644
+ var import_polyfill = __toESM(require_browser_polyfill());
645
+ function CheckFlagResponseDataFromJSON(json) {
646
+ return CheckFlagResponseDataFromJSONTyped(json, false);
647
+ }
648
+ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
649
+ if (json == null) {
650
+ return json;
651
+ }
652
+ return {
653
+ companyId: json["company_id"] == null ? void 0 : json["company_id"],
654
+ error: json["error"] == null ? void 0 : json["error"],
655
+ featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
656
+ featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
657
+ featureUsageEvent: json["feature_usage_event"] == null ? void 0 : json["feature_usage_event"],
658
+ featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : json["feature_usage_period"],
659
+ featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
660
+ flag: json["flag"],
661
+ flagId: json["flag_id"] == null ? void 0 : json["flag_id"],
662
+ reason: json["reason"],
663
+ ruleId: json["rule_id"] == null ? void 0 : json["rule_id"],
664
+ ruleType: json["rule_type"] == null ? void 0 : json["rule_type"],
665
+ userId: json["user_id"] == null ? void 0 : json["user_id"],
666
+ value: json["value"]
667
+ };
668
+ }
669
+ function EventBodyFlagCheckToJSON(json) {
670
+ return EventBodyFlagCheckToJSONTyped(json, false);
671
+ }
672
+ function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
673
+ if (value == null) {
674
+ return value;
675
+ }
676
+ return {
677
+ company_id: value["companyId"],
678
+ error: value["error"],
679
+ flag_id: value["flagId"],
680
+ flag_key: value["flagKey"],
681
+ reason: value["reason"],
682
+ req_company: value["reqCompany"],
683
+ req_user: value["reqUser"],
684
+ rule_id: value["ruleId"],
685
+ user_id: value["userId"],
686
+ value: value["value"]
687
+ };
688
+ }
689
+ function CheckFlagResponseFromJSON(json) {
690
+ return CheckFlagResponseFromJSONTyped(json, false);
691
+ }
692
+ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
693
+ if (json == null) {
694
+ return json;
695
+ }
696
+ return {
697
+ data: CheckFlagResponseDataFromJSON(json["data"]),
698
+ params: json["params"]
699
+ };
700
+ }
701
+ function CheckFlagsResponseDataFromJSON(json) {
702
+ return CheckFlagsResponseDataFromJSONTyped(json, false);
703
+ }
704
+ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
705
+ if (json == null) {
706
+ return json;
707
+ }
708
+ return {
709
+ flags: json["flags"].map(CheckFlagResponseDataFromJSON)
710
+ };
711
+ }
712
+ function CheckFlagsResponseFromJSON(json) {
713
+ return CheckFlagsResponseFromJSONTyped(json, false);
714
+ }
715
+ function CheckFlagsResponseFromJSONTyped(json, ignoreDiscriminator) {
716
+ if (json == null) {
717
+ return json;
718
+ }
719
+ return {
720
+ data: CheckFlagsResponseDataFromJSON(json["data"]),
721
+ params: json["params"]
722
+ };
723
+ }
724
+ var RuleType = /* @__PURE__ */ ((RuleType2) => {
725
+ RuleType2["GLOBAL_OVERRIDE"] = "global_override";
726
+ RuleType2["COMPANY_OVERRIDE"] = "company_override";
727
+ RuleType2["COMPANY_OVERRIDE_USAGE_EXCEEDED"] = "company_override_usage_exceeded";
728
+ RuleType2["PLAN_ENTITLEMENT"] = "plan_entitlement";
729
+ RuleType2["PLAN_ENTITLEMENT_USAGE_EXCEEDED"] = "plan_entitlement_usage_exceeded";
730
+ RuleType2["STANDARD"] = "standard";
731
+ RuleType2["DEFAULT"] = "default";
732
+ return RuleType2;
733
+ })(RuleType || {});
734
+ var UsagePeriod = /* @__PURE__ */ ((UsagePeriod2) => {
735
+ UsagePeriod2["ALL_TIME"] = "all_time";
736
+ UsagePeriod2["CURRENT_DAY"] = "current_day";
737
+ UsagePeriod2["CURRENT_MONTH"] = "current_month";
738
+ UsagePeriod2["CURRENT_WEEK"] = "current_week";
739
+ return UsagePeriod2;
740
+ })(UsagePeriod || {});
741
+ var CheckFlagReturnFromJSON = (json) => {
742
+ const {
743
+ companyId,
744
+ error,
745
+ featureAllocation,
746
+ featureUsage,
747
+ featureUsageEvent,
748
+ featureUsagePeriod,
749
+ featureUsageResetAt,
750
+ flag,
751
+ flagId,
752
+ reason,
753
+ ruleId,
754
+ ruleType,
755
+ userId,
756
+ value
757
+ } = CheckFlagResponseDataFromJSON(json);
758
+ const featureUsageExceeded = !value && // if flag is not false, then we haven't exceeded usage
759
+ (ruleType == "company_override_usage_exceeded" || // if the rule type is one of these, then we have exceeded usage
760
+ ruleType == "plan_entitlement_usage_exceeded");
761
+ return {
762
+ featureUsageExceeded,
763
+ companyId: companyId == null ? void 0 : companyId,
764
+ error: error == null ? void 0 : error,
765
+ featureAllocation: featureAllocation == null ? void 0 : featureAllocation,
766
+ featureUsage: featureUsage == null ? void 0 : featureUsage,
767
+ featureUsageEvent: featureUsageEvent === null ? void 0 : featureUsageEvent,
768
+ featureUsagePeriod: featureUsagePeriod == null ? void 0 : featureUsagePeriod,
769
+ featureUsageResetAt: featureUsageResetAt == null ? void 0 : featureUsageResetAt,
770
+ flag,
771
+ flagId: flagId == null ? void 0 : flagId,
772
+ reason,
773
+ ruleId: ruleId == null ? void 0 : ruleId,
774
+ ruleType: ruleType == null ? void 0 : ruleType,
775
+ userId: userId == null ? void 0 : userId,
776
+ value
777
+ };
778
+ };
779
+ function contextString(context) {
780
+ const sortedContext = Object.keys(context).reduce((acc, key) => {
781
+ const sortedKeys = Object.keys(
782
+ context[key] || {}
783
+ ).sort();
784
+ const sortedObj = sortedKeys.reduce((obj, sortedKey) => {
785
+ obj[sortedKey] = context[key][sortedKey];
786
+ return obj;
787
+ }, {});
788
+ acc[key] = sortedObj;
789
+ return acc;
790
+ }, {});
791
+ return JSON.stringify(sortedContext);
792
+ }
793
+ var version = "1.2.6";
794
+ var anonymousIdKey = "schematicId";
795
+ var Schematic = class {
796
+ additionalHeaders = {};
797
+ apiKey;
798
+ apiUrl = "https://api.schematichq.com";
799
+ conn = null;
800
+ context = {};
801
+ debugEnabled = false;
802
+ offlineEnabled = false;
803
+ eventQueue;
804
+ contextDependentEventQueue;
805
+ eventUrl = "https://c.schematichq.com";
806
+ flagCheckListeners = {};
807
+ flagValueListeners = {};
808
+ isPending = true;
809
+ isPendingListeners = /* @__PURE__ */ new Set();
810
+ storage;
811
+ useWebSocket = false;
812
+ checks = {};
813
+ featureUsageEventMap = {};
814
+ webSocketUrl = "wss://api.schematichq.com";
815
+ constructor(apiKey, options) {
816
+ this.apiKey = apiKey;
817
+ this.eventQueue = [];
818
+ this.contextDependentEventQueue = [];
819
+ this.useWebSocket = options?.useWebSocket ?? false;
820
+ this.debugEnabled = options?.debug ?? false;
821
+ this.offlineEnabled = options?.offline ?? false;
822
+ if (typeof window !== "undefined" && typeof window.location !== "undefined") {
823
+ const params = new URLSearchParams(window.location.search);
824
+ const debugParam = params.get("schematic_debug");
825
+ if (debugParam !== null && (debugParam === "" || debugParam === "true" || debugParam === "1")) {
826
+ this.debugEnabled = true;
827
+ }
828
+ const offlineParam = params.get("schematic_offline");
829
+ if (offlineParam !== null && (offlineParam === "" || offlineParam === "true" || offlineParam === "1")) {
830
+ this.offlineEnabled = true;
831
+ this.debugEnabled = true;
832
+ }
833
+ }
834
+ if (this.offlineEnabled && options?.debug !== false) {
835
+ this.debugEnabled = true;
836
+ }
837
+ if (this.offlineEnabled) {
838
+ this.setIsPending(false);
839
+ }
840
+ this.additionalHeaders = {
841
+ "X-Schematic-Client-Version": `schematic-js@${version}`,
842
+ ...options?.additionalHeaders ?? {}
843
+ };
844
+ if (options?.storage) {
845
+ this.storage = options.storage;
846
+ } else if (typeof localStorage !== "undefined") {
847
+ this.storage = localStorage;
848
+ }
849
+ if (options?.apiUrl !== void 0) {
850
+ this.apiUrl = options.apiUrl;
851
+ }
852
+ if (options?.eventUrl !== void 0) {
853
+ this.eventUrl = options.eventUrl;
854
+ }
855
+ if (options?.webSocketUrl !== void 0) {
856
+ this.webSocketUrl = options.webSocketUrl;
857
+ }
858
+ if (typeof window !== "undefined" && window?.addEventListener) {
859
+ window.addEventListener("beforeunload", () => {
860
+ this.flushEventQueue();
861
+ this.flushContextDependentEventQueue();
862
+ });
863
+ }
864
+ if (this.offlineEnabled) {
865
+ this.debug(
866
+ "Initialized with offline mode enabled - no network requests will be made"
867
+ );
868
+ } else if (this.debugEnabled) {
869
+ this.debug("Initialized with debug mode enabled");
870
+ }
871
+ }
872
+ /**
873
+ * Get value for a single flag.
874
+ * In WebSocket mode, returns cached values if connection is active, otherwise establishes
875
+ * new connection and then returns the requestedvalue. Falls back to REST API if WebSocket
876
+ * connection fails.
877
+ * In REST mode, makes an API call for each check.
878
+ */
879
+ async checkFlag(options) {
880
+ const { fallback = false, key } = options;
881
+ const context = options.context || this.context;
882
+ const contextStr = contextString(context);
883
+ this.debug(`checkFlag: ${key}`, { context, fallback });
884
+ if (this.isOffline()) {
885
+ this.debug(`checkFlag offline result: ${key}`, {
886
+ value: fallback,
887
+ offlineMode: true
888
+ });
889
+ return fallback;
890
+ }
891
+ if (!this.useWebSocket) {
892
+ const requestUrl = `${this.apiUrl}/flags/${key}/check`;
893
+ return fetch(requestUrl, {
894
+ method: "POST",
895
+ headers: {
896
+ ...this.additionalHeaders ?? {},
897
+ "Content-Type": "application/json;charset=UTF-8",
898
+ "X-Schematic-Api-Key": this.apiKey
899
+ },
900
+ body: JSON.stringify(context)
901
+ }).then((response) => {
902
+ if (!response.ok) {
903
+ throw new Error("Network response was not ok");
904
+ }
905
+ return response.json();
906
+ }).then((response) => {
907
+ const parsedResponse = CheckFlagResponseFromJSON(response);
908
+ this.debug(`checkFlag result: ${key}`, parsedResponse);
909
+ const result = CheckFlagReturnFromJSON(parsedResponse.data);
910
+ if (typeof result.featureUsageEvent === "string") {
911
+ this.updateFeatureUsageEventMap(result);
912
+ }
913
+ this.submitFlagCheckEvent(key, result, context);
914
+ return result.value;
915
+ }).catch((error) => {
916
+ console.error("There was a problem with the fetch operation:", error);
917
+ const errorResult = {
918
+ flag: key,
919
+ value: fallback,
920
+ reason: "API request failed",
921
+ error: error instanceof Error ? error.message : String(error)
922
+ };
923
+ this.submitFlagCheckEvent(key, errorResult, context);
924
+ return fallback;
925
+ });
926
+ }
927
+ try {
928
+ const existingVals = this.checks[contextStr];
929
+ if (this.conn !== null && typeof existingVals !== "undefined" && typeof existingVals[key] !== "undefined") {
930
+ this.debug(`checkFlag cached result: ${key}`, existingVals[key]);
931
+ return existingVals[key].value;
932
+ }
933
+ if (this.isOffline()) {
934
+ return fallback;
935
+ }
936
+ try {
937
+ await this.setContext(context);
938
+ } catch (error) {
939
+ console.error(
940
+ "WebSocket connection failed, falling back to REST:",
941
+ error
942
+ );
943
+ return this.fallbackToRest(key, context, fallback);
944
+ }
945
+ const contextVals = this.checks[contextStr] ?? {};
946
+ const flagCheck = contextVals[key];
947
+ const result = flagCheck?.value ?? fallback;
948
+ this.debug(
949
+ `checkFlag WebSocket result: ${key}`,
950
+ typeof flagCheck !== "undefined" ? flagCheck : { value: fallback, fallbackUsed: true }
951
+ );
952
+ if (typeof flagCheck !== "undefined") {
953
+ this.submitFlagCheckEvent(key, flagCheck, context);
954
+ }
955
+ return result;
956
+ } catch (error) {
957
+ console.error("Unexpected error in checkFlag:", error);
958
+ const errorResult = {
959
+ flag: key,
960
+ value: fallback,
961
+ reason: "Unexpected error in flag check",
962
+ error: error instanceof Error ? error.message : String(error)
963
+ };
964
+ this.submitFlagCheckEvent(key, errorResult, context);
965
+ return fallback;
966
+ }
967
+ }
968
+ /**
969
+ * Helper function to log debug messages
970
+ * Only logs if debug mode is enabled
971
+ */
972
+ debug(message, ...args) {
973
+ if (this.debugEnabled) {
974
+ console.log(`[Schematic] ${message}`, ...args);
975
+ }
976
+ }
977
+ /**
978
+ * Helper function to check if client is in offline mode
979
+ */
980
+ isOffline() {
981
+ return this.offlineEnabled;
982
+ }
983
+ /**
984
+ * Submit a flag check event
985
+ * Records data about a flag check for analytics
986
+ */
987
+ submitFlagCheckEvent(flagKey, result, context) {
988
+ const eventBody = {
989
+ flagKey,
990
+ value: result.value,
991
+ reason: result.reason,
992
+ flagId: result.flagId,
993
+ ruleId: result.ruleId,
994
+ companyId: result.companyId,
995
+ userId: result.userId,
996
+ error: result.error,
997
+ reqCompany: context.company,
998
+ reqUser: context.user
999
+ };
1000
+ this.debug(`submitting flag check event:`, eventBody);
1001
+ return this.handleEvent("flag_check", EventBodyFlagCheckToJSON(eventBody));
1002
+ }
1003
+ /**
1004
+ * Helper method for falling back to REST API when WebSocket connection fails
1005
+ */
1006
+ async fallbackToRest(key, context, fallback) {
1007
+ if (this.isOffline()) {
1008
+ this.debug(`fallbackToRest offline result: ${key}`, {
1009
+ value: fallback,
1010
+ offlineMode: true
1011
+ });
1012
+ return fallback;
1013
+ }
1014
+ try {
1015
+ const requestUrl = `${this.apiUrl}/flags/${key}/check`;
1016
+ const response = await fetch(requestUrl, {
1017
+ method: "POST",
1018
+ headers: {
1019
+ ...this.additionalHeaders ?? {},
1020
+ "Content-Type": "application/json;charset=UTF-8",
1021
+ "X-Schematic-Api-Key": this.apiKey
1022
+ },
1023
+ body: JSON.stringify(context)
1024
+ });
1025
+ if (!response.ok) {
1026
+ throw new Error("Network response was not ok");
1027
+ }
1028
+ const responseJson = await response.json();
1029
+ const data = CheckFlagResponseFromJSON(responseJson);
1030
+ this.debug(`fallbackToRest result: ${key}`, data);
1031
+ const result = CheckFlagReturnFromJSON(data.data);
1032
+ if (typeof result.featureUsageEvent === "string") {
1033
+ this.updateFeatureUsageEventMap(result);
1034
+ }
1035
+ this.submitFlagCheckEvent(key, result, context);
1036
+ return result.value;
1037
+ } catch (error) {
1038
+ console.error("REST API call failed, using fallback value:", error);
1039
+ const errorResult = {
1040
+ flag: key,
1041
+ value: fallback,
1042
+ reason: "API request failed (fallback)",
1043
+ error: error instanceof Error ? error.message : String(error)
1044
+ };
1045
+ this.submitFlagCheckEvent(key, errorResult, context);
1046
+ return fallback;
1047
+ }
1048
+ }
1049
+ /**
1050
+ * Make an API call to fetch all flag values for a given context.
1051
+ * Recommended for use in REST mode only.
1052
+ * In offline mode, returns an empty object.
1053
+ */
1054
+ checkFlags = async (context) => {
1055
+ context = context || this.context;
1056
+ this.debug(`checkFlags`, { context });
1057
+ if (this.isOffline()) {
1058
+ this.debug(`checkFlags offline result: returning empty object`);
1059
+ return {};
1060
+ }
1061
+ const requestUrl = `${this.apiUrl}/flags/check`;
1062
+ const requestBody = JSON.stringify(context);
1063
+ return fetch(requestUrl, {
1064
+ method: "POST",
1065
+ headers: {
1066
+ ...this.additionalHeaders ?? {},
1067
+ "Content-Type": "application/json;charset=UTF-8",
1068
+ "X-Schematic-Api-Key": this.apiKey
1069
+ },
1070
+ body: requestBody
1071
+ }).then((response) => {
1072
+ if (!response.ok) {
1073
+ throw new Error("Network response was not ok");
1074
+ }
1075
+ return response.json();
1076
+ }).then((responseJson) => {
1077
+ const resp = CheckFlagsResponseFromJSON(responseJson);
1078
+ this.debug(`checkFlags result:`, resp);
1079
+ return (resp?.data?.flags ?? []).reduce(
1080
+ (accum, flag) => {
1081
+ accum[flag.flag] = flag.value;
1082
+ return accum;
1083
+ },
1084
+ {}
1085
+ );
1086
+ }).catch((error) => {
1087
+ console.error("There was a problem with the fetch operation:", error);
1088
+ return {};
1089
+ });
1090
+ };
1091
+ /**
1092
+ * Send an identify event.
1093
+ * This will set the context for subsequent flag evaluation and events, and will also
1094
+ * send an identify event to the Schematic API which will upsert a user and company.
1095
+ */
1096
+ identify = (body) => {
1097
+ this.debug(`identify:`, body);
1098
+ try {
1099
+ this.setContext({
1100
+ company: body.company?.keys,
1101
+ user: body.keys
1102
+ });
1103
+ } catch (error) {
1104
+ console.error("Error setting context:", error);
1105
+ }
1106
+ return this.handleEvent("identify", body);
1107
+ };
1108
+ /**
1109
+ * Set the flag evaluation context.
1110
+ * In WebSocket mode, this will:
1111
+ * 1. Open a websocket connection if not already open
1112
+ * 2. Send the context to the server
1113
+ * 3. Wait for initial flag values to be returned
1114
+ * The promise resolves when initial flag values are received.
1115
+ * In offline mode, this will just set the context locally without connecting.
1116
+ */
1117
+ setContext = async (context) => {
1118
+ if (this.isOffline() || !this.useWebSocket) {
1119
+ this.context = context;
1120
+ this.flushContextDependentEventQueue();
1121
+ this.setIsPending(false);
1122
+ return Promise.resolve();
1123
+ }
1124
+ try {
1125
+ this.setIsPending(true);
1126
+ if (!this.conn) {
1127
+ this.conn = this.wsConnect();
1128
+ }
1129
+ const socket = await this.conn;
1130
+ await this.wsSendMessage(socket, context);
1131
+ } catch (error) {
1132
+ console.error("Failed to establish WebSocket connection:", error);
1133
+ throw error;
1134
+ }
1135
+ };
1136
+ /**
1137
+ * Send a track event
1138
+ * Track usage for a company and/or user.
1139
+ * Optimistically updates feature usage flags if tracking a featureUsageEvent.
1140
+ */
1141
+ track = (body) => {
1142
+ const { company, user, event, traits, quantity = 1 } = body;
1143
+ if (!this.hasContext(company, user)) {
1144
+ this.debug(`track: queuing event "${event}" until context is available`);
1145
+ const queuedEvent = {
1146
+ api_key: this.apiKey,
1147
+ body: {
1148
+ company,
1149
+ event,
1150
+ traits: traits ?? {},
1151
+ user,
1152
+ quantity
1153
+ },
1154
+ sent_at: (/* @__PURE__ */ new Date()).toISOString(),
1155
+ tracker_event_id: v4_default(),
1156
+ tracker_user_id: this.getAnonymousId(),
1157
+ type: "track"
1158
+ };
1159
+ this.contextDependentEventQueue.push(queuedEvent);
1160
+ return Promise.resolve();
1161
+ }
1162
+ const trackData = {
1163
+ company: company ?? this.context.company,
1164
+ event,
1165
+ traits: traits ?? {},
1166
+ user: user ?? this.context.user,
1167
+ quantity
1168
+ };
1169
+ this.debug(`track:`, trackData);
1170
+ if (event in this.featureUsageEventMap) {
1171
+ this.optimisticallyUpdateFeatureUsage(event, quantity);
1172
+ }
1173
+ return this.handleEvent("track", trackData);
1174
+ };
1175
+ /**
1176
+ * Optimistically update feature usage flags associated with a tracked event
1177
+ * This updates flags in memory with updated usage counts and value/featureUsageExceeded flags
1178
+ * before the network request completes
1179
+ */
1180
+ optimisticallyUpdateFeatureUsage = (eventName, quantity = 1) => {
1181
+ const flagsForEvent = this.featureUsageEventMap[eventName];
1182
+ if (flagsForEvent === void 0 || flagsForEvent === null) return;
1183
+ this.debug(
1184
+ `Optimistically updating feature usage for event: ${eventName}`,
1185
+ { quantity }
1186
+ );
1187
+ Object.entries(flagsForEvent).forEach(([flagKey, check]) => {
1188
+ if (check === void 0) return;
1189
+ const updatedCheck = { ...check };
1190
+ if (typeof updatedCheck.featureUsage === "number") {
1191
+ updatedCheck.featureUsage += quantity;
1192
+ if (typeof updatedCheck.featureAllocation === "number") {
1193
+ const wasExceeded = updatedCheck.featureUsageExceeded === true;
1194
+ const nowExceeded = updatedCheck.featureUsage >= updatedCheck.featureAllocation;
1195
+ if (nowExceeded !== wasExceeded) {
1196
+ updatedCheck.featureUsageExceeded = nowExceeded;
1197
+ if (nowExceeded) {
1198
+ updatedCheck.value = false;
1199
+ }
1200
+ this.debug(`Usage limit status changed for flag: ${flagKey}`, {
1201
+ was: wasExceeded ? "exceeded" : "within limits",
1202
+ now: nowExceeded ? "exceeded" : "within limits",
1203
+ featureUsage: updatedCheck.featureUsage,
1204
+ featureAllocation: updatedCheck.featureAllocation,
1205
+ value: updatedCheck.value
1206
+ });
1207
+ }
1208
+ }
1209
+ if (this.featureUsageEventMap[eventName] !== void 0) {
1210
+ this.featureUsageEventMap[eventName][flagKey] = updatedCheck;
1211
+ }
1212
+ const contextStr = contextString(this.context);
1213
+ if (this.checks[contextStr] !== void 0 && this.checks[contextStr] !== null) {
1214
+ this.checks[contextStr][flagKey] = updatedCheck;
1215
+ }
1216
+ this.notifyFlagCheckListeners(flagKey, updatedCheck);
1217
+ this.notifyFlagValueListeners(flagKey, updatedCheck.value);
1218
+ }
1219
+ });
1220
+ };
1221
+ /**
1222
+ * Event processing
1223
+ */
1224
+ hasContext = (company, user) => {
1225
+ const hasProvidedContext = company !== void 0 && company !== null && Object.keys(company).length > 0 || user !== void 0 && user !== null && Object.keys(user).length > 0;
1226
+ const hasInstanceContext = this.context.company !== void 0 && this.context.company !== null && Object.keys(this.context.company).length > 0 || this.context.user !== void 0 && this.context.user !== null && Object.keys(this.context.user).length > 0;
1227
+ return hasProvidedContext || hasInstanceContext;
1228
+ };
1229
+ flushContextDependentEventQueue = () => {
1230
+ this.debug(
1231
+ `flushing ${this.contextDependentEventQueue.length} context-dependent events`
1232
+ );
1233
+ while (this.contextDependentEventQueue.length > 0) {
1234
+ const event = this.contextDependentEventQueue.shift();
1235
+ if (event) {
1236
+ if (event.type === "track" && typeof event.body === "object" && event.body !== null) {
1237
+ const trackBody = event.body;
1238
+ const updatedBody = {
1239
+ ...trackBody,
1240
+ company: trackBody.company ?? this.context.company,
1241
+ user: trackBody.user ?? this.context.user
1242
+ };
1243
+ const updatedEvent = {
1244
+ ...event,
1245
+ body: updatedBody,
1246
+ sent_at: (/* @__PURE__ */ new Date()).toISOString()
1247
+ // Update timestamp to actual send time
1248
+ };
1249
+ this.sendEvent(updatedEvent);
1250
+ } else {
1251
+ this.sendEvent(event);
1252
+ }
1253
+ }
1254
+ }
1255
+ };
1256
+ flushEventQueue = () => {
1257
+ while (this.eventQueue.length > 0) {
1258
+ const event = this.eventQueue.shift();
1259
+ if (event) {
1260
+ this.sendEvent(event);
1261
+ }
1262
+ }
1263
+ };
1264
+ getAnonymousId = () => {
1265
+ if (!this.storage) {
1266
+ return v4_default();
1267
+ }
1268
+ const storedAnonymousId = this.storage.getItem(anonymousIdKey);
1269
+ if (typeof storedAnonymousId !== "undefined") {
1270
+ return storedAnonymousId;
1271
+ }
1272
+ const generatedAnonymousId = v4_default();
1273
+ this.storage.setItem(anonymousIdKey, generatedAnonymousId);
1274
+ return generatedAnonymousId;
1275
+ };
1276
+ handleEvent = (eventType, eventBody) => {
1277
+ const event = {
1278
+ api_key: this.apiKey,
1279
+ body: eventBody,
1280
+ sent_at: (/* @__PURE__ */ new Date()).toISOString(),
1281
+ tracker_event_id: v4_default(),
1282
+ tracker_user_id: this.getAnonymousId(),
1283
+ type: eventType
1284
+ };
1285
+ if (typeof document !== "undefined" && document?.hidden) {
1286
+ return this.storeEvent(event);
1287
+ } else {
1288
+ return this.sendEvent(event);
1289
+ }
1290
+ };
1291
+ sendEvent = async (event) => {
1292
+ const captureUrl = `${this.eventUrl}/e`;
1293
+ const payload = JSON.stringify(event);
1294
+ this.debug(`sending event:`, { url: captureUrl, event });
1295
+ if (this.isOffline()) {
1296
+ this.debug(`event not sent (offline mode):`, { event });
1297
+ return Promise.resolve();
1298
+ }
1299
+ try {
1300
+ const response = await fetch(captureUrl, {
1301
+ method: "POST",
1302
+ headers: {
1303
+ ...this.additionalHeaders ?? {},
1304
+ "Content-Type": "application/json;charset=UTF-8"
1305
+ },
1306
+ body: payload
1307
+ });
1308
+ this.debug(`event sent:`, {
1309
+ status: response.status,
1310
+ statusText: response.statusText
1311
+ });
1312
+ } catch (error) {
1313
+ console.error("Error sending Schematic event: ", error);
1314
+ }
1315
+ return Promise.resolve();
1316
+ };
1317
+ storeEvent = (event) => {
1318
+ this.eventQueue.push(event);
1319
+ return Promise.resolve();
1320
+ };
1321
+ /**
1322
+ * Websocket management
1323
+ */
1324
+ /**
1325
+ * If using websocket mode, close the connection when done.
1326
+ * In offline mode, this is a no-op.
1327
+ */
1328
+ cleanup = async () => {
1329
+ if (this.isOffline()) {
1330
+ this.debug("cleanup: skipped (offline mode)");
1331
+ return Promise.resolve();
1332
+ }
1333
+ if (this.conn) {
1334
+ try {
1335
+ const socket = await this.conn;
1336
+ socket.close();
1337
+ } catch (error) {
1338
+ console.error("Error during cleanup:", error);
1339
+ } finally {
1340
+ this.conn = null;
1341
+ }
1342
+ }
1343
+ };
1344
+ // Open a websocket connection
1345
+ wsConnect = () => {
1346
+ if (this.isOffline()) {
1347
+ this.debug("wsConnect: skipped (offline mode)");
1348
+ return Promise.reject(
1349
+ new Error("WebSocket connection skipped in offline mode")
1350
+ );
1351
+ }
1352
+ return new Promise((resolve, reject) => {
1353
+ const wsUrl = `${this.webSocketUrl}/flags/bootstrap?apiKey=${this.apiKey}`;
1354
+ this.debug(`connecting to WebSocket:`, wsUrl);
1355
+ const webSocket = new WebSocket(wsUrl);
1356
+ webSocket.onopen = () => {
1357
+ this.debug(`WebSocket connection opened`);
1358
+ resolve(webSocket);
1359
+ };
1360
+ webSocket.onerror = (error) => {
1361
+ this.debug(`WebSocket connection error:`, error);
1362
+ reject(error);
1363
+ };
1364
+ webSocket.onclose = () => {
1365
+ this.debug(`WebSocket connection closed`);
1366
+ this.conn = null;
1367
+ };
1368
+ });
1369
+ };
1370
+ // Send a message on the websocket indicating interest in a particular evaluation context
1371
+ // and wait for the initial set of flag values to be returned
1372
+ wsSendMessage = (socket, context) => {
1373
+ if (this.isOffline()) {
1374
+ this.debug("wsSendMessage: skipped (offline mode)");
1375
+ this.setIsPending(false);
1376
+ return Promise.resolve();
1377
+ }
1378
+ return new Promise((resolve, reject) => {
1379
+ if (contextString(context) == contextString(this.context)) {
1380
+ this.debug(`WebSocket context unchanged, skipping update`);
1381
+ return resolve(this.setIsPending(false));
1382
+ }
1383
+ this.debug(`WebSocket context updated:`, context);
1384
+ this.context = context;
1385
+ const sendMessage = () => {
1386
+ let resolved = false;
1387
+ const messageHandler = (event) => {
1388
+ const message = JSON.parse(event.data);
1389
+ this.debug(`WebSocket message received:`, message);
1390
+ if (!(contextString(context) in this.checks)) {
1391
+ this.checks[contextString(context)] = {};
1392
+ }
1393
+ (message.flags ?? []).forEach((flag) => {
1394
+ const flagCheck = CheckFlagReturnFromJSON(flag);
1395
+ const contextStr = contextString(context);
1396
+ if (this.checks[contextStr] === void 0) {
1397
+ this.checks[contextStr] = {};
1398
+ }
1399
+ this.checks[contextStr][flagCheck.flag] = flagCheck;
1400
+ this.debug(`WebSocket flag update:`, {
1401
+ flag: flagCheck.flag,
1402
+ value: flagCheck.value,
1403
+ flagCheck
1404
+ });
1405
+ if (typeof flagCheck.featureUsageEvent === "string") {
1406
+ this.updateFeatureUsageEventMap(flagCheck);
1407
+ }
1408
+ if (this.flagCheckListeners[flag.flag]?.size > 0 || this.flagValueListeners[flag.flag]?.size > 0) {
1409
+ this.submitFlagCheckEvent(flagCheck.flag, flagCheck, context);
1410
+ }
1411
+ this.notifyFlagCheckListeners(flag.flag, flagCheck);
1412
+ this.notifyFlagValueListeners(flag.flag, flagCheck.value);
1413
+ });
1414
+ this.flushContextDependentEventQueue();
1415
+ this.setIsPending(false);
1416
+ if (!resolved) {
1417
+ resolved = true;
1418
+ resolve();
1419
+ }
1420
+ };
1421
+ socket.addEventListener("message", messageHandler);
1422
+ const clientVersion = this.additionalHeaders["X-Schematic-Client-Version"] ?? `schematic-js@${version}`;
1423
+ const messagePayload = {
1424
+ apiKey: this.apiKey,
1425
+ clientVersion,
1426
+ data: context
1427
+ };
1428
+ this.debug(`WebSocket sending message:`, messagePayload);
1429
+ socket.send(JSON.stringify(messagePayload));
1430
+ };
1431
+ if (socket.readyState === WebSocket.OPEN) {
1432
+ this.debug(`WebSocket already open, sending message`);
1433
+ sendMessage();
1434
+ } else if (socket.readyState === WebSocket.CONNECTING) {
1435
+ this.debug(`WebSocket connecting, waiting for open to send message`);
1436
+ socket.addEventListener("open", sendMessage);
1437
+ } else {
1438
+ this.debug(`WebSocket is closed, cannot send message`);
1439
+ reject("WebSocket is not open or connecting");
1440
+ }
1441
+ });
1442
+ };
1443
+ /**
1444
+ * State management
1445
+ */
1446
+ // isPending state
1447
+ getIsPending = () => {
1448
+ return this.isPending;
1449
+ };
1450
+ addIsPendingListener = (listener) => {
1451
+ this.isPendingListeners.add(listener);
1452
+ return () => {
1453
+ this.isPendingListeners.delete(listener);
1454
+ };
1455
+ };
1456
+ setIsPending = (isPending) => {
1457
+ this.isPending = isPending;
1458
+ this.isPendingListeners.forEach(
1459
+ (listener) => notifyPendingListener(listener, isPending)
1460
+ );
1461
+ };
1462
+ // flag checks state
1463
+ getFlagCheck = (flagKey) => {
1464
+ const contextStr = contextString(this.context);
1465
+ const checks = this.checks[contextStr] ?? {};
1466
+ return checks[flagKey];
1467
+ };
1468
+ // flagValues state
1469
+ getFlagValue = (flagKey) => {
1470
+ const check = this.getFlagCheck(flagKey);
1471
+ return check?.value;
1472
+ };
1473
+ /** Register an event listener that will be notified with the boolean value for a given flag when this value changes */
1474
+ addFlagValueListener = (flagKey, listener) => {
1475
+ if (!(flagKey in this.flagValueListeners)) {
1476
+ this.flagValueListeners[flagKey] = /* @__PURE__ */ new Set();
1477
+ }
1478
+ this.flagValueListeners[flagKey].add(listener);
1479
+ return () => {
1480
+ this.flagValueListeners[flagKey].delete(listener);
1481
+ };
1482
+ };
1483
+ /** Register an event listener that will be notified with the full flag check response for a given flag whenever this value changes */
1484
+ addFlagCheckListener = (flagKey, listener) => {
1485
+ if (!(flagKey in this.flagCheckListeners)) {
1486
+ this.flagCheckListeners[flagKey] = /* @__PURE__ */ new Set();
1487
+ }
1488
+ this.flagCheckListeners[flagKey].add(listener);
1489
+ return () => {
1490
+ this.flagCheckListeners[flagKey].delete(listener);
1491
+ };
1492
+ };
1493
+ notifyFlagCheckListeners = (flagKey, check) => {
1494
+ const listeners = this.flagCheckListeners?.[flagKey] ?? [];
1495
+ if (listeners.size > 0) {
1496
+ this.debug(
1497
+ `Notifying ${listeners.size} flag check listeners for ${flagKey}`,
1498
+ check
1499
+ );
1500
+ }
1501
+ if (typeof check.featureUsageEvent === "string") {
1502
+ this.updateFeatureUsageEventMap(check);
1503
+ }
1504
+ listeners.forEach((listener) => notifyFlagCheckListener(listener, check));
1505
+ };
1506
+ /** Add or update a CheckFlagReturn in the featureUsageEventMap */
1507
+ updateFeatureUsageEventMap = (check) => {
1508
+ if (typeof check.featureUsageEvent !== "string") return;
1509
+ const eventName = check.featureUsageEvent;
1510
+ if (this.featureUsageEventMap[eventName] === void 0 || this.featureUsageEventMap[eventName] === null) {
1511
+ this.featureUsageEventMap[eventName] = {};
1512
+ }
1513
+ if (this.featureUsageEventMap[eventName] !== void 0) {
1514
+ this.featureUsageEventMap[eventName][check.flag] = check;
1515
+ }
1516
+ this.debug(
1517
+ `Updated featureUsageEventMap for event: ${eventName}, flag: ${check.flag}`,
1518
+ check
1519
+ );
1520
+ };
1521
+ notifyFlagValueListeners = (flagKey, value) => {
1522
+ const listeners = this.flagValueListeners?.[flagKey] ?? [];
1523
+ if (listeners.size > 0) {
1524
+ this.debug(
1525
+ `Notifying ${listeners.size} flag value listeners for ${flagKey}`,
1526
+ { value }
1527
+ );
1528
+ }
1529
+ listeners.forEach((listener) => notifyFlagValueListener(listener, value));
1530
+ };
1531
+ };
1532
+ var notifyPendingListener = (listener, value) => {
1533
+ if (listener.length > 0) {
1534
+ listener(value);
1535
+ } else {
1536
+ listener();
1537
+ }
1538
+ };
1539
+ var notifyFlagCheckListener = (listener, value) => {
1540
+ if (listener.length > 0) {
1541
+ listener(value);
1542
+ } else {
1543
+ listener();
1544
+ }
1545
+ };
1546
+ var notifyFlagValueListener = (listener, value) => {
1547
+ if (listener.length > 0) {
1548
+ listener(value);
1549
+ } else {
1550
+ listener();
1551
+ }
1552
+ };
1553
+
1554
+ // src/context/schematic.ts
1555
+ var import_vue = require("vue");
1556
+
1557
+ // src/version.ts
1558
+ var version2 = "0.1.0";
1559
+
1560
+ // src/context/schematic.ts
1561
+ var SchematicSymbol = Symbol("schematic");
1562
+ var SchematicPlugin = {
1563
+ install(app, options) {
1564
+ let client;
1565
+ if ("client" in options && options.client) {
1566
+ client = options.client;
1567
+ } else if ("publishableKey" in options && options.publishableKey) {
1568
+ const { publishableKey, ...clientOpts } = options;
1569
+ client = new Schematic(publishableKey, {
1570
+ useWebSocket: clientOpts.useWebSocket ?? true,
1571
+ additionalHeaders: {
1572
+ "X-Schematic-Client-Version": `schematic-vue@${version2}`
1573
+ },
1574
+ ...clientOpts
1575
+ });
1576
+ } else {
1577
+ throw new Error(
1578
+ "SchematicPlugin requires either 'publishableKey' or 'client' option"
1579
+ );
1580
+ }
1581
+ const contextValue = {
1582
+ client
1583
+ };
1584
+ app.provide(SchematicSymbol, contextValue);
1585
+ }
1586
+ };
1587
+ var useSchematic = () => {
1588
+ const context = (0, import_vue.inject)(SchematicSymbol);
1589
+ if (!context) {
1590
+ throw new Error(
1591
+ "useSchematic must be used within a component where SchematicPlugin is installed"
1592
+ );
1593
+ }
1594
+ return context;
1595
+ };
1596
+
1597
+ // src/composables/schematic.ts
1598
+ var import_vue2 = require("vue");
1599
+ var useSchematicClient = (opts) => {
1600
+ const schematic = useSchematic();
1601
+ const { client } = opts ?? {};
1602
+ return client ?? schematic.client;
1603
+ };
1604
+ var useSchematicContext = (opts) => {
1605
+ const client = useSchematicClient(opts);
1606
+ return {
1607
+ setContext: (context) => client.setContext(context)
1608
+ };
1609
+ };
1610
+ var useSchematicEvents = (opts) => {
1611
+ const client = useSchematicClient(opts);
1612
+ const track = (body) => client.track(body);
1613
+ const identify = (body) => {
1614
+ client.identify(body);
1615
+ };
1616
+ return {
1617
+ track,
1618
+ identify
1619
+ };
1620
+ };
1621
+ var useSchematicFlag = (key, opts) => {
1622
+ const client = useSchematicClient(opts);
1623
+ const fallback = opts?.fallback ?? false;
1624
+ const flagValue = (0, import_vue2.ref)(client.getFlagValue(key) ?? fallback);
1625
+ let unsubscribe = null;
1626
+ (0, import_vue2.onMounted)(() => {
1627
+ unsubscribe = client.addFlagValueListener(key, (value) => {
1628
+ flagValue.value = value;
1629
+ });
1630
+ });
1631
+ (0, import_vue2.onScopeDispose)(() => {
1632
+ unsubscribe?.();
1633
+ });
1634
+ return flagValue;
1635
+ };
1636
+ var useSchematicEntitlement = (key, opts) => {
1637
+ const client = useSchematicClient(opts);
1638
+ const fallback = opts?.fallback ?? false;
1639
+ const fallbackCheck = {
1640
+ flag: key,
1641
+ reason: "Fallback",
1642
+ value: fallback
1643
+ };
1644
+ const flagCheck = (0, import_vue2.ref)(
1645
+ client.getFlagCheck(key) ?? fallbackCheck
1646
+ );
1647
+ let unsubscribe = null;
1648
+ (0, import_vue2.onMounted)(() => {
1649
+ unsubscribe = client.addFlagCheckListener(key, (check) => {
1650
+ flagCheck.value = check;
1651
+ });
1652
+ });
1653
+ (0, import_vue2.onScopeDispose)(() => {
1654
+ unsubscribe?.();
1655
+ });
1656
+ return {
1657
+ // Full check object
1658
+ check: (0, import_vue2.computed)(() => flagCheck.value),
1659
+ // Individual properties as computed refs
1660
+ value: (0, import_vue2.computed)(() => flagCheck.value.value),
1661
+ flag: (0, import_vue2.computed)(() => flagCheck.value.flag),
1662
+ reason: (0, import_vue2.computed)(() => flagCheck.value.reason),
1663
+ featureUsage: (0, import_vue2.computed)(() => flagCheck.value.featureUsage),
1664
+ featureAllocation: (0, import_vue2.computed)(() => flagCheck.value.featureAllocation),
1665
+ featureUsageExceeded: (0, import_vue2.computed)(() => flagCheck.value.featureUsageExceeded),
1666
+ featureUsageEvent: (0, import_vue2.computed)(() => flagCheck.value.featureUsageEvent),
1667
+ featureUsagePeriod: (0, import_vue2.computed)(() => flagCheck.value.featureUsagePeriod),
1668
+ flagId: (0, import_vue2.computed)(() => flagCheck.value.flagId),
1669
+ ruleId: (0, import_vue2.computed)(() => flagCheck.value.ruleId),
1670
+ companyId: (0, import_vue2.computed)(() => flagCheck.value.companyId),
1671
+ userId: (0, import_vue2.computed)(() => flagCheck.value.userId)
1672
+ };
1673
+ };
1674
+ var useSchematicIsPending = (opts) => {
1675
+ const client = useSchematicClient(opts);
1676
+ const isPending = (0, import_vue2.ref)(client.getIsPending());
1677
+ let unsubscribe = null;
1678
+ (0, import_vue2.onMounted)(() => {
1679
+ unsubscribe = client.addIsPendingListener((value) => {
1680
+ isPending.value = value;
1681
+ });
1682
+ });
1683
+ (0, import_vue2.onScopeDispose)(() => {
1684
+ unsubscribe?.();
1685
+ });
1686
+ return isPending;
1687
+ };
1688
+ /*! Bundled license information:
1689
+
1690
+ @schematichq/schematic-js/dist/schematic.esm.js:
1691
+ (* @preserve *)
1692
+ */