@arcblock/did-connect-service 4.1.21 → 4.1.23
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/_generated/asset-bytes.js +1 -1
- package/dist/_generated/asset-manifest.js +3 -3
- package/dist/assets/admin-core.1fc3260c.js +1623 -0
- package/dist/assets/admin-core.5a2d69b0.js +2067 -0
- package/dist/assets/admin-core.9fff6042.js +2083 -0
- package/dist/assets/admin-core.a13c2729.js +1461 -0
- package/dist/assets/{admin-core.40671087.js → admin-core.a63bbc69.js} +2 -12
- package/dist/assets/admin-core.c0b5af61.js +1393 -0
- package/dist/assets/admin-core.cbbdbe6d.js +1465 -0
- package/dist/assets/admin-core.e83fd379.js +1397 -0
- package/dist/assets/admin-extra.143b5774.js +2543 -0
- package/dist/assets/admin-extra.35b91f98.js +2543 -0
- package/dist/assets/admin-extra.531b187f.js +2552 -0
- package/dist/assets/admin-extra.7ca9c16b.js +2529 -0
- package/dist/assets/admin-extra.841b2bbe.js +2530 -0
- package/dist/assets/admin-extra.afcb3651.js +2528 -0
- package/dist/assets/admin.7c5d5f04.css +2312 -0
- package/dist/assets/admin.c26bb17a.css +2219 -0
- package/dist/assets/login.4404e695.js +720 -0
- package/dist/assets/login.bb9f8b03.js +720 -0
- package/dist/assets/login.d3f05790.js +720 -0
- package/dist/assets/login.fa25f37a.js +720 -0
- package/dist/blocklet-service-rpc.d.ts.map +1 -1
- package/dist/blocklet-service-rpc.js +11 -8
- package/dist/blocklet-service-rpc.js.map +1 -1
- package/dist/blocklet-service.d.ts +11 -8
- package/dist/blocklet-service.d.ts.map +1 -1
- package/dist/blocklet-service.js +32 -38
- package/dist/blocklet-service.js.map +1 -1
- package/dist/embedded.d.ts +6 -0
- package/dist/embedded.d.ts.map +1 -1
- package/dist/embedded.js +1 -0
- package/dist/embedded.js.map +1 -1
- package/dist/handlers/account-merge-handler.d.ts +63 -0
- package/dist/handlers/account-merge-handler.d.ts.map +1 -0
- package/dist/handlers/account-merge-handler.js +263 -0
- package/dist/handlers/account-merge-handler.js.map +1 -0
- package/dist/handlers/auth-handler.d.ts +9 -5
- package/dist/handlers/auth-handler.d.ts.map +1 -1
- package/dist/handlers/auth-handler.js +28 -7
- package/dist/handlers/auth-handler.js.map +1 -1
- package/dist/handlers/blocklet-js-handler.d.ts +3 -2
- package/dist/handlers/blocklet-js-handler.d.ts.map +1 -1
- package/dist/handlers/blocklet-js-handler.js +4 -2
- package/dist/handlers/blocklet-js-handler.js.map +1 -1
- package/dist/handlers/branding-handler.d.ts +4 -0
- package/dist/handlers/branding-handler.d.ts.map +1 -1
- package/dist/handlers/branding-handler.js +12 -6
- package/dist/handlers/branding-handler.js.map +1 -1
- package/dist/handlers/cimd.d.ts +6 -1
- package/dist/handlers/cimd.d.ts.map +1 -1
- package/dist/handlers/cimd.js +12 -2
- package/dist/handlers/cimd.js.map +1 -1
- package/dist/handlers/did-connect-handler.d.ts +22 -0
- package/dist/handlers/did-connect-handler.d.ts.map +1 -1
- package/dist/handlers/did-connect-handler.js +191 -17
- package/dist/handlers/did-connect-handler.js.map +1 -1
- package/dist/handlers/email-login-handler.d.ts +2 -0
- package/dist/handlers/email-login-handler.d.ts.map +1 -1
- package/dist/handlers/email-login-handler.js +30 -14
- package/dist/handlers/email-login-handler.js.map +1 -1
- package/dist/handlers/oauth-handler.d.ts +15 -0
- package/dist/handlers/oauth-handler.d.ts.map +1 -1
- package/dist/handlers/oauth-handler.js +107 -43
- package/dist/handlers/oauth-handler.js.map +1 -1
- package/dist/handlers/passkey-handler.d.ts.map +1 -1
- package/dist/handlers/passkey-handler.js +40 -8
- package/dist/handlers/passkey-handler.js.map +1 -1
- package/dist/handlers/team-handler.d.ts +1 -1
- package/dist/handlers/team-handler.d.ts.map +1 -1
- package/dist/handlers/team-handler.js +43 -3
- package/dist/handlers/team-handler.js.map +1 -1
- package/dist/handlers/ticket-handler.d.ts.map +1 -1
- package/dist/handlers/ticket-handler.js +4 -2
- package/dist/handlers/ticket-handler.js.map +1 -1
- package/dist/handlers/unbind-account.d.ts +22 -0
- package/dist/handlers/unbind-account.d.ts.map +1 -0
- package/dist/handlers/unbind-account.js +20 -0
- package/dist/handlers/unbind-account.js.map +1 -0
- package/dist/http/security-headers.d.ts +38 -0
- package/dist/http/security-headers.d.ts.map +1 -0
- package/dist/http/security-headers.js +67 -0
- package/dist/http/security-headers.js.map +1 -0
- package/dist/identity/account-state.d.ts +37 -0
- package/dist/identity/account-state.d.ts.map +1 -0
- package/dist/identity/account-state.js +97 -0
- package/dist/identity/account-state.js.map +1 -0
- package/dist/identity/json-content-type.d.ts +14 -0
- package/dist/identity/json-content-type.d.ts.map +1 -0
- package/dist/identity/json-content-type.js +26 -0
- package/dist/identity/json-content-type.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/oauth-adapters/apple.d.ts +1 -1
- package/dist/oauth-adapters/apple.d.ts.map +1 -1
- package/dist/oauth-adapters/apple.js +2 -0
- package/dist/oauth-adapters/apple.js.map +1 -1
- package/dist/oauth-adapters/auth0-legacy.d.ts +1 -1
- package/dist/oauth-adapters/auth0-legacy.d.ts.map +1 -1
- package/dist/oauth-adapters/auth0-legacy.js +2 -0
- package/dist/oauth-adapters/auth0-legacy.js.map +1 -1
- package/dist/oauth-adapters/auth0.d.ts +1 -1
- package/dist/oauth-adapters/auth0.d.ts.map +1 -1
- package/dist/oauth-adapters/auth0.js +2 -0
- package/dist/oauth-adapters/auth0.js.map +1 -1
- package/dist/oauth-adapters/github.d.ts.map +1 -1
- package/dist/oauth-adapters/github.js +19 -12
- package/dist/oauth-adapters/github.js.map +1 -1
- package/dist/oauth-adapters/google.d.ts +1 -1
- package/dist/oauth-adapters/google.d.ts.map +1 -1
- package/dist/oauth-adapters/google.js +2 -0
- package/dist/oauth-adapters/google.js.map +1 -1
- package/dist/oauth-adapters/types.d.ts +7 -0
- package/dist/oauth-adapters/types.d.ts.map +1 -1
- package/dist/oauth-adapters/types.js +4 -1
- package/dist/oauth-adapters/types.js.map +1 -1
- package/dist/package-branding.d.ts +18 -0
- package/dist/package-branding.d.ts.map +1 -0
- package/dist/package-branding.js +103 -0
- package/dist/package-branding.js.map +1 -0
- package/dist/pages/admin/i18n.d.ts.map +1 -1
- package/dist/pages/admin/i18n.js +86 -0
- package/dist/pages/admin/i18n.js.map +1 -1
- package/dist/pages/admin/index.d.ts +4 -0
- package/dist/pages/admin/index.d.ts.map +1 -1
- package/dist/pages/admin/index.js +10 -2
- package/dist/pages/admin/index.js.map +1 -1
- package/dist/pages/admin/merge-confirm-view.d.ts +48 -0
- package/dist/pages/admin/merge-confirm-view.d.ts.map +1 -0
- package/dist/pages/admin/merge-confirm-view.js +85 -0
- package/dist/pages/admin/merge-confirm-view.js.map +1 -0
- package/dist/pages/admin/merge-method-picker.d.ts +12 -0
- package/dist/pages/admin/merge-method-picker.d.ts.map +1 -0
- package/dist/pages/admin/merge-method-picker.js +34 -0
- package/dist/pages/admin/merge-method-picker.js.map +1 -0
- package/dist/pages/admin/oauth-popup-close.d.ts +13 -0
- package/dist/pages/admin/oauth-popup-close.d.ts.map +1 -0
- package/dist/pages/admin/oauth-popup-close.js +15 -0
- package/dist/pages/admin/oauth-popup-close.js.map +1 -0
- package/dist/pages/admin/styles.d.ts +1 -1
- package/dist/pages/admin/styles.d.ts.map +1 -1
- package/dist/pages/admin/styles.js +83 -0
- package/dist/pages/admin/styles.js.map +1 -1
- package/dist/pages/admin/tab-audit.d.ts +1 -1
- package/dist/pages/admin/tab-audit.d.ts.map +1 -1
- package/dist/pages/admin/tab-audit.js +12 -0
- package/dist/pages/admin/tab-audit.js.map +1 -1
- package/dist/pages/admin/tab-profile-accounts.d.ts.map +1 -1
- package/dist/pages/admin/tab-profile-accounts.js +509 -3
- package/dist/pages/admin/tab-profile-accounts.js.map +1 -1
- package/dist/pages/invite-page.d.ts +1 -0
- package/dist/pages/invite-page.d.ts.map +1 -1
- package/dist/pages/invite-page.js +13 -3
- package/dist/pages/invite-page.js.map +1 -1
- package/dist/store/account-merge.d.ts +167 -0
- package/dist/store/account-merge.d.ts.map +1 -0
- package/dist/store/account-merge.js +313 -0
- package/dist/store/account-merge.js.map +1 -0
- package/dist/store/d1-store.d.ts +97 -7
- package/dist/store/d1-store.d.ts.map +1 -1
- package/dist/store/d1-store.js +421 -23
- package/dist/store/d1-store.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/migrations/0015_connected_accounts_id_index.sql +6 -0
- package/migrations/0016_did_aliases.sql +11 -0
- package/migrations/0017_unbind_revoke_and_cascade.sql +49 -0
- package/migrations/0018_primary_credential_did.sql +54 -0
- package/migrations/0019_account_merge.sql +16 -0
- package/migrations/0020_dedupe_connected_accounts.sql +24 -0
- package/package.json +3 -3
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account-merge store operations (#149). Writers flatten aliases and keep
|
|
3
|
+
* the higher `roleLevel()` membership per instance. Callers pass a D1
|
|
4
|
+
* database; D1Store wraps these and invalidates membership cache.
|
|
5
|
+
*/
|
|
6
|
+
export declare const MERGE_START_TTL_SECONDS: number;
|
|
7
|
+
export declare const MERGE_INTENT_TTL_MS: number;
|
|
8
|
+
export declare const MERGE_START_CACHE_PREFIX = "merge-start:";
|
|
9
|
+
/** Refuse a single merge batch that would monopolize D1 (#174). */
|
|
10
|
+
export declare const MERGE_BATCH_MAX_STATEMENTS = 800;
|
|
11
|
+
/** Fixed statements in every merge batch: alias insert, flatten, revoke A, revoke B, mark A, bump B. */
|
|
12
|
+
export declare const MERGE_BATCH_FIXED_STATEMENTS = 6;
|
|
13
|
+
export declare const MERGE_TOO_LARGE_ERROR = "Merge touches too many rows; split the accounts or handle this merge manually";
|
|
14
|
+
/** Stable host-side warning codes. User copy lives in i18n.ts (#189). */
|
|
15
|
+
export declare const MERGE_HOST_WARNINGS: readonly ["blocklet-owner-clash", "external-token-rebind"];
|
|
16
|
+
export type MergeHostWarningCode = (typeof MERGE_HOST_WARNINGS)[number];
|
|
17
|
+
export interface MergeCredential {
|
|
18
|
+
did: string;
|
|
19
|
+
provider: string;
|
|
20
|
+
id: string | null;
|
|
21
|
+
}
|
|
22
|
+
export interface MergeSkippedConflict extends MergeCredential {
|
|
23
|
+
reason: string;
|
|
24
|
+
}
|
|
25
|
+
export interface MergeMovedMembership {
|
|
26
|
+
instanceDid: string;
|
|
27
|
+
role: string;
|
|
28
|
+
invitedBy: string | null;
|
|
29
|
+
createdAt: string | null;
|
|
30
|
+
createdBy: string | null;
|
|
31
|
+
}
|
|
32
|
+
export interface MergeMergedMembership {
|
|
33
|
+
instanceDid: string;
|
|
34
|
+
fromRole: string;
|
|
35
|
+
intoRoleBefore: string;
|
|
36
|
+
keptRole: string;
|
|
37
|
+
fromRow: MergeMovedMembership;
|
|
38
|
+
}
|
|
39
|
+
export interface MergeAccessKey {
|
|
40
|
+
accessKeyId: string;
|
|
41
|
+
createdBy: string;
|
|
42
|
+
}
|
|
43
|
+
export interface MergeAliasCreated {
|
|
44
|
+
did: string;
|
|
45
|
+
canonicalDid: string;
|
|
46
|
+
reason: "merged";
|
|
47
|
+
}
|
|
48
|
+
export interface MergeAliasRewritten {
|
|
49
|
+
did: string;
|
|
50
|
+
fromCanonicalDid: string;
|
|
51
|
+
toCanonicalDid: string;
|
|
52
|
+
}
|
|
53
|
+
export interface MergeIntoRole {
|
|
54
|
+
instanceDid: string;
|
|
55
|
+
role: string;
|
|
56
|
+
}
|
|
57
|
+
export interface MergeSnapshot {
|
|
58
|
+
fromDid: string;
|
|
59
|
+
intoDid: string;
|
|
60
|
+
credentials: MergeCredential[];
|
|
61
|
+
skippedConflicts: MergeSkippedConflict[];
|
|
62
|
+
memberships: {
|
|
63
|
+
moved: MergeMovedMembership[];
|
|
64
|
+
merged: MergeMergedMembership[];
|
|
65
|
+
};
|
|
66
|
+
accessKeys: MergeAccessKey[];
|
|
67
|
+
aliasesCreated: MergeAliasCreated[];
|
|
68
|
+
aliasesRewritten: MergeAliasRewritten[];
|
|
69
|
+
intoPreMergeRoles: MergeIntoRole[];
|
|
70
|
+
didSpace: {
|
|
71
|
+
copied: false;
|
|
72
|
+
pointer: string;
|
|
73
|
+
};
|
|
74
|
+
hostWarnings: MergeHostWarningCode[];
|
|
75
|
+
fromPrimaryCredentialDid: string | null;
|
|
76
|
+
fromPasskeyCount: number;
|
|
77
|
+
intoPasskeyCount: number;
|
|
78
|
+
movedPasskeyCount: number;
|
|
79
|
+
}
|
|
80
|
+
export interface MergeIntentRow {
|
|
81
|
+
tokenHash: string;
|
|
82
|
+
fromDid: string;
|
|
83
|
+
intoDid: string;
|
|
84
|
+
expiresAt: string;
|
|
85
|
+
usedAt: string | null;
|
|
86
|
+
}
|
|
87
|
+
export interface MergePlanView {
|
|
88
|
+
fromDid: string;
|
|
89
|
+
intoDid: string;
|
|
90
|
+
credentials: MergeCredential[];
|
|
91
|
+
skippedConflicts: MergeSkippedConflict[];
|
|
92
|
+
memberships: MergeSnapshot["memberships"];
|
|
93
|
+
accessKeys: MergeAccessKey[];
|
|
94
|
+
aliasesCreated: MergeAliasCreated[];
|
|
95
|
+
aliasesRewritten: MergeAliasRewritten[];
|
|
96
|
+
intoPreMergeRoles: MergeIntoRole[];
|
|
97
|
+
didSpace: {
|
|
98
|
+
copied: false;
|
|
99
|
+
pointer: string;
|
|
100
|
+
};
|
|
101
|
+
hostWarnings: MergeHostWarningCode[];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Dry-run payload for the confirm page (#189). Counts + provider/role lists;
|
|
105
|
+
* no credential id, instanceDid, or accessKeyId (#176).
|
|
106
|
+
*/
|
|
107
|
+
export interface MergeConfirmPlan {
|
|
108
|
+
fromDid: string;
|
|
109
|
+
intoDid: string;
|
|
110
|
+
credentialCount: number;
|
|
111
|
+
credentialsByProvider: Array<{
|
|
112
|
+
provider: string;
|
|
113
|
+
}>;
|
|
114
|
+
skippedConflictCount: number;
|
|
115
|
+
skippedConflicts: Array<{
|
|
116
|
+
provider: string;
|
|
117
|
+
reason: string;
|
|
118
|
+
}>;
|
|
119
|
+
membershipMovedCount: number;
|
|
120
|
+
membershipMergedCount: number;
|
|
121
|
+
membershipChanges: Array<{
|
|
122
|
+
fromRole: string;
|
|
123
|
+
intoRoleBefore: string;
|
|
124
|
+
keptRole: string;
|
|
125
|
+
}>;
|
|
126
|
+
accessKeyCount: number;
|
|
127
|
+
aliasCreatedCount: number;
|
|
128
|
+
aliasRewrittenCount: number;
|
|
129
|
+
didSpace: {
|
|
130
|
+
copied: false;
|
|
131
|
+
pointer: string;
|
|
132
|
+
};
|
|
133
|
+
hostWarningCodes: MergeHostWarningCode[];
|
|
134
|
+
tooLarge: boolean;
|
|
135
|
+
}
|
|
136
|
+
export declare function mergeStartCacheKey(tokenHash: string): string;
|
|
137
|
+
export declare function didSpacePointer(fromDid: string): string;
|
|
138
|
+
export declare function higherRole(a: string, b: string): string;
|
|
139
|
+
export declare function createMergeStartChallenge(): Promise<{
|
|
140
|
+
challenge: string;
|
|
141
|
+
tokenHash: string;
|
|
142
|
+
expiresAt: string;
|
|
143
|
+
}>;
|
|
144
|
+
export declare function createMergeIntentToken(): Promise<{
|
|
145
|
+
token: string;
|
|
146
|
+
tokenHash: string;
|
|
147
|
+
expiresAt: string;
|
|
148
|
+
}>;
|
|
149
|
+
export declare function hashMergeToken(token: string): Promise<string>;
|
|
150
|
+
export declare function insertMergeIntent(db: D1Database, input: {
|
|
151
|
+
tokenHash: string;
|
|
152
|
+
fromDid: string;
|
|
153
|
+
intoDid: string;
|
|
154
|
+
expiresAt: string;
|
|
155
|
+
}): Promise<void>;
|
|
156
|
+
export declare function getMergeIntentByHash(db: D1Database, tokenHash: string): Promise<MergeIntentRow | null>;
|
|
157
|
+
export declare function intentIsUsable(intent: MergeIntentRow, now?: number): "ok" | "used" | "expired";
|
|
158
|
+
export declare function consumeMergeIntent(db: D1Database, tokenHash: string, usedAt: string): Promise<boolean>;
|
|
159
|
+
export declare function buildMergeSnapshot(db: D1Database, fromDid: string, intoDid: string): Promise<MergeSnapshot>;
|
|
160
|
+
export declare function toMergePlanView(snapshot: MergeSnapshot): MergePlanView;
|
|
161
|
+
export declare function willMovePrimaryCredential(snapshot: MergeSnapshot): boolean;
|
|
162
|
+
/** Same formula `commitMergeBatch` uses to size the D1 batch (#189). */
|
|
163
|
+
export declare function countMergeStatements(snapshot: MergeSnapshot): number;
|
|
164
|
+
export declare function toMergeConfirmPlan(snapshot: MergeSnapshot): MergeConfirmPlan;
|
|
165
|
+
export declare function commitMergeBatch(db: D1Database, snapshot: MergeSnapshot, now: string): Promise<void>;
|
|
166
|
+
export declare function hashSnapshot(snapshot: MergeSnapshot): Promise<string>;
|
|
167
|
+
//# sourceMappingURL=account-merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-merge.d.ts","sourceRoot":"","sources":["../../src/store/account-merge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account-merge store operations (#149). Writers flatten aliases and keep
|
|
3
|
+
* the higher `roleLevel()` membership per instance. Callers pass a D1
|
|
4
|
+
* database; D1Store wraps these and invalidates membership cache.
|
|
5
|
+
*/
|
|
6
|
+
import { roleLevel } from "../access/rbac.js";
|
|
7
|
+
import { hashRefreshToken } from "../identity/refresh-tokens.js";
|
|
8
|
+
const FLATTEN_DID_ALIASES_SQL = "UPDATE cs_did_aliases SET canonicalDid = ? WHERE canonicalDid = ?";
|
|
9
|
+
export const MERGE_START_TTL_SECONDS = 10 * 60;
|
|
10
|
+
export const MERGE_INTENT_TTL_MS = 10 * 60 * 1000;
|
|
11
|
+
export const MERGE_START_CACHE_PREFIX = "merge-start:";
|
|
12
|
+
/** Refuse a single merge batch that would monopolize D1 (#174). */
|
|
13
|
+
export const MERGE_BATCH_MAX_STATEMENTS = 800;
|
|
14
|
+
/** Fixed statements in every merge batch: alias insert, flatten, revoke A, revoke B, mark A, bump B. */
|
|
15
|
+
export const MERGE_BATCH_FIXED_STATEMENTS = 6;
|
|
16
|
+
export const MERGE_TOO_LARGE_ERROR = "Merge touches too many rows; split the accounts or handle this merge manually";
|
|
17
|
+
/** Stable host-side warning codes. User copy lives in i18n.ts (#189). */
|
|
18
|
+
export const MERGE_HOST_WARNINGS = ["blocklet-owner-clash", "external-token-rebind"];
|
|
19
|
+
function randomToken() {
|
|
20
|
+
const bytes = new Uint8Array(32);
|
|
21
|
+
crypto.getRandomValues(bytes);
|
|
22
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
23
|
+
}
|
|
24
|
+
export function mergeStartCacheKey(tokenHash) {
|
|
25
|
+
return `${MERGE_START_CACHE_PREFIX}${tokenHash}`;
|
|
26
|
+
}
|
|
27
|
+
export function didSpacePointer(fromDid) {
|
|
28
|
+
return `/user/.archive/${fromDid}/`;
|
|
29
|
+
}
|
|
30
|
+
export function higherRole(a, b) {
|
|
31
|
+
return roleLevel(a) >= roleLevel(b) ? a : b;
|
|
32
|
+
}
|
|
33
|
+
export async function createMergeStartChallenge() {
|
|
34
|
+
const challenge = randomToken();
|
|
35
|
+
const tokenHash = await hashRefreshToken(challenge);
|
|
36
|
+
const expiresAt = new Date(Date.now() + MERGE_START_TTL_SECONDS * 1000).toISOString();
|
|
37
|
+
return { challenge, tokenHash, expiresAt };
|
|
38
|
+
}
|
|
39
|
+
export async function createMergeIntentToken() {
|
|
40
|
+
const token = randomToken();
|
|
41
|
+
const tokenHash = await hashRefreshToken(token);
|
|
42
|
+
const expiresAt = new Date(Date.now() + MERGE_INTENT_TTL_MS).toISOString();
|
|
43
|
+
return { token, tokenHash, expiresAt };
|
|
44
|
+
}
|
|
45
|
+
export async function hashMergeToken(token) {
|
|
46
|
+
return hashRefreshToken(token);
|
|
47
|
+
}
|
|
48
|
+
export async function insertMergeIntent(db, input) {
|
|
49
|
+
await db
|
|
50
|
+
.prepare(`INSERT INTO cs_merge_intents (tokenHash, fromDid, intoDid, expiresAt, usedAt)
|
|
51
|
+
VALUES (?, ?, ?, ?, NULL)`)
|
|
52
|
+
.bind(input.tokenHash, input.fromDid, input.intoDid, input.expiresAt)
|
|
53
|
+
.run();
|
|
54
|
+
}
|
|
55
|
+
export async function getMergeIntentByHash(db, tokenHash) {
|
|
56
|
+
return ((await db
|
|
57
|
+
.prepare("SELECT tokenHash, fromDid, intoDid, expiresAt, usedAt FROM cs_merge_intents WHERE tokenHash = ?")
|
|
58
|
+
.bind(tokenHash)
|
|
59
|
+
.first()) ?? null);
|
|
60
|
+
}
|
|
61
|
+
export function intentIsUsable(intent, now = Date.now()) {
|
|
62
|
+
if (intent.usedAt)
|
|
63
|
+
return "used";
|
|
64
|
+
if (new Date(intent.expiresAt).getTime() <= now)
|
|
65
|
+
return "expired";
|
|
66
|
+
return "ok";
|
|
67
|
+
}
|
|
68
|
+
export async function consumeMergeIntent(db, tokenHash, usedAt) {
|
|
69
|
+
await db
|
|
70
|
+
.prepare(`UPDATE cs_merge_intents SET usedAt = ?
|
|
71
|
+
WHERE tokenHash = ? AND usedAt IS NULL AND expiresAt > ?`)
|
|
72
|
+
.bind(usedAt, tokenHash, usedAt)
|
|
73
|
+
.run();
|
|
74
|
+
const row = await db
|
|
75
|
+
.prepare("SELECT usedAt FROM cs_merge_intents WHERE tokenHash = ?")
|
|
76
|
+
.bind(tokenHash)
|
|
77
|
+
.first();
|
|
78
|
+
return row?.usedAt === usedAt;
|
|
79
|
+
}
|
|
80
|
+
async function listConnected(db, userDid) {
|
|
81
|
+
const rows = await db
|
|
82
|
+
.prepare("SELECT did, provider, id, userDid FROM cs_connected_accounts WHERE userDid = ?")
|
|
83
|
+
.bind(userDid)
|
|
84
|
+
.all();
|
|
85
|
+
return rows.results ?? [];
|
|
86
|
+
}
|
|
87
|
+
async function listMembershipsForUser(db, userDid) {
|
|
88
|
+
const rows = await db
|
|
89
|
+
.prepare("SELECT user_did, instance_did, role, invited_by, created_at, created_by FROM cs_memberships WHERE user_did = ?")
|
|
90
|
+
.bind(userDid)
|
|
91
|
+
.all();
|
|
92
|
+
return rows.results ?? [];
|
|
93
|
+
}
|
|
94
|
+
async function listAccessKeysByCreator(db, createdBy) {
|
|
95
|
+
const rows = await db
|
|
96
|
+
.prepare("SELECT accessKeyId, createdBy FROM cs_access_keys WHERE createdBy = ?")
|
|
97
|
+
.bind(createdBy)
|
|
98
|
+
.all();
|
|
99
|
+
return rows.results ?? [];
|
|
100
|
+
}
|
|
101
|
+
async function listAliasesPointingAt(db, canonicalDid) {
|
|
102
|
+
const rows = await db
|
|
103
|
+
.prepare("SELECT did, canonicalDid FROM cs_did_aliases WHERE canonicalDid = ?")
|
|
104
|
+
.bind(canonicalDid)
|
|
105
|
+
.all();
|
|
106
|
+
return rows.results ?? [];
|
|
107
|
+
}
|
|
108
|
+
export async function buildMergeSnapshot(db, fromDid, intoDid) {
|
|
109
|
+
const [fromAccounts, intoAccounts, fromMemberships, intoMemberships, accessKeys, ancestorAliases, fromUser, intoUser] = await Promise.all([
|
|
110
|
+
listConnected(db, fromDid),
|
|
111
|
+
listConnected(db, intoDid),
|
|
112
|
+
listMembershipsForUser(db, fromDid),
|
|
113
|
+
listMembershipsForUser(db, intoDid),
|
|
114
|
+
listAccessKeysByCreator(db, fromDid),
|
|
115
|
+
listAliasesPointingAt(db, fromDid),
|
|
116
|
+
db
|
|
117
|
+
.prepare("SELECT primaryCredentialDid, passkeyCount FROM cs_users WHERE did = ?")
|
|
118
|
+
.bind(fromDid)
|
|
119
|
+
.first(),
|
|
120
|
+
db
|
|
121
|
+
.prepare("SELECT passkeyCount FROM cs_users WHERE did = ?")
|
|
122
|
+
.bind(intoDid)
|
|
123
|
+
.first(),
|
|
124
|
+
]);
|
|
125
|
+
const intoByProviderId = new Set(intoAccounts.filter((a) => a.provider && a.id).map((a) => `${a.provider}\0${a.id}`));
|
|
126
|
+
const credentials = [];
|
|
127
|
+
const skippedConflicts = [];
|
|
128
|
+
for (const account of fromAccounts) {
|
|
129
|
+
const key = account.provider && account.id ? `${account.provider}\0${account.id}` : "";
|
|
130
|
+
if (key && intoByProviderId.has(key)) {
|
|
131
|
+
skippedConflicts.push({
|
|
132
|
+
did: account.did,
|
|
133
|
+
provider: account.provider,
|
|
134
|
+
id: account.id,
|
|
135
|
+
reason: "UNIQUE(provider,id)",
|
|
136
|
+
});
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
credentials.push({ did: account.did, provider: account.provider, id: account.id });
|
|
140
|
+
}
|
|
141
|
+
const intoByInstance = new Map(intoMemberships.map((m) => [m.instance_did, m]));
|
|
142
|
+
const moved = [];
|
|
143
|
+
const merged = [];
|
|
144
|
+
for (const row of fromMemberships) {
|
|
145
|
+
const existing = intoByInstance.get(row.instance_did);
|
|
146
|
+
const fromRow = {
|
|
147
|
+
instanceDid: row.instance_did,
|
|
148
|
+
role: row.role,
|
|
149
|
+
invitedBy: row.invited_by,
|
|
150
|
+
createdAt: row.created_at,
|
|
151
|
+
createdBy: row.created_by,
|
|
152
|
+
};
|
|
153
|
+
if (!existing) {
|
|
154
|
+
moved.push(fromRow);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
merged.push({
|
|
158
|
+
instanceDid: row.instance_did,
|
|
159
|
+
fromRole: row.role,
|
|
160
|
+
intoRoleBefore: existing.role,
|
|
161
|
+
keptRole: higherRole(row.role, existing.role),
|
|
162
|
+
fromRow,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
const intoPreMergeRoles = intoMemberships.map((m) => ({
|
|
166
|
+
instanceDid: m.instance_did,
|
|
167
|
+
role: m.role,
|
|
168
|
+
}));
|
|
169
|
+
const aliasesCreated = [{ did: fromDid, canonicalDid: intoDid, reason: "merged" }];
|
|
170
|
+
const aliasesRewritten = ancestorAliases
|
|
171
|
+
.filter((row) => row.did !== fromDid)
|
|
172
|
+
.map((row) => ({
|
|
173
|
+
did: row.did,
|
|
174
|
+
fromCanonicalDid: row.canonicalDid,
|
|
175
|
+
toCanonicalDid: intoDid,
|
|
176
|
+
}));
|
|
177
|
+
const movedPasskeyCount = credentials.filter((c) => c.provider === "passkey").length;
|
|
178
|
+
return {
|
|
179
|
+
fromDid,
|
|
180
|
+
intoDid,
|
|
181
|
+
credentials,
|
|
182
|
+
skippedConflicts,
|
|
183
|
+
memberships: { moved, merged },
|
|
184
|
+
accessKeys,
|
|
185
|
+
aliasesCreated,
|
|
186
|
+
aliasesRewritten,
|
|
187
|
+
intoPreMergeRoles,
|
|
188
|
+
didSpace: { copied: false, pointer: didSpacePointer(fromDid) },
|
|
189
|
+
hostWarnings: [...MERGE_HOST_WARNINGS],
|
|
190
|
+
fromPrimaryCredentialDid: fromUser?.primaryCredentialDid ?? null,
|
|
191
|
+
fromPasskeyCount: Number(fromUser?.passkeyCount ?? 0),
|
|
192
|
+
intoPasskeyCount: Number(intoUser?.passkeyCount ?? 0),
|
|
193
|
+
movedPasskeyCount,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
export function toMergePlanView(snapshot) {
|
|
197
|
+
return {
|
|
198
|
+
fromDid: snapshot.fromDid,
|
|
199
|
+
intoDid: snapshot.intoDid,
|
|
200
|
+
credentials: snapshot.credentials,
|
|
201
|
+
skippedConflicts: snapshot.skippedConflicts,
|
|
202
|
+
memberships: snapshot.memberships,
|
|
203
|
+
accessKeys: snapshot.accessKeys,
|
|
204
|
+
aliasesCreated: snapshot.aliasesCreated,
|
|
205
|
+
aliasesRewritten: snapshot.aliasesRewritten,
|
|
206
|
+
intoPreMergeRoles: snapshot.intoPreMergeRoles,
|
|
207
|
+
didSpace: snapshot.didSpace,
|
|
208
|
+
hostWarnings: snapshot.hostWarnings,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
export function willMovePrimaryCredential(snapshot) {
|
|
212
|
+
return Boolean(snapshot.fromPrimaryCredentialDid &&
|
|
213
|
+
snapshot.credentials.some((c) => c.did === snapshot.fromPrimaryCredentialDid));
|
|
214
|
+
}
|
|
215
|
+
/** Same formula `commitMergeBatch` uses to size the D1 batch (#189). */
|
|
216
|
+
export function countMergeStatements(snapshot) {
|
|
217
|
+
return (snapshot.credentials.length +
|
|
218
|
+
(willMovePrimaryCredential(snapshot) ? 1 : 0) +
|
|
219
|
+
snapshot.memberships.moved.length +
|
|
220
|
+
2 * snapshot.memberships.merged.length +
|
|
221
|
+
snapshot.accessKeys.length +
|
|
222
|
+
MERGE_BATCH_FIXED_STATEMENTS);
|
|
223
|
+
}
|
|
224
|
+
export function toMergeConfirmPlan(snapshot) {
|
|
225
|
+
return {
|
|
226
|
+
fromDid: snapshot.fromDid,
|
|
227
|
+
intoDid: snapshot.intoDid,
|
|
228
|
+
credentialCount: snapshot.credentials.length,
|
|
229
|
+
credentialsByProvider: snapshot.credentials.map((c) => ({ provider: c.provider })),
|
|
230
|
+
skippedConflictCount: snapshot.skippedConflicts.length,
|
|
231
|
+
skippedConflicts: snapshot.skippedConflicts.map((row) => ({
|
|
232
|
+
provider: row.provider,
|
|
233
|
+
reason: row.reason,
|
|
234
|
+
})),
|
|
235
|
+
membershipMovedCount: snapshot.memberships.moved.length,
|
|
236
|
+
membershipMergedCount: snapshot.memberships.merged.length,
|
|
237
|
+
membershipChanges: snapshot.memberships.merged.map((row) => ({
|
|
238
|
+
fromRole: row.fromRole,
|
|
239
|
+
intoRoleBefore: row.intoRoleBefore,
|
|
240
|
+
keptRole: row.keptRole,
|
|
241
|
+
})),
|
|
242
|
+
accessKeyCount: snapshot.accessKeys.length,
|
|
243
|
+
aliasCreatedCount: snapshot.aliasesCreated.length,
|
|
244
|
+
aliasRewrittenCount: snapshot.aliasesRewritten.length,
|
|
245
|
+
didSpace: snapshot.didSpace,
|
|
246
|
+
hostWarningCodes: [...MERGE_HOST_WARNINGS],
|
|
247
|
+
tooLarge: countMergeStatements(snapshot) > MERGE_BATCH_MAX_STATEMENTS,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
export async function commitMergeBatch(db, snapshot, now) {
|
|
251
|
+
const { fromDid, intoDid } = snapshot;
|
|
252
|
+
const stmts = [];
|
|
253
|
+
for (const cred of snapshot.credentials) {
|
|
254
|
+
stmts.push(db.prepare("UPDATE cs_connected_accounts SET userDid = ?, updatedAt = ? WHERE did = ?").bind(intoDid, now, cred.did));
|
|
255
|
+
}
|
|
256
|
+
const movedPrimary = willMovePrimaryCredential(snapshot);
|
|
257
|
+
if (movedPrimary) {
|
|
258
|
+
stmts.push(db
|
|
259
|
+
.prepare("UPDATE cs_users SET primaryCredentialDid = NULL, updatedAt = ? WHERE did = ?")
|
|
260
|
+
.bind(now, fromDid));
|
|
261
|
+
}
|
|
262
|
+
for (const row of snapshot.memberships.moved) {
|
|
263
|
+
stmts.push(db
|
|
264
|
+
.prepare("UPDATE cs_memberships SET user_did = ?, updated_at = ? WHERE user_did = ? AND instance_did = ?")
|
|
265
|
+
.bind(intoDid, now, fromDid, row.instanceDid));
|
|
266
|
+
}
|
|
267
|
+
for (const row of snapshot.memberships.merged) {
|
|
268
|
+
stmts.push(db
|
|
269
|
+
.prepare("UPDATE cs_memberships SET role = ?, updated_at = ? WHERE user_did = ? AND instance_did = ?")
|
|
270
|
+
.bind(row.keptRole, now, intoDid, row.instanceDid));
|
|
271
|
+
stmts.push(db
|
|
272
|
+
.prepare("DELETE FROM cs_memberships WHERE user_did = ? AND instance_did = ?")
|
|
273
|
+
.bind(fromDid, row.instanceDid));
|
|
274
|
+
}
|
|
275
|
+
for (const key of snapshot.accessKeys) {
|
|
276
|
+
stmts.push(db
|
|
277
|
+
.prepare("UPDATE cs_access_keys SET createdBy = ?, updatedAt = ? WHERE accessKeyId = ?")
|
|
278
|
+
.bind(intoDid, now, key.accessKeyId));
|
|
279
|
+
}
|
|
280
|
+
stmts.push(db
|
|
281
|
+
.prepare(`INSERT INTO cs_did_aliases (did, canonicalDid, reason, evidence, createdAt)
|
|
282
|
+
VALUES (?, ?, 'merged', NULL, ?)
|
|
283
|
+
ON CONFLICT(did) DO UPDATE SET
|
|
284
|
+
canonicalDid = excluded.canonicalDid,
|
|
285
|
+
reason = excluded.reason`)
|
|
286
|
+
.bind(fromDid, intoDid, now));
|
|
287
|
+
stmts.push(db.prepare(FLATTEN_DID_ALIASES_SQL).bind(intoDid, fromDid));
|
|
288
|
+
stmts.push(db
|
|
289
|
+
.prepare("UPDATE cs_refresh_tokens SET revokedAt = datetime('now') WHERE userDid = ? AND revokedAt IS NULL")
|
|
290
|
+
.bind(fromDid));
|
|
291
|
+
stmts.push(db
|
|
292
|
+
.prepare("UPDATE cs_refresh_tokens SET revokedAt = datetime('now') WHERE userDid = ? AND revokedAt IS NULL")
|
|
293
|
+
.bind(intoDid));
|
|
294
|
+
const fromPasskey = Math.max(0, snapshot.fromPasskeyCount - snapshot.movedPasskeyCount);
|
|
295
|
+
const intoPasskey = snapshot.intoPasskeyCount + snapshot.movedPasskeyCount;
|
|
296
|
+
stmts.push(db
|
|
297
|
+
.prepare(`UPDATE cs_users SET mergedInto = ?, mergedAt = ?, mergeSnapshot = ?, passkeyCount = ?, updatedAt = ?
|
|
298
|
+
WHERE did = ?`)
|
|
299
|
+
.bind(intoDid, now, JSON.stringify(snapshot), fromPasskey, now, fromDid));
|
|
300
|
+
stmts.push(db.prepare("UPDATE cs_users SET passkeyCount = ?, updatedAt = ? WHERE did = ?").bind(intoPasskey, now, intoDid));
|
|
301
|
+
const expected = countMergeStatements(snapshot);
|
|
302
|
+
if (stmts.length !== expected) {
|
|
303
|
+
throw new Error(`Merge statement count mismatch: expected ${expected}, built ${stmts.length}`);
|
|
304
|
+
}
|
|
305
|
+
if (stmts.length > MERGE_BATCH_MAX_STATEMENTS) {
|
|
306
|
+
throw new Error(`${MERGE_TOO_LARGE_ERROR} (${stmts.length})`);
|
|
307
|
+
}
|
|
308
|
+
await db.batch(stmts);
|
|
309
|
+
}
|
|
310
|
+
export async function hashSnapshot(snapshot) {
|
|
311
|
+
return hashRefreshToken(JSON.stringify(snapshot));
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=account-merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-merge.js","sourceRoot":"","sources":["../../src/store/account-merge.ts"],"names":[],"mappings":"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"}
|
package/dist/store/d1-store.d.ts
CHANGED
|
@@ -6,6 +6,44 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { BindHostResult } from "../blocklet-service-rpc-types.js";
|
|
8
8
|
import type { AccessKeyInfo, AccessPolicyInfo, AuditLogInfo, CreateAccessKeyInput, CreateAccessPolicyInput, CreateAuditLogInput, CreateInvitationInput, CreateSecurityRuleInput, InvitationInfo, MemberInfo, SecurityRuleInfo, StoredAccessKey, StoredConnectedAccount, StoredInvitation, StoredUser, UpdateAccessKeyInput, UpdateAccessPolicyInput, UpdateSecurityRuleInput } from "../types.js";
|
|
9
|
+
import { type MergeIntentRow, type MergeSnapshot } from "./account-merge.js";
|
|
10
|
+
/** Allowed `cs_did_aliases.reason` values. Unknown reasons are rejected on write. */
|
|
11
|
+
export declare const DID_ALIAS_REASONS: readonly ["merged", "chain-migrated"];
|
|
12
|
+
export type DidAliasReason = (typeof DID_ALIAS_REASONS)[number];
|
|
13
|
+
export interface UpsertDidAliasInput {
|
|
14
|
+
did: string;
|
|
15
|
+
canonicalDid: string;
|
|
16
|
+
reason: DidAliasReason;
|
|
17
|
+
evidence?: string | null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Identity lookup: user DID → connected-account DID → alias source.
|
|
21
|
+
*
|
|
22
|
+
* The user arm excludes alias sources so a retained merged `cs_users(A)`
|
|
23
|
+
* row cannot hide alias `A→B` (#149 / SD-147). The connected-account arm
|
|
24
|
+
* excludes alias-source `ca.did` so a leftover wallet row on a
|
|
25
|
+
* chain-migrated OLD DID cannot hide `OLD→NEW` (#169). Skipped merge
|
|
26
|
+
* credentials are not alias sources; `getUserByDidOrConnectedAccount`
|
|
27
|
+
* follows `mergedInto` so those rows resolve to the surviving account
|
|
28
|
+
* (#176). Do not reorder the arms.
|
|
29
|
+
*/
|
|
30
|
+
export declare const GET_USER_BY_DID_OR_CONNECTED_ACCOUNT_SQL = "SELECT u.* FROM cs_users u\n WHERE u.did = ?\n AND NOT EXISTS (SELECT 1 FROM cs_did_aliases a WHERE a.did = u.did)\nUNION ALL\nSELECT u.* FROM cs_connected_accounts ca\n JOIN cs_users u ON ca.userDid = u.did\n WHERE ca.did = ?\n AND NOT EXISTS (SELECT 1 FROM cs_did_aliases a WHERE a.did = ca.did)\nUNION ALL\nSELECT u.* FROM cs_did_aliases a\n JOIN cs_users u ON a.canonicalDid = u.did WHERE a.did = ?\nLIMIT 1";
|
|
31
|
+
/** Flatten ancestors when a canonical DID itself becomes an alias (one hop). */
|
|
32
|
+
export declare const FLATTEN_DID_ALIASES_SQL = "UPDATE cs_did_aliases SET canonicalDid = ? WHERE canonicalDid = ?";
|
|
33
|
+
/**
|
|
34
|
+
* Backfill `cs_users.primaryCredentialDid` from `sourceProvider`.
|
|
35
|
+
* Among matching connected-account rows, prefer `account.did === user.did`,
|
|
36
|
+
* else oldest `createdAt` (then `did` for a stable tie-break). Leave NULL
|
|
37
|
+
* when no row matches. Idempotent: already-set values are left alone.
|
|
38
|
+
*/
|
|
39
|
+
export declare const BACKFILL_PRIMARY_CREDENTIAL_SQL = "UPDATE cs_users\nSET primaryCredentialDid = picked.credDid\nFROM (\n SELECT ownerDid, credDid FROM (\n SELECT\n u.did AS ownerDid,\n ca.did AS credDid,\n ROW_NUMBER() OVER (\n PARTITION BY u.did\n ORDER BY\n CASE WHEN ca.did = u.did THEN 0 ELSE 1 END,\n ca.createdAt ASC,\n ca.did ASC\n ) AS rn\n FROM cs_users u\n JOIN cs_connected_accounts ca\n ON ca.userDid = u.did AND ca.provider = u.sourceProvider\n ) ranked\n WHERE rn = 1\n) picked\nWHERE cs_users.did = picked.ownerDid\n AND cs_users.primaryCredentialDid IS NULL";
|
|
40
|
+
/**
|
|
41
|
+
* Drop extra `(provider, id)` rows so UNIQUE(provider, id) can be created
|
|
42
|
+
* on a legacy database. Keep `did = userDid`, else the oldest `createdAt`
|
|
43
|
+
* (then `did`). `id IS NULL` rows are left alone — SQLite UNIQUE treats
|
|
44
|
+
* NULL as distinct.
|
|
45
|
+
*/
|
|
46
|
+
export declare const DEDUPE_CONNECTED_ACCOUNTS_SQL = "DELETE FROM cs_connected_accounts\nWHERE id IS NOT NULL\n AND rowid IN (\n SELECT rowid FROM (\n SELECT\n rowid,\n ROW_NUMBER() OVER (\n PARTITION BY provider, id\n ORDER BY\n CASE WHEN did = userDid THEN 0 ELSE 1 END,\n COALESCE(createdAt, '') ASC,\n did ASC\n ) AS rn\n FROM cs_connected_accounts\n WHERE id IS NOT NULL\n ) ranked\n WHERE rn > 1\n )";
|
|
9
47
|
/** Session-JWT and OAuth refresh TTL. W4 aligns OAuth to this; do not invent a second constant. */
|
|
10
48
|
export declare const REFRESH_TOKEN_TTL_SECONDS: number;
|
|
11
49
|
export interface IssuedRefreshToken {
|
|
@@ -87,7 +125,7 @@ export declare class D1Store {
|
|
|
87
125
|
assumeMigrated?: boolean;
|
|
88
126
|
});
|
|
89
127
|
/** Run schema migration. Idempotent — only executes once per isolate.
|
|
90
|
-
* Optimized:
|
|
128
|
+
* Optimized: CREATE TABLE in a batch, ALTER TABLE in parallel, then indexes. */
|
|
91
129
|
migrate(): Promise<void>;
|
|
92
130
|
/** @internal Backwards-compatible alias for migrate(). */
|
|
93
131
|
ensureSchema(): Promise<void>;
|
|
@@ -119,6 +157,12 @@ export declare class D1Store {
|
|
|
119
157
|
}): Promise<void>;
|
|
120
158
|
getUserByDid(did: string): Promise<StoredUser | null>;
|
|
121
159
|
getUserByEmail(email: string): Promise<StoredUser | null>;
|
|
160
|
+
/**
|
|
161
|
+
* True iff another unmerged user shares `selfDid`'s verified email.
|
|
162
|
+
* Uses `lower(trim(email))` — do not call `getUserByEmail` (exact match,
|
|
163
|
+
* may return self). Users are global; no instanceDid filter. `SELECT 1 LIMIT 1`.
|
|
164
|
+
*/
|
|
165
|
+
hasVerifiedEmailMergeCandidate(selfDid: string): Promise<boolean>;
|
|
122
166
|
updateLastLogin(did: string, ip?: string, domain?: string): Promise<void>;
|
|
123
167
|
incrementPasskeyCount(did: string): Promise<void>;
|
|
124
168
|
getUserCount(): Promise<number>;
|
|
@@ -222,23 +266,41 @@ export declare class D1Store {
|
|
|
222
266
|
userInfo?: string;
|
|
223
267
|
}, actor: string): Promise<void>;
|
|
224
268
|
/**
|
|
225
|
-
* Update a user's `sourceProvider` (
|
|
269
|
+
* Update a user's `sourceProvider` (display-only registration label).
|
|
226
270
|
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
* a row for would silently disarm that guard.
|
|
271
|
+
* Security guards read `primaryCredentialDid`, not this field. Relabel is
|
|
272
|
+
* kept so profile `isMain` / audit display stay in step with the bound
|
|
273
|
+
* provider; it must not arm or disarm unbind / last-passkey checks.
|
|
231
274
|
*/
|
|
232
275
|
updateUserSourceProvider(did: string, sourceProvider: string, actor: string): Promise<void>;
|
|
233
|
-
getConnectedAccountById(
|
|
276
|
+
getConnectedAccountById(id: string, provider: string): Promise<StoredConnectedAccount | null>;
|
|
234
277
|
getConnectedAccountByDid(did: string): Promise<StoredConnectedAccount | null>;
|
|
235
278
|
updateCounter(did: string, counter: number): Promise<void>;
|
|
236
279
|
getConnectedAccountsByUserDid(userDid: string): Promise<StoredConnectedAccount[]>;
|
|
237
280
|
getConnectedAccountByProviderAndUser(provider: string, userDid: string): Promise<StoredConnectedAccount | null>;
|
|
238
281
|
getConnectedAccountsByProviderAndUser(provider: string, userDid: string): Promise<StoredConnectedAccount[]>;
|
|
239
282
|
getUserByDidOrConnectedAccount(did: string): Promise<StoredUser | null>;
|
|
283
|
+
/**
|
|
284
|
+
* Insert or update a one-hop DID alias. When `canonicalDid` is itself an
|
|
285
|
+
* alias, the write lands on that row's canonical. When `did` becomes an
|
|
286
|
+
* alias, every row pointing at it is rewritten in the same `db.batch`.
|
|
287
|
+
*/
|
|
288
|
+
upsertDidAlias(input: UpsertDidAliasInput): Promise<void>;
|
|
289
|
+
upsertDidAliases(inputs: UpsertDidAliasInput[]): Promise<void>;
|
|
240
290
|
decrementPasskeyCount(did: string): Promise<void>;
|
|
241
291
|
updateConnectedAccountName(did: string, name: string, actor: string): Promise<void>;
|
|
292
|
+
/**
|
|
293
|
+
* Point `primaryCredentialDid` at a credential the user owns, or NULL.
|
|
294
|
+
* Rejects a pointer at another user's row so writers cannot cross tenants.
|
|
295
|
+
*/
|
|
296
|
+
setPrimaryCredentialDid(userDid: string, credentialDid: string | null, actor?: string): Promise<void>;
|
|
297
|
+
/** Fill primary only when it is still NULL. Used after first credential insert. */
|
|
298
|
+
private maybeFillPrimaryCredentialDid;
|
|
299
|
+
/**
|
|
300
|
+
* Next primary among remaining credentials of the same user.
|
|
301
|
+
* Prefer `account.did === user.did`, else oldest `createdAt` (then `did`).
|
|
302
|
+
*/
|
|
303
|
+
private pickReplacementPrimaryDid;
|
|
242
304
|
deleteConnectedAccount(did: string): Promise<void>;
|
|
243
305
|
createAccessKey(input: CreateAccessKeyInput): Promise<StoredAccessKey>;
|
|
244
306
|
getAccessKeyById(accessKeyId: string): Promise<AccessKeyInfo | null>;
|
|
@@ -496,6 +558,12 @@ export declare class D1Store {
|
|
|
496
558
|
rotateRefreshToken(oldPlaintext: string, rotationSecret: string): Promise<IssuedRefreshToken>;
|
|
497
559
|
/** Revoke every token in a rotation family (theft containment). */
|
|
498
560
|
revokeRefreshTokenFamily(familyId: string): Promise<void>;
|
|
561
|
+
/**
|
|
562
|
+
* Revoke every refresh family for a user (unbind / delete stop-loss).
|
|
563
|
+
* `cs_refresh_tokens` has no credential column — this is user-scoped, not
|
|
564
|
+
* per-provider. Uses `idx_refresh_tokens_userDid`. Does not touch access JWTs.
|
|
565
|
+
*/
|
|
566
|
+
revokeRefreshTokensForUser(userDid: string): Promise<void>;
|
|
499
567
|
/**
|
|
500
568
|
* Look up a refresh token by plaintext. Used by the OAuth refresh grant.
|
|
501
569
|
* Session-JWT rows have accessKeyId = NULL — callers must reject those.
|
|
@@ -526,6 +594,28 @@ export declare class D1Store {
|
|
|
526
594
|
expiresAt: string;
|
|
527
595
|
};
|
|
528
596
|
}): Promise<void>;
|
|
597
|
+
createMergeStart(intoDid: string): Promise<{
|
|
598
|
+
challenge: string;
|
|
599
|
+
expiresAt: string;
|
|
600
|
+
}>;
|
|
601
|
+
getMergeStart(challenge: string): Promise<{
|
|
602
|
+
intoDid: string;
|
|
603
|
+
} | null>;
|
|
604
|
+
deleteMergeStart(challenge: string): Promise<void>;
|
|
605
|
+
createMergeIntent(fromDid: string, intoDid: string): Promise<{
|
|
606
|
+
token: string;
|
|
607
|
+
expiresAt: string;
|
|
608
|
+
}>;
|
|
609
|
+
getMergeIntent(tokenHash: string): Promise<MergeIntentRow | null>;
|
|
610
|
+
planAccountMerge(fromDid: string, intoDid: string): Promise<MergeSnapshot>;
|
|
611
|
+
commitAccountMerge(tokenHash: string, actorDid: string): Promise<{
|
|
612
|
+
ok: true;
|
|
613
|
+
snapshot: MergeSnapshot;
|
|
614
|
+
} | {
|
|
615
|
+
ok: false;
|
|
616
|
+
error: string;
|
|
617
|
+
status: number;
|
|
618
|
+
}>;
|
|
529
619
|
}
|
|
530
620
|
export {};
|
|
531
621
|
//# sourceMappingURL=d1-store.d.ts.map
|