@wireai/activation 0.13.0 → 0.13.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.
Files changed (82) hide show
  1. package/AGENTS.md +7 -4
  2. package/CHANGELOG.md +341 -4
  3. package/README.md +98 -2
  4. package/dist/analytics/index.d.mts +4 -4
  5. package/dist/analytics/index.d.ts +4 -4
  6. package/dist/analytics/index.js +164 -471
  7. package/dist/analytics/index.js.map +1 -1
  8. package/dist/analytics/index.mjs +162 -469
  9. package/dist/analytics/index.mjs.map +1 -1
  10. package/dist/coachmarks/index.d.mts +14 -1
  11. package/dist/coachmarks/index.d.ts +14 -1
  12. package/dist/coachmarks/index.js +58 -14
  13. package/dist/coachmarks/index.js.map +1 -1
  14. package/dist/coachmarks/index.mjs +58 -14
  15. package/dist/coachmarks/index.mjs.map +1 -1
  16. package/dist/{currentSession-_GynvhzT.d.mts → currentSession-BoWtr3Jp.d.mts} +299 -14
  17. package/dist/{currentSession-D7zabMXK.d.ts → currentSession-CCOMlaQ2.d.ts} +299 -14
  18. package/dist/{decision-Bl_M2y3r.d.mts → decision-Cjw0jbEj.d.mts} +1 -1
  19. package/dist/{decision-Cau5KmP6.d.ts → decision-GfpXAsk_.d.ts} +1 -1
  20. package/dist/index.d.mts +218 -4
  21. package/dist/index.d.ts +218 -4
  22. package/dist/index.js +1104 -888
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.mjs +887 -692
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/questionnaire/index.d.mts +42 -10
  27. package/dist/questionnaire/index.d.ts +42 -10
  28. package/dist/questionnaire/index.js +45 -13
  29. package/dist/questionnaire/index.js.map +1 -1
  30. package/dist/questionnaire/index.mjs +45 -13
  31. package/dist/questionnaire/index.mjs.map +1 -1
  32. package/dist/reviews/index.d.mts +4 -4
  33. package/dist/reviews/index.d.ts +4 -4
  34. package/dist/reviews/index.js +39 -8
  35. package/dist/reviews/index.js.map +1 -1
  36. package/dist/reviews/index.mjs +39 -8
  37. package/dist/reviews/index.mjs.map +1 -1
  38. package/dist/showcase/index.js +7 -2
  39. package/dist/showcase/index.js.map +1 -1
  40. package/dist/showcase/index.mjs +7 -2
  41. package/dist/showcase/index.mjs.map +1 -1
  42. package/dist/{transport-DsRe4epC.d.ts → transport-CefdERPs.d.mts} +44 -5
  43. package/dist/{transport-CF_eHwzC.d.mts → transport-DFuPyCoJ.d.ts} +44 -5
  44. package/dist/{types-Buj9Lw9t.d.ts → types-UVYt9BJe.d.ts} +41 -1
  45. package/dist/{types-CNUqMK0D.d.mts → types-l2tfg23P.d.mts} +41 -1
  46. package/package.json +4 -1
  47. package/src/OnboardingFlow.tsx +175 -15
  48. package/src/WireOnboarding.tsx +70 -8
  49. package/src/activation/wireActivation.ts +3 -3
  50. package/src/analytics/analyticsEvent.ts +16 -1
  51. package/src/analytics/analyticsFacade.ts +2 -2
  52. package/src/analytics/eventQueue.ts +85 -20
  53. package/src/analytics/reportClientEvent.ts +68 -12
  54. package/src/cards/CardGridSelectCard.tsx +1 -1
  55. package/src/cards/ChipSelectCard.tsx +2 -2
  56. package/src/cards/PermissionCard.tsx +438 -0
  57. package/src/cards/SelectionCard.tsx +1 -1
  58. package/src/cards/index.ts +7 -0
  59. package/src/coachmarks/runtime.ts +62 -2
  60. package/src/coachmarks/useCoachmarkTour.ts +62 -14
  61. package/src/context/deviceId.ts +4 -4
  62. package/src/features/WireFeaturesProvider.tsx +4 -1
  63. package/src/identity/userIdentity.ts +1 -1
  64. package/src/illustrations/defaultIllustrations.tsx +44 -3
  65. package/src/index.ts +38 -0
  66. package/src/permissions/index.ts +64 -0
  67. package/src/permissions/permissionCopy.ts +87 -0
  68. package/src/permissions/permissionEvents.ts +76 -0
  69. package/src/permissions/permissionMemory.ts +88 -0
  70. package/src/permissions/placement.ts +88 -0
  71. package/src/permissions/types.ts +131 -0
  72. package/src/questionnaire/QuestionnaireGate.tsx +90 -10
  73. package/src/questionnaire/index.ts +9 -1
  74. package/src/questionnaire/transport.ts +46 -11
  75. package/src/reviews/ReviewGate.tsx +61 -6
  76. package/src/reviews/index.ts +10 -1
  77. package/src/reviews/transport.ts +58 -12
  78. package/src/session/persistedSession.ts +10 -3
  79. package/src/session-analytics/useLifecycleEvents.ts +1 -1
  80. package/src/theme/ThemeContext.tsx +42 -1
  81. package/src/types.ts +66 -4
  82. package/src/utils/submitResult.ts +39 -0
