@mindful-web/marko-web-identity-x 1.83.0 → 1.85.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.
Files changed (35) hide show
  1. package/CLAUDE.md +301 -7
  2. package/api/mutations/progressive-profile-update.js +29 -0
  3. package/browser/index.js +13 -0
  4. package/browser/progressive-profile.vue +388 -0
  5. package/components/access.marko.js +2 -2
  6. package/components/comment-stream.marko.js +2 -2
  7. package/components/context.marko.js +2 -2
  8. package/components/form-access.marko.js +2 -2
  9. package/components/form-authenticate.marko.js +2 -2
  10. package/components/form-change-email.marko.js +2 -2
  11. package/components/form-login.marko.js +2 -2
  12. package/components/form-logout.marko.js +2 -2
  13. package/components/form-profile.marko.js +2 -2
  14. package/components/form-register.marko.js +2 -2
  15. package/components/google-init.marko.js +2 -2
  16. package/components/google-sign-in-button.marko.js +2 -2
  17. package/components/identify.marko.js +2 -2
  18. package/components/marko.json +16 -0
  19. package/components/non-auth-identify.marko +6 -1
  20. package/components/non-auth-identify.marko.js +3 -3
  21. package/components/progressive-profile-form.marko +106 -0
  22. package/components/progressive-profile-form.marko.js +138 -0
  23. package/components/subscribe.marko.js +2 -2
  24. package/config.js +98 -0
  25. package/package.json +6 -5
  26. package/routes/google.js +5 -0
  27. package/routes/index.js +3 -0
  28. package/routes/progressive-profile.js +296 -0
  29. package/service.js +31 -0
  30. package/utils/add-custom-attributes.js +19 -46
  31. package/utils/build-progressive-profile-payload.js +117 -0
  32. package/utils/get-missing-progressive-fields.js +114 -0
  33. package/utils/get-progressive-form-fields.js +67 -0
  34. package/utils/progressive-profile-cookies.js +120 -0
  35. package/utils/progressive-profile-telemetry.js +148 -0
