@schematichq/schematic-react 1.0.3 → 1.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.
@@ -28,11 +28,12 @@ var require_browser_polyfill = __commonJS({
28
28
  "node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
29
29
  (function(self2) {
30
30
  var irrelevant = function(exports2) {
31
- var global = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || typeof global !== "undefined" && global;
31
+ var g = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || // eslint-disable-next-line no-undef
32
+ typeof global !== "undefined" && global || {};
32
33
  var support = {
33
- searchParams: "URLSearchParams" in global,
34
- iterable: "Symbol" in global && "iterator" in Symbol,
35
- blob: "FileReader" in global && "Blob" in global && function() {
34
+ searchParams: "URLSearchParams" in g,
35
+ iterable: "Symbol" in g && "iterator" in Symbol,
36
+ blob: "FileReader" in g && "Blob" in g && function() {
36
37
  try {
37
38
  new Blob();
38
39
  return true;
@@ -40,8 +41,8 @@ var require_browser_polyfill = __commonJS({
40
41
  return false;
41
42
  }
42
43
  }(),
43
- formData: "FormData" in global,
44
- arrayBuffer: "ArrayBuffer" in global
44
+ formData: "FormData" in g,
45
+ arrayBuffer: "ArrayBuffer" in g
45
46
  };
46
47
  function isDataView(obj) {
47
48
  return obj && DataView.prototype.isPrototypeOf(obj);
@@ -99,6 +100,9 @@ var require_browser_polyfill = __commonJS({
99
100
  }, this);
100
101
  } else if (Array.isArray(headers)) {
101
102
  headers.forEach(function(header) {
103
+ if (header.length != 2) {
104
+ throw new TypeError("Headers constructor: expected name/value pair to be length 2, found" + header.length);
105
+ }
102
106
  this.append(header[0], header[1]);
103
107
  }, this);
104
108
  } else if (headers) {
@@ -158,6 +162,7 @@ var require_browser_polyfill = __commonJS({
158
162
  Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
159
163
  }
160
164
  function consumed(body) {
165
+ if (body._noBody) return;
161
166
  if (body.bodyUsed) {
162
167
  return Promise.reject(new TypeError("Already read"));
163
168
  }
@@ -182,14 +187,16 @@ var require_browser_polyfill = __commonJS({
182
187
  function readBlobAsText(blob) {
183
188
  var reader = new FileReader();
184
189
  var promise = fileReaderReady(reader);
185
- reader.readAsText(blob);
190
+ var match = /charset=([A-Za-z0-9_-]+)/.exec(blob.type);
191
+ var encoding = match ? match[1] : "utf-8";
192
+ reader.readAsText(blob, encoding);
186
193
  return promise;
187
194
  }
188
195
  function readArrayBufferAsText(buf) {
189
196
  var view = new Uint8Array(buf);
190
197
  var chars = new Array(view.length);
191
- for (var i2 = 0; i2 < view.length; i2++) {
192
- chars[i2] = String.fromCharCode(view[i2]);
198
+ for (var i = 0; i < view.length; i++) {
199
+ chars[i] = String.fromCharCode(view[i]);
193
200
  }
194
201
  return chars.join("");
195
202
  }
@@ -208,6 +215,7 @@ var require_browser_polyfill = __commonJS({
208
215
  this.bodyUsed = this.bodyUsed;
209
216
  this._bodyInit = body;
210
217
  if (!body) {
218
+ this._noBody = true;
211
219
  this._bodyText = "";
212
220
  } else if (typeof body === "string") {
213
221
  this._bodyText = body;
@@ -251,27 +259,28 @@ var require_browser_polyfill = __commonJS({
251
259
  return Promise.resolve(new Blob([this._bodyText]));
252
260
  }
253
261
  };
254
- this.arrayBuffer = function() {
255
- if (this._bodyArrayBuffer) {
256
- var isConsumed = consumed(this);
257
- if (isConsumed) {
258
- return isConsumed;
259
- }
260
- if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
261
- return Promise.resolve(
262
- this._bodyArrayBuffer.buffer.slice(
263
- this._bodyArrayBuffer.byteOffset,
264
- this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength
265
- )
266
- );
267
- } else {
268
- return Promise.resolve(this._bodyArrayBuffer);
269
- }
262
+ }
263
+ this.arrayBuffer = function() {
264
+ if (this._bodyArrayBuffer) {
265
+ var isConsumed = consumed(this);
266
+ if (isConsumed) {
267
+ return isConsumed;
268
+ } else if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
269
+ return Promise.resolve(
270
+ this._bodyArrayBuffer.buffer.slice(
271
+ this._bodyArrayBuffer.byteOffset,
272
+ this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength
273
+ )
274
+ );
270
275
  } else {
271
- return this.blob().then(readBlobAsArrayBuffer);
276
+ return Promise.resolve(this._bodyArrayBuffer);
272
277
  }
273
- };
274
- }
278
+ } else if (support.blob) {
279
+ return this.blob().then(readBlobAsArrayBuffer);
280
+ } else {
281
+ throw new Error("could not read as ArrayBuffer");
282
+ }
283
+ };
275
284
  this.text = function() {
276
285
  var rejected = consumed(this);
277
286
  if (rejected) {
@@ -297,7 +306,7 @@ var require_browser_polyfill = __commonJS({
297
306
  };
298
307
  return this;
299
308
  }
300
- var methods = ["DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT"];
309
+ var methods = ["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"];
301
310
  function normalizeMethod(method) {
302
311
  var upcased = method.toUpperCase();
303
312
  return methods.indexOf(upcased) > -1 ? upcased : method;
@@ -333,7 +342,12 @@ var require_browser_polyfill = __commonJS({
333
342
  }
334
343
  this.method = normalizeMethod(options.method || this.method || "GET");
335
344
  this.mode = options.mode || this.mode || null;
336
- this.signal = options.signal || this.signal;
345
+ this.signal = options.signal || this.signal || function() {
346
+ if ("AbortController" in g) {
347
+ var ctrl = new AbortController();
348
+ return ctrl.signal;
349
+ }
350
+ }();
337
351
  this.referrer = null;
338
352
  if ((this.method === "GET" || this.method === "HEAD") && body) {
339
353
  throw new TypeError("Body not allowed for GET or HEAD requests");
@@ -376,7 +390,11 @@ var require_browser_polyfill = __commonJS({
376
390
  var key = parts.shift().trim();
377
391
  if (key) {
378
392
  var value = parts.join(":").trim();
379
- headers.append(key, value);
393
+ try {
394
+ headers.append(key, value);
395
+ } catch (error) {
396
+ console.warn("Response " + error.message);
397
+ }
380
398
  }
381
399
  });
382
400
  return headers;
@@ -391,6 +409,9 @@ var require_browser_polyfill = __commonJS({
391
409
  }
392
410
  this.type = "default";
393
411
  this.status = options.status === void 0 ? 200 : options.status;
412
+ if (this.status < 200 || this.status > 599) {
413
+ throw new RangeError("Failed to construct 'Response': The status provided (0) is outside the range [200, 599].");
414
+ }
394
415
  this.ok = this.status >= 200 && this.status < 300;
395
416
  this.statusText = options.statusText === void 0 ? "" : "" + options.statusText;
396
417
  this.headers = new Headers(options.headers);
@@ -407,7 +428,9 @@ var require_browser_polyfill = __commonJS({
407
428
  });
408
429
  };
409
430
  Response.error = function() {
410
- var response = new Response(null, { status: 0, statusText: "" });
431
+ var response = new Response(null, { status: 200, statusText: "" });
432
+ response.ok = false;
433
+ response.status = 0;
411
434
  response.type = "error";
412
435
  return response;
413
436
  };
@@ -418,7 +441,7 @@ var require_browser_polyfill = __commonJS({
418
441
  }
419
442
  return new Response(null, { status, headers: { location: url } });
420
443
  };
421
- exports2.DOMException = global.DOMException;
444
+ exports2.DOMException = g.DOMException;
422
445
  try {
423
446
  new exports2.DOMException();
424
447
  } catch (err) {
@@ -443,10 +466,14 @@ var require_browser_polyfill = __commonJS({
443
466
  }
444
467
  xhr.onload = function() {
445
468
  var options = {
446
- status: xhr.status,
447
469
  statusText: xhr.statusText,
448
470
  headers: parseHeaders(xhr.getAllResponseHeaders() || "")
449
471
  };
472
+ if (request.url.indexOf("file://") === 0 && (xhr.status < 200 || xhr.status > 599)) {
473
+ options.status = 200;
474
+ } else {
475
+ options.status = xhr.status;
476
+ }
450
477
  options.url = "responseURL" in xhr ? xhr.responseURL : options.headers.get("X-Request-URL");
451
478
  var body = "response" in xhr ? xhr.response : xhr.responseText;
452
479
  setTimeout(function() {
@@ -460,7 +487,7 @@ var require_browser_polyfill = __commonJS({
460
487
  };
461
488
  xhr.ontimeout = function() {
462
489
  setTimeout(function() {
463
- reject(new TypeError("Network request failed"));
490
+ reject(new TypeError("Network request timed out"));
464
491
  }, 0);
465
492
  };
466
493
  xhr.onabort = function() {
@@ -470,7 +497,7 @@ var require_browser_polyfill = __commonJS({
470
497
  };
471
498
  function fixUrl(url) {
472
499
  try {
473
- return url === "" && global.location.href ? global.location.href : url;
500
+ return url === "" && g.location.href ? g.location.href : url;
474
501
  } catch (e) {
475
502
  return url;
476
503
  }
@@ -484,14 +511,21 @@ var require_browser_polyfill = __commonJS({
484
511
  if ("responseType" in xhr) {
485
512
  if (support.blob) {
486
513
  xhr.responseType = "blob";
487
- } else if (support.arrayBuffer && request.headers.get("Content-Type") && request.headers.get("Content-Type").indexOf("application/octet-stream") !== -1) {
514
+ } else if (support.arrayBuffer) {
488
515
  xhr.responseType = "arraybuffer";
489
516
  }
490
517
  }
491
- if (init && typeof init.headers === "object" && !(init.headers instanceof Headers)) {
518
+ if (init && typeof init.headers === "object" && !(init.headers instanceof Headers || g.Headers && init.headers instanceof g.Headers)) {
519
+ var names = [];
492
520
  Object.getOwnPropertyNames(init.headers).forEach(function(name) {
521
+ names.push(normalizeName(name));
493
522
  xhr.setRequestHeader(name, normalizeValue(init.headers[name]));
494
523
  });
524
+ request.headers.forEach(function(value, name) {
525
+ if (names.indexOf(name) === -1) {
526
+ xhr.setRequestHeader(name, value);
527
+ }
528
+ });
495
529
  } else {
496
530
  request.headers.forEach(function(value, name) {
497
531
  xhr.setRequestHeader(name, value);
@@ -509,11 +543,11 @@ var require_browser_polyfill = __commonJS({
509
543
  });
510
544
  }
511
545
  fetch2.polyfill = true;
512
- if (!global.fetch) {
513
- global.fetch = fetch2;
514
- global.Headers = Headers;
515
- global.Request = Request;
516
- global.Response = Response;
546
+ if (!g.fetch) {
547
+ g.fetch = fetch2;
548
+ g.Headers = Headers;
549
+ g.Request = Request;
550
+ g.Response = Response;
517
551
  }
518
552
  exports2.Headers = Headers;
519
553
  exports2.Request = Request;
@@ -525,10 +559,9 @@ var require_browser_polyfill = __commonJS({
525
559
  }
526
560
  });
527
561
  var byteToHex = [];
528
- for (i = 0; i < 256; ++i) {
562
+ for (let i = 0; i < 256; ++i) {
529
563
  byteToHex.push((i + 256).toString(16).slice(1));
530
564
  }
531
- var i;
532
565
  function unsafeStringify(arr, offset = 0) {
533
566
  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();
534
567
  }
@@ -536,29 +569,33 @@ var getRandomValues;
536
569
  var rnds8 = new Uint8Array(16);
537
570
  function rng() {
538
571
  if (!getRandomValues) {
539
- getRandomValues = typeof crypto !== "undefined" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
540
- if (!getRandomValues) {
572
+ if (typeof crypto === "undefined" || !crypto.getRandomValues) {
541
573
  throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
542
574
  }
575
+ getRandomValues = crypto.getRandomValues.bind(crypto);
543
576
  }
544
577
  return getRandomValues(rnds8);
545
578
  }
546
579
  var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
547
- var native_default = {
548
- randomUUID
549
- };
580
+ var native_default = { randomUUID };
550
581
  function v4(options, buf, offset) {
551
582
  if (native_default.randomUUID && !buf && !options) {
552
583
  return native_default.randomUUID();
553
584
  }
554
585
  options = options || {};
555
- var rnds = options.random || (options.rng || rng)();
586
+ const rnds = options.random ?? options.rng?.() ?? rng();
587
+ if (rnds.length < 16) {
588
+ throw new Error("Random bytes length must be >= 16");
589
+ }
556
590
  rnds[6] = rnds[6] & 15 | 64;
557
591
  rnds[8] = rnds[8] & 63 | 128;
558
592
  if (buf) {
559
593
  offset = offset || 0;
560
- for (var i2 = 0; i2 < 16; ++i2) {
561
- buf[offset + i2] = rnds[i2];
594
+ if (offset < 0 || offset + 16 > buf.length) {
595
+ throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
596
+ }
597
+ for (let i = 0; i < 16; ++i) {
598
+ buf[offset + i] = rnds[i];
562
599
  }
563
600
  return buf;
564
601
  }
@@ -566,6 +603,117 @@ function v4(options, buf, offset) {
566
603
  }
567
604
  var v4_default = v4;
568
605
  var import_polyfill = __toESM(require_browser_polyfill());
606
+ function CheckFlagResponseDataFromJSON(json) {
607
+ return CheckFlagResponseDataFromJSONTyped(json, false);
608
+ }
609
+ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
610
+ if (json == null) {
611
+ return json;
612
+ }
613
+ return {
614
+ companyId: json["company_id"] == null ? void 0 : json["company_id"],
615
+ error: json["error"] == null ? void 0 : json["error"],
616
+ featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
617
+ featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
618
+ featureUsagePeriod: json["feature_usage_period"] == null ? void 0 : json["feature_usage_period"],
619
+ featureUsageResetAt: json["feature_usage_reset_at"] == null ? void 0 : new Date(json["feature_usage_reset_at"]),
620
+ flag: json["flag"],
621
+ flagId: json["flag_id"] == null ? void 0 : json["flag_id"],
622
+ reason: json["reason"],
623
+ ruleId: json["rule_id"] == null ? void 0 : json["rule_id"],
624
+ ruleType: json["rule_type"] == null ? void 0 : json["rule_type"],
625
+ userId: json["user_id"] == null ? void 0 : json["user_id"],
626
+ value: json["value"]
627
+ };
628
+ }
629
+ function CheckFlagResponseFromJSON(json) {
630
+ return CheckFlagResponseFromJSONTyped(json, false);
631
+ }
632
+ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
633
+ if (json == null) {
634
+ return json;
635
+ }
636
+ return {
637
+ data: CheckFlagResponseDataFromJSON(json["data"]),
638
+ params: json["params"]
639
+ };
640
+ }
641
+ function CheckFlagsResponseDataFromJSON(json) {
642
+ return CheckFlagsResponseDataFromJSONTyped(json, false);
643
+ }
644
+ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
645
+ if (json == null) {
646
+ return json;
647
+ }
648
+ return {
649
+ flags: json["flags"].map(CheckFlagResponseDataFromJSON)
650
+ };
651
+ }
652
+ function CheckFlagsResponseFromJSON(json) {
653
+ return CheckFlagsResponseFromJSONTyped(json, false);
654
+ }
655
+ function CheckFlagsResponseFromJSONTyped(json, ignoreDiscriminator) {
656
+ if (json == null) {
657
+ return json;
658
+ }
659
+ return {
660
+ data: CheckFlagsResponseDataFromJSON(json["data"]),
661
+ params: json["params"]
662
+ };
663
+ }
664
+ var RuleType = /* @__PURE__ */ ((RuleType2) => {
665
+ RuleType2["GLOBAL_OVERRIDE"] = "global_override";
666
+ RuleType2["COMPANY_OVERRIDE"] = "company_override";
667
+ RuleType2["COMPANY_OVERRIDE_USAGE_EXCEEDED"] = "company_override_usage_exceeded";
668
+ RuleType2["PLAN_ENTITLEMENT"] = "plan_entitlement";
669
+ RuleType2["PLAN_ENTITLEMENT_USAGE_EXCEEDED"] = "plan_entitlement_usage_exceeded";
670
+ RuleType2["STANDARD"] = "standard";
671
+ RuleType2["DEFAULT"] = "default";
672
+ return RuleType2;
673
+ })(RuleType || {});
674
+ var UsagePeriod = /* @__PURE__ */ ((UsagePeriod2) => {
675
+ UsagePeriod2["ALL_TIME"] = "all_time";
676
+ UsagePeriod2["CURRENT_DAY"] = "current_day";
677
+ UsagePeriod2["CURRENT_MONTH"] = "current_month";
678
+ UsagePeriod2["CURRENT_WEEK"] = "current_week";
679
+ return UsagePeriod2;
680
+ })(UsagePeriod || {});
681
+ var CheckFlagReturnFromJSON = (json) => {
682
+ const {
683
+ companyId,
684
+ error,
685
+ featureAllocation,
686
+ featureUsage,
687
+ featureUsagePeriod,
688
+ featureUsageResetAt,
689
+ flag,
690
+ flagId,
691
+ reason,
692
+ ruleId,
693
+ ruleType,
694
+ userId,
695
+ value
696
+ } = CheckFlagResponseDataFromJSON(json);
697
+ const featureUsageExceeded = !value && // if flag is not false, then we haven't exceeded usage
698
+ (ruleType == "company_override_usage_exceeded" || // if the rule type is one of these, then we have exceeded usage
699
+ ruleType == "plan_entitlement_usage_exceeded");
700
+ return {
701
+ featureUsageExceeded,
702
+ companyId: companyId == null ? void 0 : companyId,
703
+ error: error == null ? void 0 : error,
704
+ featureAllocation: featureAllocation == null ? void 0 : featureAllocation,
705
+ featureUsage: featureUsage == null ? void 0 : featureUsage,
706
+ featureUsagePeriod: featureUsagePeriod == null ? void 0 : featureUsagePeriod,
707
+ featureUsageResetAt: featureUsageResetAt == null ? void 0 : featureUsageResetAt,
708
+ flag,
709
+ flagId: flagId == null ? void 0 : flagId,
710
+ reason,
711
+ ruleId: ruleId == null ? void 0 : ruleId,
712
+ ruleType: ruleType == null ? void 0 : ruleType,
713
+ userId: userId == null ? void 0 : userId,
714
+ value
715
+ };
716
+ };
569
717
  function contextString(context) {
570
718
  const sortedContext = Object.keys(context).reduce((acc, key) => {
571
719
  const sortedKeys = Object.keys(
@@ -589,19 +737,18 @@ var Schematic = class {
589
737
  context = {};
590
738
  eventQueue;
591
739
  eventUrl = "https://c.schematichq.com";
592
- flagListener;
740
+ flagCheckListeners = {};
593
741
  flagValueListeners = {};
594
742
  isPending = true;
595
743
  isPendingListeners = /* @__PURE__ */ new Set();
596
744
  storage;
597
745
  useWebSocket = false;
598
- values = {};
746
+ checks = {};
599
747
  webSocketUrl = "wss://api.schematichq.com";
600
748
  constructor(apiKey, options) {
601
749
  this.apiKey = apiKey;
602
750
  this.eventQueue = [];
603
751
  this.useWebSocket = options?.useWebSocket ?? false;
604
- this.flagListener = options?.flagListener;
605
752
  if (options?.additionalHeaders) {
606
753
  this.additionalHeaders = options.additionalHeaders;
607
754
  }
@@ -651,17 +798,17 @@ var Schematic = class {
651
798
  throw new Error("Network response was not ok");
652
799
  }
653
800
  return response.json();
654
- }).then((data) => {
655
- return data.data.value;
801
+ }).then((response) => {
802
+ return CheckFlagResponseFromJSON(response).data.value;
656
803
  }).catch((error) => {
657
804
  console.error("There was a problem with the fetch operation:", error);
658
805
  return fallback;
659
806
  });
660
807
  }
661
808
  try {
662
- const existingVals = this.values[contextStr];
809
+ const existingVals = this.checks[contextStr];
663
810
  if (this.conn && typeof existingVals !== "undefined" && typeof existingVals[key] !== "undefined") {
664
- return existingVals[key];
811
+ return existingVals[key].value;
665
812
  }
666
813
  try {
667
814
  await this.setContext(context);
@@ -672,8 +819,8 @@ var Schematic = class {
672
819
  );
673
820
  return this.fallbackToRest(key, context, fallback);
674
821
  }
675
- const contextVals = this.values[contextStr] ?? {};
676
- return typeof contextVals[key] === "undefined" ? fallback : contextVals[key];
822
+ const contextVals = this.checks[contextStr] ?? {};
823
+ return contextVals[key]?.value ?? fallback;
677
824
  } catch (error) {
678
825
  console.error("Unexpected error in checkFlag:", error);
679
826
  return fallback;
@@ -697,8 +844,8 @@ var Schematic = class {
697
844
  if (!response.ok) {
698
845
  throw new Error("Network response was not ok");
699
846
  }
700
- const data = await response.json();
701
- return data.data.value;
847
+ const data = CheckFlagResponseFromJSON(await response.json());
848
+ return data?.data?.value ?? false;
702
849
  } catch (error) {
703
850
  console.error("REST API call failed, using fallback value:", error);
704
851
  return fallback;
@@ -725,8 +872,9 @@ var Schematic = class {
725
872
  throw new Error("Network response was not ok");
726
873
  }
727
874
  return response.json();
728
- }).then((data) => {
729
- return (data?.data?.flags ?? []).reduce(
875
+ }).then((responseJson) => {
876
+ const resp = CheckFlagsResponseFromJSON(responseJson);
877
+ return (resp?.data?.flags ?? []).reduce(
730
878
  (accum, flag) => {
731
879
  accum[flag.flag] = flag.value;
732
880
  return accum;
@@ -735,7 +883,7 @@ var Schematic = class {
735
883
  );
736
884
  }).catch((error) => {
737
885
  console.error("There was a problem with the fetch operation:", error);
738
- return false;
886
+ return {};
739
887
  });
740
888
  };
741
889
  /**
@@ -897,18 +1045,15 @@ var Schematic = class {
897
1045
  let resolved = false;
898
1046
  const messageHandler = (event) => {
899
1047
  const message = JSON.parse(event.data);
900
- if (!(contextString(context) in this.values)) {
901
- this.values[contextString(context)] = {};
902
- }
903
- (message.flags ?? []).forEach(
904
- (flag) => {
905
- this.values[contextString(context)][flag.flag] = flag.value;
906
- this.notifyFlagValueListeners(flag.flag, flag.value);
907
- }
908
- );
909
- if (this.flagListener) {
910
- this.flagListener(this.getFlagValues());
1048
+ if (!(contextString(context) in this.checks)) {
1049
+ this.checks[contextString(context)] = {};
911
1050
  }
1051
+ (message.flags ?? []).forEach((flag) => {
1052
+ const flagCheck = CheckFlagReturnFromJSON(flag);
1053
+ this.checks[contextString(context)][flagCheck.flag] = flagCheck;
1054
+ this.notifyFlagCheckListeners(flag.flag, flagCheck);
1055
+ this.notifyFlagValueListeners(flag.flag, flagCheck.value);
1056
+ });
912
1057
  this.setIsPending(false);
913
1058
  if (!resolved) {
914
1059
  resolved = true;
@@ -948,18 +1093,21 @@ var Schematic = class {
948
1093
  setIsPending = (isPending) => {
949
1094
  this.isPending = isPending;
950
1095
  this.isPendingListeners.forEach(
951
- (listener) => notifyListener(listener, isPending)
1096
+ (listener) => notifyPendingListener(listener, isPending)
952
1097
  );
953
1098
  };
1099
+ // flag checks state
1100
+ getFlagCheck = (flagKey) => {
1101
+ const contextStr = contextString(this.context);
1102
+ const checks = this.checks[contextStr] ?? {};
1103
+ return checks[flagKey];
1104
+ };
954
1105
  // flagValues state
955
1106
  getFlagValue = (flagKey) => {
956
- const values = this.getFlagValues();
957
- return values[flagKey];
958
- };
959
- getFlagValues = () => {
960
- const contextStr = contextString(this.context);
961
- return this.values[contextStr] ?? {};
1107
+ const check = this.getFlagCheck(flagKey);
1108
+ return check?.value;
962
1109
  };
1110
+ /** Register an event listener that will be notified with the boolean value for a given flag when this value changes */
963
1111
  addFlagValueListener = (flagKey, listener) => {
964
1112
  if (!(flagKey in this.flagValueListeners)) {
965
1113
  this.flagValueListeners[flagKey] = /* @__PURE__ */ new Set();
@@ -969,12 +1117,40 @@ var Schematic = class {
969
1117
  this.flagValueListeners[flagKey].delete(listener);
970
1118
  };
971
1119
  };
1120
+ /** Register an event listener that will be notified with the full flag check response for a given flag whenever this value changes */
1121
+ addFlagCheckListener = (flagKey, listener) => {
1122
+ if (!(flagKey in this.flagCheckListeners)) {
1123
+ this.flagCheckListeners[flagKey] = /* @__PURE__ */ new Set();
1124
+ }
1125
+ this.flagCheckListeners[flagKey].add(listener);
1126
+ return () => {
1127
+ this.flagCheckListeners[flagKey].delete(listener);
1128
+ };
1129
+ };
1130
+ notifyFlagCheckListeners = (flagKey, check) => {
1131
+ const listeners = this.flagCheckListeners?.[flagKey] ?? [];
1132
+ listeners.forEach((listener) => notifyFlagCheckListener(listener, check));
1133
+ };
972
1134
  notifyFlagValueListeners = (flagKey, value) => {
973
1135
  const listeners = this.flagValueListeners?.[flagKey] ?? [];
974
- listeners.forEach((listener) => notifyListener(listener, value));
1136
+ listeners.forEach((listener) => notifyFlagValueListener(listener, value));
975
1137
  };
976
1138
  };
977
- var notifyListener = (listener, value) => {
1139
+ var notifyPendingListener = (listener, value) => {
1140
+ if (listener.length > 0) {
1141
+ listener(value);
1142
+ } else {
1143
+ listener();
1144
+ }
1145
+ };
1146
+ var notifyFlagCheckListener = (listener, value) => {
1147
+ if (listener.length > 0) {
1148
+ listener(value);
1149
+ } else {
1150
+ listener();
1151
+ }
1152
+ };
1153
+ var notifyFlagValueListener = (listener, value) => {
978
1154
  if (listener.length > 0) {
979
1155
  listener(value);
980
1156
  } else {
@@ -1078,6 +1254,27 @@ var useSchematicFlag = (key, opts) => {
1078
1254
  }, [client, key, fallback]);
1079
1255
  return useSyncExternalStore(subscribe, getSnapshot);
1080
1256
  };
1257
+ var useSchematicEntitlement = (key, opts) => {
1258
+ const client = useSchematicClient(opts);
1259
+ const fallback = opts?.fallback ?? false;
1260
+ const fallbackCheck = useMemo2(
1261
+ () => ({
1262
+ flag: key,
1263
+ reason: "Fallback",
1264
+ value: fallback
1265
+ }),
1266
+ [key, fallback]
1267
+ );
1268
+ const subscribe = useCallback(
1269
+ (callback) => client.addFlagCheckListener(key, callback),
1270
+ [client, key]
1271
+ );
1272
+ const getSnapshot = useCallback(() => {
1273
+ const check = client.getFlagCheck(key);
1274
+ return check ?? fallbackCheck;
1275
+ }, [client, key, fallbackCheck]);
1276
+ return useSyncExternalStore(subscribe, getSnapshot);
1277
+ };
1081
1278
  var useSchematicIsPending = (opts) => {
1082
1279
  const client = useSchematicClient(opts);
1083
1280
  const subscribe = useCallback(
@@ -1088,10 +1285,13 @@ var useSchematicIsPending = (opts) => {
1088
1285
  return useSyncExternalStore(subscribe, getSnapshot);
1089
1286
  };
1090
1287
  export {
1288
+ RuleType,
1091
1289
  Schematic,
1092
1290
  SchematicProvider,
1291
+ UsagePeriod,
1093
1292
  useSchematic,
1094
1293
  useSchematicContext,
1294
+ useSchematicEntitlement,
1095
1295
  useSchematicEvents,
1096
1296
  useSchematicFlag,
1097
1297
  useSchematicIsPending
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schematichq/schematic-react",
3
- "version": "1.0.3",
3
+ "version": "1.1.1",
4
4
  "main": "dist/schematic-react.cjs.js",
5
5
  "module": "dist/schematic-react.esm.js",
6
6
  "types": "dist/schematic-react.d.ts",
@@ -28,7 +28,7 @@
28
28
  "tsc": "npx tsc"
29
29
  },
30
30
  "dependencies": {
31
- "@schematichq/schematic-js": "^1.0.2"
31
+ "@schematichq/schematic-js": "^1.1.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@microsoft/api-extractor": "^7.47.9",