@@ -2,8 +2,8 @@ import React__default from 'react';
2
2
  import { O as OnboardingTheme } from '../types-BKfpdZzX.mjs';
3
3
  import { C as CoachmarkStorage } from '../types-BcmagF6K.mjs';
4
4
  import { W as WireFeatures, a as WireFeaturesConfig } from '../types-CKFhyrMu.mjs';
5
- export { G as GateRules, a as GateSignals, e as evaluateGate, r as resolveRules } from '../decision-Bl_M2y3r.mjs';
6
- import '../types-CNUqMK0D.mjs';
5
+ import { S as SubmitResult } from '../types-l2tfg23P.mjs';
6
+ export { G as GateRules, a as GateSignals, e as evaluateGate, r as resolveRules } from '../decision-Cjw0jbEj.mjs';
7
7
 
8
8
  /**
9
9
  * The firing verdict - the SAME contract on both sides of the seam. `decideQuestionnaire`
@@ -208,8 +208,10 @@ interface QuestionnaireGateController {
208
208
  * step is simply an empty answer, which is what the builder already handled.
209
209
  *
210
210
  * ⚠️ This gate now REQUIRES the server to accept an empty `answers.opinion` - step 1 is
211
- * skippable and the live endpoint still 422s a blank opinion, silently (the transport is
212
- * fire-and-forget). See the REQUIRED_STEPS note in steps.ts. Server fix, not a client one.
211
+ * skippable and the live endpoint still 422s a blank opinion. The 422 is read (the transport
212
+ * resolves `"rejected"`) but deliberately not retried the server ANSWERED, so re-posting could
213
+ * duplicate the row. The user still sees the thank-you either way. See the REQUIRED_STEPS note in
214
+ * steps.ts. Server fix, not a client one.
213
215
  *
214
216
  * Motion: `ModalPaneHost` slides step→step (and mirrors the slide on Back) and resizes the
215
217
  * card; `StepDots` fills; `DoneCheck` plays the submit payoff. All shared, all reduce-motion
@@ -245,9 +247,9 @@ declare const buildQuestionnaireSubmission: (input: {
245
247
  }) => QuestionnaireSubmission;
246
248
 
247
249
  /**
248
- * transport.ts - kit → Wire server requests for the questionnaire module, all fire-and-forget
250
+ * transport.ts - kit → Wire server requests for the questionnaire module, never throwing
249
251
  * (a pre-onboarding questionnaire must NEVER break the app). Mirrors `submitReview`: a thin
250
- * fetch wrapper, Bearer tenant key, swallow every error.
252
+ * fetch wrapper, Bearer tenant key, and since 0.13.3 — the SAME three-outcome delivery ack.
251
253
  *
252
254
  * • submitQuestionnaireResponse → POST {serverUrl}/v1/questionnaires/{id}/responses
253
255
  * • fetchQuestionnaireDecision → GET {serverUrl}/v1/questionnaires/decision (best-effort)
@@ -258,10 +260,40 @@ declare const buildQuestionnaireSubmission: (input: {
258
260
  */
259
261
 
