@mindful-web/marko-web-identity-x 1.80.0 → 1.80.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.
- package/CLAUDE.md +22 -1
- package/components/access.marko.js +2 -2
- package/components/comment-stream.marko.js +2 -2
- package/components/context.marko.js +2 -2
- package/components/form-access.marko.js +2 -2
- package/components/form-authenticate.marko.js +2 -2
- package/components/form-change-email.marko.js +2 -2
- package/components/form-login.marko.js +2 -2
- package/components/form-logout.marko.js +2 -2
- package/components/form-profile.marko.js +2 -2
- package/components/form-register.marko.js +2 -2
- package/components/google-init.marko.js +2 -2
- package/components/google-sign-in-button.marko.js +2 -2
- package/components/identify.marko.js +2 -2
- package/components/non-auth-identify.marko.js +2 -2
- package/components/subscribe.marko.js +2 -2
- package/package.json +2 -2
- package/routes/google.js +67 -4
package/CLAUDE.md
CHANGED
|
@@ -150,6 +150,26 @@ so it bails, writes no `autoSignups`, and **no `subscribe` conversion is ever re
|
|
|
150
150
|
`idxAutoSignupCount: 0` seen on every completed One Tap sign-in on overdriveonline.com. Safe to await
|
|
151
151
|
only because the Omeda client now has a request timeout.
|
|
152
152
|
|
|
153
|
+
**The name backfill is non-fatal, and must stay that way.** `GoogleSignInUpdateUser`
|
|
154
|
+
(`updateOwnAppUser`) is the **only** call in this route authenticated as the *user* rather than the
|
|
155
|
+
org — every other one passes `context: { apiToken: getOrgUserApiToken() }` — so it is the only one
|
|
156
|
+
depending on the session token minted moments earlier already being readable. Production shows it
|
|
157
|
+
returning *"The provided value is not a valid token"*, while the same token value works on the very
|
|
158
|
+
next request arriving from the cookie: a read-after-write race on the idx token store. Retried once
|
|
159
|
+
for that reason.
|
|
160
|
+
|
|
161
|
+
Non-fatal matters more than the retry. It backfills a first and last name — cosmetic — but
|
|
162
|
+
`tokenCookie.setTo` has **already run**, so the user is authenticated by the time it executes.
|
|
163
|
+
Throwing turned a fully successful sign-in into a 500, and the client, seeing `!data.ok`, ran `fail()`
|
|
164
|
+
and redirected a *logged-in* user to `/user/login`. A missing display name must never cost someone
|
|
165
|
+
their session. Failures report through `onHookError` and the route continues.
|
|
166
|
+
|
|
167
|
+
`FACET idxNameBackfill` (`ok` | `retried` | `failed`) distinguishes the two bugs that share this one
|
|
168
|
+
error message: if `retried` dominates it is the race; if `failed` dominates the impersonation token
|
|
169
|
+
simply cannot authorize this mutation, and the fix is to stop using it — backfill before impersonation
|
|
170
|
+
via `setUnverifiedAppUserData` (org-token, but writes *unverified* data, so it is a semantic change
|
|
171
|
+
worth deciding deliberately).
|
|
172
|
+
|
|
153
173
|
`idxGoogleStepMs` records elapsed ms at the start of each step, making the route self-profiling:
|
|
154
174
|
`FACET idxGoogleStep SELECT max(idxGoogleStepMs)` shows where the ~12s on a *successful* sign-in
|
|
155
175
|
goes, and a request that dies mid-flight still reports how far it got. Responds `{ ok, requiresUserInput,
|
|
@@ -218,7 +238,8 @@ meter / gate.
|
|
|
218
238
|
**Telemetry.** Two seams. Neither needs site configuration:
|
|
219
239
|
- `config.addRequestAttributes` — called with a flat object as the route progresses
|
|
220
240
|
(`idxGoogleStep`, `idxUserId`, `idxCreatedNewUser`, `idxRequiresUserInput`, `idxGoogleSurface`,
|
|
221
|
-
`idxGoogleMissingFieldsBehavior`, `idxAutoSignupCount`, `idxImpersonateAttempts
|
|
241
|
+
`idxGoogleMissingFieldsBehavior`, `idxAutoSignupCount`, `idxImpersonateAttempts`,
|
|
242
|
+
`idxNameBackfill`, `idxNameBackfillAttempts`). **Defaults to `utils/add-custom-attributes.js`**, which tags
|
|
222
243
|
the current New Relic transaction, so the attributes ride on the `Transaction` *and* any
|
|
223
244
|
`TransactionError` it produces — a 500 says which step failed instead of being a bare GraphQL
|
|
224
245
|
message. That default resolves the agent **only if the app already loaded it** (checks
|
|
@@ -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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
56
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
94
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
52
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
182
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
84
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
62
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
95
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
32
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
87
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
28
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
242
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
43
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
53
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
48
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
5
|
+
marko_componentType = "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
76
|
+
id: "/@mindful-web/marko-web-identity-x$1.80.1/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.80.
|
|
3
|
+
"version": "1.80.1",
|
|
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>",
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "956e3462d636f6e7785c1e82b99d66b4c410e9df"
|
|
42
42
|
}
|
package/routes/google.js
CHANGED
|
@@ -33,6 +33,24 @@ const LOGIN_SOURCE = 'google-one-tap';
|
|
|
33
33
|
const IMPERSONATE_MAX_ATTEMPTS = 2;
|
|
34
34
|
const IMPERSONATE_RETRY_DELAY_MS = 250;
|
|
35
35
|
|
|
36
|
+
// Same shape as the impersonation retry, and for the same suspected cause: a
|
|
37
|
+
// read-after-write race, this time on the token the previous step just minted.
|
|
38
|
+
const NAME_BACKFILL_MAX_ATTEMPTS = 2;
|
|
39
|
+
const NAME_BACKFILL_RETRY_DELAY_MS = 250;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A session token that the idx API does not (yet) recognise.
|
|
43
|
+
*
|
|
44
|
+
* Apollo exposes GraphQL errors both individually on `graphQLErrors` and folded
|
|
45
|
+
* into `error.message` as "GraphQL error: <message>"; check both so this does not
|
|
46
|
+
* depend on which shape the caller happens to see.
|
|
47
|
+
*/
|
|
48
|
+
const isFreshTokenError = (e) => {
|
|
49
|
+
if (!e) return false;
|
|
50
|
+
const messages = [e.message, ...asArray(e.graphQLErrors).map((g) => g && g.message)];
|
|
51
|
+
return messages.some((m) => /not a valid token|invalid token|token was not found/i.test(String(m)));
|
|
52
|
+
};
|
|
53
|
+
|
|
36
54
|
/**
|
|
37
55
|
* Transport-level failures only — a timeout, reset or DNS blip is worth
|
|
38
56
|
* repeating; a GraphQL validation or authorization error is not, and repeating
|
|
@@ -266,10 +284,55 @@ module.exports = asyncRoute(async (req, res) => {
|
|
|
266
284
|
if (familyName && !appUser.familyName) nameInput.familyName = familyName;
|
|
267
285
|
if (Object.keys(nameInput).length) {
|
|
268
286
|
setStep('update-own-app-user');
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
287
|
+
// This is the ONLY call in the route authenticated as the *user* rather than
|
|
288
|
+
// the org — every other one passes `context: { apiToken: getOrgUserApiToken() }`
|
|
289
|
+
// — so it is the only one that depends on the session token minted moments
|
|
290
|
+
// earlier already being readable. That is exactly why it is the only
|
|
291
|
+
// operation reported failing: production shows `GoogleSignInUpdateUser`
|
|
292
|
+
// returning "The provided value is not a valid token".
|
|
293
|
+
//
|
|
294
|
+
// The same token value works on the *next* request, arriving from the cookie
|
|
295
|
+
// set above — which is what makes a read-after-write race on the idx token
|
|
296
|
+
// store the leading explanation, so retry once.
|
|
297
|
+
//
|
|
298
|
+
// Non-fatal regardless of the cause, which matters more than the retry. This
|
|
299
|
+
// backfills a first and last name; it is cosmetic. But `tokenCookie.setTo`
|
|
300
|
+
// has already run, so the user IS authenticated by the time we get here —
|
|
301
|
+
// throwing turned a fully successful sign-in into a 500, and the client, on
|
|
302
|
+
// seeing `!data.ok`, ran `fail()` and redirected a logged-in user to
|
|
303
|
+
// /user/login. A missing display name must never cost someone their session.
|
|
304
|
+
let backfill = 'ok';
|
|
305
|
+
let attempts = 0;
|
|
306
|
+
for (;;) {
|
|
307
|
+
attempts += 1;
|
|
308
|
+
try {
|
|
309
|
+
// eslint-disable-next-line no-await-in-loop
|
|
310
|
+
await identityX.client.mutate({
|
|
311
|
+
mutation: UPDATE_OWN_APP_USER,
|
|
312
|
+
variables: { input: nameInput },
|
|
313
|
+
});
|
|
314
|
+
break;
|
|
315
|
+
} catch (e) {
|
|
316
|
+
const retryable = attempts < NAME_BACKFILL_MAX_ATTEMPTS
|
|
317
|
+
&& (isFreshTokenError(e) || isRetryableIdxError(e));
|
|
318
|
+
if (!retryable) {
|
|
319
|
+
backfill = 'failed';
|
|
320
|
+
onError(e, {
|
|
321
|
+
idxGoogleStep: 'update-own-app-user',
|
|
322
|
+
idxUserId: appUser.id,
|
|
323
|
+
idxNameBackfillAttempts: attempts,
|
|
324
|
+
});
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
backfill = 'retried';
|
|
328
|
+
// eslint-disable-next-line no-await-in-loop
|
|
329
|
+
await sleep(NAME_BACKFILL_RETRY_DELAY_MS);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// Measurable: `FACET idxNameBackfill` separates "the retry rescues it" (a
|
|
333
|
+
// race) from "it always fails" (an impersonation token that simply cannot
|
|
334
|
+
// authorize this mutation) — two different bugs with one error message.
|
|
335
|
+
addAttrs({ idxNameBackfill: backfill, idxNameBackfillAttempts: attempts });
|
|
273
336
|
}
|
|
274
337
|
|
|
275
338
|
// Load the refreshed user so hooks and field checks have up-to-date data.
|