@mindful-web/marko-web-identity-x 1.85.4 → 1.87.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.
package/CLAUDE.md CHANGED
@@ -426,6 +426,22 @@ before the hooks run and essentially never rejects. An async failure is reported
426
426
  reach this field; `error` is a *synchronous* dispatch throw only. Deliberately **not** `onLoginLinkSent` / `onAuthenticationSuccess`: those drive
427
427
  auto-signup and the GA4 `subscribe` conversion, and this is not a registration.
428
428
 
429
+ **The hook payload strips `customBooleanFieldAnswers` — load-bearing, do not "restore" it.**
430
+ The omeda consumer (`marko-web-omeda-identity-x/rapid-identify.js`) maps *every* boolean answer on
431
+ the user it receives into provider writes: product-namespace booleans become
432
+ `subscriptions: [{ id, receive }]`, deployment-type booleans become opt-ins/opt-outs. idx-compat
433
+ surfaces every email/**magazine** channel as a boolean field whose "answer" is the member's stored
434
+ subscription state — `active: false` reads as an explicitly-answered no (`hasAnswered` is
435
+ `answer != null`; channels have no unanswered state). This form cannot collect booleans
436
+ (boot-validation forbids the rows), so any boolean reaching the hook is state the visitor never
437
+ touched. Passing them through let a progressive submit overwrite Omeda subscription state
438
+ wholesale: 18 of the first 48 production submitters on athleticbusiness had their print-magazine
439
+ subscription killed (`Receive: 0`, "Controlled Kills") at their exact submit second — the
440
+ 2026-08-19 incident. The spec asserting the payload shape lives in
441
+ `marko-web-omeda-identity-x/test/rapid-identify.spec.js`. The profile route (`routes/profile.js`)
442
+ still passes booleans deliberately — its form renders the subscription checkboxes — but it shares
443
+ the divergence exposure; see the incident follow-ups in the rollout doc.
444
+
429
445
  ### Bot protection — verify, then discard the write rather than the visitor
430
446
 
431
447
  The threat is concrete: `marko-web-omeda-identity-x/middleware/set-identity-cookie.js` mints
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/access.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/access.marko",
6
6
  marko_component = require("./access.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  module_objectPath_module = require("@mindful-web/object-path"),
@@ -53,7 +53,7 @@ marko_template._ = marko_renderer(render, {
53
53
  }, marko_component);
54
54
 
55
55
  marko_template.meta = {
56
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/access.marko",
56
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/access.marko",
57
57
  component: "./access.marko",
58
58
  tags: [
59
59
  "@mindful-web/marko-core/components/resolve.marko"
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/comment-stream.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/comment-stream.marko",
6
6
  marko_component = require("./comment-stream.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  module_objectPath_module = require("@mindful-web/object-path"),
@@ -91,7 +91,7 @@ marko_template._ = marko_renderer(render, {
91
91
  }, marko_component);
92
92
 
93
93
  marko_template.meta = {
94
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/comment-stream.marko",
94
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/comment-stream.marko",
95
95
  component: "./comment-stream.marko",
96
96
  tags: [
97
97
  "@mindful-web/marko-web/components/browser-component.marko",
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/context.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/context.marko",
6
6
  marko_component = require("./context.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  marko_dynamicTag = require("marko/dist/runtime/helpers/dynamic-tag"),
@@ -49,7 +49,7 @@ marko_template._ = marko_renderer(render, {
49
49
  }, marko_component);
50
50
 
51
51
  marko_template.meta = {
52
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/context.marko",
52
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/context.marko",
53
53
  component: "./context.marko",
54
54
  tags: [
55
55
  "@mindful-web/marko-core/components/resolve.marko"
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-access.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/form-access.marko",
6
6
  marko_component = require("./form-access.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  module_defaultValue = require("@mindful-web/marko-core/utils/default-value"),
@@ -179,7 +179,7 @@ marko_template._ = marko_renderer(render, {
179
179
  }, marko_component);
180
180
 
181
181
  marko_template.meta = {
182
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-access.marko",
182
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/form-access.marko",
183
183
  component: "./form-access.marko",
184
184
  tags: [
185
185
  "@mindful-web/marko-web/components/browser-component.marko",
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-authenticate.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/form-authenticate.marko",
6
6
  marko_component = require("./form-authenticate.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  module_objectPath_module = require("@mindful-web/object-path"),
@@ -81,7 +81,7 @@ marko_template._ = marko_renderer(render, {
81
81
  }, marko_component);
82
82
 
83
83
  marko_template.meta = {
84
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-authenticate.marko",
84
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/form-authenticate.marko",
85
85
  component: "./form-authenticate.marko",
86
86
  tags: [
87
87
  "@mindful-web/marko-web/components/browser-component.marko",
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-change-email.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/form-change-email.marko",
6
6
  marko_component = require("./form-change-email.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  module_objectPath_module = require("@mindful-web/object-path"),
@@ -59,7 +59,7 @@ marko_template._ = marko_renderer(render, {
59
59
  }, marko_component);
60
60
 
61
61
  marko_template.meta = {
62
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-change-email.marko",
62
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/form-change-email.marko",
63
63
  component: "./form-change-email.marko",
64
64
  tags: [
65
65
  "@mindful-web/marko-web/components/browser-component.marko",
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-login.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/form-login.marko",
6
6
  marko_component = require("./form-login.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  module_objectPath_module = require("@mindful-web/object-path"),
@@ -92,7 +92,7 @@ marko_template._ = marko_renderer(render, {
92
92
  }, marko_component);
93
93
 
94
94
  marko_template.meta = {
95
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-login.marko",
95
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/form-login.marko",
96
96
  component: "./form-login.marko",
97
97
  tags: [
98
98
  "@mindful-web/marko-web/components/browser-component.marko",
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-logout.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/form-logout.marko",
6
6
  marko_renderer = require("marko/dist/runtime/components/renderer"),
7
7
  module_defaultValue = require("@mindful-web/marko-core/utils/default-value"),
8
8
  defaultValue = module_defaultValue.default || module_defaultValue,
@@ -29,7 +29,7 @@ marko_template._ = marko_renderer(render, {
29
29
  });
30
30
 
31
31
  marko_template.meta = {
32
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-logout.marko",
32
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/form-logout.marko",
33
33
  tags: [
34
34
  "@mindful-web/marko-web/components/browser-component.marko"
35
35
  ]
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-profile.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/form-profile.marko",
6
6
  marko_component = require("./form-profile.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  module_objectPath_module = require("@mindful-web/object-path"),
@@ -84,7 +84,7 @@ marko_template._ = marko_renderer(render, {
84
84
  }, marko_component);
85
85
 
86
86
  marko_template.meta = {
87
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-profile.marko",
87
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/form-profile.marko",
88
88
  component: "./form-profile.marko",
89
89
  tags: [
90
90
  "@mindful-web/marko-web/components/browser-component.marko",
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/form-register.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/form-register.marko",
6
6
  marko_renderer = require("marko/dist/runtime/components/renderer"),
7
7
  marko_assign = require("marko/dist/runtime/helpers/assign"),
8
8
  marko_web_identity_x_form_login_template = require("./form-login.marko"),
@@ -25,7 +25,7 @@ marko_template._ = marko_renderer(render, {
25
25
  });
26
26
 
27
27
  marko_template.meta = {
28
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/form-register.marko",
28
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/form-register.marko",
29
29
  tags: [
30
30
  "./form-login.marko"
31
31
  ]
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/google-init.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/google-init.marko",
6
6
  marko_renderer = require("marko/dist/runtime/components/renderer"),
7
7
  marko_attr = require("marko/dist/runtime/html/helpers/attr"),
8
8
  marko_str = require("marko/dist/runtime/helpers/to-string");
@@ -239,5 +239,5 @@ marko_template._ = marko_renderer(render, {
239
239
  });
240
240
 
241
241
  marko_template.meta = {
242
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/google-init.marko"
242
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/google-init.marko"
243
243
  };
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/google-sign-in-button.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/google-sign-in-button.marko",
6
6
  marko_renderer = require("marko/dist/runtime/components/renderer"),
7
7
  helpers_escape_xml = require("marko/dist/runtime/html/helpers/escape-xml"),
8
8
  marko_escapeXml = helpers_escape_xml.x,
@@ -40,5 +40,5 @@ marko_template._ = marko_renderer(render, {
40
40
  });
41
41
 
42
42
  marko_template.meta = {
43
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/google-sign-in-button.marko"
43
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/google-sign-in-button.marko"
44
44
  };
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/identify.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/identify.marko",
6
6
  marko_component = require("./identify.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  module_objectPath_module = require("@mindful-web/object-path"),
@@ -50,7 +50,7 @@ marko_template._ = marko_renderer(render, {
50
50
  }, marko_component);
51
51
 
52
52
  marko_template.meta = {
53
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/identify.marko",
53
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/identify.marko",
54
54
  component: "./identify.marko",
55
55
  tags: [
56
56
  "@mindful-web/marko-web-gtm/components/push.marko",
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/non-auth-identify.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/non-auth-identify.marko",
6
6
  marko_component = require("./non-auth-identify.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  marko_dynamicTag = require("marko/dist/runtime/helpers/dynamic-tag"),
@@ -45,7 +45,7 @@ marko_template._ = marko_renderer(render, {
45
45
  }, marko_component);
46
46
 
47
47
  marko_template.meta = {
48
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/non-auth-identify.marko",
48
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/non-auth-identify.marko",
49
49
  component: "./non-auth-identify.marko",
50
50
  tags: [
51
51
  "@mindful-web/marko-core/components/resolve.marko"
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/progressive-profile-form.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/progressive-profile-form.marko",
6
6
  marko_component = require("./progressive-profile-form.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  module_defaultValue = require("@mindful-web/marko-core/utils/default-value"),
@@ -137,7 +137,7 @@ marko_template._ = marko_renderer(render, {
137
137
  }, marko_component);
138
138
 
139
139
  marko_template.meta = {
140
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/progressive-profile-form.marko",
140
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/progressive-profile-form.marko",
141
141
  component: "./progressive-profile-form.marko",
142
142
  tags: [
143
143
  "@mindful-web/marko-web/components/browser-component.marko",
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
 
4
4
  var marko_template = module.exports = require("marko/dist/html").t(__filename),
5
- marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.4/components/subscribe.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.87.0/components/subscribe.marko",
6
6
  marko_component = require("./subscribe.marko"),
7
7
  marko_renderer = require("marko/dist/runtime/components/renderer"),
8
8
  module_objectPath_module = require("@mindful-web/object-path"),
@@ -73,7 +73,7 @@ marko_template._ = marko_renderer(render, {
73
73
  }, marko_component);
74
74
 
75
75
  marko_template.meta = {
76
- id: "/@mindful-web/marko-web-identity-x$1.85.4/components/subscribe.marko",
76
+ id: "/@mindful-web/marko-web-identity-x$1.87.0/components/subscribe.marko",
77
77
  component: "./subscribe.marko",
78
78
  tags: [
79
79
  "@mindful-web/marko-web/components/browser-component.marko",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindful-web/marko-web-identity-x",
3
- "version": "1.85.4",
3
+ "version": "1.87.0",
4
4
  "description": "Marko Wrapper for IdentityX",
5
5
  "repository": "https://github.com/parameter1/mindful-web/tree/main/packages/marko-web-identity-x",
6
6
  "author": "Josh Worden <josh@parameter1.com>",
@@ -43,5 +43,5 @@
43
43
  "chai": "^4.3.7",
44
44
  "mocha": "^6.2.3"
45
45
  },
46
- "gitHead": "e793692becf12f650680a93a12f36f227aaace30"
46
+ "gitHead": "ff4b26653f19375680d94b56997484a7dab24f05"
47
47
  }
package/routes/profile.js CHANGED
@@ -114,6 +114,12 @@ module.exports = asyncRoute(async (req, res) => {
114
114
  await identityX.client.mutate({ mutation: consentAnswers, variables: { input: { answers } } });
115
115
  }
116
116
 
117
+ // The custom field ids this request actually submitted AND was allowed to write (the same
118
+ // filtered sets the mutations below receive). Passed to the profile-update hooks so provider
119
+ // syncs (Omeda rapid-identify) scope their answer payload to what the form displayed — stored
120
+ // answers for fields this form never rendered must not be rebroadcast as writes.
121
+ const submittedFieldIds = [];
122
+
117
123
  if (customBooleanFieldAnswers.length) {
118
124
  // only update custom questions when there some :)
119
125
  const customBooleanFieldsInput = customBooleanFieldAnswers.map((fieldAnswer) => ({
@@ -126,6 +132,7 @@ module.exports = asyncRoute(async (req, res) => {
126
132
  ? ({ fieldId }) => customFieldIds.includes(fieldId)
127
133
  : () => true,
128
134
  );
135
+ submittedFieldIds.push(...customBooleanFieldsInput.map(({ fieldId }) => fieldId));
129
136
  await identityX.client.mutate({
130
137
  mutation: customBooleanFieldsMutation,
131
138
  variables: { input: { answers: customBooleanFieldsInput } },
@@ -146,6 +153,7 @@ module.exports = asyncRoute(async (req, res) => {
146
153
  ? ({ fieldId }) => customFieldIds.includes(fieldId)
147
154
  : () => true,
148
155
  );
156
+ submittedFieldIds.push(...customSelectFieldsInput.map(({ fieldId }) => fieldId));
149
157
  await identityX.client.mutate({
150
158
  mutation: customSelectFieldsMutation,
151
159
  variables: { input: { answers: customSelectFieldsInput } },
@@ -163,6 +171,7 @@ module.exports = asyncRoute(async (req, res) => {
163
171
  ? ({ fieldId }) => customFieldIds.includes(fieldId)
164
172
  : () => true,
165
173
  );
174
+ submittedFieldIds.push(...customTextFieldsInput.map(({ fieldId }) => fieldId));
166
175
  await identityX.client.mutate({
167
176
  mutation: customTextFieldsMutation,
168
177
  variables: { input: { answers: customTextFieldsInput } },
@@ -176,6 +185,7 @@ module.exports = asyncRoute(async (req, res) => {
176
185
  ...(additionalEventData || {}),
177
186
  req,
178
187
  user,
188
+ submittedFieldIds,
179
189
  });
180
190
  const entity = await identityX.generateEntityId({ userId: user.id });
181
191
  res.json({
@@ -240,7 +240,26 @@ const submit = asyncRoute(async (req, res) => {
240
240
  try {
241
241
  await callHooksFor(identityX, 'onUserProfileUpdate', {
242
242
  req,
243
- user: appUser,
243
+ // Boolean answers are stripped, deliberately and load-bearingly. The omeda hook maps
244
+ // EVERY boolean answer on the user it receives into provider writes -- product booleans
245
+ // become `subscriptions: [{ id, receive }]`, deployment-type booleans become opt-ins/
246
+ // opt-outs -- and idx-compat surfaces every email/magazine *channel* as a boolean whose
247
+ // "answer" is the member's stored subscription state (`active: false` reads as an
248
+ // explicitly-answered no; channels have no unanswered state). This form cannot collect
249
+ // booleans (boot-validation forbids the rows), so any boolean here is by definition
250
+ // state the visitor never touched -- and passing it through let a progressive submit
251
+ // overwrite Omeda subscription state wholesale, unsubscribing magazine subscribers
252
+ // whose idx state had diverged (2026-08-19 incident, athleticbusiness).
253
+ user: { ...appUser, customBooleanFieldAnswers: [] },
254
+ // The fields THIS submit wrote (definition-filtered, same sets the mutation received).
255
+ // Provider syncs scope their answer payload to these ids, so a progressive submit can
256
+ // never rebroadcast stored answers for questions it did not ask. Belt to the boolean
257
+ // strip's suspenders — selects/texts get the same protection booleans already had.
258
+ submittedFieldIds: [
259
+ ...selectAnswers.map(({ fieldId }) => fieldId),
260
+ ...booleanAnswers.map(({ fieldId }) => fieldId),
261
+ ...textAnswers.map(({ fieldId }) => fieldId),
262
+ ],
244
263
  additionalEventData: { actionSource: ACTION_SOURCE },
245
264
  actionSource: ACTION_SOURCE,
246
265
  });