260
262
  /**
261
- * POST a questionnaire response. Fire-and-forget: a missing target, a missing id, a build
262
- * error, a missing `fetch`, or a network failure is swallowed and the call returns immediately.
263
+ * What became of a questionnaire POST. The SHARED verdict identical values, identical meaning,
264
+ * identical retry rule as `ReviewSubmitResult`. The reasoning lives once, in `utils/submitResult.ts`.
263
265
  */
264
- declare const submitQuestionnaireResponse: (target: QuestionnaireTarget | undefined, id: string, submission: QuestionnaireSubmission) => void;
266
+ type QuestionnaireSubmitResult = SubmitResult;
267
+ /**
268
+ * POST a questionnaire response.
269
+ *
270
+ * NON-BLOCKING, and ACKED. It never throws and never makes a caller wait — the request is fired
271
+ * synchronously and the UI is free to advance on the next line — but it RESOLVES with what became
272
+ * of the response.
273
+ *
274
+ * ── WHY THE RETURN VALUE EXISTS (this used to be `void`) ─────────────────────────────────────
275
+ *
276
+ * The body was `void fetch(...).catch(() => {})`: the response was never read, so the caller could
277
+ * not tell a delivered submission from one that died in the socket. `QuestionnaireGate.finish`
278
+ * therefore latched the run as submitted unconditionally and resolved the gate, and `onResolved` →
279
+ * `markResolved` writes the PERMANENT `wire_questionnaire_<id>_<ver>_seen` key. A user who answered
280
+ * offline was never asked again and their answers were gone — the exact failure 0.13.3's
281
+ * `submitReview` fix was written for ("a detractor who rated offline was dropped AND never asked
282
+ * again"), on the one surface that both burns a permanent once-gate and had zero evidence of
283
+ * delivery. This is the twin of that fix.
284
+ *
285
+ * ── ONLY `unsent` MAY BE RETRIED ─────────────────────────────────────────────────────────────
286
+ *
287
+ * The same rule as reviews, for the same reason: the server mints the response id and the body
288
+ * carries no client id, so there is no idempotency key on the wire. A non-2xx proves the server was
289
+ * REACHED — a gateway 502 after the insert commits is indistinguishable from a refusal — so
290
+ * re-posting on it writes a SECOND response row. See `utils/submitResult.ts` for the full split and
291
+ * the honest residual.
292
+ *
293
+ * A missing target or a missing id resolves `"unsent"` with no request at all: nothing reached a
294
+ * server, which is exactly what a caller must be told before it decides the answers are delivered.
295
+ */
296
+ declare const submitQuestionnaireResponse: (target: QuestionnaireTarget | undefined, id: string, submission: QuestionnaireSubmission) => Promise<QuestionnaireSubmitResult>;
265
297
  /** Options for the best-effort decision fetch. `deviceKey` groups a device's sessions server-side. */
