@undefineds.co/xpod 0.4.9 → 0.4.11
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/api/auth/ClientCredentialsAuthenticator.d.ts +0 -1
- package/dist/api/auth/ClientCredentialsAuthenticator.js +0 -3
- package/dist/api/auth/index.d.ts +1 -0
- package/dist/api/auth/index.js +1 -1
- package/dist/identity/drizzle/AccountRoleRepository.d.ts +30 -2
- package/dist/identity/drizzle/AccountRoleRepository.js +163 -15
- package/dist/identity/drizzle/PodLookupRepository.d.ts +55 -12
- package/dist/identity/drizzle/PodLookupRepository.js +225 -243
- package/dist/identity/drizzle/db.d.ts +19 -0
- package/dist/identity/drizzle/db.js +39 -4
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.js +1 -0
- package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +1 -0
- package/node_modules/@undefineds.co/ai-connections/dist/controller.js +94 -16
- package/node_modules/@undefineds.co/shared-ui/dist/index.d.ts +0 -1
- package/node_modules/@undefineds.co/shared-ui/dist/index.js +0 -1
- package/node_modules/@undefineds.co/solid-sdk/dist/index.cjs +112 -11
- package/node_modules/@undefineds.co/solid-sdk/dist/session.d.ts +2 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/session.js +135 -11
- package/package.json +2 -2
- package/static/app/assets/main.css +1 -1
- package/static/app/assets/main.js +12 -13
- package/static/auth-callback/assets/{AiConfigContext-DJKvxduw.js → AiConfigContext-DqWRSm7n.js} +1 -1
- package/static/auth-callback/assets/{AiConfigPage-DgGmHb18.js → AiConfigPage-C5YYyvzl.js} +1 -1
- package/static/auth-callback/assets/{DocumentProcessingPanel-CJmxu8x1.js → DocumentProcessingPanel-DZCiacBz.js} +1 -1
- package/static/auth-callback/assets/{IndexLifecyclePanel-byCa7h7L.js → IndexLifecyclePanel-CCLeOljB.js} +1 -1
- package/static/auth-callback/assets/{IndexSubjectPanel-CDwT4Yx1.js → IndexSubjectPanel-BbUqop4b.js} +1 -1
- package/static/auth-callback/assets/{ModelAssignmentsPanel-CwM3k8w7.js → ModelAssignmentsPanel-jUUTDKuh.js} +1 -1
- package/static/auth-callback/assets/ModelsPage-B08zdtff.js +10 -0
- package/static/auth-callback/assets/{NetworkPage-DkVgxtNj.js → NetworkPage-Vp2PrMxs.js} +1 -1
- package/static/auth-callback/assets/{PaneListHeader-DRI0hjmt.js → PaneListHeader-DY7baSFl.js} +1 -1
- package/static/auth-callback/assets/{SearchIndexingPanel-mbppDZFE.js → SearchIndexingPanel-D4YRg1-8.js} +1 -1
- package/static/auth-callback/assets/{StatusSubjectPanel-DNsW76aC.js → StatusSubjectPanel-ArIS-TxT.js} +1 -1
- package/static/auth-callback/assets/{StatusWorkspace-DGcTbHT5.js → StatusWorkspace-Cp5LQ9Yx.js} +1 -1
- package/static/auth-callback/assets/SystemSettingsPage-BDvT1NUz.js +1 -0
- package/static/auth-callback/assets/SystemSettingsSubjectPanel-CDqRuC4t.js +33 -0
- package/static/auth-callback/assets/{activity-Ck-Mfxxo.js → activity-D1Dsfa_0.js} +1 -1
- package/static/auth-callback/assets/admin-C6qCRFiY.js +1 -0
- package/static/auth-callback/assets/{auth-callback-DG4Ge40c.js → auth-callback-Cmf4hXVZ.js} +105 -109
- package/static/auth-callback/assets/auth-callback-DWMMiFjh.css +1 -0
- package/static/auth-callback/assets/{badge-GSSnw1VV.js → badge-CZsHq3Ih.js} +1 -1
- package/static/auth-callback/assets/{download-BYyRX-K2.js → download-DU9ntlHw.js} +1 -1
- package/static/auth-callback/assets/{external-link-WEC0Ki-0.js → external-link-BfzaaZDx.js} +1 -1
- package/static/auth-callback/assets/{index-kju2k4Dp.js → index-DSNnLUbU.js} +4 -4
- package/static/auth-callback/assets/{index-DlsMCgo8.js → index-FHhHoKgp.js} +1 -1
- package/static/auth-callback/assets/{index-browser-D8YW6coF.js → index-browser-BNFqqC74.js} +1 -1
- package/static/auth-callback/assets/{key-round-DJUT5Nh0.js → key-round-BwP3DBWo.js} +1 -1
- package/static/auth-callback/assets/{rotate-ccw-CXwfZUKU.js → rotate-ccw-VMwnmyab.js} +1 -1
- package/static/auth-callback/assets/settings-projection-CUkyprDQ.js +1 -0
- package/static/auth-callback/assets/{skeleton-DWPtNhUB.js → skeleton-CoD55rBT.js} +1 -1
- package/static/auth-callback/assets/{waypoints-l1oDnRJ0.js → waypoints-DRo_1Ca7.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-B7iKpK-Q.js → workspace-layout--mcXl3My.js} +1 -1
- package/static/auth-callback/auth-callback.html +2 -2
- package/static/dashboard/assets/{AiConfigContext-U0cCSY28.js → AiConfigContext-BpPDKSzI.js} +1 -1
- package/static/dashboard/assets/{AiConfigPage-CMi0uJdo.js → AiConfigPage-wsqEZDIX.js} +1 -1
- package/static/dashboard/assets/{DocumentProcessingPanel-DEZiEpft.js → DocumentProcessingPanel-CDSy3juc.js} +1 -1
- package/static/dashboard/assets/{IndexLifecyclePanel-CGZfLUog.js → IndexLifecyclePanel-CVd6vQCX.js} +1 -1
- package/static/dashboard/assets/{IndexSubjectPanel-DiDZauHk.js → IndexSubjectPanel-B2cXwl8X.js} +1 -1
- package/static/dashboard/assets/{ModelAssignmentsPanel-DaGGZKuf.js → ModelAssignmentsPanel-BeBZhnQd.js} +1 -1
- package/static/dashboard/assets/ModelsPage-B6McSCJw.js +25 -0
- package/static/dashboard/assets/{NetworkPage-DI5-O7GT.js → NetworkPage-DV2V0qWO.js} +1 -1
- package/static/dashboard/assets/{PaneListHeader-4oa7uf59.js → PaneListHeader-D0c1yCFH.js} +1 -1
- package/static/dashboard/assets/{SearchIndexingPanel-DoqEwocD.js → SearchIndexingPanel-CGs0OZ12.js} +1 -1
- package/static/dashboard/assets/{StatusSubjectPanel-CLzBC5fu.js → StatusSubjectPanel-oPSECj7i.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-UyKADZoM.js → StatusWorkspace-PdovQPKa.js} +1 -1
- package/static/dashboard/assets/SystemSettingsPage-CtNDklkx.js +1 -0
- package/static/dashboard/assets/SystemSettingsSubjectPanel-WaE8mTQi.js +33 -0
- package/static/dashboard/assets/{activity-CjIoNU4S.js → activity-B9ylSoyr.js} +1 -1
- package/static/dashboard/assets/admin-C6qCRFiY.js +1 -0
- package/static/dashboard/assets/{badge-dcDZpKh3.js → badge-BNbFbpIb.js} +1 -1
- package/static/dashboard/assets/{dashboard-BY8GdnEI.js → dashboard-CD-FFVRD.js} +129 -133
- package/static/dashboard/assets/dashboard-DWMMiFjh.css +1 -0
- package/static/dashboard/assets/{download-BeYCrc-_.js → download-nOP38LtW.js} +1 -1
- package/static/dashboard/assets/{external-link-626-5KVx.js → external-link-Bh2ewN9E.js} +1 -1
- package/static/dashboard/assets/{index-CBbk6hx-.js → index-PgS-Bt7X.js} +1 -1
- package/static/dashboard/assets/{index-CsxH6Hmz.js → index-QN2QgEwr.js} +4 -4
- package/static/dashboard/assets/{key-round-B9IL4Wua.js → key-round-bGmguBLv.js} +1 -1
- package/static/dashboard/assets/{rotate-ccw-DM4vCfiI.js → rotate-ccw-D2x__ODW.js} +1 -1
- package/static/dashboard/assets/settings-projection-CUkyprDQ.js +1 -0
- package/static/dashboard/assets/{skeleton-ChlFAPvP.js → skeleton-VOqft8WS.js} +1 -1
- package/static/dashboard/assets/{waypoints-CvpZzf_I.js → waypoints-fgRqm4oH.js} +1 -1
- package/static/dashboard/assets/{workspace-layout-Bxv7V-tt.js → workspace-layout-DV4dgeHX.js} +1 -1
- package/static/dashboard/dashboard.html +2 -2
- package/static/settings/assets/{AiConfigContext-CDVIHLBb.js → AiConfigContext-zKQYdfai.js} +1 -1
- package/static/settings/assets/{AiConfigPage-C7qfiiaJ.js → AiConfigPage-Bs1EE3Ei.js} +1 -1
- package/static/settings/assets/{DocumentProcessingPanel-B59QTe-V.js → DocumentProcessingPanel-CSFfdOXS.js} +1 -1
- package/static/settings/assets/{IndexLifecyclePanel-C-e-3eVi.js → IndexLifecyclePanel-BR9Su49B.js} +1 -1
- package/static/settings/assets/{IndexSubjectPanel-B-scRZ1u.js → IndexSubjectPanel-BgbI9c-a.js} +1 -1
- package/static/settings/assets/{ModelAssignmentsPanel-Wy8jzVg4.js → ModelAssignmentsPanel-C0BE7nbk.js} +1 -1
- package/static/settings/assets/ModelsPage-CU-YQ8_7.js +10 -0
- package/static/settings/assets/{NetworkPage-tBB-4Ox8.js → NetworkPage-C8OA9Mtp.js} +1 -1
- package/static/settings/assets/{PaneListHeader-DuD6glzn.js → PaneListHeader-COvlPJWj.js} +1 -1
- package/static/settings/assets/{SearchIndexingPanel-CiDHc0nx.js → SearchIndexingPanel-Bdd46mIV.js} +1 -1
- package/static/settings/assets/{StatusSubjectPanel-OF5cgWwt.js → StatusSubjectPanel-BuLml7qn.js} +1 -1
- package/static/settings/assets/{StatusWorkspace-CZ8Oa0gV.js → StatusWorkspace-CoMFRXoV.js} +1 -1
- package/static/settings/assets/SystemSettingsPage-DlzmaWV-.js +1 -0
- package/static/settings/assets/SystemSettingsSubjectPanel-DExjDo_v.js +33 -0
- package/static/settings/assets/{activity-2M1f5eBS.js → activity-TLerXgMs.js} +1 -1
- package/static/settings/assets/admin-C6qCRFiY.js +1 -0
- package/static/settings/assets/{badge-CRKan0qX.js → badge-Bcs8iWrH.js} +1 -1
- package/static/settings/assets/{download-PCHldCdu.js → download-Ct3QmHPt.js} +1 -1
- package/static/settings/assets/{external-link-tmKe7eYO.js → external-link-C8KiHbss.js} +1 -1
- package/static/settings/assets/{index-Cek02M79.js → index-1Q2cRjZd.js} +1 -1
- package/static/settings/assets/{index-BDCNTwWz.js → index-DBO_Vq0P.js} +4 -4
- package/static/settings/assets/{index-browser-EVDVm9T5.js → index-browser-CazX1pc2.js} +1 -1
- package/static/settings/assets/{key-round-CUGvQCkt.js → key-round-B19YD1GA.js} +1 -1
- package/static/settings/assets/{rotate-ccw-BRA3lIHM.js → rotate-ccw-AQm2kMgU.js} +1 -1
- package/static/settings/assets/{settings-BdlKrzJ3.js → settings-C-VBtt9r.js} +129 -133
- package/static/settings/assets/settings-DWMMiFjh.css +1 -0
- package/static/settings/assets/settings-projection-CUkyprDQ.js +1 -0
- package/static/settings/assets/{skeleton-CuDeifWb.js → skeleton-DyZ1OBYf.js} +1 -1
- package/static/settings/assets/{waypoints-w6LxsFY1.js → waypoints-CC3wq-SU.js} +1 -1
- package/static/settings/assets/{workspace-layout-TN-BWmT5.js → workspace-layout-BxXNKgf9.js} +1 -1
- package/static/settings/settings.html +2 -2
- package/node_modules/@undefineds.co/shared-ui/dist/oidc-consent.d.ts +0 -54
- package/node_modules/@undefineds.co/shared-ui/dist/oidc-consent.js +0 -21
- package/static/auth-callback/assets/ModelsPage-DapY2Dwf.js +0 -10
- package/static/auth-callback/assets/SystemSettingsPage-C6qklJ9k.js +0 -1
- package/static/auth-callback/assets/SystemSettingsSubjectPanel-B4VV9xkG.js +0 -31
- package/static/auth-callback/assets/admin-BU4m6Ko2.js +0 -1
- package/static/auth-callback/assets/auth-callback-C_7MUXJb.css +0 -1
- package/static/dashboard/assets/ModelsPage-DZgAOdxO.js +0 -25
- package/static/dashboard/assets/SystemSettingsPage-qP0hLHNV.js +0 -1
- package/static/dashboard/assets/SystemSettingsSubjectPanel-EaWax9Ot.js +0 -31
- package/static/dashboard/assets/admin-BU4m6Ko2.js +0 -1
- package/static/dashboard/assets/dashboard-C_7MUXJb.css +0 -1
- package/static/settings/assets/ModelsPage-DHNiaodk.js +0 -10
- package/static/settings/assets/SystemSettingsPage-DT2tC0F_.js +0 -1
- package/static/settings/assets/SystemSettingsSubjectPanel-Bkta1oDw.js +0 -31
- package/static/settings/assets/admin-BU4m6Ko2.js +0 -1
- package/static/settings/assets/settings-C_7MUXJb.css +0 -1
|
@@ -8,6 +8,12 @@ const db_1 = require("./db");
|
|
|
8
8
|
*
|
|
9
9
|
* Reads Pod facts from the canonical identity_store table and from CSS
|
|
10
10
|
* WrappedIndexedStorage rows when that storage backend is active.
|
|
11
|
+
*
|
|
12
|
+
* 点查(findById / findAllByWebId / findByWebIds / listByAccountId)走字段下推
|
|
13
|
+
* 快路径,避免每请求全扫 identity_store;KV 历史账户记录独立读取,
|
|
14
|
+
* 同 ID 的 canonical 记录整条优先,包括无法解析的记录,不能恢复旧身份。
|
|
15
|
+
* findByResourceIdentifier / listAllPods 本质上需要
|
|
16
|
+
* 候选全集,仍保留全量读取(identity_store 侧用反向前缀 LIKE 下推预筛)。
|
|
11
17
|
*/
|
|
12
18
|
class PodLookupRepository {
|
|
13
19
|
constructor(db, kvTableName) {
|
|
@@ -17,9 +23,13 @@ class PodLookupRepository {
|
|
|
17
23
|
}
|
|
18
24
|
/**
|
|
19
25
|
* Find Pod by resource path (matches longest canonical storage/base URL prefix).
|
|
26
|
+
*
|
|
27
|
+
* kv 账户行无法按 URL 下推,保持全量解析(cloud 部署 kv 为空,local 规模有限)。
|
|
20
28
|
*/
|
|
21
29
|
async findByResourceIdentifier(resourcePath) {
|
|
22
|
-
const
|
|
30
|
+
const kvRows = await this.getAccountRowsFromKv();
|
|
31
|
+
const nodeAssignments = await this.getNodeAssignments();
|
|
32
|
+
const pods = await this.mergeCanonicalPods(this.extractKvPods(kvRows, nodeAssignments), await this.findIndexedStorePodsByResource(resourcePath, nodeAssignments), nodeAssignments);
|
|
23
33
|
let bestMatch;
|
|
24
34
|
let bestLength = 0;
|
|
25
35
|
for (const pod of pods) {
|
|
@@ -33,15 +43,19 @@ class PodLookupRepository {
|
|
|
33
43
|
}
|
|
34
44
|
/**
|
|
35
45
|
* Get Pod by ID.
|
|
46
|
+
*
|
|
47
|
+
* 快路径按主键直查 identity_store 的 pod 行并补齐 owner/node 关联;
|
|
48
|
+
* 独立读取 KV 历史记录,并按原始 ID 检查 canonical 遮蔽。
|
|
36
49
|
*/
|
|
37
50
|
async findById(podId) {
|
|
38
|
-
const
|
|
39
|
-
|
|
51
|
+
const fast = await this.getIndexedStorePodsByIds([podId]);
|
|
52
|
+
const legacy = (await this.getLegacyPods()).filter((pod) => pod.podId === podId);
|
|
53
|
+
return (await this.mergeCanonicalPods(legacy, fast)).find((pod) => pod.podId === podId);
|
|
40
54
|
}
|
|
41
55
|
/**
|
|
42
|
-
* Find Pod by
|
|
56
|
+
* Find Pod by an explicit owner or pod.webId URL.
|
|
43
57
|
*
|
|
44
|
-
*
|
|
58
|
+
* Pod ownership stores WebIDs separately from Pod base URLs. This is
|
|
45
59
|
* the precise lookup for IdP/SP split deployments where the WebID path does
|
|
46
60
|
* not have to match the storage base URL.
|
|
47
61
|
*/
|
|
@@ -49,82 +63,39 @@ class PodLookupRepository {
|
|
|
49
63
|
return (await this.findAllByWebId(webId))[0];
|
|
50
64
|
}
|
|
51
65
|
/**
|
|
52
|
-
* Find all Pods
|
|
66
|
+
* Find all Pods explicitly owned by a WebID.
|
|
53
67
|
*
|
|
54
68
|
* A Cloud WebID can legitimately back both a Cloud Pod and a Local SP Pod.
|
|
55
69
|
* Callers that are scoped to a storage provider must inspect all candidates
|
|
56
70
|
* instead of accepting the first account record returned by CSS storage.
|
|
57
71
|
*/
|
|
58
72
|
async findAllByWebId(webId) {
|
|
59
|
-
|
|
60
|
-
if (!exact) {
|
|
61
|
-
return [];
|
|
62
|
-
}
|
|
63
|
-
const results = [];
|
|
64
|
-
const pods = await this.getAllPods();
|
|
65
|
-
for (const pod of pods) {
|
|
66
|
-
const matchedWebId = getPodWebIds(pod).find((candidate) => exactWebId(candidate) === exact);
|
|
67
|
-
if (matchedWebId) {
|
|
68
|
-
results.push({
|
|
69
|
-
...pod,
|
|
70
|
-
webId: matchedWebId,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (results.length > 0) {
|
|
75
|
-
return results;
|
|
76
|
-
}
|
|
77
|
-
const indexed = await this.findByWebIdIndex(exact);
|
|
78
|
-
if (!indexed) {
|
|
79
|
-
return [];
|
|
80
|
-
}
|
|
81
|
-
return [{
|
|
82
|
-
...indexed,
|
|
83
|
-
}];
|
|
73
|
+
return this.findByWebIds([webId]);
|
|
84
74
|
}
|
|
85
75
|
/**
|
|
86
|
-
* Find Pods by
|
|
76
|
+
* Find Pods by explicit WebID bindings with batched canonical queries.
|
|
87
77
|
*/
|
|
88
78
|
async findByWebIds(webIds) {
|
|
89
79
|
const exactTargets = new Set(webIds.map(exactWebId).filter((value) => Boolean(value)));
|
|
90
80
|
if (exactTargets.size === 0) {
|
|
91
81
|
return [];
|
|
92
82
|
}
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
const matchedWebId = getPodWebIds(pod).find((candidate) => {
|
|
97
|
-
const exact = exactWebId(candidate);
|
|
98
|
-
return exact ? exactTargets.has(exact) : false;
|
|
99
|
-
});
|
|
100
|
-
if (!matchedWebId) {
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
results.push({
|
|
104
|
-
...pod,
|
|
105
|
-
webId: matchedWebId,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
if (results.length < exactTargets.size) {
|
|
109
|
-
const seen = new Set(results.map((result) => exactWebId(result.webId)).filter(Boolean));
|
|
110
|
-
for (const exact of exactTargets) {
|
|
111
|
-
if (seen.has(exact)) {
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
const indexed = await this.findByWebIdIndex(exact);
|
|
115
|
-
if (indexed) {
|
|
116
|
-
results.push(indexed);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return results;
|
|
83
|
+
const legacy = await this.getLegacyPods();
|
|
84
|
+
const candidates = await this.findIndexedStorePodsByWebIds([...exactTargets]);
|
|
85
|
+
return this.filterPodsByWebIds(await this.mergeCanonicalPods(legacy, candidates), exactTargets);
|
|
121
86
|
}
|
|
122
87
|
/**
|
|
123
88
|
* List Pods for a specific account.
|
|
89
|
+
*
|
|
90
|
+
* 定向查询与全扫描等价:kv 按账户键直取,identity_store 按 accountId 下推,
|
|
91
|
+
* canonical 整条优先与 getAllPods 一致,KV 扫描补齐 .json 等历史键。
|
|
124
92
|
*/
|
|
125
93
|
async listByAccountId(accountId) {
|
|
126
|
-
const
|
|
127
|
-
|
|
94
|
+
const nodeAssignments = await this.getNodeAssignments();
|
|
95
|
+
const storePods = await this.getIndexedStorePodsByAccountId(accountId, nodeAssignments);
|
|
96
|
+
const legacy = (await this.getLegacyPods(nodeAssignments)).filter((pod) => pod.accountId === accountId);
|
|
97
|
+
return (await this.mergeCanonicalPods(legacy, storePods, nodeAssignments))
|
|
98
|
+
.filter((pod) => pod.accountId === accountId);
|
|
128
99
|
}
|
|
129
100
|
/**
|
|
130
101
|
* List all pods.
|
|
@@ -138,8 +109,18 @@ class PodLookupRepository {
|
|
|
138
109
|
async getAllPods() {
|
|
139
110
|
const result = await this.getAccountRowsFromKv();
|
|
140
111
|
const nodeAssignments = await this.getNodeAssignments();
|
|
112
|
+
return this.mergeCanonicalPods(this.extractKvPods(result, nodeAssignments), await this.getPodsFromIndexedStore(nodeAssignments), nodeAssignments);
|
|
113
|
+
}
|
|
114
|
+
// Legacy KV rows need independent discovery: an indexed match says nothing
|
|
115
|
+
// about other unindexed Pods or overlapping records. Keep identity_store
|
|
116
|
+
// queries targeted while applying canonical precedence to overlapping IDs.
|
|
117
|
+
async getLegacyPods(nodeAssignments) {
|
|
118
|
+
const rows = await this.getAccountRowsFromKv();
|
|
119
|
+
return this.extractKvPods(rows, nodeAssignments ?? await this.getNodeAssignments());
|
|
120
|
+
}
|
|
121
|
+
extractKvPods(rows, nodeAssignments) {
|
|
141
122
|
const pods = [];
|
|
142
|
-
for (const row of
|
|
123
|
+
for (const row of rows) {
|
|
143
124
|
if (!row.key || row.value === undefined) {
|
|
144
125
|
continue;
|
|
145
126
|
}
|
|
@@ -149,34 +130,13 @@ class PodLookupRepository {
|
|
|
149
130
|
continue;
|
|
150
131
|
}
|
|
151
132
|
const data = unwrapStoredValue(typeof row.value === 'string' ? JSON.parse(row.value) : row.value);
|
|
152
|
-
|
|
153
|
-
const webIds = extractAccountWebIds(data);
|
|
154
|
-
for (const [podId, podData] of Object.entries(podMap)) {
|
|
155
|
-
const pod = podData;
|
|
156
|
-
if (pod.baseUrl && typeof pod.baseUrl === 'string') {
|
|
157
|
-
const storageUrl = stringValue(pod.storageUrl) ?? stringValue(pod.storage);
|
|
158
|
-
const podWebIds = resolvePodWebIds(pod, webIds);
|
|
159
|
-
pods.push({
|
|
160
|
-
podId,
|
|
161
|
-
accountId,
|
|
162
|
-
baseUrl: pod.baseUrl,
|
|
163
|
-
storageUrl,
|
|
164
|
-
webId: dedupeStrings(podWebIds)[0],
|
|
165
|
-
...webIdsProperty(podWebIds),
|
|
166
|
-
nodeId: typeof pod.nodeId === 'string' ? pod.nodeId : findNodeIdForPod(nodeAssignments, [storageUrl, pod.baseUrl]),
|
|
167
|
-
edgeNodeId: typeof pod.edgeNodeId === 'string' ? pod.edgeNodeId : undefined,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
|
133
|
+
pods.push(...this.extractPodsFromAccountData(accountId, data, nodeAssignments));
|
|
171
134
|
}
|
|
172
135
|
catch {
|
|
173
136
|
// Skip malformed entries.
|
|
174
137
|
}
|
|
175
138
|
}
|
|
176
|
-
return
|
|
177
|
-
...pods,
|
|
178
|
-
...await this.getPodsFromIndexedStore(nodeAssignments),
|
|
179
|
-
]);
|
|
139
|
+
return pods;
|
|
180
140
|
}
|
|
181
141
|
async getAccountRowsFromKv() {
|
|
182
142
|
const kvTableId = drizzle_orm_1.sql.identifier(this.kvTableName);
|
|
@@ -213,76 +173,29 @@ class PodLookupRepository {
|
|
|
213
173
|
return [];
|
|
214
174
|
}
|
|
215
175
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if (match) {
|
|
231
|
-
return {
|
|
232
|
-
...match,
|
|
233
|
-
webId,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
if (pods.length === 1 && !hasExplicitPodWebIds(account, pods[0].podId)) {
|
|
237
|
-
return {
|
|
238
|
-
...pods[0],
|
|
239
|
-
webId,
|
|
240
|
-
...webIdsProperty([webId, ...getPodWebIds(pods[0])]),
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return undefined;
|
|
245
|
-
}
|
|
246
|
-
async readAccountData(accountId) {
|
|
247
|
-
for (const key of [`accounts/data/${accountId}`, `/.internal/accounts/data/${accountId}`]) {
|
|
248
|
-
const value = await this.readKvValue(key);
|
|
249
|
-
const record = parsePayloadRecord(value);
|
|
250
|
-
if (record) {
|
|
251
|
-
return record;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
return undefined;
|
|
255
|
-
}
|
|
256
|
-
async readStringArrayFromKv(key) {
|
|
257
|
-
const value = await this.readKvValue(key);
|
|
258
|
-
return Array.isArray(value) ? value.filter((entry) => typeof entry === 'string') : [];
|
|
259
|
-
}
|
|
260
|
-
async readKvValue(key) {
|
|
261
|
-
const tableId = drizzle_orm_1.sql.identifier(this.kvTableName);
|
|
262
|
-
try {
|
|
263
|
-
const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
|
|
264
|
-
SELECT value FROM ${tableId}
|
|
265
|
-
WHERE key = ${key}
|
|
266
|
-
LIMIT 1
|
|
267
|
-
`);
|
|
268
|
-
if (result.rows.length === 0) {
|
|
269
|
-
return undefined;
|
|
270
|
-
}
|
|
271
|
-
return parseStoredValue(result.rows[0].value);
|
|
272
|
-
}
|
|
273
|
-
catch {
|
|
274
|
-
return undefined;
|
|
275
|
-
}
|
|
176
|
+
// Predicate pushdown can omit a canonical replacement with a different owner,
|
|
177
|
+
// account or URL. Check legacy IDs separately, registering existence before
|
|
178
|
+
// parsing so a malformed canonical record also suppresses the old Pod.
|
|
179
|
+
async mergeCanonicalPods(legacy, candidates, nodeAssignments) {
|
|
180
|
+
const ids = dedupeStrings(legacy.map((pod) => pod.podId));
|
|
181
|
+
const rows = ids.length > 0
|
|
182
|
+
? await this.queryIndexedStoreRows((0, drizzle_orm_1.sql) `container = 'pod' AND ${idIn(ids)}`)
|
|
183
|
+
: [];
|
|
184
|
+
const canonicalIds = new Set(rows.map((row) => row.id));
|
|
185
|
+
const replacements = rows.length > 0
|
|
186
|
+
? await this.enrichIndexedStorePods(rowsToPodPayloadMap(rows), nodeAssignments ?? await this.getNodeAssignments())
|
|
187
|
+
: [];
|
|
188
|
+
const all = [...legacy.filter((pod) => !canonicalIds.has(pod.podId)), ...candidates, ...replacements];
|
|
189
|
+
return [...new Map(all.map((pod) => [pod.podId, pod])).values()];
|
|
276
190
|
}
|
|
277
|
-
extractPodsFromAccountData(accountId, data) {
|
|
191
|
+
extractPodsFromAccountData(accountId, data, nodeAssignments = []) {
|
|
278
192
|
const podMap = data['**pod**'] || data.pod || {};
|
|
279
|
-
const webIds = extractAccountWebIds(data);
|
|
280
193
|
const pods = [];
|
|
281
194
|
for (const [podId, podData] of Object.entries(podMap)) {
|
|
282
195
|
const pod = podData;
|
|
283
196
|
if (pod.baseUrl && typeof pod.baseUrl === 'string') {
|
|
284
197
|
const storageUrl = stringValue(pod.storageUrl) ?? stringValue(pod.storage);
|
|
285
|
-
const podWebIds =
|
|
198
|
+
const podWebIds = dedupeStrings(explicitPodWebIds(pod));
|
|
286
199
|
pods.push({
|
|
287
200
|
podId,
|
|
288
201
|
accountId,
|
|
@@ -290,58 +203,166 @@ class PodLookupRepository {
|
|
|
290
203
|
storageUrl,
|
|
291
204
|
webId: dedupeStrings(podWebIds)[0],
|
|
292
205
|
...webIdsProperty(podWebIds),
|
|
293
|
-
nodeId: typeof pod.nodeId === 'string' ? pod.nodeId :
|
|
206
|
+
nodeId: typeof pod.nodeId === 'string' ? pod.nodeId : findNodeIdForPod(nodeAssignments, [storageUrl, pod.baseUrl]),
|
|
294
207
|
edgeNodeId: typeof pod.edgeNodeId === 'string' ? pod.edgeNodeId : undefined,
|
|
295
208
|
});
|
|
296
209
|
}
|
|
297
210
|
}
|
|
298
211
|
return pods;
|
|
299
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* 与全扫描一致的 WebID 匹配过滤:按 Pod 解析后的 WebID 列表按原字符串比较,
|
|
215
|
+
* 命中时附加该 Pod 自身存储的 WebID。
|
|
216
|
+
*/
|
|
217
|
+
filterPodsByWebIds(pods, exactTargets) {
|
|
218
|
+
const results = [];
|
|
219
|
+
for (const pod of pods) {
|
|
220
|
+
const matchedWebId = getPodWebIds(pod).find((candidate) => {
|
|
221
|
+
const exact = exactWebId(candidate);
|
|
222
|
+
return exact ? exactTargets.has(exact) : false;
|
|
223
|
+
});
|
|
224
|
+
if (matchedWebId) {
|
|
225
|
+
results.push({
|
|
226
|
+
...pod,
|
|
227
|
+
webId: matchedWebId,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return results;
|
|
232
|
+
}
|
|
300
233
|
/**
|
|
301
234
|
* DrizzleIndexedStorage stores CSS identity facts as typed rows in
|
|
302
235
|
* identity_store; this is the canonical clustered identity source.
|
|
303
236
|
*/
|
|
304
237
|
async getPodsFromIndexedStore(nodeAssignments = []) {
|
|
305
238
|
const storeTableId = drizzle_orm_1.sql.identifier(this.indexedStoreTableName);
|
|
306
|
-
let
|
|
239
|
+
let rows = [];
|
|
307
240
|
try {
|
|
308
|
-
result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
|
|
241
|
+
const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
|
|
309
242
|
SELECT container, id, payload FROM ${storeTableId}
|
|
310
|
-
WHERE container IN ('pod', 'owner'
|
|
243
|
+
WHERE container IN ('pod', 'owner')
|
|
311
244
|
`);
|
|
245
|
+
rows = result.rows;
|
|
312
246
|
}
|
|
313
|
-
catch {
|
|
314
|
-
|
|
247
|
+
catch (error) {
|
|
248
|
+
if (isMissingIdentityStore(error))
|
|
249
|
+
return [];
|
|
250
|
+
throw error;
|
|
315
251
|
}
|
|
316
252
|
const podPayloads = new Map();
|
|
317
|
-
const
|
|
318
|
-
const
|
|
319
|
-
for (const row of result?.rows ?? []) {
|
|
253
|
+
const ownerRows = [];
|
|
254
|
+
for (const row of rows) {
|
|
320
255
|
if (!row.id || !row.container) {
|
|
321
256
|
continue;
|
|
322
257
|
}
|
|
323
|
-
const payload = parsePayloadRecord(row.payload);
|
|
324
|
-
if (!payload) {
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
258
|
if (row.container === 'pod') {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
if (row.container === 'owner') {
|
|
332
|
-
const podId = stringValue(payload.podId);
|
|
333
|
-
const webId = stringValue(payload.webId);
|
|
334
|
-
if (podId && webId) {
|
|
335
|
-
appendMapValue(ownerWebIdsByPodId, podId, webId);
|
|
259
|
+
const payload = parsePayloadRecord(row.payload);
|
|
260
|
+
if (payload) {
|
|
261
|
+
podPayloads.set(row.id, payload);
|
|
336
262
|
}
|
|
337
|
-
continue;
|
|
338
263
|
}
|
|
339
|
-
if (row.container === '
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
264
|
+
else if (row.container === 'owner') {
|
|
265
|
+
ownerRows.push(row);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return this.buildIndexedStorePods(podPayloads, ownerRows, nodeAssignments);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* 按主键直查 identity_store pod 行并补齐关联。
|
|
272
|
+
*/
|
|
273
|
+
async getIndexedStorePodsByIds(podIds) {
|
|
274
|
+
if (podIds.length === 0) {
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
const rows = await this.queryIndexedStoreRows((0, drizzle_orm_1.sql) `container = 'pod' AND ${idIn(podIds)}`);
|
|
278
|
+
return this.enrichIndexedStorePods(rowsToPodPayloadMap(rows), await this.getNodeAssignments());
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* 按 payload.accountId 下推查询 identity_store pod 行并补齐关联。
|
|
282
|
+
*/
|
|
283
|
+
async getIndexedStorePodsByAccountId(accountId, nodeAssignments) {
|
|
284
|
+
const rows = await this.queryIndexedStoreRows((0, drizzle_orm_1.sql) `container = 'pod'`, (0, db_1.jsonFieldEquals)(this.db, 'accountId', accountId));
|
|
285
|
+
return this.enrichIndexedStorePods(rowsToPodPayloadMap(rows), nodeAssignments);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* 反向前缀 LIKE 预筛候选 pod 行(baseUrl/storageUrl/storage 任一前缀),
|
|
289
|
+
* JS 侧 startsWith 复核由调用方(findByResourceIdentifier)执行。
|
|
290
|
+
*/
|
|
291
|
+
async findIndexedStorePodsByResource(resourcePath, nodeAssignments) {
|
|
292
|
+
const conditions = ['baseUrl', 'storageUrl', 'storage']
|
|
293
|
+
.map((field) => (0, db_1.jsonFieldIsPrefixOf)(this.db, field, resourcePath));
|
|
294
|
+
const rows = await this.queryIndexedStoreRows((0, drizzle_orm_1.sql) `container = 'pod'`, (0, drizzle_orm_1.sql) `(${drizzle_orm_1.sql.join(conditions, (0, drizzle_orm_1.sql) ` OR `)})`);
|
|
295
|
+
return this.enrichIndexedStorePods(rowsToPodPayloadMap(rows), nodeAssignments);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* WebID → Pod 的下推解析:owner 按 webId 命中拿 podId,pod.webId
|
|
299
|
+
* 直查;Account webIdLink 不建立 Pod ownership。
|
|
300
|
+
* webIdForms 只携带完整原字符串;URL 等价不代表相同身份。
|
|
301
|
+
*/
|
|
302
|
+
async findIndexedStorePodsByWebIds(webIdForms) {
|
|
303
|
+
const forms = dedupeStrings(webIdForms);
|
|
304
|
+
if (forms.length === 0) {
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
307
|
+
const [ownerMatchRows, directPodRows] = await Promise.all([
|
|
308
|
+
this.queryIndexedStoreRows((0, drizzle_orm_1.sql) `container = 'owner'`, (0, db_1.jsonFieldIn)(this.db, 'webId', forms)),
|
|
309
|
+
this.queryIndexedStoreRows((0, drizzle_orm_1.sql) `container = 'pod'`, (0, db_1.jsonFieldIn)(this.db, 'webId', forms)),
|
|
310
|
+
]);
|
|
311
|
+
const podIds = dedupeStrings([
|
|
312
|
+
...ownerMatchRows.map((row) => stringValue(parsePayloadRecord(row.payload)?.podId)),
|
|
313
|
+
...directPodRows.map((row) => row.id),
|
|
314
|
+
].filter((value) => Boolean(value)));
|
|
315
|
+
if (podIds.length === 0) {
|
|
316
|
+
return [];
|
|
317
|
+
}
|
|
318
|
+
const podRows = await this.queryIndexedStoreRows((0, drizzle_orm_1.sql) `container = 'pod' AND ${idIn(podIds)}`);
|
|
319
|
+
return this.enrichIndexedStorePods(rowsToPodPayloadMap(podRows), await this.getNodeAssignments());
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* 为候选 pod 行补齐 owner 关联与 nodeAssignments,组装最终结果。
|
|
323
|
+
* 与全扫描共用 buildIndexedStorePods,保证返回形状一致。
|
|
324
|
+
*/
|
|
325
|
+
async enrichIndexedStorePods(podPayloads, nodeAssignments) {
|
|
326
|
+
if (podPayloads.size === 0) {
|
|
327
|
+
return [];
|
|
328
|
+
}
|
|
329
|
+
const podIds = [...podPayloads.keys()];
|
|
330
|
+
const ownerRows = await this.queryIndexedStoreRows((0, drizzle_orm_1.sql) `container = 'owner'`, (0, db_1.jsonFieldIn)(this.db, 'podId', podIds));
|
|
331
|
+
return this.buildIndexedStorePods(podPayloads, ownerRows, nodeAssignments);
|
|
332
|
+
}
|
|
333
|
+
async queryIndexedStoreRows(condition, jsonCondition) {
|
|
334
|
+
const storeTableId = drizzle_orm_1.sql.identifier(this.indexedStoreTableName);
|
|
335
|
+
// Keep indexed columns outside CASE; only JSON evaluation needs protection.
|
|
336
|
+
// Raw ID queries must still see malformed rows for canonical shadowing.
|
|
337
|
+
const safeJsonCondition = jsonCondition && (0, db_1.isDatabaseSqlite)(this.db)
|
|
338
|
+
? (0, drizzle_orm_1.sql) `CASE WHEN json_valid(payload) THEN ${jsonCondition} ELSE 0 END`
|
|
339
|
+
: jsonCondition;
|
|
340
|
+
const safeCondition = safeJsonCondition ? (0, drizzle_orm_1.sql) `${condition} AND (${safeJsonCondition})` : condition;
|
|
341
|
+
try {
|
|
342
|
+
const result = await (0, db_1.executeQuery)(this.db, (0, drizzle_orm_1.sql) `
|
|
343
|
+
SELECT id, payload FROM ${storeTableId}
|
|
344
|
+
WHERE ${safeCondition}
|
|
345
|
+
`);
|
|
346
|
+
return result.rows;
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
if (isMissingIdentityStore(error))
|
|
350
|
+
return [];
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* 组装 identity_store Pod 视图:pod 行为主体,owner 行补充 WebID,
|
|
356
|
+
* nodeAssignments 兜底 nodeId。全扫描与下推快路径共用,保证返回形状一致。
|
|
357
|
+
*/
|
|
358
|
+
buildIndexedStorePods(podPayloads, ownerRows, nodeAssignments) {
|
|
359
|
+
const ownerWebIdsByPodId = new Map();
|
|
360
|
+
for (const row of ownerRows) {
|
|
361
|
+
const payload = parsePayloadRecord(row.payload);
|
|
362
|
+
const podId = payload ? stringValue(payload.podId) : undefined;
|
|
363
|
+
const webId = payload ? stringValue(payload.webId) : undefined;
|
|
364
|
+
if (podId && webId) {
|
|
365
|
+
appendMapValue(ownerWebIdsByPodId, podId, webId);
|
|
345
366
|
}
|
|
346
367
|
}
|
|
347
368
|
const pods = [];
|
|
@@ -355,9 +376,7 @@ class PodLookupRepository {
|
|
|
355
376
|
stringValue(pod.webId),
|
|
356
377
|
...(ownerWebIdsByPodId.get(podId) ?? []),
|
|
357
378
|
].filter((value) => typeof value === 'string');
|
|
358
|
-
const podWebIds = dedupeStrings(explicitPodWebIds
|
|
359
|
-
? explicitPodWebIds
|
|
360
|
-
: webIdsByAccountId.get(accountId) ?? []);
|
|
379
|
+
const podWebIds = dedupeStrings(explicitPodWebIds);
|
|
361
380
|
const storageUrl = stringValue(pod.storageUrl) ?? stringValue(pod.storage);
|
|
362
381
|
pods.push({
|
|
363
382
|
podId,
|
|
@@ -383,25 +402,6 @@ function extractAccountIdFromAccountDataKey(key) {
|
|
|
383
402
|
const accountId = key.slice(index + marker.length).replace(/\.json$/u, '');
|
|
384
403
|
return accountId || undefined;
|
|
385
404
|
}
|
|
386
|
-
function extractAccountWebIds(data) {
|
|
387
|
-
if (!data || typeof data !== 'object') {
|
|
388
|
-
return [];
|
|
389
|
-
}
|
|
390
|
-
const record = data;
|
|
391
|
-
const linkMap = record['**webIdLink**'] || record.webIdLink || {};
|
|
392
|
-
if (!linkMap || typeof linkMap !== 'object') {
|
|
393
|
-
return [];
|
|
394
|
-
}
|
|
395
|
-
return Object.values(linkMap)
|
|
396
|
-
.map((value) => {
|
|
397
|
-
if (!value || typeof value !== 'object') {
|
|
398
|
-
return undefined;
|
|
399
|
-
}
|
|
400
|
-
const webId = value.webId;
|
|
401
|
-
return typeof webId === 'string' ? webId : undefined;
|
|
402
|
-
})
|
|
403
|
-
.filter((value) => typeof value === 'string');
|
|
404
|
-
}
|
|
405
405
|
function extractPodOwnerWebIds(pod) {
|
|
406
406
|
const ownerMap = pod['**owner**'] || pod.owner || {};
|
|
407
407
|
if (!ownerMap || typeof ownerMap !== 'object') {
|
|
@@ -423,17 +423,6 @@ function explicitPodWebIds(pod) {
|
|
|
423
423
|
...extractPodOwnerWebIds(pod),
|
|
424
424
|
].filter((value) => typeof value === 'string');
|
|
425
425
|
}
|
|
426
|
-
function hasExplicitPodWebIds(account, podId) {
|
|
427
|
-
const podMap = account['**pod**'] ?? account.pod;
|
|
428
|
-
if (!podMap || typeof podMap !== 'object')
|
|
429
|
-
return false;
|
|
430
|
-
const pod = podMap[podId];
|
|
431
|
-
return Boolean(pod && typeof pod === 'object' && explicitPodWebIds(pod).length > 0);
|
|
432
|
-
}
|
|
433
|
-
function resolvePodWebIds(pod, accountWebIds) {
|
|
434
|
-
const explicit = explicitPodWebIds(pod);
|
|
435
|
-
return dedupeStrings(explicit.length > 0 ? explicit : accountWebIds);
|
|
436
|
-
}
|
|
437
426
|
function exactWebId(webId) {
|
|
438
427
|
// WebID identity is the complete original string, not URL equivalence.
|
|
439
428
|
return webId && webId === webId.trim() && !/[\r\n\t]/u.test(webId) ? webId : undefined;
|
|
@@ -466,30 +455,21 @@ function webIdsProperty(values) {
|
|
|
466
455
|
const webIds = dedupeStrings(values);
|
|
467
456
|
return webIds.length > 1 ? { webIds } : {};
|
|
468
457
|
}
|
|
469
|
-
function
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
458
|
+
function idIn(ids) {
|
|
459
|
+
return (0, drizzle_orm_1.sql) `id IN (${drizzle_orm_1.sql.join(ids.map((id) => (0, drizzle_orm_1.sql) `${id}`), (0, drizzle_orm_1.sql) `, `)})`;
|
|
460
|
+
}
|
|
461
|
+
function rowsToPodPayloadMap(rows) {
|
|
462
|
+
const map = new Map();
|
|
463
|
+
for (const row of rows) {
|
|
464
|
+
if (!row.id) {
|
|
475
465
|
continue;
|
|
476
466
|
}
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
baseUrl: existing.baseUrl || value.baseUrl,
|
|
484
|
-
storageUrl: existing.storageUrl ?? value.storageUrl,
|
|
485
|
-
accountId: existing.accountId || value.accountId,
|
|
486
|
-
webId: webIds[0],
|
|
487
|
-
...webIdsProperty(webIds),
|
|
488
|
-
nodeId: existing.nodeId ?? value.nodeId,
|
|
489
|
-
edgeNodeId: existing.edgeNodeId ?? value.edgeNodeId,
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
return [...byPodId.values()];
|
|
467
|
+
const payload = parsePayloadRecord(row.payload);
|
|
468
|
+
if (payload) {
|
|
469
|
+
map.set(row.id, payload);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return map;
|
|
493
473
|
}
|
|
494
474
|
function parsePayloadRecord(value) {
|
|
495
475
|
if (!value) {
|
|
@@ -508,17 +488,6 @@ function parsePayloadRecord(value) {
|
|
|
508
488
|
const unwrapped = unwrapStoredValue(value);
|
|
509
489
|
return typeof unwrapped === 'object' ? unwrapped : undefined;
|
|
510
490
|
}
|
|
511
|
-
function parseStoredValue(value) {
|
|
512
|
-
if (typeof value === 'string') {
|
|
513
|
-
try {
|
|
514
|
-
return unwrapStoredValue(JSON.parse(value));
|
|
515
|
-
}
|
|
516
|
-
catch {
|
|
517
|
-
return undefined;
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
return unwrapStoredValue(value);
|
|
521
|
-
}
|
|
522
491
|
function unwrapStoredValue(value) {
|
|
523
492
|
if (value && typeof value === 'object' && 'key' in value && 'payload' in value) {
|
|
524
493
|
return value.payload;
|
|
@@ -575,4 +544,17 @@ function findNodeIdForPod(assignments, urls) {
|
|
|
575
544
|
}
|
|
576
545
|
return bestMatch?.nodeId;
|
|
577
546
|
}
|
|
547
|
+
function isMissingIdentityStore(error) {
|
|
548
|
+
const visited = new Set();
|
|
549
|
+
while (error && typeof error === 'object' && !visited.has(error)) {
|
|
550
|
+
visited.add(error);
|
|
551
|
+
const failure = error;
|
|
552
|
+
if (failure.message === 'no such table: identity_store'
|
|
553
|
+
|| (failure.code === '42P01' && failure.message === 'relation "identity_store" does not exist')) {
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
error = failure.cause;
|
|
557
|
+
}
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
578
560
|
//# sourceMappingURL=PodLookupRepository.js.map
|
|
@@ -69,3 +69,22 @@ export declare function toDbTimestamp(db: IdentityDatabase, date: Date): number
|
|
|
69
69
|
* Handles both Unix timestamps (SQLite) and Date objects (PostgreSQL).
|
|
70
70
|
*/
|
|
71
71
|
export declare function fromDbTimestamp(value: unknown): Date | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* `payload` JSON 字段提取表达式,按方言生成(SQLite json_extract / PG ->>)。
|
|
74
|
+
* alias 用于 join 场景下限定来源表。
|
|
75
|
+
*/
|
|
76
|
+
export declare function jsonFieldExtract(db: IdentityDatabase, field: string, alias?: string): SQL;
|
|
77
|
+
/**
|
|
78
|
+
* `payload` 字段等于标量值的方言条件。
|
|
79
|
+
*/
|
|
80
|
+
export declare function jsonFieldEquals(db: IdentityDatabase, field: string, value: string, alias?: string): SQL;
|
|
81
|
+
/**
|
|
82
|
+
* `payload` 字段落在值集合内的方言条件。values 为空时调用方应跳过查询。
|
|
83
|
+
*/
|
|
84
|
+
export declare function jsonFieldIn(db: IdentityDatabase, field: string, values: string[], alias?: string): SQL;
|
|
85
|
+
/**
|
|
86
|
+
* 反向前缀匹配:`value LIKE payload->field || '%'`。
|
|
87
|
+
* 用于"资源 URL 以存储的 baseUrl 为前缀"的下推预筛;存储值中的 LIKE 元字符只会多匹配,
|
|
88
|
+
* 调用方需在 JS 侧用 startsWith 复核,不会漏匹配。
|
|
89
|
+
*/
|
|
90
|
+
export declare function jsonFieldIsPrefixOf(db: IdentityDatabase, field: string, value: string, alias?: string): SQL;
|