@undefineds.co/xpod 0.4.8 → 0.4.10
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/identity/drizzle/PodLookupRepository.d.ts +5 -16
- package/dist/identity/drizzle/PodLookupRepository.js +40 -201
- 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/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 +8 -2
- package/static/app/assets/main.js +12 -12
- package/static/auth-callback/assets/{AiConfigContext-DJKvxduw.js → AiConfigContext-C81deMM9.js} +1 -1
- package/static/auth-callback/assets/{AiConfigPage-DgGmHb18.js → AiConfigPage-evWI8T56.js} +1 -1
- package/static/auth-callback/assets/{DocumentProcessingPanel-CJmxu8x1.js → DocumentProcessingPanel-B9GrDEMe.js} +1 -1
- package/static/auth-callback/assets/{IndexLifecyclePanel-byCa7h7L.js → IndexLifecyclePanel-qCo8ABQZ.js} +1 -1
- package/static/auth-callback/assets/{IndexSubjectPanel-CDwT4Yx1.js → IndexSubjectPanel-C4YG0whI.js} +1 -1
- package/static/auth-callback/assets/{ModelAssignmentsPanel-CwM3k8w7.js → ModelAssignmentsPanel-DG7Lxh3t.js} +1 -1
- package/static/auth-callback/assets/ModelsPage-CgEuqE6p.js +10 -0
- package/static/auth-callback/assets/{NetworkPage-DkVgxtNj.js → NetworkPage-Cbdn_P1e.js} +1 -1
- package/static/auth-callback/assets/{PaneListHeader-DRI0hjmt.js → PaneListHeader-jy70Q00L.js} +1 -1
- package/static/auth-callback/assets/{SearchIndexingPanel-mbppDZFE.js → SearchIndexingPanel-ByU3u7kp.js} +1 -1
- package/static/auth-callback/assets/{StatusSubjectPanel-DNsW76aC.js → StatusSubjectPanel-hfjoB5aS.js} +1 -1
- package/static/auth-callback/assets/{StatusWorkspace-DGcTbHT5.js → StatusWorkspace-BZd617sV.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsPage-C6qklJ9k.js → SystemSettingsPage-BirzWAQM.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsSubjectPanel-B4VV9xkG.js → SystemSettingsSubjectPanel-CmsVWNCx.js} +1 -1
- package/static/auth-callback/assets/{activity-Ck-Mfxxo.js → activity-BcsZZxxw.js} +1 -1
- package/static/auth-callback/assets/{auth-callback-DG4Ge40c.js → auth-callback-atKg_oig.js} +124 -124
- package/static/auth-callback/assets/{badge-GSSnw1VV.js → badge-BWbRHThQ.js} +1 -1
- package/static/auth-callback/assets/{download-BYyRX-K2.js → download-BmvG1Vya.js} +1 -1
- package/static/auth-callback/assets/{external-link-WEC0Ki-0.js → external-link-DZ34d3g3.js} +1 -1
- package/static/auth-callback/assets/{index-kju2k4Dp.js → index-BpV1hsqs.js} +1 -1
- package/static/auth-callback/assets/{index-DlsMCgo8.js → index-D9oE6FXK.js} +1 -1
- package/static/auth-callback/assets/{index-browser-D8YW6coF.js → index-browser-B9Z7GU-T.js} +1 -1
- package/static/auth-callback/assets/{key-round-DJUT5Nh0.js → key-round-tjP76Se-.js} +1 -1
- package/static/auth-callback/assets/{rotate-ccw-CXwfZUKU.js → rotate-ccw-C_L5ZLx1.js} +1 -1
- package/static/auth-callback/assets/{skeleton-DWPtNhUB.js → skeleton-C7tGDQIs.js} +1 -1
- package/static/auth-callback/assets/{waypoints-l1oDnRJ0.js → waypoints-VMNQlWdU.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-B7iKpK-Q.js → workspace-layout-SAp6BtYK.js} +1 -1
- package/static/auth-callback/auth-callback.html +1 -1
- package/static/dashboard/assets/{AiConfigContext-U0cCSY28.js → AiConfigContext-De-OtAWo.js} +1 -1
- package/static/dashboard/assets/{AiConfigPage-CMi0uJdo.js → AiConfigPage-macP4Mop.js} +1 -1
- package/static/dashboard/assets/{DocumentProcessingPanel-DEZiEpft.js → DocumentProcessingPanel-C5ObvCCl.js} +1 -1
- package/static/dashboard/assets/{IndexLifecyclePanel-CGZfLUog.js → IndexLifecyclePanel-xVNa2l40.js} +1 -1
- package/static/dashboard/assets/{IndexSubjectPanel-DiDZauHk.js → IndexSubjectPanel-DQFPP6-p.js} +1 -1
- package/static/dashboard/assets/{ModelAssignmentsPanel-DaGGZKuf.js → ModelAssignmentsPanel-DMOATFpQ.js} +1 -1
- package/static/dashboard/assets/ModelsPage-91UbnETA.js +25 -0
- package/static/dashboard/assets/{NetworkPage-DI5-O7GT.js → NetworkPage-CHQ3YxIB.js} +1 -1
- package/static/dashboard/assets/{PaneListHeader-4oa7uf59.js → PaneListHeader-DsXemAdR.js} +1 -1
- package/static/dashboard/assets/{SearchIndexingPanel-DoqEwocD.js → SearchIndexingPanel-Dh70PNFZ.js} +1 -1
- package/static/dashboard/assets/{StatusSubjectPanel-CLzBC5fu.js → StatusSubjectPanel-D3PGEYT4.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-UyKADZoM.js → StatusWorkspace-BcpePYUW.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-qP0hLHNV.js → SystemSettingsPage-BiN5GcKx.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsSubjectPanel-EaWax9Ot.js → SystemSettingsSubjectPanel-B9QrSiFp.js} +1 -1
- package/static/dashboard/assets/{activity-CjIoNU4S.js → activity-j5zrznu-.js} +1 -1
- package/static/dashboard/assets/{badge-dcDZpKh3.js → badge-CzeBdG7h.js} +1 -1
- package/static/dashboard/assets/{dashboard-BY8GdnEI.js → dashboard-D-xANHk1.js} +103 -103
- package/static/dashboard/assets/{download-BeYCrc-_.js → download-IcNdEZWi.js} +1 -1
- package/static/dashboard/assets/{external-link-626-5KVx.js → external-link-DxBxK8Vu.js} +1 -1
- package/static/dashboard/assets/{index-CBbk6hx-.js → index-FWZ-s52O.js} +1 -1
- package/static/dashboard/assets/{index-CsxH6Hmz.js → index-ZiQZ96oC.js} +1 -1
- package/static/dashboard/assets/{key-round-B9IL4Wua.js → key-round-D1K7warM.js} +1 -1
- package/static/dashboard/assets/{rotate-ccw-DM4vCfiI.js → rotate-ccw-CcN1N6p9.js} +1 -1
- package/static/dashboard/assets/{skeleton-ChlFAPvP.js → skeleton-CKnmJMUH.js} +1 -1
- package/static/dashboard/assets/{waypoints-CvpZzf_I.js → waypoints-DuZPO_wu.js} +1 -1
- package/static/dashboard/assets/{workspace-layout-Bxv7V-tt.js → workspace-layout-BUj3wZ_m.js} +1 -1
- package/static/dashboard/dashboard.html +1 -1
- package/static/settings/assets/{AiConfigContext-CDVIHLBb.js → AiConfigContext-C0cQMPfG.js} +1 -1
- package/static/settings/assets/{AiConfigPage-C7qfiiaJ.js → AiConfigPage-CPhB4iFb.js} +1 -1
- package/static/settings/assets/{DocumentProcessingPanel-B59QTe-V.js → DocumentProcessingPanel-sYI7OpuH.js} +1 -1
- package/static/settings/assets/{IndexLifecyclePanel-C-e-3eVi.js → IndexLifecyclePanel-yj8iyiT8.js} +1 -1
- package/static/settings/assets/{IndexSubjectPanel-B-scRZ1u.js → IndexSubjectPanel-73sM16Ma.js} +1 -1
- package/static/settings/assets/{ModelAssignmentsPanel-Wy8jzVg4.js → ModelAssignmentsPanel-BFIgUX5v.js} +1 -1
- package/static/settings/assets/ModelsPage-BdppXl7E.js +10 -0
- package/static/settings/assets/{NetworkPage-tBB-4Ox8.js → NetworkPage-i6j-M2RY.js} +1 -1
- package/static/settings/assets/{PaneListHeader-DuD6glzn.js → PaneListHeader-DpqC0jd5.js} +1 -1
- package/static/settings/assets/{SearchIndexingPanel-CiDHc0nx.js → SearchIndexingPanel-BlPnrkT3.js} +1 -1
- package/static/settings/assets/{StatusSubjectPanel-OF5cgWwt.js → StatusSubjectPanel-Dv4q3PGh.js} +1 -1
- package/static/settings/assets/{StatusWorkspace-CZ8Oa0gV.js → StatusWorkspace-CKD_Rzdr.js} +1 -1
- package/static/settings/assets/{SystemSettingsPage-DT2tC0F_.js → SystemSettingsPage-CiOm2NzV.js} +1 -1
- package/static/settings/assets/{SystemSettingsSubjectPanel-Bkta1oDw.js → SystemSettingsSubjectPanel-Cd-GECon.js} +1 -1
- package/static/settings/assets/{activity-2M1f5eBS.js → activity-DaFkk8f3.js} +1 -1
- package/static/settings/assets/{badge-CRKan0qX.js → badge-d5SHdc-x.js} +1 -1
- package/static/settings/assets/{download-PCHldCdu.js → download-CpkwomDr.js} +1 -1
- package/static/settings/assets/{external-link-tmKe7eYO.js → external-link-_4YT42Mf.js} +1 -1
- package/static/settings/assets/{index-Cek02M79.js → index-BFi9yn7_.js} +1 -1
- package/static/settings/assets/{index-BDCNTwWz.js → index-BGgEhIUy.js} +1 -1
- package/static/settings/assets/{index-browser-EVDVm9T5.js → index-browser-B06xjBdZ.js} +1 -1
- package/static/settings/assets/{key-round-CUGvQCkt.js → key-round-Dlqmp1Kq.js} +1 -1
- package/static/settings/assets/{rotate-ccw-BRA3lIHM.js → rotate-ccw-TAY65xWT.js} +1 -1
- package/static/settings/assets/{settings-BdlKrzJ3.js → settings-ExBXGgbj.js} +103 -103
- package/static/settings/assets/{skeleton-CuDeifWb.js → skeleton-DKIWjNr9.js} +1 -1
- package/static/settings/assets/{waypoints-w6LxsFY1.js → waypoints-9erLIxyR.js} +1 -1
- package/static/settings/assets/{workspace-layout-TN-BWmT5.js → workspace-layout-CYXfYIa3.js} +1 -1
- package/static/settings/settings.html +1 -1
- package/static/auth-callback/assets/ModelsPage-DapY2Dwf.js +0 -10
- package/static/dashboard/assets/ModelsPage-DZgAOdxO.js +0 -25
- package/static/settings/assets/ModelsPage-DHNiaodk.js +0 -10
|
@@ -117,11 +117,24 @@ function createSolidSessionRuntime(options = {}) {
|
|
|
117
117
|
let isInitializing = false;
|
|
118
118
|
let initializationErrorSnapshot;
|
|
119
119
|
let disposed = false;
|
|
120
|
+
let authenticationGeneration = 0;
|
|
121
|
+
let authenticationUnavailable = false;
|
|
122
|
+
let authenticationOperations = 0;
|
|
123
|
+
let identityOperationGeneration = 0;
|
|
124
|
+
let pendingIdentity;
|
|
125
|
+
const invalidateAuthentication = () => {
|
|
126
|
+
authenticationGeneration += 1;
|
|
127
|
+
authenticationUnavailable = true;
|
|
128
|
+
};
|
|
120
129
|
const publish = (nextSnapshot) => {
|
|
121
|
-
|
|
122
|
-
if (disposed) {
|
|
130
|
+
if (disposed)
|
|
123
131
|
return snapshot;
|
|
132
|
+
if (nextSnapshot.status !== "authenticated" || snapshot.status !== "authenticated" || snapshot.webId !== nextSnapshot.webId) {
|
|
133
|
+
invalidateAuthentication();
|
|
124
134
|
}
|
|
135
|
+
if (nextSnapshot.status === "authenticated")
|
|
136
|
+
authenticationUnavailable = false;
|
|
137
|
+
snapshot = nextSnapshot;
|
|
125
138
|
if (areSnapshotsEqual(lastNotifiedSnapshot, snapshot)) {
|
|
126
139
|
return snapshot;
|
|
127
140
|
}
|
|
@@ -131,10 +144,28 @@ function createSolidSessionRuntime(options = {}) {
|
|
|
131
144
|
}
|
|
132
145
|
return snapshot;
|
|
133
146
|
};
|
|
134
|
-
const publishSessionInfo = () =>
|
|
135
|
-
|
|
136
|
-
|
|
147
|
+
const publishSessionInfo = () => {
|
|
148
|
+
if (pendingIdentity) {
|
|
149
|
+
if (pendingIdentity.generation !== identityOperationGeneration)
|
|
150
|
+
return snapshot;
|
|
151
|
+
if (pendingIdentity.eventWebId && pendingIdentity.eventWebId !== session.info.webId)
|
|
152
|
+
return snapshot;
|
|
153
|
+
pendingIdentity.eventWebId = session.info.webId;
|
|
154
|
+
}
|
|
155
|
+
invalidateAuthentication();
|
|
156
|
+
lastNotifiedSnapshot = undefined;
|
|
157
|
+
return publish(snapshotFromSessionInfo(session.info));
|
|
158
|
+
};
|
|
159
|
+
const publishAnonymous = () => {
|
|
160
|
+
identityOperationGeneration += 1;
|
|
161
|
+
return publish({ status: "anonymous" });
|
|
162
|
+
};
|
|
163
|
+
const publishSessionExpired = () => {
|
|
164
|
+
identityOperationGeneration += 1;
|
|
165
|
+
return publish(snapshotFromSessionExpired(session.info));
|
|
166
|
+
};
|
|
137
167
|
const publishSessionError = (code, description) => {
|
|
168
|
+
identityOperationGeneration += 1;
|
|
138
169
|
const errorSnapshot = snapshotFromSessionError(description ?? code ?? "Solid session error", session.info);
|
|
139
170
|
if (isInitializing) {
|
|
140
171
|
initializationErrorSnapshot = errorSnapshot;
|
|
@@ -149,6 +180,29 @@ function createSolidSessionRuntime(options = {}) {
|
|
|
149
180
|
errorEvents.on(import_solid_client_authn_browser.EVENTS.ERROR, publishSessionError);
|
|
150
181
|
return {
|
|
151
182
|
fetch: session.fetch,
|
|
183
|
+
createAuthenticatedFetch(webId) {
|
|
184
|
+
const generation = authenticationGeneration;
|
|
185
|
+
const assertCurrent = () => {
|
|
186
|
+
if (disposed || authenticationOperations > 0 || authenticationUnavailable || generation !== authenticationGeneration || snapshot.status !== "authenticated" || snapshot.webId !== webId || !session.info.isLoggedIn || session.info.webId !== webId) {
|
|
187
|
+
const error = new Error("Authenticated session is no longer current");
|
|
188
|
+
error.name = "AbortError";
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
return async (input, init) => {
|
|
193
|
+
assertCurrent();
|
|
194
|
+
const response = await (init === undefined ? session.fetch(input) : session.fetch(input, init));
|
|
195
|
+
try {
|
|
196
|
+
assertCurrent();
|
|
197
|
+
} catch (error) {
|
|
198
|
+
response.body?.cancel().catch(() => {
|
|
199
|
+
return;
|
|
200
|
+
});
|
|
201
|
+
throw error;
|
|
202
|
+
}
|
|
203
|
+
return response;
|
|
204
|
+
};
|
|
205
|
+
},
|
|
152
206
|
getSnapshot() {
|
|
153
207
|
return snapshot;
|
|
154
208
|
},
|
|
@@ -159,20 +213,29 @@ function createSolidSessionRuntime(options = {}) {
|
|
|
159
213
|
if (initialized) {
|
|
160
214
|
return Promise.resolve(snapshot);
|
|
161
215
|
}
|
|
216
|
+
if (disposed)
|
|
217
|
+
return Promise.resolve(snapshot);
|
|
218
|
+
const operation = { generation: ++identityOperationGeneration, eventWebId: undefined };
|
|
219
|
+
pendingIdentity = operation;
|
|
220
|
+
const isCurrentOperation = (info) => !disposed && operation.generation === identityOperationGeneration && (!info?.isLoggedIn || !operation.eventWebId || operation.eventWebId === info.webId);
|
|
162
221
|
isInitializing = true;
|
|
163
222
|
initializationErrorSnapshot = undefined;
|
|
164
223
|
publish({ status: "initializing" });
|
|
165
224
|
const nextInitialization = session.handleIncomingRedirect({
|
|
166
225
|
restorePreviousSession: options2.restorePreviousSession ?? true
|
|
167
226
|
}).then((info) => {
|
|
227
|
+
if (!isCurrentOperation(info ?? session.info))
|
|
228
|
+
return snapshot;
|
|
168
229
|
const nextSnapshot = snapshotFromSessionInfo(info ?? session.info);
|
|
169
230
|
if (nextSnapshot.status === "anonymous" && initializationErrorSnapshot?.status === "error") {
|
|
170
231
|
return initializationErrorSnapshot;
|
|
171
232
|
}
|
|
172
233
|
initialized = true;
|
|
173
234
|
return publish(nextSnapshot);
|
|
174
|
-
}).catch((error) => publish(snapshotFromSessionError(error, session.info))).finally(() => {
|
|
235
|
+
}).catch((error) => isCurrentOperation() ? publish(snapshotFromSessionError(error, session.info)) : snapshot).finally(() => {
|
|
175
236
|
if (initialization === nextInitialization) {
|
|
237
|
+
if (pendingIdentity === operation)
|
|
238
|
+
pendingIdentity = undefined;
|
|
176
239
|
initialization = undefined;
|
|
177
240
|
isInitializing = false;
|
|
178
241
|
initializationErrorSnapshot = undefined;
|
|
@@ -185,18 +248,27 @@ function createSolidSessionRuntime(options = {}) {
|
|
|
185
248
|
if (initialization) {
|
|
186
249
|
return initialization;
|
|
187
250
|
}
|
|
251
|
+
if (disposed)
|
|
252
|
+
return Promise.resolve(snapshot);
|
|
253
|
+
const operation = { generation: ++identityOperationGeneration, eventWebId: undefined };
|
|
254
|
+
pendingIdentity = operation;
|
|
255
|
+
const isCurrentOperation = (info) => !disposed && operation.generation === identityOperationGeneration && (!info?.isLoggedIn || !operation.eventWebId || operation.eventWebId === info.webId);
|
|
188
256
|
isInitializing = true;
|
|
189
257
|
initializationErrorSnapshot = undefined;
|
|
190
258
|
publish({ status: "initializing" });
|
|
191
259
|
const nextInitialization = session.handleIncomingRedirect(url).then((info) => {
|
|
260
|
+
if (!isCurrentOperation(info ?? session.info))
|
|
261
|
+
return snapshot;
|
|
192
262
|
const nextSnapshot = snapshotFromSessionInfo(info ?? session.info);
|
|
193
263
|
if (nextSnapshot.status === "anonymous" && initializationErrorSnapshot?.status === "error") {
|
|
194
264
|
return initializationErrorSnapshot;
|
|
195
265
|
}
|
|
196
266
|
initialized = true;
|
|
197
267
|
return publish(nextSnapshot);
|
|
198
|
-
}).catch((error) => publish(snapshotFromSessionError(error, session.info))).finally(() => {
|
|
268
|
+
}).catch((error) => isCurrentOperation() ? publish(snapshotFromSessionError(error, session.info)) : snapshot).finally(() => {
|
|
199
269
|
if (initialization === nextInitialization) {
|
|
270
|
+
if (pendingIdentity === operation)
|
|
271
|
+
pendingIdentity = undefined;
|
|
200
272
|
initialization = undefined;
|
|
201
273
|
isInitializing = false;
|
|
202
274
|
initializationErrorSnapshot = undefined;
|
|
@@ -205,12 +277,39 @@ function createSolidSessionRuntime(options = {}) {
|
|
|
205
277
|
initialization = nextInitialization;
|
|
206
278
|
return nextInitialization;
|
|
207
279
|
},
|
|
208
|
-
login(options2) {
|
|
209
|
-
|
|
280
|
+
async login(options2) {
|
|
281
|
+
identityOperationGeneration += 1;
|
|
282
|
+
invalidateAuthentication();
|
|
283
|
+
authenticationOperations += 1;
|
|
284
|
+
try {
|
|
285
|
+
if (initialization) {
|
|
286
|
+
const error = new Error("Previous login is still completing. Reload before reconnecting.");
|
|
287
|
+
error.name = "SolidSessionPendingError";
|
|
288
|
+
throw error;
|
|
289
|
+
}
|
|
290
|
+
if (disposed)
|
|
291
|
+
throw new Error("Solid session runtime is disposed");
|
|
292
|
+
await session.login(options2);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
publish(snapshotFromSessionError(error, session.info));
|
|
295
|
+
throw error;
|
|
296
|
+
} finally {
|
|
297
|
+
authenticationOperations -= 1;
|
|
298
|
+
}
|
|
210
299
|
},
|
|
211
300
|
async logout(options2) {
|
|
212
|
-
|
|
213
|
-
|
|
301
|
+
identityOperationGeneration += 1;
|
|
302
|
+
invalidateAuthentication();
|
|
303
|
+
authenticationOperations += 1;
|
|
304
|
+
try {
|
|
305
|
+
await session.logout(options2);
|
|
306
|
+
publish({ status: "anonymous" });
|
|
307
|
+
} catch (error) {
|
|
308
|
+
publish(snapshotFromSessionError(error, session.info));
|
|
309
|
+
throw error;
|
|
310
|
+
} finally {
|
|
311
|
+
authenticationOperations -= 1;
|
|
312
|
+
}
|
|
214
313
|
},
|
|
215
314
|
subscribe(listener) {
|
|
216
315
|
listeners.add(listener);
|
|
@@ -219,6 +318,8 @@ function createSolidSessionRuntime(options = {}) {
|
|
|
219
318
|
};
|
|
220
319
|
},
|
|
221
320
|
dispose() {
|
|
321
|
+
identityOperationGeneration += 1;
|
|
322
|
+
invalidateAuthentication();
|
|
222
323
|
disposed = true;
|
|
223
324
|
listeners.clear();
|
|
224
325
|
session.events.off(import_solid_client_authn_browser.EVENTS.LOGIN, publishSessionInfo);
|
|
@@ -31,6 +31,8 @@ export type SolidSessionAdapter = {
|
|
|
31
31
|
};
|
|
32
32
|
export type SolidSessionRuntime = {
|
|
33
33
|
readonly fetch: typeof fetch;
|
|
34
|
+
/** A revocable capability for this exact WebID and authenticated session. */
|
|
35
|
+
createAuthenticatedFetch(webId: string): typeof fetch;
|
|
34
36
|
getSnapshot(): SolidSessionSnapshot;
|
|
35
37
|
initialize(options?: {
|
|
36
38
|
restorePreviousSession?: boolean;
|
|
@@ -46,11 +46,27 @@ export function createSolidSessionRuntime(options = {}) {
|
|
|
46
46
|
let isInitializing = false;
|
|
47
47
|
let initializationErrorSnapshot;
|
|
48
48
|
let disposed = false;
|
|
49
|
+
let authenticationGeneration = 0;
|
|
50
|
+
let authenticationUnavailable = false;
|
|
51
|
+
let authenticationOperations = 0;
|
|
52
|
+
// Redirect completion has a lifecycle separate from signer renewal. Its own
|
|
53
|
+
// LOGIN event may advance authenticationGeneration without cancelling it.
|
|
54
|
+
let identityOperationGeneration = 0;
|
|
55
|
+
let pendingIdentity;
|
|
56
|
+
const invalidateAuthentication = () => {
|
|
57
|
+
authenticationGeneration += 1;
|
|
58
|
+
authenticationUnavailable = true;
|
|
59
|
+
};
|
|
49
60
|
const publish = (nextSnapshot) => {
|
|
50
|
-
|
|
51
|
-
if (disposed) {
|
|
61
|
+
if (disposed)
|
|
52
62
|
return snapshot;
|
|
63
|
+
if (nextSnapshot.status !== 'authenticated'
|
|
64
|
+
|| snapshot.status !== 'authenticated' || snapshot.webId !== nextSnapshot.webId) {
|
|
65
|
+
invalidateAuthentication();
|
|
53
66
|
}
|
|
67
|
+
if (nextSnapshot.status === 'authenticated')
|
|
68
|
+
authenticationUnavailable = false;
|
|
69
|
+
snapshot = nextSnapshot;
|
|
54
70
|
if (areSnapshotsEqual(lastNotifiedSnapshot, snapshot)) {
|
|
55
71
|
return snapshot;
|
|
56
72
|
}
|
|
@@ -60,10 +76,32 @@ export function createSolidSessionRuntime(options = {}) {
|
|
|
60
76
|
}
|
|
61
77
|
return snapshot;
|
|
62
78
|
};
|
|
63
|
-
const publishSessionInfo = () =>
|
|
64
|
-
|
|
65
|
-
|
|
79
|
+
const publishSessionInfo = () => {
|
|
80
|
+
// Inrupt may emit LOGIN while a cancelled redirect is still settling.
|
|
81
|
+
// These events cannot restore authority after logout/disposal.
|
|
82
|
+
if (pendingIdentity) {
|
|
83
|
+
if (pendingIdentity.generation !== identityOperationGeneration)
|
|
84
|
+
return snapshot;
|
|
85
|
+
if (pendingIdentity.eventWebId && pendingIdentity.eventWebId !== session.info.webId)
|
|
86
|
+
return snapshot;
|
|
87
|
+
pendingIdentity.eventWebId = session.info.webId;
|
|
88
|
+
}
|
|
89
|
+
// LOGIN/RESTORED establishes a new session even when the WebID is unchanged.
|
|
90
|
+
// Token renewal changes Inrupt's signer without these login events.
|
|
91
|
+
invalidateAuthentication();
|
|
92
|
+
lastNotifiedSnapshot = undefined;
|
|
93
|
+
return publish(snapshotFromSessionInfo(session.info));
|
|
94
|
+
};
|
|
95
|
+
const publishAnonymous = () => {
|
|
96
|
+
identityOperationGeneration += 1;
|
|
97
|
+
return publish({ status: 'anonymous' });
|
|
98
|
+
};
|
|
99
|
+
const publishSessionExpired = () => {
|
|
100
|
+
identityOperationGeneration += 1;
|
|
101
|
+
return publish(snapshotFromSessionExpired(session.info));
|
|
102
|
+
};
|
|
66
103
|
const publishSessionError = (code, description) => {
|
|
104
|
+
identityOperationGeneration += 1;
|
|
67
105
|
const errorSnapshot = snapshotFromSessionError(description ?? code ?? 'Solid session error', session.info);
|
|
68
106
|
if (isInitializing) {
|
|
69
107
|
initializationErrorSnapshot = errorSnapshot;
|
|
@@ -78,6 +116,32 @@ export function createSolidSessionRuntime(options = {}) {
|
|
|
78
116
|
errorEvents.on(EVENTS.ERROR, publishSessionError);
|
|
79
117
|
return {
|
|
80
118
|
fetch: session.fetch,
|
|
119
|
+
createAuthenticatedFetch(webId) {
|
|
120
|
+
const generation = authenticationGeneration;
|
|
121
|
+
const assertCurrent = () => {
|
|
122
|
+
if (disposed || authenticationOperations > 0 || authenticationUnavailable || generation !== authenticationGeneration
|
|
123
|
+
|| snapshot.status !== 'authenticated' || snapshot.webId !== webId
|
|
124
|
+
|| !session.info.isLoggedIn || session.info.webId !== webId) {
|
|
125
|
+
const error = new Error('Authenticated session is no longer current');
|
|
126
|
+
error.name = 'AbortError';
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
return async (input, init) => {
|
|
131
|
+
assertCurrent();
|
|
132
|
+
const response = await (init === undefined ? session.fetch(input) : session.fetch(input, init));
|
|
133
|
+
try {
|
|
134
|
+
assertCurrent();
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
// The request may already have reached the server. Discard its stale
|
|
138
|
+
// response rather than returning it to the previous identity's work.
|
|
139
|
+
void response.body?.cancel().catch(() => undefined);
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
return response;
|
|
143
|
+
};
|
|
144
|
+
},
|
|
81
145
|
getSnapshot() {
|
|
82
146
|
return snapshot;
|
|
83
147
|
},
|
|
@@ -92,12 +156,21 @@ export function createSolidSessionRuntime(options = {}) {
|
|
|
92
156
|
if (initialized) {
|
|
93
157
|
return Promise.resolve(snapshot);
|
|
94
158
|
}
|
|
159
|
+
if (disposed)
|
|
160
|
+
return Promise.resolve(snapshot);
|
|
161
|
+
const operation = { generation: ++identityOperationGeneration, eventWebId: undefined };
|
|
162
|
+
pendingIdentity = operation;
|
|
163
|
+
const isCurrentOperation = (info) => !disposed
|
|
164
|
+
&& operation.generation === identityOperationGeneration
|
|
165
|
+
&& (!info?.isLoggedIn || !operation.eventWebId || operation.eventWebId === info.webId);
|
|
95
166
|
isInitializing = true;
|
|
96
167
|
initializationErrorSnapshot = undefined;
|
|
97
168
|
publish({ status: 'initializing' });
|
|
98
169
|
const nextInitialization = session.handleIncomingRedirect({
|
|
99
170
|
restorePreviousSession: options.restorePreviousSession ?? true,
|
|
100
171
|
}).then((info) => {
|
|
172
|
+
if (!isCurrentOperation(info ?? session.info))
|
|
173
|
+
return snapshot;
|
|
101
174
|
const nextSnapshot = snapshotFromSessionInfo(info ?? session.info);
|
|
102
175
|
if (nextSnapshot.status === 'anonymous' && initializationErrorSnapshot?.status === 'error') {
|
|
103
176
|
return initializationErrorSnapshot;
|
|
@@ -105,9 +178,12 @@ export function createSolidSessionRuntime(options = {}) {
|
|
|
105
178
|
initialized = true;
|
|
106
179
|
return publish(nextSnapshot);
|
|
107
180
|
})
|
|
108
|
-
.catch((error) =>
|
|
181
|
+
.catch((error) => isCurrentOperation()
|
|
182
|
+
? publish(snapshotFromSessionError(error, session.info)) : snapshot)
|
|
109
183
|
.finally(() => {
|
|
110
184
|
if (initialization === nextInitialization) {
|
|
185
|
+
if (pendingIdentity === operation)
|
|
186
|
+
pendingIdentity = undefined;
|
|
111
187
|
initialization = undefined;
|
|
112
188
|
isInitializing = false;
|
|
113
189
|
initializationErrorSnapshot = undefined;
|
|
@@ -120,10 +196,19 @@ export function createSolidSessionRuntime(options = {}) {
|
|
|
120
196
|
if (initialization) {
|
|
121
197
|
return initialization;
|
|
122
198
|
}
|
|
199
|
+
if (disposed)
|
|
200
|
+
return Promise.resolve(snapshot);
|
|
201
|
+
const operation = { generation: ++identityOperationGeneration, eventWebId: undefined };
|
|
202
|
+
pendingIdentity = operation;
|
|
203
|
+
const isCurrentOperation = (info) => !disposed
|
|
204
|
+
&& operation.generation === identityOperationGeneration
|
|
205
|
+
&& (!info?.isLoggedIn || !operation.eventWebId || operation.eventWebId === info.webId);
|
|
123
206
|
isInitializing = true;
|
|
124
207
|
initializationErrorSnapshot = undefined;
|
|
125
208
|
publish({ status: 'initializing' });
|
|
126
209
|
const nextInitialization = session.handleIncomingRedirect(url).then((info) => {
|
|
210
|
+
if (!isCurrentOperation(info ?? session.info))
|
|
211
|
+
return snapshot;
|
|
127
212
|
const nextSnapshot = snapshotFromSessionInfo(info ?? session.info);
|
|
128
213
|
if (nextSnapshot.status === 'anonymous' && initializationErrorSnapshot?.status === 'error') {
|
|
129
214
|
return initializationErrorSnapshot;
|
|
@@ -131,9 +216,12 @@ export function createSolidSessionRuntime(options = {}) {
|
|
|
131
216
|
initialized = true;
|
|
132
217
|
return publish(nextSnapshot);
|
|
133
218
|
})
|
|
134
|
-
.catch((error) =>
|
|
219
|
+
.catch((error) => isCurrentOperation()
|
|
220
|
+
? publish(snapshotFromSessionError(error, session.info)) : snapshot)
|
|
135
221
|
.finally(() => {
|
|
136
222
|
if (initialization === nextInitialization) {
|
|
223
|
+
if (pendingIdentity === operation)
|
|
224
|
+
pendingIdentity = undefined;
|
|
137
225
|
initialization = undefined;
|
|
138
226
|
isInitializing = false;
|
|
139
227
|
initializationErrorSnapshot = undefined;
|
|
@@ -142,12 +230,46 @@ export function createSolidSessionRuntime(options = {}) {
|
|
|
142
230
|
initialization = nextInitialization;
|
|
143
231
|
return nextInitialization;
|
|
144
232
|
},
|
|
145
|
-
login(options) {
|
|
146
|
-
|
|
233
|
+
async login(options) {
|
|
234
|
+
identityOperationGeneration += 1;
|
|
235
|
+
invalidateAuthentication();
|
|
236
|
+
authenticationOperations += 1;
|
|
237
|
+
try {
|
|
238
|
+
// Inrupt mutates one shared signer and emits untagged events. A new
|
|
239
|
+
// login cannot safely overlap a previous redirect. Fail promptly so
|
|
240
|
+
// callers can retry after it settles, or reload to obtain a new Session.
|
|
241
|
+
if (initialization) {
|
|
242
|
+
const error = new Error('Previous login is still completing. Reload before reconnecting.');
|
|
243
|
+
error.name = 'SolidSessionPendingError';
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
if (disposed)
|
|
247
|
+
throw new Error('Solid session runtime is disposed');
|
|
248
|
+
await session.login(options);
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
publish(snapshotFromSessionError(error, session.info));
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
finally {
|
|
255
|
+
authenticationOperations -= 1;
|
|
256
|
+
}
|
|
147
257
|
},
|
|
148
258
|
async logout(options) {
|
|
149
|
-
|
|
150
|
-
|
|
259
|
+
identityOperationGeneration += 1;
|
|
260
|
+
invalidateAuthentication();
|
|
261
|
+
authenticationOperations += 1;
|
|
262
|
+
try {
|
|
263
|
+
await session.logout(options);
|
|
264
|
+
publish({ status: 'anonymous' });
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
publish(snapshotFromSessionError(error, session.info));
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
finally {
|
|
271
|
+
authenticationOperations -= 1;
|
|
272
|
+
}
|
|
151
273
|
},
|
|
152
274
|
subscribe(listener) {
|
|
153
275
|
listeners.add(listener);
|
|
@@ -156,6 +278,8 @@ export function createSolidSessionRuntime(options = {}) {
|
|
|
156
278
|
};
|
|
157
279
|
},
|
|
158
280
|
dispose() {
|
|
281
|
+
identityOperationGeneration += 1;
|
|
282
|
+
invalidateAuthentication();
|
|
159
283
|
disposed = true;
|
|
160
284
|
listeners.clear();
|
|
161
285
|
session.events.off(EVENTS.LOGIN, publishSessionInfo);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@undefineds.co/xpod",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
4
4
|
"description": "Xpod is an extended Community Solid Server, offering rich-feature, production-level Solid Pod and identity management.",
|
|
5
5
|
"repository": "https://github.com/undefinedsco/xpod",
|
|
6
6
|
"author": "developer@undefineds.co",
|
|
@@ -342,6 +342,12 @@
|
|
|
342
342
|
"abort-controller": "^3.0.0",
|
|
343
343
|
"process": "^0.11.10",
|
|
344
344
|
"string_decoder": "^1.3.0",
|
|
345
|
+
"@undefineds.co/drizzle-solid": "file:./node_modules/@undefineds.co/drizzle-solid",
|
|
346
|
+
"@undefineds.co/extensions": "file:./node_modules/@undefineds.co/extensions",
|
|
347
|
+
"@undefineds.co/ai-connections": "file:./node_modules/@undefineds.co/ai-connections",
|
|
348
|
+
"@undefineds.co/extension-sdk": "file:./node_modules/@undefineds.co/extension-sdk",
|
|
349
|
+
"@undefineds.co/shared-ui": "file:./node_modules/@undefineds.co/shared-ui",
|
|
350
|
+
"@undefineds.co/solid-sdk": "file:./node_modules/@undefineds.co/solid-sdk",
|
|
345
351
|
"oidc-provider": "9.5.1",
|
|
346
352
|
"@inrupt/solid-client-authn-browser": "3.1.1",
|
|
347
353
|
"jose": "5.10.0",
|
|
@@ -370,7 +376,7 @@
|
|
|
370
376
|
}
|
|
371
377
|
},
|
|
372
378
|
"optionalDependencies": {
|
|
373
|
-
"@undefineds.co/xpod-darwin-arm64": "0.4.
|
|
379
|
+
"@undefineds.co/xpod-darwin-arm64": "0.4.10"
|
|
374
380
|
},
|
|
375
381
|
"resolutions": {
|
|
376
382
|
"@inrupt/solid-client-authn-browser": "^3.1.1",
|