266
298
  interface FetchQuestionnaireDecisionOptions {
267
299
  /** The onboarding/session id to correlate with, when known. */
@@ -293,4 +325,4 @@ declare const questionnaireLastShownKey: (id: string) => string;
293
325
  /** Session-count key, incremented once per APP-OPEN (not per mount), for the min-sessions rule. */
294
326
  declare const questionnaireSessionsKey: (id: string) => string;
295
327
 
296
- export { type FetchQuestionnaireDecisionOptions, type QuestionnaireAnswers, type QuestionnaireDecision, type QuestionnaireDecisionResponse, type QuestionnaireDefinition, QuestionnaireGate, type QuestionnaireGateController, type QuestionnaireGateEvent, type QuestionnaireGateEventName, type QuestionnaireGateProps, type QuestionnaireMeta, type QuestionnaireSubmission, type QuestionnaireTarget, type UseQuestionnaireGateOptions, buildQuestionnaireSubmission, decideQuestionnaire, fetchQuestionnaireDecision, questionnaireLastShownKey, questionnaireSeenKey, questionnaireSessionsKey, submitQuestionnaireResponse, useQuestionnaireGate };
328
+ export { type FetchQuestionnaireDecisionOptions, type QuestionnaireAnswers, type QuestionnaireDecision, type QuestionnaireDecisionResponse, type QuestionnaireDefinition, QuestionnaireGate, type QuestionnaireGateController, type QuestionnaireGateEvent, type QuestionnaireGateEventName, type QuestionnaireGateProps, type QuestionnaireMeta, type QuestionnaireSubmission, type QuestionnaireSubmitResult, type QuestionnaireTarget, SubmitResult, type UseQuestionnaireGateOptions, buildQuestionnaireSubmission, decideQuestionnaire, fetchQuestionnaireDecision, questionnaireLastShownKey, questionnaireSeenKey, questionnaireSessionsKey, submitQuestionnaireResponse, useQuestionnaireGate };
@@ -2,8 +2,8 @@ import React__default from 'react';
2
2
  import { O as OnboardingTheme } from '../types-BKfpdZzX.js';
3
3
  import { C as CoachmarkStorage } from '../types-BcmagF6K.js';
4
4
  import { W as WireFeatures, a as WireFeaturesConfig } from '../types-CKFhyrMu.js';
5
- export { G as GateRules, a as GateSignals, e as evaluateGate, r as resolveRules } from '../decision-Cau5KmP6.js';
6
- import '../types-Buj9Lw9t.js';
5
+ import { S as SubmitResult } from '../types-UVYt9BJe.js';
6
+ export { G as GateRules, a as GateSignals, e as evaluateGate, r as resolveRules } from '../decision-GfpXAsk_.js';
7
7
 
8
8
  /**
9
9
  * The firing verdict - the SAME contract on both sides of the seam. `decideQuestionnaire`
@@ -208,8 +208,10 @@ interface QuestionnaireGateController {
208
208
  * step is simply an empty answer, which is what the builder already handled.
209
209
  *
210
210
  * ⚠️ This gate now REQUIRES the server to accept an empty `answers.opinion` - step 1 is
211
- * skippable and the live endpoint still 422s a blank opinion, silently (the transport is
212
- * fire-and-forget). See the REQUIRED_STEPS note in steps.ts. Server fix, not a client one.
211
+ * skippable and the live endpoint still 422s a blank opinion. The 422 is read (the transport
212
+ * resolves `"rejected"`) but deliberately not retried the server ANSWERED, so re-posting could
213
+ * duplicate the row. The user still sees the thank-you either way. See the REQUIRED_STEPS note in
214
+ * steps.ts. Server fix, not a client one.
213
215
  *
214
216
  * Motion: `ModalPaneHost` slides step→step (and mirrors the slide on Back) and resizes the
215
217
  * card; `StepDots` fills; `DoneCheck` plays the submit payoff. All shared, all reduce-motion
@@ -245,9 +247,9 @@ declare const buildQuestionnaireSubmission: (input: {
245
247
  }) => QuestionnaireSubmission;
246
248
 
247
249
  /**
248
- * transport.ts - kit → Wire server requests for the questionnaire module, all fire-and-forget
250
+ * transport.ts - kit → Wire server requests for the questionnaire module, never throwing
249
251
  * (a pre-onboarding questionnaire must NEVER break the app). Mirrors `submitReview`: a thin
250
- * fetch wrapper, Bearer tenant key, swallow every error.
252
+ * fetch wrapper, Bearer tenant key, and since 0.13.3 — the SAME three-outcome delivery ack.
251
253
  *
252
254
  * • submitQuestionnaireResponse → POST {serverUrl}/v1/questionnaires/{id}/responses
253
255
  * • fetchQuestionnaireDecision → GET {serverUrl}/v1/questionnaires/decision (best-effort)
@@ -258,10 +260,40 @@ declare const buildQuestionnaireSubmission: (input: {
258
260
  */
259
261
 
260
262
  /**
261
- * POST a questionnaire response. Fire-and-forget: a missing target, a missing id, a build
262
- * error, a missing `fetch`, or a network failure is swallowed and the call returns immediately.
263
+ * What became of a questionnaire POST. The SHARED verdict identical values, identical meaning,
264
+ * identical retry rule as `ReviewSubmitResult`. The reasoning lives once, in `utils/submitResult.ts`.
263
265
  */
264
- declare const submitQuestionnaireResponse: (target: QuestionnaireTarget | undefined, id: string, submission: QuestionnaireSubmission) => void;
266
+ type QuestionnaireSubmitResult = SubmitResult;
267
+ /**
268
+ * POST a questionnaire response.
269
+ *
270
+ * NON-BLOCKING, and ACKED. It never throws and never makes a caller wait — the request is fired
271
+ * synchronously and the UI is free to advance on the next line — but it RESOLVES with what became
272
+ * of the response.
273
+ *
274
+ * ── WHY THE RETURN VALUE EXISTS (this used to be `void`) ─────────────────────────────────────
275
+ *
276
+ * The body was `void fetch(...).catch(() => {})`: the response was never read, so the caller could
277
+ * not tell a delivered submission from one that died in the socket. `QuestionnaireGate.finish`
278
+ * therefore latched the run as submitted unconditionally and resolved the gate, and `onResolved` →
279
+ * `markResolved` writes the PERMANENT `wire_questionnaire_<id>_<ver>_seen` key. A user who answered
280
+ * offline was never asked again and their answers were gone — the exact failure 0.13.3's
281
+ * `submitReview` fix was written for ("a detractor who rated offline was dropped AND never asked
282
+ * again"), on the one surface that both burns a permanent once-gate and had zero evidence of
283
+ * delivery. This is the twin of that fix.
284
+ *
285
+ * ── ONLY `unsent` MAY BE RETRIED ─────────────────────────────────────────────────────────────
286
+ *
287
+ * The same rule as reviews, for the same reason: the server mints the response id and the body
288
+ * carries no client id, so there is no idempotency key on the wire. A non-2xx proves the server was
289
+ * REACHED — a gateway 502 after the insert commits is indistinguishable from a refusal — so
290
+ * re-posting on it writes a SECOND response row. See `utils/submitResult.ts` for the full split and
291
+ * the honest residual.
292
+ *
293
+ * A missing target or a missing id resolves `"unsent"` with no request at all: nothing reached a
294
+ * server, which is exactly what a caller must be told before it decides the answers are delivered.
295
+ */
296
+ declare const submitQuestionnaireResponse: (target: QuestionnaireTarget | undefined, id: string, submission: QuestionnaireSubmission) => Promise<QuestionnaireSubmitResult>;
265
297
  /** Options for the best-effort decision fetch. `deviceKey` groups a device's sessions server-side. */
266
298
  interface FetchQuestionnaireDecisionOptions {
267
299
  /** The onboarding/session id to correlate with, when known. */
@@ -293,4 +325,4 @@ declare const questionnaireLastShownKey: (id: string) => string;
293
325
  /** Session-count key, incremented once per APP-OPEN (not per mount), for the min-sessions rule. */
294
326
  declare const questionnaireSessionsKey: (id: string) => string;
295
327
 
296
- export { type FetchQuestionnaireDecisionOptions, type QuestionnaireAnswers, type QuestionnaireDecision, type QuestionnaireDecisionResponse, type QuestionnaireDefinition, QuestionnaireGate, type QuestionnaireGateController, type QuestionnaireGateEvent, type QuestionnaireGateEventName, type QuestionnaireGateProps, type QuestionnaireMeta, type QuestionnaireSubmission, type QuestionnaireTarget, type UseQuestionnaireGateOptions, buildQuestionnaireSubmission, decideQuestionnaire, fetchQuestionnaireDecision, questionnaireLastShownKey, questionnaireSeenKey, questionnaireSessionsKey, submitQuestionnaireResponse, useQuestionnaireGate };
328
+ export { type FetchQuestionnaireDecisionOptions, type QuestionnaireAnswers, type QuestionnaireDecision, type QuestionnaireDecisionResponse, type QuestionnaireDefinition, QuestionnaireGate, type QuestionnaireGateController, type QuestionnaireGateEvent, type QuestionnaireGateEventName, type QuestionnaireGateProps, type QuestionnaireMeta, type QuestionnaireSubmission, type QuestionnaireSubmitResult, type QuestionnaireTarget, SubmitResult, type UseQuestionnaireGateOptions, buildQuestionnaireSubmission, decideQuestionnaire, fetchQuestionnaireDecision, questionnaireLastShownKey, questionnaireSeenKey, questionnaireSessionsKey, submitQuestionnaireResponse, useQuestionnaireGate };
@@ -60,7 +60,12 @@ var defaultOnboardingTheme = {
60
60
  var mergeTheme = (override) => {
61
61
  return defaultOnboardingTheme;
62
62
  };
63
- var OnboardingThemeContext = React8.createContext(null);
63
+ var THEME_CONTEXT_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:themeContext");
64
+ var themeGlobal = globalThis;
65
+ if (!themeGlobal[THEME_CONTEXT_SLOT]) {
66
+ themeGlobal[THEME_CONTEXT_SLOT] = React8.createContext(null);
67
+ }
68
+ var OnboardingThemeContext = themeGlobal[THEME_CONTEXT_SLOT];
64
69
  var useOnboardingTheme = () => {
65
70
  const ctx = React8.useContext(OnboardingThemeContext);
66
71
  return ctx != null ? ctx : mergeTheme();
@@ -839,20 +844,22 @@ var toAnswers = (drafts) => {
839
844
  };
840
845
 
841
846
  // src/questionnaire/transport.ts
842
- var submitQuestionnaireResponse = (target, id, submission) => {
843
- if (!(target == null ? void 0 : target.serverUrl) || !id) return;
847
+ var submitQuestionnaireResponse = async (target, id, submission) => {
848
+ if (!(target == null ? void 0 : target.serverUrl) || !id) return "unsent";
844
849
  try {
845
850
  const base = target.serverUrl.replace(/\/$/, "");
846
851
  const url = `${base}/v1/questionnaires/${encodeURIComponent(id)}/responses`;
847
852
  const headers = { "Content-Type": "application/json" };
848
853
  if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;
849
- void fetch(url, {
854
+ const res = await fetch(url, {
850
855
  method: "POST",
851
856
  headers,
852
857
  body: JSON.stringify(submission)
853
- }).catch(() => {
854
858
  });
859
+ if (!res) return "unsent";
860
+ return res.ok ? "accepted" : "rejected";
855
861
  } catch {
862
+ return "unsent";
856
863
  }
857
864
  };
858
865
  var fetchQuestionnaireDecision = async (target, options = {}) => {
@@ -945,14 +952,39 @@ var _QuestionnaireGate = ({
945
952
  }
946
953
  onResolved == null ? void 0 : onResolved();
947
954
  }, [id, onResolved]);
955
+ const postedRef = React8.useRef(false);
956
+ const unackedRef = React8.useRef(null);
957
+ const postOnce = React8.useCallback(
958
+ (body) => {
959
+ if (postedRef.current) return;
960
+ postedRef.current = true;
961
+ unackedRef.current = body;
962
+ void submitQuestionnaireResponse(target, id, body).then((result) => {
963
+ if (result === "unsent") {
964
+ postedRef.current = false;
965
+ return;
966
+ }
967
+ unackedRef.current = null;
968
+ });
969
+ },
970
+ [target, id]
971
+ );
972
+ const recoverRef = React8.useRef(() => {
973
+ });
974
+ recoverRef.current = () => {
975
+ const undelivered = unackedRef.current;
976
+ if (undelivered && !postedRef.current) postOnce(undelivered);
977
+ };
978
+ React8__default.default.useEffect(() => () => recoverRef.current(), []);
948
979
  const finish = React8.useCallback(
949
980
  (drafts) => {
950
- const submission = buildQuestionnaireSubmission({
951
- answers: toAnswers(drafts),
952
- sessionId,
953
- meta
954
- });
955
- submitQuestionnaireResponse(target, id, submission);
981
+ postOnce(
982
+ buildQuestionnaireSubmission({
983
+ answers: toAnswers(drafts),
984
+ sessionId,
985
+ meta
986
+ })
987
+ );
956
988
  submittedRef.current = true;
957
989
  onEvent == null ? void 0 : onEvent({ name: "questionnaire_submitted", id });
958
990
  playHaptic("success");
@@ -963,7 +995,7 @@ var _QuestionnaireGate = ({
963
995
  (_a2 = modalRef.current) == null ? void 0 : _a2.close();
964
996
  }, 1500);
965
997
  },
966
- [sessionId, meta, target, id, onEvent]
998
+ [sessionId, meta, postOnce, id, onEvent]
967
999
  );
968
1000
  const applyTransition = React8.useCallback(
969
1001
  (next) => {
@@ -1262,7 +1294,7 @@ var useWireFeatures = (config) => {
1262
1294
  return flags;
1263
1295
  };
1264
1296
  var CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("wireai.features.context");
1265
- var globalObj = global;
1297
+ var globalObj = globalThis;
1266
1298
  if (!globalObj[CONTEXT_SYMBOL]) {
1267
1299
  globalObj[CONTEXT_SYMBOL] = React8.createContext(null);
1268
1300
  }