@@ -0,0 +1,388 @@
1
+ <template>
2
+ <div
3
+ id="progressive-profile-idx-form"
4
+ ref="root"
5
+ class="content-page-gate content-page-gate--progressive-profile p-block"
6
+ >
7
+ <h5 class="content-page-gate__title">
8
+ {{ translate({ key: title }) }}
9
+ </h5>
10
+
11
+ <template v-if="!didSubmit">
12
+ <p class="content-page-gate__description" v-html="callToAction" />
13
+ <form @submit.prevent="handleSubmit">
14
+ <fieldset :disabled="isLoading">
15
+ <div v-for="(row, ridx) in fieldRows" :key="ridx" class="row">
16
+ <custom-column
17
+ v-for="(col, cidx) in row"
18
+ :key="`${ridx}_${cidx}`"
19
+ :custom-boolean-field-answers="customBooleanFieldAnswers"
20
+ :custom-select-field-answers="customSelectFieldAnswers"
21
+ :custom-text-field-answers="customTextFieldAnswers"
22
+ :label="col.label || defaultFieldLabels[col.key]"
23
+ :field-key="col.key"
24
+ :field-id="col.id"
25
+ :type="col.type"
26
+ :required="true"
27
+ :width="col.width || 1"
28
+ :user="user"
29
+ :endpoints="endpoints"
30
+ :enable-change-email="enableChangeEmail"
31
+ :lang="lang"
32
+ />
33
+ </div>
34
+
35
+ <div class="content-page-gate__actions d-flex align-items-center">
36
+ <button
37
+ type="submit"
38
+ class="btn btn-primary"
39
+ :disabled="isLoading || recaptcha.loading"
40
+ >
41
+ {{ translate({ key: buttonLabel }) }}
42
+ </button>
43
+ <button
44
+ v-if="dismissible"
45
+ type="button"
46
+ class="btn btn-link ml-2"
47
+ @click="handleDismiss"
48
+ >
49
+ {{ translate({ key: dismissLabel }) }}
50
+ </button>
51
+ </div>
52
+ </fieldset>
53
+ <p v-if="error" class="mt-3 text-danger">
54
+ {{ translate({ key: 'An error occurred:' }) }} {{ error }}
55
+ </p>
56
+ </form>
57
+ </template>
58
+
59
+ <div v-else class="success-message">
60
+ <p class="success-message__title">
61
+ {{
62
+ translate({
63
+ key: 'Thank you. This page will automatically reload.'
64
+ })
65
+ }}
66
+ </p>
67
+ <p class="success-message__title d-flex justify-content-between">
68
+ {{ translate({ key: 'If not, click the reload button' }) }}
69
+ <a class="btn btn-primary mr-3" href="#" @click.prevent="reload">{{
70
+ translate({ key: 'Reload' })
71
+ }}</a>
72
+ </p>
73
+ </div>
74
+ </div>
75
+ </template>
76
+
77
+ <script>
78
+ import recaptchaLoad from '@mindful-web/marko-web-recaptcha/browser/load';
79
+ import recaptchaGetToken from '@mindful-web/marko-web-recaptcha/browser/get-token';
80
+
81
+ import post from './utils/post';
82
+ import cookiesEnabled from './utils/cookies-enabled';
83
+
84
+ import CustomColumn from './custom-column.vue';
85
+ import FeatureError from './errors/feature';
86
+ import FormError from './errors/form';
87
+ import EventEmitter from './mixins/global-event-emitter';
88
+
89
+ // Deferred navigation, same reasoning as `google-init.marko`: give the dataLayer/p1events
90
+ // subscribers a tick to dispatch before the page goes away.
91
+ const RELOAD_DELAY_MS = 300;
92
+
93
+ // Declared here and checked server-side, so a v3 token minted for another form on the site cannot
94
+ // be replayed against this one. Must match `routes/progressive-profile.js`.
95
+ const RECAPTCHA_ACTION = 'progressiveProfileSubmit';
96
+
97
+ export default {
98
+ components: { CustomColumn },
99
+
100
+ mixins: [EventEmitter],
101
+
102
+ props: {
103
+ /**
104
+ * `state.missingRows` — only the questions this visitor has not answered, every one required.
105
+ */
106
+ fieldRows: {
107
+ type: Array,
108
+ required: true,
109
+ },
110
+ activeUser: {
111
+ type: Object,
112
+ default: () => ({}),
113
+ },
114
+ customBooleanFieldAnswers: {
115
+ type: Array,
116
+ default: () => [],
117
+ },
118
+ customSelectFieldAnswers: {
119
+ type: Array,
120
+ default: () => [],
121
+ },
122
+ customTextFieldAnswers: {
123
+ type: Array,
124
+ default: () => [],
125
+ },
126
+ content: {
127
+ type: Object,
128
+ required: true,
129
+ },
130
+ /**
131
+ * `base.<tenant>.content-<type>*<id>` — the gated article. Passed to `emit` as the event's
132
+ * top-level entity, NOT nested inside `additionalEventData`: `global-event-emitter.js`
133
+ * assigns `additionalEventData` *after* spreading `data`, so anything the caller puts under
134
+ * that key is clobbered.
135
+ */
136
+ contentEntity: {
137
+ type: String,
138
+ default: null,
139
+ },
140
+ /**
141
+ * `identity-x.<appId>.app-user*<oid>`. Already known at render time — resolving the identity
142
+ * is what decided to show this gate at all — so the view event is never anonymous.
143
+ */
144
+ idxEntity: {
145
+ type: String,
146
+ default: null,
147
+ },
148
+ userId: {
149
+ type: String,
150
+ required: true,
151
+ },
152
+ /**
153
+ * `identified` | `authenticated`.
154
+ */
155
+ audience: {
156
+ type: String,
157
+ default: 'identified',
158
+ },
159
+ fieldIds: {
160
+ type: Array,
161
+ default: () => [],
162
+ },
163
+ recaptchaSiteKey: {
164
+ type: String,
165
+ default: null,
166
+ },
167
+ dismissible: {
168
+ type: Boolean,
169
+ default: false,
170
+ },
171
+ title: {
172
+ type: String,
173
+ default: 'Tell us a bit more about yourself',
174
+ },
175
+ callToAction: {
176
+ type: String,
177
+ default: 'Please answer the questions below to continue reading.',
178
+ },
179
+ buttonLabel: {
180
+ type: String,
181
+ default: 'Continue Reading',
182
+ },
183
+ dismissLabel: {
184
+ type: String,
185
+ default: 'Not right now',
186
+ },
187
+ endpoints: {
188
+ type: Object,
189
+ required: true,
190
+ },
191
+ enableChangeEmail: {
192
+ type: Boolean,
193
+ default: false,
194
+ },
195
+ defaultFieldLabels: {
196
+ type: Object,
197
+ default: () => ({}),
198
+ },
199
+ loginSource: {
200
+ type: String,
201
+ default: 'progressiveProfile',
202
+ },
203
+ lang: {
204
+ type: String,
205
+ default: 'en',
206
+ },
207
+ },
208
+
209
+ data() {
210
+ return {
211
+ error: null,
212
+ isLoading: false,
213
+ didSubmit: false,
214
+ recaptcha: { loading: false, error: null },
215
+ user: { ...this.activeUser },
216
+ };
217
+ },
218
+
219
+ computed: {
220
+ fieldCount() {
221
+ return this.fieldIds.length;
222
+ },
223
+ },
224
+
225
+ mounted() {
226
+ if (!cookiesEnabled()) {
227
+ // A cookie-less browser can never satisfy this gate: the identity itself lives in a cookie.
228
+ const error = new FeatureError('Your browser does not support cookies. Please enable cookies to use this feature.');
229
+ this.error = error.message;
230
+ this.emit('progressive-profile-errored', { message: error.message });
231
+ return;
232
+ }
233
+
234
+ this.loadRecaptcha();
235
+
236
+ this.emit('progressive-profile-mounted', {
237
+ contentId: this.content.id,
238
+ contentType: this.content.type,
239
+ userId: this.userId,
240
+ audience: this.audience,
241
+ fieldCount: this.fieldCount,
242
+ // Which questions were asked — ids only. Submitted *answers* are never tracked.
243
+ fieldKeys: this.fieldIds.join(','),
244
+ contentGateType: 'progressive-profile',
245
+ idxEntity: this.idxEntity,
246
+ }, this.contentEntity);
247
+ },
248
+
249
+ methods: {
250
+ /**
251
+ * Loaded in `mounted`, as every other reCAPTCHA-protected form on the fleet does — but with one
252
+ * deliberate difference: a load failure does **not** disable submit.
253
+ *
254
+ * Elsewhere it does, which is right for a newsletter signup: the worst case is a signup that
255
+ * has to be retried. Here the form is the only way past a gate on the article, so blocking
256
+ * submit on a script an ad blocker routinely eats would lock a real reader out of the content
257
+ * entirely, with nothing to click. Instead the submit goes through with no token, the server
258
+ * records `no-token`, and the write is dropped rather than the visitor.
259
+ */
260
+ async loadRecaptcha() {
261
+ this.recaptcha.loading = true;
262
+ try {
263
+ await recaptchaLoad({ siteKey: this.recaptchaSiteKey });
264
+ this.recaptcha.error = null;
265
+ } catch (e) {
266
+ this.recaptcha.error = e;
267
+ } finally {
268
+ this.recaptcha.loading = false;
269
+ }
270
+ },
271
+
272
+ async getRecaptchaToken() {
273
+ if (this.recaptcha.error || !this.recaptchaSiteKey) return null;
274
+ try {
275
+ const { recaptchaSiteKey: siteKey } = this;
276
+ return await recaptchaGetToken({ siteKey, action: RECAPTCHA_ACTION });
277
+ } catch (e) {
278
+ return null;
279
+ }
280
+ },
281
+
282
+ reload() {
283
+ window.location.reload();
284
+ },
285
+
286
+ async handleSubmit() {
287
+ this.error = null;
288
+ this.isLoading = true;
289
+ try {
290
+ // A fresh token per attempt — they are single-use and expire after two minutes. Never
291
+ // fatal: if the script was blocked or `execute` rejects, submit without one and let the
292
+ // server decide. The alternative is refusing to submit, which strands the visitor behind
293
+ // a gate they have no way to clear.
294
+ const recaptchaToken = await this.getRecaptchaToken();
295
+
296
+ const res = await post('/progressive-profile', {
297
+ recaptchaToken,
298
+ userId: this.userId,
299
+ contentId: this.content.id,
300
+ // Only the answers. The route resolves the target member and the writable field set
301
+ // itself, so nothing else in the body would be read.
302
+ customSelectFieldAnswers: this.user.customSelectFieldAnswers,
303
+ customBooleanFieldAnswers: this.user.customBooleanFieldAnswers,
304
+ customTextFieldAnswers: this.user.customTextFieldAnswers,
305
+ });
306
+ const data = await res.json();
307
+ if (!res.ok) throw new FormError(data.message, res.status);
308
+
309
+ this.didSubmit = true;
310
+
311
+ // Emitted for the dataLayer only — the p1events bridge deliberately does not map this
312
+ // event. `member-events` is the authoritative submission count; GA4 exists here for the
313
+ // campaign/source attribution a server-side record cannot provide, and its conversion
314
+ // trigger filters on `changed === true`. `changed` is server-truth, not a client guess.
315
+ this.emit('progressive-profile-submitted', {
316
+ contentId: this.content.id,
317
+ contentType: this.content.type,
318
+ userId: this.userId,
319
+ audience: this.audience,
320
+ changed: Boolean(data.changed),
321
+ // 'written' | 'unverified'. The GA4 conversion already filters on `changed === true`, so
322
+ // a discarded submit is excluded from completions without a GTM change; this just makes
323
+ // the discards separately countable.
324
+ accepted: data.accepted || null,
325
+ fieldCount: this.fieldCount,
326
+ contentGateType: 'progressive-profile',
327
+ idxEntity: this.idxEntity,
328
+ }, this.contentEntity);
329
+
330
+ setTimeout(() => this.reload(), RELOAD_DELAY_MS);
331
+ } catch (e) {
332
+ this.error = e.message;
333
+ this.emit('progressive-profile-errored', { message: e.message });
334
+ } finally {
335
+ this.isLoading = false;
336
+ }
337
+ },
338
+
339
+ async handleDismiss() {
340
+ try {
341
+ const res = await post('/progressive-profile/dismiss');
342
+ const data = await res.json();
343
+ if (!res.ok) throw new FormError(data.message, res.status);
344
+ this.emit('progressive-profile-dismissed', {
345
+ contentId: this.content.id,
346
+ contentType: this.content.type,
347
+ userId: this.userId,
348
+ contentGateType: 'progressive-profile',
349
+ idxEntity: this.idxEntity,
350
+ }, this.contentEntity);
351
+ setTimeout(() => this.reload(), RELOAD_DELAY_MS);
352
+ } catch (e) {
353
+ this.error = e.message;
354
+ this.emit('progressive-profile-errored', { message: e.message });
355
+ }
356
+ },
357
+
358
+ translate({ key }) {
359
+ const { lang } = this;
360
+ const i18n = {
361
+ pt: {
362
+ 'Tell us a bit more about yourself': 'Conte-nos um pouco mais sobre você',
363
+ 'Please answer the questions below to continue reading.': 'Responda às perguntas abaixo para continuar lendo.',
364
+ 'Continue Reading': 'Continuar lendo',
365
+ 'Not right now': 'Agora não',
366
+ 'An error occurred:': 'Ocorreu um erro:',
367
+ 'Thank you. This page will automatically reload.': 'Obrigado. Esta página será recarregada automaticamente.',
368
+ 'If not, click the reload button': 'Caso contrário, clique no botão de recarregar',
369
+ Reload: 'Recarregar',
370
+ },
371
+ es: {
372
+ 'Tell us a bit more about yourself': 'Cuéntenos un poco más sobre usted',
373
+ 'Please answer the questions below to continue reading.': 'Responda las siguientes preguntas para continuar leyendo.',
374
+ 'Continue Reading': 'Continuar leyendo',
375
+ 'Not right now': 'Ahora no',
376
+ 'An error occurred:': 'Se produjo un error:',
377
+ 'Thank you. This page will automatically reload.': 'Gracias. Esta página se recargará automáticamente.',
378
+ 'If not, click the reload button': 'En caso contrario, haga clic en el botón recargar',
379
+ Reload: 'Recargar',
380
+ },
381
+ en: {},
382
+ };
383
+ const value = (i18n[lang] && i18n[lang][key]) ? i18n[lang][key] : key;
384
+ return value;
385
+ },
386
+ },
387
+ };
388
+ </script>
@@ -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.83.0/components/access.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/access.marko",
56
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/comment-stream.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/comment-stream.marko",
94
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/context.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/context.marko",
52
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-access.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-access.marko",
182
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-authenticate.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-authenticate.marko",
84
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-change-email.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-change-email.marko",
62
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-login.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-login.marko",
95
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-logout.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-logout.marko",
32
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-profile.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-profile.marko",
87
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-register.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/form-register.marko",
28
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/google-init.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/google-init.marko"
242
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/google-sign-in-button.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/google-sign-in-button.marko"
43
+ id: "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/identify.marko",
5
+ marko_componentType = "/@mindful-web/marko-web-identity-x$1.85.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.83.0/components/identify.marko",
53
+ id: "/@mindful-web/marko-web-identity-x$1.85.0/components/identify.marko",
54
54
  component: "./identify.marko",
