@oddington/sdk 0.1.18 → 0.1.19
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/README.md +14 -13
- package/dist/browser.js +192 -173
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -312,12 +312,13 @@ both shipped SDK inputs and every emitted helper, rejects unexpected inputs and
|
|
|
312
312
|
imports, and retains the full credential/server/customer leak scan. Node retains
|
|
313
313
|
the complete package-root exports; provider classes are never public.
|
|
314
314
|
|
|
315
|
-
Current auth measurement is **
|
|
316
|
-
bytes** and **
|
|
317
|
-
|
|
318
|
-
bytes**, with **14,
|
|
319
|
-
|
|
320
|
-
|
|
315
|
+
Current auth measurement is **171,346 minified bytes**, including **6,322 fixture
|
|
316
|
+
bytes** and **165,024 SDK bytes**, with **45,466 total gzip bytes**. Current
|
|
317
|
+
Data/Files fixture measures **47,254 total / 5,893 fixture / 41,361 SDK
|
|
318
|
+
bytes**, with **14,906 total gzip bytes**. The shipped runtime now also carries
|
|
319
|
+
the local Questions transport and transparent Local Host renewal.
|
|
320
|
+
Both fit their explicitly reviewed ceilings: **42,000 SDK bytes** for the pinned
|
|
321
|
+
Data/Files fixture and **166,000 SDK bytes** for the separately pinned auth fixture.
|
|
321
322
|
Those ceilings are fixed review decisions, not values regenerated from later
|
|
322
323
|
measurements. The installed auth realm/host-handoff proof passes alongside the
|
|
323
324
|
Node exports, declarations, tarball leak scan and browser compatibility audits.
|
|
@@ -331,17 +332,17 @@ bytes; generated helpers count toward the SDK. Gzip is diagnostic only.
|
|
|
331
332
|
|
|
332
333
|
| Same named-import fixture | Legacy diagnostic | Current strict proof |
|
|
333
334
|
| --- | ---: | ---: |
|
|
334
|
-
| Total minified JavaScript bytes | 488,539 |
|
|
335
|
+
| Total minified JavaScript bytes | 488,539 | 47,254 |
|
|
335
336
|
| Fixture-attributed bytes | 5,954 | 5,893 |
|
|
336
|
-
| SDK bytes | 482,585 |
|
|
337
|
-
| Total gzip bytes | 198,612 | 14,
|
|
337
|
+
| SDK bytes | 482,585 | 41,361 |
|
|
338
|
+
| Total gzip bytes | 198,612 | 14,906 |
|
|
338
339
|
|
|
339
340
|
The legacy diagnostic externalized three unresolved Node built-ins and failed
|
|
340
341
|
browser compatibility. The current strict proof has no imports, shims or warnings
|
|
341
|
-
and reduces SDK bytes by 91.
|
|
342
|
-
|
|
343
|
-
the Local Host bootstrap
|
|
344
|
-
select at runtime. The verifier pins the fixture
|
|
342
|
+
and reduces SDK bytes by 91.4%. Its literal ceiling is **42,000 SDK bytes**:
|
|
343
|
+
639 bytes of deliberately limited headroom. The reviewed measurement includes
|
|
344
|
+
the Local Host bootstrap, local Questions transport, transparent renewal and
|
|
345
|
+
opaque browser-auth handoff that `os.init` must select at runtime. The verifier pins the fixture
|
|
345
346
|
hash and bundler version; changing either requires a reviewed measurement
|
|
346
347
|
comparison. Future ceiling increases require explicit review of added browser
|
|
347
348
|
capability and must never be automatically regenerated from an oversized output.
|
package/dist/browser.js
CHANGED
|
@@ -2149,6 +2149,19 @@ var sessionKey = "_os.app.session", responseChecks = /* @__PURE__ */ new WeakMap
|
|
|
2149
2149
|
}, AppContextDenied = class extends Error {
|
|
2150
2150
|
}, AppRenewalUnavailable = class extends Error {
|
|
2151
2151
|
};
|
|
2152
|
+
async function untilAborted(work, signal) {
|
|
2153
|
+
if (signal.aborted)
|
|
2154
|
+
throw work.catch(() => {
|
|
2155
|
+
}), new AppRenewalUnavailable();
|
|
2156
|
+
let abort, cancelled = new Promise((_resolve, reject) => {
|
|
2157
|
+
abort = () => reject(new AppRenewalUnavailable()), signal.addEventListener("abort", abort, { once: !0 });
|
|
2158
|
+
});
|
|
2159
|
+
try {
|
|
2160
|
+
return await Promise.race([work, cancelled]);
|
|
2161
|
+
} finally {
|
|
2162
|
+
signal.removeEventListener("abort", abort);
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2152
2165
|
async function appResponse(response2, maximum, signal) {
|
|
2153
2166
|
if (signal.aborted || !response2.body || response2.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() !== "application/json") throw new Error();
|
|
2154
2167
|
let reader = response2.body.getReader(), abort = () => {
|
|
@@ -2188,159 +2201,164 @@ function isAppOrigin(value) {
|
|
|
2188
2201
|
}
|
|
2189
2202
|
}
|
|
2190
2203
|
function appContext(origin, active2) {
|
|
2191
|
-
let binding, credential, denied = !1, controller = new AbortController(), expiry, startup, renewalTimer, renewal, observation, resolution2, disposed = !1, stored = () => globalThis.localStorage.getItem(sessionKey), alive = () => {
|
|
2204
|
+
let binding, credential, pair, serialized, denied = !1, controller = new AbortController(), access = new AbortController(), expiry, startup, renewalTimer, renewal, observation, resolution2, disposed = !1, stored = () => globalThis.localStorage.getItem(sessionKey), alive = () => {
|
|
2192
2205
|
try {
|
|
2193
|
-
return !denied && !disposed && active2() && globalThis.location.origin === origin
|
|
2206
|
+
return !denied && !disposed && active2() && globalThis.location.origin === origin;
|
|
2194
2207
|
} catch {
|
|
2195
2208
|
return !1;
|
|
2196
2209
|
}
|
|
2197
2210
|
}, cancel = () => {
|
|
2198
|
-
controller.abort(), clearTimeout(expiry), clearTimeout(startup), clearTimeout(renewalTimer), clearInterval(monitor), globalThis.removeEventListener?.("storage", storageChanged);
|
|
2211
|
+
controller.abort(), access.abort(), clearTimeout(expiry), clearTimeout(startup), clearTimeout(renewalTimer), clearInterval(monitor), globalThis.removeEventListener?.("storage", storageChanged);
|
|
2212
|
+
for (let event2 of ["pageshow", "focus", "visibilitychange"]) globalThis.removeEventListener?.(event2, wake);
|
|
2199
2213
|
}, invalidate = () => {
|
|
2200
2214
|
denied = !0, cancel();
|
|
2201
2215
|
try {
|
|
2202
|
-
!disposed && active2() && globalThis.location.origin === origin && (!
|
|
2216
|
+
!disposed && active2() && globalThis.location.origin === origin && (!serialized || globalThis.localStorage.getItem(sessionKey) === serialized) && globalThis.localStorage.removeItem(sessionKey);
|
|
2203
2217
|
} catch {
|
|
2204
2218
|
}
|
|
2205
2219
|
}, current2 = () => {
|
|
2206
2220
|
try {
|
|
2207
|
-
return alive() && stored() ===
|
|
2221
|
+
return alive() && !!binding && binding.expiresAt > Date.now() && stored() === serialized;
|
|
2208
2222
|
} catch {
|
|
2209
2223
|
return !1;
|
|
2210
2224
|
}
|
|
2211
|
-
}, sameSession = (value) => !binding ||
|
|
2212
|
-
|
|
2213
|
-
if (!
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2225
|
+
}, sameSession = (value) => !binding || ["appId", "memberId", "workspace", "sessionId"].every((key) => value[key] === binding[key]), bounded = (value) => validBinding(value) && value.expiresAt > Date.now() && value.expiresAt <= Date.now() + 6e5 && sameSession(value), readPair = (candidate) => {
|
|
2226
|
+
let value = JSON.parse(candidate ?? "null");
|
|
2227
|
+
if (!validPair(value) || value.context.expiresAt > Date.now() + 6e5 || !sameSession(value.context)) throw new Error();
|
|
2228
|
+
return value;
|
|
2229
|
+
}, expireAccess = () => {
|
|
2230
|
+
binding && binding.expiresAt <= Date.now() && access.abort();
|
|
2231
|
+
};
|
|
2232
|
+
async function send3(path, candidate, signal, init2 = {}) {
|
|
2233
|
+
let url = `${origin}/_os/app/${path}`, response2;
|
|
2234
|
+
try {
|
|
2235
|
+
response2 = await fetch(url, {
|
|
2236
|
+
...init2,
|
|
2237
|
+
credentials: "omit",
|
|
2238
|
+
redirect: "error",
|
|
2239
|
+
cache: "no-store",
|
|
2240
|
+
referrerPolicy: "no-referrer",
|
|
2241
|
+
signal,
|
|
2242
|
+
headers: {
|
|
2243
|
+
...init2.body === void 0 ? {} : { "content-type": "application/json" },
|
|
2244
|
+
authorization: `Bearer ${candidate}`
|
|
2245
|
+
}
|
|
2246
|
+
});
|
|
2247
|
+
} catch {
|
|
2248
|
+
throw new AppRenewalUnavailable();
|
|
2249
|
+
}
|
|
2222
2250
|
if (response2.redirected || response2.url && response2.url !== url) throw new Error();
|
|
2251
|
+
return response2;
|
|
2252
|
+
}
|
|
2253
|
+
async function proof(candidate, signal = controller.signal) {
|
|
2254
|
+
if (!alive() || !validProof(candidate)) throw new Error();
|
|
2255
|
+
let response2 = await send3("context", candidate, signal);
|
|
2223
2256
|
if (response2.status === 401 || response2.status === 403) throw new AppContextDenied();
|
|
2257
|
+
if (response2.status >= 500) throw new AppRenewalUnavailable();
|
|
2224
2258
|
if (!response2.ok) throw new Error();
|
|
2225
2259
|
let value = await appResponse(response2, 4096, signal);
|
|
2226
2260
|
if (!alive() || !bounded(value)) throw new Error();
|
|
2227
2261
|
return value;
|
|
2228
2262
|
}
|
|
2229
|
-
function install(value, candidate) {
|
|
2230
|
-
binding = { ...value }, credential = candidate, clearTimeout(expiry), clearTimeout(renewalTimer);
|
|
2263
|
+
function install(value, candidate, raw) {
|
|
2264
|
+
expireAccess(), access.signal.aborted && (access = new AbortController()), binding = { ...value }, pair = candidate, credential = candidate.credential, serialized = raw, clearTimeout(expiry), clearTimeout(renewalTimer);
|
|
2231
2265
|
let remaining = binding.expiresAt - Date.now();
|
|
2232
|
-
expiry = setTimeout(
|
|
2233
|
-
renew()
|
|
2266
|
+
expiry = setTimeout(expireAccess, remaining), renewalTimer = setTimeout(() => {
|
|
2267
|
+
renew().catch(() => {
|
|
2268
|
+
});
|
|
2234
2269
|
}, remaining - Math.min(6e4, remaining / 5));
|
|
2235
2270
|
}
|
|
2236
|
-
async function synchronize() {
|
|
2271
|
+
async function synchronize(signal = controller.signal) {
|
|
2237
2272
|
if (!alive()) throw new Error();
|
|
2238
|
-
if (
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2273
|
+
if (signal.aborted) throw new AppRenewalUnavailable();
|
|
2274
|
+
if (!credential || stored() === serialized) return;
|
|
2275
|
+
if (!binding) throw new Error();
|
|
2276
|
+
if (observation) return untilAborted(observation, signal);
|
|
2277
|
+
observation = (async () => {
|
|
2278
|
+
for (; alive(); ) {
|
|
2279
|
+
let candidate = stored();
|
|
2280
|
+
if (!candidate) throw new Error();
|
|
2281
|
+
let value, replacement;
|
|
2282
|
+
try {
|
|
2283
|
+
replacement = readPair(candidate), value = await proof(replacement.credential, signal);
|
|
2284
|
+
} catch (error) {
|
|
2285
|
+
if (stored() !== candidate) continue;
|
|
2286
|
+
throw error;
|
|
2287
|
+
}
|
|
2288
|
+
if (stored() === candidate) {
|
|
2289
|
+
if (value.expiresAt !== replacement.context.expiresAt) throw new Error();
|
|
2290
|
+
install(value, replacement, candidate);
|
|
2291
|
+
return;
|
|
2256
2292
|
}
|
|
2257
|
-
throw new Error();
|
|
2258
|
-
})();
|
|
2259
|
-
try {
|
|
2260
|
-
await observation;
|
|
2261
|
-
} catch {
|
|
2262
|
-
throw invalidate(), new Error("Local app context unavailable.");
|
|
2263
|
-
} finally {
|
|
2264
|
-
observation = void 0;
|
|
2265
2293
|
}
|
|
2294
|
+
throw new Error();
|
|
2295
|
+
})();
|
|
2296
|
+
let observed = observation;
|
|
2297
|
+
try {
|
|
2298
|
+
await untilAborted(observed, signal);
|
|
2299
|
+
} catch (error) {
|
|
2300
|
+
throw error instanceof AppRenewalUnavailable || error instanceof AppResponseReadError || invalidate(), error;
|
|
2301
|
+
} finally {
|
|
2302
|
+
observation === observed && (observation = void 0);
|
|
2266
2303
|
}
|
|
2267
2304
|
}
|
|
2268
2305
|
async function renew() {
|
|
2269
|
-
if (
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2306
|
+
if (renewal) return renewal;
|
|
2307
|
+
if (!binding || !pair || !alive()) throw new Error();
|
|
2308
|
+
renewal = (async () => {
|
|
2309
|
+
let requestController = new AbortController(), abort = () => requestController.abort();
|
|
2310
|
+
controller.signal.addEventListener("abort", abort, { once: !0 });
|
|
2311
|
+
let timeout = setTimeout(abort, 2e4), previous = serialized;
|
|
2312
|
+
try {
|
|
2313
|
+
if (await synchronize(requestController.signal), serialized !== previous) return;
|
|
2314
|
+
let response2 = await send3("renew", pair.renewalCredential, requestController.signal, { method: "POST" }), value = await appResponse(response2, 4096, requestController.signal);
|
|
2315
|
+
if (response2.status === 503 && value && typeof value == "object" && !Array.isArray(value) && Object.keys(value).join(",") === "error" && "error" in value && value.error === "renewal_unavailable")
|
|
2316
|
+
throw new AppRenewalUnavailable();
|
|
2317
|
+
if (response2.status === 403 && value && typeof value == "object" && !Array.isArray(value) && Object.keys(value).join(",") === "error" && "error" in value && value.error === "renewal_conflict") {
|
|
2318
|
+
for (; alive() && stored() === previous && !requestController.signal.aborted; )
|
|
2319
|
+
await new Promise((resolve2, reject) => {
|
|
2320
|
+
let abortWait = () => {
|
|
2321
|
+
clearTimeout(timer), reject(new Error());
|
|
2322
|
+
}, timer = setTimeout(() => {
|
|
2323
|
+
requestController.signal.removeEventListener("abort", abortWait), resolve2();
|
|
2324
|
+
}, 100);
|
|
2325
|
+
requestController.signal.addEventListener("abort", abortWait, { once: !0 });
|
|
2286
2326
|
});
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
});
|
|
2304
|
-
if (requestController.signal.aborted) throw new Error();
|
|
2305
|
-
await synchronize();
|
|
2306
|
-
return;
|
|
2307
|
-
}
|
|
2308
|
-
if (!response2.ok) throw new Error();
|
|
2309
|
-
if (!alive() || Date.now() >= deadline || !value || typeof value != "object" || Array.isArray(value) || Object.keys(value).sort().join(",") !== "context,credential") throw new Error();
|
|
2310
|
-
let result2 = value;
|
|
2311
|
-
if (!bounded(result2.context) || typeof result2.credential != "string" || !/^[A-Za-z0-9_-]{43}$/.test(result2.credential) || result2.credential === previous) throw new Error();
|
|
2312
|
-
if (stored() !== previous) {
|
|
2313
|
-
await synchronize();
|
|
2327
|
+
if (requestController.signal.aborted) throw new Error();
|
|
2328
|
+
await synchronize(requestController.signal);
|
|
2329
|
+
return;
|
|
2330
|
+
}
|
|
2331
|
+
if (!response2.ok) throw new Error();
|
|
2332
|
+
if (!alive() || !validPair(value) || !bounded(value.context) || (/* @__PURE__ */ new Set([value.credential, value.renewalCredential, pair.credential, pair.renewalCredential])).size !== 4) throw new Error();
|
|
2333
|
+
if (stored() !== previous) {
|
|
2334
|
+
await synchronize(requestController.signal);
|
|
2335
|
+
return;
|
|
2336
|
+
}
|
|
2337
|
+
let raw = JSON.stringify(value);
|
|
2338
|
+
globalThis.localStorage.setItem(sessionKey, raw), install(value.context, value, raw);
|
|
2339
|
+
} catch (error) {
|
|
2340
|
+
try {
|
|
2341
|
+
if (alive() && stored() && stored() !== previous) {
|
|
2342
|
+
await synchronize(requestController.signal);
|
|
2314
2343
|
return;
|
|
2315
2344
|
}
|
|
2316
|
-
|
|
2317
|
-
} catch (error) {
|
|
2318
|
-
try {
|
|
2319
|
-
if (alive() && stored() && stored() !== previous) {
|
|
2320
|
-
await synchronize();
|
|
2321
|
-
return;
|
|
2322
|
-
}
|
|
2323
|
-
} catch {
|
|
2324
|
-
}
|
|
2325
|
-
try {
|
|
2326
|
-
if (alive() && stored() && stored() !== previous) {
|
|
2327
|
-
await synchronize();
|
|
2328
|
-
return;
|
|
2329
|
-
}
|
|
2330
|
-
} catch {
|
|
2331
|
-
}
|
|
2332
|
-
(error instanceof AppRenewalUnavailable || error instanceof AppResponseReadError || requestController.signal.aborted) && current2() && Date.now() < deadline ? renewalTimer = setTimeout(() => {
|
|
2333
|
-
renew();
|
|
2334
|
-
}, Math.min(5e3, (deadline - Date.now()) / 5)) : invalidate();
|
|
2335
|
-
} finally {
|
|
2336
|
-
clearTimeout(timeout), controller.signal.removeEventListener("abort", abort);
|
|
2345
|
+
} catch {
|
|
2337
2346
|
}
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2347
|
+
throw (error instanceof AppRenewalUnavailable || error instanceof AppResponseReadError || requestController.signal.aborted) && alive() ? current2() && (renewalTimer = setTimeout(
|
|
2348
|
+
() => {
|
|
2349
|
+
renew().catch(() => {
|
|
2350
|
+
});
|
|
2351
|
+
},
|
|
2352
|
+
Math.min(5e3, (binding.expiresAt - Date.now()) / 5)
|
|
2353
|
+
)) : invalidate(), new AppRenewalUnavailable();
|
|
2341
2354
|
} finally {
|
|
2342
|
-
|
|
2355
|
+
clearTimeout(timeout), controller.signal.removeEventListener("abort", abort);
|
|
2343
2356
|
}
|
|
2357
|
+
})();
|
|
2358
|
+
try {
|
|
2359
|
+
await renewal;
|
|
2360
|
+
} finally {
|
|
2361
|
+
renewal = void 0;
|
|
2344
2362
|
}
|
|
2345
2363
|
}
|
|
2346
2364
|
let storageChanged = () => {
|
|
@@ -2349,36 +2367,33 @@ function appContext(origin, active2) {
|
|
|
2349
2367
|
invalidate();
|
|
2350
2368
|
return;
|
|
2351
2369
|
}
|
|
2352
|
-
synchronize().catch(
|
|
2370
|
+
expireAccess(), synchronize().catch(() => {
|
|
2371
|
+
});
|
|
2353
2372
|
}
|
|
2354
2373
|
}, monitor = setInterval(() => {
|
|
2355
2374
|
storageChanged();
|
|
2356
2375
|
}, 100);
|
|
2357
2376
|
globalThis.addEventListener?.("storage", storageChanged);
|
|
2377
|
+
let wake = () => {
|
|
2378
|
+
alive() && resolve().catch(() => {
|
|
2379
|
+
});
|
|
2380
|
+
};
|
|
2381
|
+
for (let event2 of ["pageshow", "focus", "visibilitychange"]) globalThis.addEventListener?.(event2, wake);
|
|
2358
2382
|
let dispose = () => {
|
|
2359
2383
|
disposed = !0, cancel();
|
|
2360
2384
|
};
|
|
2385
|
+
async function settledAccess(signal) {
|
|
2386
|
+
for (await synchronize(); alive() && stored() !== serialized; ) await synchronize();
|
|
2387
|
+
if (signal.aborted || !current2()) throw new Error();
|
|
2388
|
+
}
|
|
2361
2389
|
async function requestData(operation2, input) {
|
|
2362
2390
|
try {
|
|
2363
2391
|
if (operation2 !== "data/query" || !current2()) throw new Error();
|
|
2364
|
-
let
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
referrerPolicy: "no-referrer",
|
|
2370
|
-
signal: controller.signal,
|
|
2371
|
-
headers: { "content-type": "application/json", authorization: `Bearer ${credential}` },
|
|
2372
|
-
body: JSON.stringify(input)
|
|
2373
|
-
});
|
|
2374
|
-
for (await synchronize(); alive() && stored() !== credential; ) await synchronize();
|
|
2375
|
-
if (!current2() || response2.redirected || response2.url && response2.url !== url) throw new Error();
|
|
2376
|
-
if (response2.status === 401 || response2.status === 403)
|
|
2377
|
-
throw admitted === credential && invalidate(), new DataOperationError("access_denied");
|
|
2378
|
-
let result2 = await appResponse(response2, Number.MAX_SAFE_INTEGER, controller.signal);
|
|
2379
|
-
for (await synchronize(); alive() && stored() !== credential; ) await synchronize();
|
|
2380
|
-
if (!current2()) throw new Error();
|
|
2381
|
-
if (!response2.ok) throw dataTransportError(response2.status, result2);
|
|
2392
|
+
let admitted = credential, signal = access.signal, response2 = await send3("data", credential, signal, { method: "POST", body: JSON.stringify(input) });
|
|
2393
|
+
if (await settledAccess(signal), response2.status === 401 || response2.status === 403)
|
|
2394
|
+
throw admitted === credential && current2() && invalidate(), new DataOperationError("access_denied");
|
|
2395
|
+
let result2 = await appResponse(response2, Number.MAX_SAFE_INTEGER, signal);
|
|
2396
|
+
if (await settledAccess(signal), !response2.ok) throw dataTransportError(response2.status, result2);
|
|
2382
2397
|
return result2;
|
|
2383
2398
|
} catch (error) {
|
|
2384
2399
|
throw error instanceof DataOperationError ? error : !current2() || controller.signal.aborted ? new DataOperationError("context_unavailable") : new DataOperationError("unavailable", !0);
|
|
@@ -2386,43 +2401,30 @@ function appContext(origin, active2) {
|
|
|
2386
2401
|
}
|
|
2387
2402
|
async function requestInbox(operation2, input) {
|
|
2388
2403
|
if (!["questions.list", "questions.answer", "questions.searchRecords"].includes(operation2)) throw new Error("Inbox operation unavailable");
|
|
2389
|
-
return requestChecked(
|
|
2404
|
+
return requestChecked("inbox", { method: "POST", body: JSON.stringify({ operation: operation2, input }) }, !0);
|
|
2390
2405
|
}
|
|
2391
2406
|
async function requestRoutine(key, suffix, init2 = {}) {
|
|
2392
|
-
return requestChecked(
|
|
2407
|
+
return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, init2);
|
|
2393
2408
|
}
|
|
2394
|
-
async function requestChecked(
|
|
2395
|
-
if (!current2())
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
credentials: "omit",
|
|
2400
|
-
redirect: "error",
|
|
2401
|
-
cache: "no-store",
|
|
2402
|
-
referrerPolicy: "no-referrer",
|
|
2403
|
-
signal: controller.signal,
|
|
2404
|
-
headers: { ...init2.body === void 0 ? {} : { "content-type": "application/json" }, authorization: `Bearer ${credential}` }
|
|
2405
|
-
});
|
|
2406
|
-
for (await synchronize(); alive() && stored() !== credential; ) await synchronize();
|
|
2407
|
-
if (!current2() || response2.redirected || response2.url && response2.url !== url)
|
|
2408
|
-
throw invalidate(), new Error("Local app context unavailable.");
|
|
2409
|
-
return (response2.status === 401 || !inbox2 && response2.status === 403) && admitted === credential && invalidate(), responseChecks.set(response2, async (value) => {
|
|
2410
|
-
for (await synchronize(); alive() && stored() !== credential; ) await synchronize();
|
|
2411
|
-
admitted === credential && value && typeof value == "object" && "error" in value && value.error === "authority_unavailable" && invalidate();
|
|
2409
|
+
async function requestChecked(path, init2, inbox2 = !1) {
|
|
2410
|
+
if (!current2()) throw new Error("Local app context unavailable.");
|
|
2411
|
+
let admitted = credential, signal = access.signal, response2 = await send3(path, credential, signal, init2);
|
|
2412
|
+
return await settledAccess(signal), (response2.status === 401 || !inbox2 && response2.status === 403) && admitted === credential && current2() && invalidate(), responseChecks.set(response2, async (value) => {
|
|
2413
|
+
await settledAccess(signal), admitted === credential && current2() && value && typeof value == "object" && "error" in value && value.error === "authority_unavailable" && invalidate();
|
|
2412
2414
|
}), response2;
|
|
2413
2415
|
}
|
|
2414
2416
|
function context2() {
|
|
2415
|
-
let issued = credential;
|
|
2417
|
+
let issued = credential, signal = access.signal;
|
|
2416
2418
|
return {
|
|
2417
2419
|
kind: "local",
|
|
2418
2420
|
...binding,
|
|
2419
2421
|
get expiresAt() {
|
|
2420
2422
|
return binding.expiresAt;
|
|
2421
2423
|
},
|
|
2422
|
-
isCurrent: current2,
|
|
2423
|
-
signal
|
|
2424
|
+
isCurrent: () => !signal.aborted && current2(),
|
|
2425
|
+
signal,
|
|
2424
2426
|
invalidate: () => {
|
|
2425
|
-
issued === credential && invalidate();
|
|
2427
|
+
issued === credential && current2() && invalidate();
|
|
2426
2428
|
},
|
|
2427
2429
|
requestRoutine,
|
|
2428
2430
|
requestData,
|
|
@@ -2433,25 +2435,34 @@ function appContext(origin, active2) {
|
|
|
2433
2435
|
let resolveOnce = async () => {
|
|
2434
2436
|
let attempted;
|
|
2435
2437
|
try {
|
|
2436
|
-
if (
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
return
|
|
2438
|
+
if (!alive()) throw new Error();
|
|
2439
|
+
if (!pair) {
|
|
2440
|
+
let candidate2 = stored(), retained2 = readPair(candidate2);
|
|
2441
|
+
pair = retained2, binding = { ...retained2.context }, credential = retained2.credential, serialized = candidate2;
|
|
2442
|
+
}
|
|
2443
|
+
if (expireAccess(), binding.expiresAt <= Date.now()) {
|
|
2444
|
+
if (await renew(), !current2()) throw new AppRenewalUnavailable();
|
|
2445
|
+
return context2();
|
|
2446
|
+
}
|
|
2447
|
+
await synchronize();
|
|
2448
|
+
let candidate = stored(), retained = readPair(candidate);
|
|
2449
|
+
if (attempted = candidate ?? void 0, !current2()) throw new AppRenewalUnavailable();
|
|
2450
|
+
let value = await proof(retained.credential);
|
|
2451
|
+
if (stored() !== candidate || serialized !== candidate)
|
|
2452
|
+
return await synchronize(), context2();
|
|
2444
2453
|
if (!current2()) throw new Error();
|
|
2445
|
-
if (binding && value.expiresAt > binding.expiresAt) throw new Error();
|
|
2446
|
-
return (!
|
|
2454
|
+
if (expiry && binding && value.expiresAt > binding.expiresAt) throw new Error();
|
|
2455
|
+
return (!expiry || value.expiresAt !== binding.expiresAt) && install(value, retained, candidate), context2();
|
|
2447
2456
|
} catch (error) {
|
|
2457
|
+
if (alive() && error instanceof AppRenewalUnavailable)
|
|
2458
|
+
throw new Error();
|
|
2448
2459
|
try {
|
|
2449
|
-
if (binding && current2() && attempted && attempted !==
|
|
2450
|
-
if (binding && alive() && stored() && stored() !==
|
|
2460
|
+
if (binding && current2() && attempted && attempted !== serialized) return context2();
|
|
2461
|
+
if (binding && alive() && stored() && stored() !== serialized)
|
|
2451
2462
|
return await synchronize(), context2();
|
|
2452
2463
|
} catch {
|
|
2453
2464
|
}
|
|
2454
|
-
throw error instanceof AppContextDenied && binding && alive() && renewal ? new Error(
|
|
2465
|
+
throw error instanceof AppContextDenied && binding && alive() && renewal ? new Error() : alive() && (error instanceof AppResponseReadError || pair && stored() === serialized && !current2()) ? new Error() : (invalidate(), new Error());
|
|
2455
2466
|
}
|
|
2456
2467
|
}, resolve = () => resolution2 || (resolution2 = resolveOnce().finally(() => {
|
|
2457
2468
|
resolution2 = void 0;
|
|
@@ -2463,10 +2474,18 @@ function appContext(origin, active2) {
|
|
|
2463
2474
|
}, 0);
|
|
2464
2475
|
}, invalidate, dispose };
|
|
2465
2476
|
}
|
|
2477
|
+
function validProof(value) {
|
|
2478
|
+
return typeof value == "string" && /^[A-Za-z0-9_-]{43}$/.test(value);
|
|
2479
|
+
}
|
|
2466
2480
|
function validBinding(value) {
|
|
2467
2481
|
if (!value || typeof value != "object" || Array.isArray(value) || Object.keys(value).sort().join(",") !== "appId,expiresAt,memberId,sessionId,workspace") return !1;
|
|
2468
2482
|
let binding = value;
|
|
2469
|
-
return typeof binding.appId == "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(binding.appId) && typeof binding.workspace == "string" && /^[a-z0-9][a-z0-9-]{0,62}$/.test(binding.workspace) && typeof binding.memberId == "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(binding.memberId) &&
|
|
2483
|
+
return typeof binding.appId == "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(binding.appId) && typeof binding.workspace == "string" && /^[a-z0-9][a-z0-9-]{0,62}$/.test(binding.workspace) && typeof binding.memberId == "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(binding.memberId) && validProof(binding.sessionId) && typeof binding.expiresAt == "number" && Number.isFinite(binding.expiresAt);
|
|
2484
|
+
}
|
|
2485
|
+
function validPair(value) {
|
|
2486
|
+
if (!value || typeof value != "object" || Array.isArray(value) || Object.keys(value).sort().join(",") !== "context,credential,renewalCredential") return !1;
|
|
2487
|
+
let pair = value;
|
|
2488
|
+
return validProof(pair.credential) && validProof(pair.renewalCredential) && pair.credential !== pair.renewalCredential && validBinding(pair.context);
|
|
2470
2489
|
}
|
|
2471
2490
|
|
|
2472
2491
|
var unavailable2 = () => new InboxOperationError(503, "unavailable"), stale = () => new InboxOperationError(401, "authority_unavailable");
|