@agent-native/core 0.158.6 → 0.158.8
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/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +234 -5
- package/dist/server/better-auth-instance.js +29 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/package.json +1 -1
|
@@ -17,11 +17,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
17
17
|
id?: undefined;
|
|
18
18
|
provider?: undefined;
|
|
19
19
|
} | {
|
|
20
|
-
error?: undefined;
|
|
21
20
|
configured?: undefined;
|
|
22
21
|
connectPath?: undefined;
|
|
23
22
|
url: string;
|
|
24
23
|
id: string;
|
|
25
24
|
provider: string;
|
|
25
|
+
error?: undefined;
|
|
26
26
|
}>;
|
|
27
27
|
export default _default;
|
|
@@ -137,13 +137,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
137
137
|
inputSchema: {
|
|
138
138
|
type: string;
|
|
139
139
|
properties: {
|
|
140
|
+
count?: undefined;
|
|
140
141
|
query?: undefined;
|
|
141
142
|
minutes?: undefined;
|
|
142
143
|
limit?: undefined;
|
|
143
144
|
clientHint?: undefined;
|
|
144
145
|
timestamp?: undefined;
|
|
145
146
|
chapterId?: undefined;
|
|
146
|
-
count?: undefined;
|
|
147
147
|
startAt?: undefined;
|
|
148
148
|
endAt?: undefined;
|
|
149
149
|
reason?: undefined;
|
|
@@ -159,6 +159,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
159
159
|
inputSchema: {
|
|
160
160
|
type: string;
|
|
161
161
|
properties: {
|
|
162
|
+
count?: undefined;
|
|
162
163
|
query: {
|
|
163
164
|
type: string;
|
|
164
165
|
description: string;
|
|
@@ -174,7 +175,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
174
175
|
clientHint?: undefined;
|
|
175
176
|
timestamp?: undefined;
|
|
176
177
|
chapterId?: undefined;
|
|
177
|
-
count?: undefined;
|
|
178
178
|
startAt?: undefined;
|
|
179
179
|
endAt?: undefined;
|
|
180
180
|
reason?: undefined;
|
|
@@ -190,6 +190,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
190
190
|
inputSchema: {
|
|
191
191
|
type: string;
|
|
192
192
|
properties: {
|
|
193
|
+
count?: undefined;
|
|
193
194
|
minutes: {
|
|
194
195
|
type: string;
|
|
195
196
|
description: string;
|
|
@@ -199,7 +200,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
199
200
|
clientHint?: undefined;
|
|
200
201
|
timestamp?: undefined;
|
|
201
202
|
chapterId?: undefined;
|
|
202
|
-
count?: undefined;
|
|
203
203
|
startAt?: undefined;
|
|
204
204
|
endAt?: undefined;
|
|
205
205
|
reason?: undefined;
|
|
@@ -216,6 +216,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
216
216
|
type: string;
|
|
217
217
|
required: string[];
|
|
218
218
|
properties: {
|
|
219
|
+
count?: undefined;
|
|
219
220
|
query: {
|
|
220
221
|
type: string;
|
|
221
222
|
description: string;
|
|
@@ -234,7 +235,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
234
235
|
};
|
|
235
236
|
timestamp?: undefined;
|
|
236
237
|
chapterId?: undefined;
|
|
237
|
-
count?: undefined;
|
|
238
238
|
startAt?: undefined;
|
|
239
239
|
endAt?: undefined;
|
|
240
240
|
reason?: undefined;
|
|
@@ -250,6 +250,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
250
250
|
type: string;
|
|
251
251
|
required: string[];
|
|
252
252
|
properties: {
|
|
253
|
+
count?: undefined;
|
|
253
254
|
query?: undefined;
|
|
254
255
|
minutes?: undefined;
|
|
255
256
|
limit?: undefined;
|
|
@@ -263,7 +264,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
263
264
|
description: string;
|
|
264
265
|
};
|
|
265
266
|
chapterId?: undefined;
|
|
266
|
-
count?: undefined;
|
|
267
267
|
startAt?: undefined;
|
|
268
268
|
endAt?: undefined;
|
|
269
269
|
includeMicrophone?: undefined;
|
|
@@ -314,13 +314,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
314
314
|
type: string;
|
|
315
315
|
required: string[];
|
|
316
316
|
properties: {
|
|
317
|
+
count?: undefined;
|
|
317
318
|
query?: undefined;
|
|
318
319
|
minutes?: undefined;
|
|
319
320
|
limit?: undefined;
|
|
320
321
|
clientHint?: undefined;
|
|
321
322
|
timestamp?: undefined;
|
|
322
323
|
chapterId?: undefined;
|
|
323
|
-
count?: undefined;
|
|
324
324
|
startAt: {
|
|
325
325
|
type: string;
|
|
326
326
|
description: string;
|
|
@@ -349,13 +349,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
349
349
|
type: string;
|
|
350
350
|
required: string[];
|
|
351
351
|
properties: {
|
|
352
|
+
count?: undefined;
|
|
352
353
|
query?: undefined;
|
|
353
354
|
minutes?: undefined;
|
|
354
355
|
limit?: undefined;
|
|
355
356
|
clientHint?: undefined;
|
|
356
357
|
timestamp?: undefined;
|
|
357
358
|
chapterId?: undefined;
|
|
358
|
-
count?: undefined;
|
|
359
359
|
startAt?: undefined;
|
|
360
360
|
endAt?: undefined;
|
|
361
361
|
reason?: undefined;
|
|
@@ -16,18 +16,18 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
|
|
|
16
16
|
error?: undefined;
|
|
17
17
|
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
|
+
count?: undefined;
|
|
19
20
|
updated: number;
|
|
20
21
|
error?: undefined;
|
|
21
22
|
ok?: undefined;
|
|
22
|
-
count?: undefined;
|
|
23
23
|
} | {
|
|
24
|
+
count?: undefined;
|
|
24
25
|
updated?: undefined;
|
|
25
26
|
error: string;
|
|
26
27
|
ok?: undefined;
|
|
27
|
-
count?: undefined;
|
|
28
28
|
} | {
|
|
29
|
+
count?: undefined;
|
|
29
30
|
updated?: undefined;
|
|
30
31
|
error?: undefined;
|
|
31
32
|
ok: boolean;
|
|
32
|
-
count?: undefined;
|
|
33
33
|
}>>;
|
|
@@ -41,27 +41,27 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
-
error?: undefined;
|
|
45
|
-
ok?: undefined;
|
|
46
44
|
summary: import("./types.js").TraceSummary;
|
|
47
45
|
spans: import("./types.js").TraceSpan[];
|
|
48
46
|
id?: undefined;
|
|
49
|
-
} | {
|
|
50
47
|
error?: undefined;
|
|
51
48
|
ok?: undefined;
|
|
49
|
+
} | {
|
|
52
50
|
summary?: undefined;
|
|
53
51
|
spans?: undefined;
|
|
54
52
|
id: string;
|
|
55
|
-
|
|
53
|
+
error?: undefined;
|
|
56
54
|
ok?: undefined;
|
|
55
|
+
} | {
|
|
57
56
|
summary?: undefined;
|
|
58
57
|
spans?: undefined;
|
|
59
58
|
id?: undefined;
|
|
60
59
|
error: any;
|
|
60
|
+
ok?: undefined;
|
|
61
61
|
} | {
|
|
62
|
-
error?: undefined;
|
|
63
62
|
summary?: undefined;
|
|
64
63
|
spans?: undefined;
|
|
65
64
|
id?: undefined;
|
|
65
|
+
error?: undefined;
|
|
66
66
|
ok: boolean;
|
|
67
67
|
}>>;
|
|
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
|
|
|
48
48
|
}>;
|
|
49
49
|
/** DELETE /_agent-native/resources/:id — delete a resource */
|
|
50
50
|
export declare function handleDeleteResource(event: any): Promise<{
|
|
51
|
-
ok?: undefined;
|
|
52
51
|
error: string;
|
|
52
|
+
ok?: undefined;
|
|
53
53
|
} | {
|
|
54
54
|
error?: undefined;
|
|
55
55
|
ok: boolean;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -34,37 +34,37 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
|
|
|
34
34
|
/** POST /_agent-native/secrets/:key — write a secret. */
|
|
35
35
|
export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
36
36
|
error: string;
|
|
37
|
-
ok?: undefined;
|
|
38
37
|
status?: undefined;
|
|
38
|
+
ok?: undefined;
|
|
39
39
|
} | {
|
|
40
|
-
error?: undefined;
|
|
41
40
|
ok: boolean;
|
|
42
41
|
status: string;
|
|
42
|
+
error?: undefined;
|
|
43
43
|
} | {
|
|
44
|
-
ok?: undefined;
|
|
45
44
|
error: string;
|
|
46
45
|
removed?: undefined;
|
|
46
|
+
ok?: undefined;
|
|
47
47
|
} | {
|
|
48
|
-
error?: undefined;
|
|
49
48
|
ok: boolean;
|
|
50
49
|
removed: boolean;
|
|
50
|
+
error?: undefined;
|
|
51
51
|
}>>;
|
|
52
52
|
/**
|
|
53
53
|
* POST /_agent-native/secrets/:key/test — validate an optional candidate value
|
|
54
54
|
* or the current stored value without changing anything.
|
|
55
55
|
*/
|
|
56
56
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
57
|
-
ok?: undefined;
|
|
58
57
|
error: string;
|
|
59
58
|
note?: undefined;
|
|
59
|
+
ok?: undefined;
|
|
60
60
|
} | {
|
|
61
|
-
error?: undefined;
|
|
62
61
|
ok: boolean;
|
|
63
62
|
note?: undefined;
|
|
64
|
-
} | {
|
|
65
63
|
error?: undefined;
|
|
64
|
+
} | {
|
|
66
65
|
ok: boolean;
|
|
67
66
|
note: string;
|
|
67
|
+
error?: undefined;
|
|
68
68
|
} | {
|
|
69
69
|
note?: undefined;
|
|
70
70
|
ok: boolean;
|
|
@@ -95,11 +95,11 @@ export interface AdHocSecretPayload {
|
|
|
95
95
|
export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
|
|
96
96
|
error: string;
|
|
97
97
|
} | {
|
|
98
|
-
error?: undefined;
|
|
99
98
|
ok: boolean;
|
|
100
99
|
key: string;
|
|
101
|
-
} | {
|
|
102
100
|
error?: undefined;
|
|
101
|
+
} | {
|
|
103
102
|
ok: boolean;
|
|
104
103
|
removed: boolean;
|
|
104
|
+
error?: undefined;
|
|
105
105
|
}>>;
|
|
@@ -27,10 +27,10 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
|
|
|
27
27
|
export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
28
28
|
error: any;
|
|
29
29
|
} | {
|
|
30
|
-
error?: undefined;
|
|
31
30
|
ok: boolean;
|
|
32
31
|
key: string;
|
|
33
32
|
baseUrlKey?: string;
|
|
34
33
|
scope: AgentEngineApiKeyScope;
|
|
34
|
+
error?: undefined;
|
|
35
35
|
}>>;
|
|
36
36
|
export {};
|
package/dist/server/auth.js
CHANGED
|
@@ -1538,6 +1538,164 @@ function escapeHtmlAttr(value) {
|
|
|
1538
1538
|
const DESKTOP_MAGIC_LINK_CALLBACK_PATH = "/_agent-native/auth/magic-link/desktop-callback";
|
|
1539
1539
|
const DESKTOP_MAGIC_LINK_LANDING_PATH = "/_agent-native/auth/magic-link/desktop-landing";
|
|
1540
1540
|
const BETTER_AUTH_MAGIC_LINK_VERIFY_PATH = "/_agent-native/auth/ba/magic-link/verify";
|
|
1541
|
+
function magicLinkDigest(value) {
|
|
1542
|
+
return crypto.createHash("sha256").update(value).digest("hex").slice(0, 16);
|
|
1543
|
+
}
|
|
1544
|
+
function magicLinkStoredIdentifier(token) {
|
|
1545
|
+
return crypto.createHash("sha256").update(token).digest("base64url");
|
|
1546
|
+
}
|
|
1547
|
+
function redactMagicLinkUrl(value, baseURL) {
|
|
1548
|
+
const redactUrl = (url, depth) => {
|
|
1549
|
+
for (const key of ["token", "flow_id", "verifier", "state"]) {
|
|
1550
|
+
if (url.searchParams.has(key))
|
|
1551
|
+
url.searchParams.set(key, "[redacted]");
|
|
1552
|
+
}
|
|
1553
|
+
if (depth >= 4)
|
|
1554
|
+
return;
|
|
1555
|
+
for (const key of [
|
|
1556
|
+
"callbackURL",
|
|
1557
|
+
"newUserCallbackURL",
|
|
1558
|
+
"errorCallbackURL",
|
|
1559
|
+
"return",
|
|
1560
|
+
]) {
|
|
1561
|
+
const callback = url.searchParams.get(key);
|
|
1562
|
+
if (!callback)
|
|
1563
|
+
continue;
|
|
1564
|
+
try {
|
|
1565
|
+
const callbackURL = new URL(callback, url.origin);
|
|
1566
|
+
redactUrl(callbackURL, depth + 1);
|
|
1567
|
+
url.searchParams.set(key, callbackURL.toString());
|
|
1568
|
+
}
|
|
1569
|
+
catch {
|
|
1570
|
+
url.searchParams.set(key, "[invalid]");
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
};
|
|
1574
|
+
try {
|
|
1575
|
+
const url = new URL(value, baseURL);
|
|
1576
|
+
redactUrl(url, 0);
|
|
1577
|
+
return `${url.pathname}${url.search}`;
|
|
1578
|
+
}
|
|
1579
|
+
catch {
|
|
1580
|
+
return "[invalid-url]";
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
function magicLinkRequestDetails(event, values, verificationURL) {
|
|
1584
|
+
const token = typeof values.token === "string" ? values.token.trim() : "";
|
|
1585
|
+
const callbackValue = typeof values.callbackURL === "string" ? values.callbackURL : "";
|
|
1586
|
+
let callback;
|
|
1587
|
+
try {
|
|
1588
|
+
callback = callbackValue
|
|
1589
|
+
? new URL(callbackValue, getOrigin(event))
|
|
1590
|
+
: undefined;
|
|
1591
|
+
}
|
|
1592
|
+
catch {
|
|
1593
|
+
callback = undefined;
|
|
1594
|
+
}
|
|
1595
|
+
return {
|
|
1596
|
+
requestMethod: getMethod(event),
|
|
1597
|
+
requestUrl: redactMagicLinkUrl(event.node?.req?.url ?? event.path ?? "", getOrigin(event)),
|
|
1598
|
+
verificationUrl: verificationURL
|
|
1599
|
+
? redactMagicLinkUrl(verificationURL.toString(), getOrigin(event))
|
|
1600
|
+
: undefined,
|
|
1601
|
+
verificationMethod: verificationURL ? "GET" : undefined,
|
|
1602
|
+
tokenPresent: Boolean(token),
|
|
1603
|
+
tokenLength: token.length || undefined,
|
|
1604
|
+
tokenDigest: token ? magicLinkDigest(token) : undefined,
|
|
1605
|
+
expectedStoredIdentifierPrefix: token
|
|
1606
|
+
? magicLinkStoredIdentifier(token).slice(0, 16)
|
|
1607
|
+
: undefined,
|
|
1608
|
+
callbackURLPresent: Boolean(callbackValue),
|
|
1609
|
+
callbackPath: callback?.pathname,
|
|
1610
|
+
hasFlowId: Boolean(callback?.searchParams.get("flow_id")),
|
|
1611
|
+
hasVerifier: Boolean(callback?.searchParams.get("verifier")),
|
|
1612
|
+
hasState: Boolean(callback?.searchParams.get("state") || values.state),
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
async function inspectMagicLinkVerification(auth, token) {
|
|
1616
|
+
const storedIdentifier = magicLinkStoredIdentifier(token);
|
|
1617
|
+
try {
|
|
1618
|
+
const context = await auth.$context;
|
|
1619
|
+
const findVerificationValue = context?.internalAdapter?.findVerificationValue;
|
|
1620
|
+
if (typeof findVerificationValue !== "function") {
|
|
1621
|
+
return {
|
|
1622
|
+
lookup: "adapter-unavailable",
|
|
1623
|
+
lookupKeyPrefix: storedIdentifier.slice(0, 16),
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
const record = await findVerificationValue(storedIdentifier);
|
|
1627
|
+
if (!record) {
|
|
1628
|
+
return {
|
|
1629
|
+
lookup: "absent",
|
|
1630
|
+
lookupKeyPrefix: storedIdentifier.slice(0, 16),
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
const expiresAt = new Date(String(record.expiresAt ?? ""));
|
|
1634
|
+
const expiryState = Number.isFinite(expiresAt.getTime())
|
|
1635
|
+
? expiresAt.getTime() <= Date.now()
|
|
1636
|
+
? "expired"
|
|
1637
|
+
: "valid"
|
|
1638
|
+
: "invalid-expiry";
|
|
1639
|
+
return {
|
|
1640
|
+
lookup: "present",
|
|
1641
|
+
lookupKeyPrefix: storedIdentifier.slice(0, 16),
|
|
1642
|
+
expiryState,
|
|
1643
|
+
expiresAt: Number.isFinite(expiresAt.getTime())
|
|
1644
|
+
? expiresAt.toISOString()
|
|
1645
|
+
: undefined,
|
|
1646
|
+
valuePresent: "value" in record,
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
catch (error) {
|
|
1650
|
+
return {
|
|
1651
|
+
lookup: "lookup-error",
|
|
1652
|
+
lookupKeyPrefix: storedIdentifier.slice(0, 16),
|
|
1653
|
+
errorType: error instanceof Error ? error.constructor.name : "unknown",
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
function logMagicLinkDebug(event, phase, details = {}) {
|
|
1658
|
+
console.info("[agent-native][magic-link]", {
|
|
1659
|
+
phase,
|
|
1660
|
+
app: getOAuthStateAppId(),
|
|
1661
|
+
agentNativeDesktop: /AgentNativeDesktop/i.test(getHeader(event, "user-agent") || ""),
|
|
1662
|
+
...details,
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1665
|
+
function magicLinkResponseError(response, baseURL) {
|
|
1666
|
+
const location = response.headers.get("location");
|
|
1667
|
+
if (!location)
|
|
1668
|
+
return undefined;
|
|
1669
|
+
try {
|
|
1670
|
+
return new URL(location, baseURL).searchParams.get("error") || undefined;
|
|
1671
|
+
// coercion-ok: a malformed redirect cannot contain a diagnostic error code.
|
|
1672
|
+
}
|
|
1673
|
+
catch {
|
|
1674
|
+
return undefined;
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
function logMagicLinkVerificationResponse(event, source, response, preConsume) {
|
|
1678
|
+
const error = magicLinkResponseError(response, getOrigin(event));
|
|
1679
|
+
const invalidToken = error === "INVALID_TOKEN";
|
|
1680
|
+
logMagicLinkDebug(event, "verify-response", {
|
|
1681
|
+
source,
|
|
1682
|
+
responseStatus: response.status,
|
|
1683
|
+
responseLocation: redactMagicLinkUrl(response.headers.get("location") || "", getOrigin(event)),
|
|
1684
|
+
producer: invalidToken ? "better-auth.magic-link.verify" : undefined,
|
|
1685
|
+
reason: invalidToken ? "consumeVerificationValue returned null" : undefined,
|
|
1686
|
+
preConsume,
|
|
1687
|
+
classification: invalidToken
|
|
1688
|
+
? preConsume?.lookup === "present" && preConsume.expiryState === "valid"
|
|
1689
|
+
? "valid-row-before-consume"
|
|
1690
|
+
: preConsume?.lookup === "present" &&
|
|
1691
|
+
preConsume.expiryState === "expired"
|
|
1692
|
+
? "expired-row"
|
|
1693
|
+
: preConsume?.lookup === "absent"
|
|
1694
|
+
? "row-absent-before-consume"
|
|
1695
|
+
: "unresolved"
|
|
1696
|
+
: undefined,
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1541
1699
|
function desktopMagicLinkVerificationUrl(event, values) {
|
|
1542
1700
|
const value = (key) => typeof values[key] === "string" ? values[key] : "";
|
|
1543
1701
|
const token = value("token").trim();
|
|
@@ -3092,19 +3250,47 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
3092
3250
|
if (getMethod(event) === "POST") {
|
|
3093
3251
|
const body = await readBody(event);
|
|
3094
3252
|
const verificationURL = desktopMagicLinkVerificationUrl(event, body);
|
|
3253
|
+
const requestDetails = magicLinkRequestDetails(event, body, verificationURL);
|
|
3095
3254
|
if (!verificationURL) {
|
|
3255
|
+
logMagicLinkDebug(event, "verify-rejected-before-better-auth", {
|
|
3256
|
+
source: "desktop-landing",
|
|
3257
|
+
...requestDetails,
|
|
3258
|
+
reason: "invalid-desktop-verification-url",
|
|
3259
|
+
});
|
|
3096
3260
|
setResponseStatus(event, 400);
|
|
3097
3261
|
return { error: "Invalid desktop magic-link" };
|
|
3098
3262
|
}
|
|
3263
|
+
const token = typeof body.token === "string" ? body.token.trim() : "";
|
|
3264
|
+
const preConsume = await inspectMagicLinkVerification(auth, token);
|
|
3265
|
+
logMagicLinkDebug(event, "verify-request", {
|
|
3266
|
+
source: "desktop-landing",
|
|
3267
|
+
...requestDetails,
|
|
3268
|
+
preConsume,
|
|
3269
|
+
});
|
|
3099
3270
|
// Verify inside the same request that received the explicit user
|
|
3100
3271
|
// confirmation. A browser redirect would create a second network
|
|
3101
3272
|
// hop where link scanners, redirect handling, or a fresh serverless
|
|
3102
3273
|
// request could consume or lose the one-time token before the
|
|
3103
3274
|
// desktop callback sees the Better Auth session cookie.
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3275
|
+
try {
|
|
3276
|
+
const response = await auth.handler(new Request(verificationURL, {
|
|
3277
|
+
method: "GET",
|
|
3278
|
+
headers: event.headers,
|
|
3279
|
+
}));
|
|
3280
|
+
if (response instanceof Response) {
|
|
3281
|
+
logMagicLinkVerificationResponse(event, "desktop-landing", response, preConsume);
|
|
3282
|
+
}
|
|
3283
|
+
return response;
|
|
3284
|
+
}
|
|
3285
|
+
catch (error) {
|
|
3286
|
+
logMagicLinkDebug(event, "verify-exception", {
|
|
3287
|
+
source: "desktop-landing",
|
|
3288
|
+
...requestDetails,
|
|
3289
|
+
preConsume,
|
|
3290
|
+
errorType: error instanceof Error ? error.constructor.name : "unknown",
|
|
3291
|
+
});
|
|
3292
|
+
throw error;
|
|
3293
|
+
}
|
|
3108
3294
|
}
|
|
3109
3295
|
if (!isReadMethod(event)) {
|
|
3110
3296
|
setResponseStatus(event, 405);
|
|
@@ -3157,6 +3343,17 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
3157
3343
|
message: AUTH_MAGIC_LINK_FALLBACK,
|
|
3158
3344
|
code: code || "callback_error",
|
|
3159
3345
|
});
|
|
3346
|
+
logMagicLinkDebug(event, "callback-error", {
|
|
3347
|
+
source: "desktop-callback",
|
|
3348
|
+
flow: oauthDebugFlowId(flowId),
|
|
3349
|
+
callbackError: code || "callback_error",
|
|
3350
|
+
producer: code === "INVALID_TOKEN"
|
|
3351
|
+
? "better-auth.magic-link.verify"
|
|
3352
|
+
: "desktop-callback",
|
|
3353
|
+
reason: code === "INVALID_TOKEN"
|
|
3354
|
+
? "upstream-verifier-reported-invalid-token"
|
|
3355
|
+
: "callback-carried-error",
|
|
3356
|
+
});
|
|
3160
3357
|
logGoogleOAuthDebug(event, "magic-link-callback-error", {
|
|
3161
3358
|
flowId,
|
|
3162
3359
|
message: callbackError,
|
|
@@ -3224,11 +3421,27 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
3224
3421
|
const isSendVerificationEmail = reqPath.includes("send-verification-email") &&
|
|
3225
3422
|
getMethod(event) === "POST";
|
|
3226
3423
|
const isMagicLinkRequest = reqPath.includes("/sign-in/magic-link") && getMethod(event) === "POST";
|
|
3424
|
+
const isMagicLinkVerification = reqPath.includes("/magic-link/verify") && getMethod(event) === "GET";
|
|
3227
3425
|
const isSignOut = reqPath.includes("sign-out") && getMethod(event) === "POST";
|
|
3228
3426
|
if (isSignOut)
|
|
3229
3427
|
optOutOfAuthDisabledSession(event);
|
|
3230
3428
|
const authRequest = toWebRequest(event);
|
|
3231
3429
|
let requestForAuth = authRequest;
|
|
3430
|
+
let magicLinkPreConsume;
|
|
3431
|
+
if (isMagicLinkVerification) {
|
|
3432
|
+
const verificationURL = new URL(authRequest.url);
|
|
3433
|
+
const values = Object.fromEntries(verificationURL.searchParams.entries());
|
|
3434
|
+
const requestDetails = magicLinkRequestDetails(event, values, verificationURL);
|
|
3435
|
+
const token = typeof values.token === "string" ? values.token.trim() : "";
|
|
3436
|
+
magicLinkPreConsume = token
|
|
3437
|
+
? await inspectMagicLinkVerification(auth, token)
|
|
3438
|
+
: undefined;
|
|
3439
|
+
logMagicLinkDebug(event, "verify-request", {
|
|
3440
|
+
source: "better-auth-catch-all",
|
|
3441
|
+
...requestDetails,
|
|
3442
|
+
preConsume: magicLinkPreConsume,
|
|
3443
|
+
});
|
|
3444
|
+
}
|
|
3232
3445
|
// Better Auth is also reachable directly, outside the legacy login
|
|
3233
3446
|
// wrapper. Check its password endpoints before handing the request to
|
|
3234
3447
|
// Better Auth so an org policy cannot be bypassed through the raw API.
|
|
@@ -3330,10 +3543,26 @@ async function mountBetterAuthRoutes(app, options) {
|
|
|
3330
3543
|
// validation error.
|
|
3331
3544
|
}
|
|
3332
3545
|
}
|
|
3333
|
-
let response
|
|
3546
|
+
let response;
|
|
3547
|
+
try {
|
|
3548
|
+
response = await auth.handler(requestForAuth);
|
|
3549
|
+
}
|
|
3550
|
+
catch (error) {
|
|
3551
|
+
if (isMagicLinkVerification) {
|
|
3552
|
+
logMagicLinkDebug(event, "verify-exception", {
|
|
3553
|
+
source: "better-auth-catch-all",
|
|
3554
|
+
errorType: error instanceof Error ? error.constructor.name : "unknown",
|
|
3555
|
+
preConsume: magicLinkPreConsume,
|
|
3556
|
+
});
|
|
3557
|
+
}
|
|
3558
|
+
throw error;
|
|
3559
|
+
}
|
|
3334
3560
|
const isResponse = response != null &&
|
|
3335
3561
|
typeof response.status === "number" &&
|
|
3336
3562
|
typeof response.headers?.get === "function";
|
|
3563
|
+
if (isMagicLinkVerification && isResponse) {
|
|
3564
|
+
logMagicLinkVerificationResponse(event, "better-auth-catch-all", response, magicLinkPreConsume);
|
|
3565
|
+
}
|
|
3337
3566
|
if (isResponse && response.status >= 400) {
|
|
3338
3567
|
// The direct Better Auth surface is also reachable from the browser,
|
|
3339
3568
|
// so wrapper-route sanitization alone is not enough to keep adapter
|
|
@@ -1158,7 +1158,35 @@ async function createBetterAuthInstance(config) {
|
|
|
1158
1158
|
storeToken: "hashed",
|
|
1159
1159
|
rateLimit: { window: 60, max: 5 },
|
|
1160
1160
|
disableSignUp,
|
|
1161
|
-
sendMagicLink: async ({ email, url }) => {
|
|
1161
|
+
sendMagicLink: async ({ email, url, token }) => {
|
|
1162
|
+
let urlPath;
|
|
1163
|
+
let urlQueryKeys;
|
|
1164
|
+
try {
|
|
1165
|
+
const parsedURL = new URL(url);
|
|
1166
|
+
urlPath = parsedURL.pathname;
|
|
1167
|
+
urlQueryKeys = [...parsedURL.searchParams.keys()].sort();
|
|
1168
|
+
}
|
|
1169
|
+
catch {
|
|
1170
|
+
// coercion-ok: diagnostics must never make email delivery fail.
|
|
1171
|
+
// Better Auth owns URL construction; keep diagnostics non-fatal.
|
|
1172
|
+
}
|
|
1173
|
+
if (typeof token === "string") {
|
|
1174
|
+
console.info("[agent-native][magic-link]", {
|
|
1175
|
+
phase: "issued",
|
|
1176
|
+
tokenDigest: crypto
|
|
1177
|
+
.createHash("sha256")
|
|
1178
|
+
.update(token)
|
|
1179
|
+
.digest("hex")
|
|
1180
|
+
.slice(0, 16),
|
|
1181
|
+
expectedStoredIdentifierPrefix: crypto
|
|
1182
|
+
.createHash("sha256")
|
|
1183
|
+
.update(token)
|
|
1184
|
+
.digest("base64url")
|
|
1185
|
+
.slice(0, 16),
|
|
1186
|
+
urlPath,
|
|
1187
|
+
urlQueryKeys,
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1162
1190
|
const appBasePath = (process.env.VITE_APP_BASE_PATH ||
|
|
1163
1191
|
process.env.APP_BASE_PATH ||
|
|
1164
1192
|
"").replace(/\/$/, "");
|
|
@@ -26,8 +26,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
expiresAt?: undefined;
|
|
27
27
|
ttlSeconds?: undefined;
|
|
28
28
|
} | {
|
|
29
|
-
error?: undefined;
|
|
30
29
|
token: string;
|
|
31
30
|
expiresAt: string;
|
|
32
31
|
ttlSeconds: number;
|
|
32
|
+
error?: undefined;
|
|
33
33
|
}>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.158.
|
|
3
|
+
"version": "0.158.8",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|