55
55
  tags: [
56
56
  "@mindful-web/marko-web-gtm/components/push.marko",
@@ -68,6 +68,22 @@
68
68
  },
69
69
  "@allow-anonymous": "string"
70
70
  },
71
+ "<marko-web-identity-x-progressive-profile-form>": {
72
+ "template": "./progressive-profile-form.marko",
73
+ "@state": {
74
+ "type": "object",
75
+ "required": true
76
+ },
77
+ "@content": {
78
+ "type": "object",
79
+ "required": true
80
+ },
81
+ "@additional-event-data": "object",
82
+ "@title": "string",
83
+ "@call-to-action": "string",
84
+ "@button-label": "string",
85
+ "@dismiss-label": "string"
86
+ },
71
87
  "<marko-web-identity-x-form-profile>": {
72
88
  "template": "./form-profile.marko",
73
89
  "@additional-event-data": "object",
@@ -4,7 +4,12 @@ $ const { identityX } = req;
4
4
  <if(Boolean(identityX))>
5
5
  <marko-web-resolve|{ resolved: user }| promise=identityX.getIdentityData()>
6
6
  <if(user && user.id)>
7
- <marko-web-resolve|{ resolved: fullUser }| promise=identityX.findUserById(user.id)>
7
+ <!--
8
+ Memoized: a progressive-profile page load resolves this same identity in the middleware and
9
+ again in `getIdentityData()`. Read-only, so a per-request cache is safe here -- see
10
+ `service.findUserByIdMemoized` for the one caller that must NOT use it.
11
+ -->
12
+ <marko-web-resolve|{ resolved: fullUser }| promise=identityX.findUserByIdMemoized(user.id)>
8
13
  <${input.renderBody} user=fullUser />
9
14
  </marko-web-resolve>
10
15
  </if>