@oddington/sdk 0.1.17 → 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/dist/browser.js
CHANGED
|
@@ -1782,9 +1782,14 @@ var InboxOperationError = class extends Error {
|
|
|
1782
1782
|
}
|
|
1783
1783
|
status;
|
|
1784
1784
|
reason;
|
|
1785
|
-
}, INBOX_RESULT_BYTES = 8 * 1024 * 1024, INBOX_INPUT_BYTES = 8192, INBOX_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
|
|
1785
|
+
}, INBOX_RESULT_BYTES = 8 * 1024 * 1024, INBOX_INPUT_BYTES = 8192, INBOX_LOCAL_INPUT_BYTES = 256 * 1024, INBOX_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
1786
|
+
function isAppQuestionOperation(operation2) {
|
|
1787
|
+
return operation2 === "questions.list" || operation2 === "questions.answer" || operation2 === "questions.searchRecords";
|
|
1788
|
+
}
|
|
1789
|
+
var operations = {
|
|
1786
1790
|
current: [],
|
|
1787
1791
|
"items.list": [],
|
|
1792
|
+
"questions.list": [],
|
|
1788
1793
|
"items.read": ["itemId"],
|
|
1789
1794
|
"items.see": ["itemId"],
|
|
1790
1795
|
"items.markDigestRead": ["itemId"],
|
|
@@ -1937,7 +1942,7 @@ function parseInboxRequest(value) {
|
|
|
1937
1942
|
let envelope = object3(value);
|
|
1938
1943
|
assert(Object.keys(envelope).sort().join(",") === "input,operation"), assert(typeof envelope.operation == "string" && Object.hasOwn(operations, envelope.operation));
|
|
1939
1944
|
let operation2 = envelope.operation, input = object3(envelope.input), required = operations[operation2];
|
|
1940
|
-
assert(required.every((key) => Object.hasOwn(input, key)) && Object.keys(input).every((key) => required.includes(key) || operation2 === "questions.searchRecords" && key === "selected" || operation2 === "items.list" && key === "beforeNumber"));
|
|
1945
|
+
assert(required.every((key) => Object.hasOwn(input, key)) && Object.keys(input).every((key) => required.includes(key) || operation2 === "questions.searchRecords" && key === "selected" || (operation2 === "items.list" || operation2 === "questions.list") && key === "beforeNumber"));
|
|
1941
1946
|
for (let key of ["itemId", "personId", "fileId"]) key in input && assert(id2(input[key]));
|
|
1942
1947
|
return "revision" in input && assert(integer(input.revision)), "beforeNumber" in input && assert(integer(input.beforeNumber)), "questionId" in input && assert(text3(input.questionId) && input.questionId === input.questionId.trim()), "title" in input && assert(text3(input.title)), "lifecycle" in input && assert(input.lifecycle === "open" || input.lifecycle === "closed"), "query" in input && assert(text3(input.query, !0) && input.query.length <= 256), "selected" in input && recordReference(input.selected), "response" in input && response(input.response), assert(new TextEncoder().encode(JSON.stringify(envelope)).byteLength <= INBOX_INPUT_BYTES), { operation: operation2, input };
|
|
1943
1948
|
} catch {
|
|
@@ -1990,12 +1995,32 @@ function parseInboxItem(value) {
|
|
|
1990
1995
|
assert(id2(work.id) && text3(work.questionId) && text3(work.reason) && optionalDate(work.settledAt));
|
|
1991
1996
|
}), item;
|
|
1992
1997
|
}
|
|
1998
|
+
function parseAnswerableQuestion(value) {
|
|
1999
|
+
let entry = object3(json2(value));
|
|
2000
|
+
keys3(entry, ["item", "origin", "question", "recordRefs"]);
|
|
2001
|
+
let item = object3(entry.item);
|
|
2002
|
+
keys3(item, ["id", "number", "revision", "title", "href"]), assert(id2(item.id) && integer(item.number) && integer(item.revision) && text3(item.title) && text3(item.href));
|
|
2003
|
+
let link = new URL(item.href), slug = link.hostname.slice(0, -13);
|
|
2004
|
+
assert(link.hostname.endsWith(".oddington.ai") && slug.length <= 63 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug) && !["auth", "www", "api", "os"].includes(slug) && item.href === `https://${slug}.oddington.ai/inbox/${item.id}`);
|
|
2005
|
+
let origin = object3(entry.origin);
|
|
2006
|
+
keys3(origin, ["routine"]), assert(text3(origin.routine) && origin.routine === origin.routine.trim());
|
|
2007
|
+
let question2 = object3(entry.question);
|
|
2008
|
+
keys3(question2, ["id", "prompt", "instructions", "response"]), assert(text3(question2.id) && question2.id === question2.id.trim() && text3(question2.prompt) && (question2.instructions === null || text3(question2.instructions, !0))), responseDefinition(question2.response);
|
|
2009
|
+
let refs = array2(entry.recordRefs);
|
|
2010
|
+
return assert(refs.every((ref) => text3(ref) && ref === ref.trim()) && new Set(refs).size === refs.length), entry;
|
|
2011
|
+
}
|
|
1993
2012
|
function parseInboxAcceptance(value) {
|
|
1994
2013
|
let accepted = object3(value);
|
|
1995
2014
|
return assert(id2(accepted.responseId) && date(accepted.acceptedAt)), "executionId" in accepted && assert(id2(accepted.executionId)), "acceptanceOrder" in accepted && assert(integer(accepted.acceptanceOrder)), "label" in accepted && assert(text3(accepted.label)), accepted;
|
|
1996
2015
|
}
|
|
1997
2016
|
function parseInboxResult(operation2, value) {
|
|
1998
2017
|
if (operation2 === "current") return parseInboxCurrent(value);
|
|
2018
|
+
if (operation2 === "questions.list") {
|
|
2019
|
+
let page = object3(value);
|
|
2020
|
+
keys3(page, ["questions", "nextBeforeNumber"]);
|
|
2021
|
+
let questions = array2(page.questions).map(parseAnswerableQuestion);
|
|
2022
|
+
return assert(page.nextBeforeNumber === null || integer(page.nextBeforeNumber)), { questions, nextBeforeNumber: page.nextBeforeNumber };
|
|
2023
|
+
}
|
|
1999
2024
|
if (operation2 === "items.read") return parseInboxItem(value);
|
|
2000
2025
|
if (operation2 === "items.list") {
|
|
2001
2026
|
let page = object3(value), items = array2(page.items).map(parseInboxItem);
|
|
@@ -2063,134 +2088,80 @@ async function limitedBody(request, limit, timeoutMs) {
|
|
|
2063
2088
|
}
|
|
2064
2089
|
}
|
|
2065
2090
|
|
|
2066
|
-
var
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2091
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
2092
|
+
function parseInboxHostContext(value) {
|
|
2093
|
+
if (!value || typeof value != "object" || Array.isArray(value)) throw new Error("Inbox context unavailable");
|
|
2094
|
+
let v = value;
|
|
2095
|
+
if (v.kind !== "inbox" && v.kind !== "focused" || Object.keys(v).sort().join(",") !== (v.kind === "inbox" ? "generation,kind,memberId,workspaceId" : "appId,generation,kind,memberId,workspaceId") || typeof v.workspaceId != "string" || !UUID.test(v.workspaceId) || typeof v.memberId != "string" || !UUID.test(v.memberId) || typeof v.generation != "string" || !UUID.test(v.generation) || v.kind === "focused" && (typeof v.appId != "string" || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(v.appId)))
|
|
2096
|
+
throw new Error("Inbox context unavailable");
|
|
2097
|
+
let base = { workspaceId: v.workspaceId, memberId: v.memberId, generation: v.generation };
|
|
2098
|
+
return Object.freeze(v.kind === "inbox" ? { ...base, kind: "inbox" } : { ...base, kind: "focused", appId: v.appId });
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
var InboxContextError = class extends Error {
|
|
2102
|
+
constructor(status) {
|
|
2103
|
+
super("Inbox context unavailable");
|
|
2104
|
+
this.status = status;
|
|
2073
2105
|
}
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2106
|
+
status;
|
|
2107
|
+
}, contexts = /* @__PURE__ */ new WeakMap();
|
|
2108
|
+
function resolveHostedInboxContext(host) {
|
|
2109
|
+
if (!host.binding || !host.memberId) throw new Error("Inbox context unavailable");
|
|
2110
|
+
let resolve = contexts.get(host.binding);
|
|
2111
|
+
return resolve || (resolve = hostedInboxContext(), contexts.set(host.binding, resolve)), resolve({ ...host, memberId: host.memberId });
|
|
2112
|
+
}
|
|
2113
|
+
function hostedInboxContext() {
|
|
2114
|
+
let installed2, revision = 0, issued = 0, settled = 0;
|
|
2115
|
+
return async (host) => {
|
|
2116
|
+
let started = ++issued, check = () => {
|
|
2117
|
+
if (!host.isCurrent() || host.expiresAt <= Date.now()) throw new Error("Inbox context unavailable");
|
|
2118
|
+
};
|
|
2119
|
+
check();
|
|
2120
|
+
let response2 = await fetch(`${host.endpoint}/api/inbox/context`, {
|
|
2121
|
+
method: "GET",
|
|
2122
|
+
headers: { authorization: `Bearer ${host.accessToken}` },
|
|
2123
|
+
credentials: "omit",
|
|
2084
2124
|
redirect: "error",
|
|
2085
2125
|
cache: "no-store",
|
|
2086
|
-
signal: AbortSignal.timeout(
|
|
2126
|
+
signal: AbortSignal.timeout(15e3)
|
|
2087
2127
|
});
|
|
2088
2128
|
try {
|
|
2089
|
-
check();
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
})
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
[400, 401, 403, 409].includes(response2.status) ? response2.status : 503,
|
|
2098
|
-
response2.status === 400 ? "invalid_input" : response2.status === 401 ? "authority_unavailable" : response2.status === 403 ? "access_denied" : response2.status === 409 ? "conflict" : "unavailable"
|
|
2099
|
-
);
|
|
2100
|
-
if (response2.status !== 200)
|
|
2101
|
-
throw response2.body?.cancel().catch(() => {
|
|
2102
|
-
}), unavailable2();
|
|
2103
|
-
if (operation2 === "files.read") {
|
|
2104
|
-
if (!response2.body) throw unavailable2();
|
|
2105
|
-
let source = response2.body, reader, size = 0, cancel = async (reason) => {
|
|
2106
|
-
try {
|
|
2107
|
-
await (reader ? reader.cancel(reason) : source.cancel(reason));
|
|
2108
|
-
} finally {
|
|
2109
|
-
reader?.releaseLock();
|
|
2110
|
-
}
|
|
2111
|
-
}, body2 = new ReadableStream({
|
|
2112
|
-
async pull(controller) {
|
|
2113
|
-
try {
|
|
2114
|
-
check(), reader ??= source.getReader();
|
|
2115
|
-
let next = await reader.read();
|
|
2116
|
-
if (check(), next.done) {
|
|
2117
|
-
reader.releaseLock(), controller.close();
|
|
2118
|
-
return;
|
|
2119
|
-
}
|
|
2120
|
-
if (size += next.value.byteLength, size > 25 * 1024 * 1024) throw unavailable2();
|
|
2121
|
-
controller.enqueue(next.value);
|
|
2122
|
-
} catch (error) {
|
|
2123
|
-
controller.error(error), await cancel(error).catch(() => {
|
|
2124
|
-
});
|
|
2125
|
-
}
|
|
2126
|
-
},
|
|
2127
|
-
cancel
|
|
2128
|
-
}, { highWaterMark: 0 });
|
|
2129
|
-
return new Response(body2, { status: response2.status, headers: response2.headers });
|
|
2130
|
-
}
|
|
2131
|
-
let bytes = await limitedBody(response2, INBOX_RESULT_BYTES);
|
|
2132
|
-
if (check(), !bytes) throw unavailable2();
|
|
2133
|
-
let value = JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes)), parsed = parseInboxResult(operation2, value);
|
|
2134
|
-
if (check(), operation2 === "current" && parsed.workspace.slug !== context2.workspace) throw unavailable2();
|
|
2135
|
-
if ("itemId" in envelope.input) {
|
|
2136
|
-
let item = operation2 === "items.read" ? parsed : operation2 === "items.rename" || operation2 === "items.setLifecycle" || operation2 === "items.addRecipient" ? parsed.item : void 0;
|
|
2137
|
-
if (item && (item.id !== envelope.input.itemId || "revision" in envelope.input && item.revision !== envelope.input.revision) || operation2 === "items.addRecipient" && parsed.addedPersonId !== envelope.input.personId || operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw unavailable2();
|
|
2138
|
-
}
|
|
2139
|
-
return parsed;
|
|
2140
|
-
} catch (error) {
|
|
2141
|
-
throw check(), error instanceof InboxOperationError ? error : unavailable2();
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2144
|
-
var inbox = {
|
|
2145
|
-
current: async () => await send2("current", {}),
|
|
2146
|
-
items: {
|
|
2147
|
-
async list() {
|
|
2148
|
-
let items = [], beforeNumber, initial;
|
|
2149
|
-
try {
|
|
2150
|
-
initial = await resolveAppContext();
|
|
2151
|
-
} catch {
|
|
2152
|
-
throw stale();
|
|
2129
|
+
if (check(), (response2.status === 401 || response2.status === 403) && (installed2 = void 0, revision++, settled = Math.max(settled, started)), !response2.ok || response2.status !== 200) throw new InboxContextError(response2.status);
|
|
2130
|
+
let bytes = await limitedBody(response2, 4096);
|
|
2131
|
+
if (check(), !bytes) throw new Error("Inbox context unavailable");
|
|
2132
|
+
let context2 = parseInboxHostContext(JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes)));
|
|
2133
|
+
if (context2.memberId !== host.memberId) throw new Error("Inbox context unavailable");
|
|
2134
|
+
if (JSON.stringify(installed2) !== JSON.stringify(context2)) {
|
|
2135
|
+
if (started < settled) throw new Error("Inbox context unavailable");
|
|
2136
|
+
installed2 = context2, revision++;
|
|
2153
2137
|
}
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
};
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
beforeNumber = page.nextBeforeNumber;
|
|
2163
|
-
} while (!0);
|
|
2164
|
-
},
|
|
2165
|
-
read: async (itemId) => await send2("items.read", { itemId }),
|
|
2166
|
-
see: async (itemId) => {
|
|
2167
|
-
await send2("items.see", { itemId });
|
|
2168
|
-
},
|
|
2169
|
-
markDigestRead: async (itemId) => await send2("items.markDigestRead", { itemId }),
|
|
2170
|
-
rename: async (input) => await send2("items.rename", input),
|
|
2171
|
-
setLifecycle: async (input) => await send2("items.setLifecycle", input),
|
|
2172
|
-
listRecipientCandidates: async (itemId) => await send2("items.listRecipientCandidates", { itemId }),
|
|
2173
|
-
addRecipient: async (input) => await send2("items.addRecipient", input)
|
|
2174
|
-
},
|
|
2175
|
-
questions: {
|
|
2176
|
-
answer: async (input) => await send2("questions.answer", input),
|
|
2177
|
-
searchRecords: async (input) => await send2("questions.searchRecords", input)
|
|
2178
|
-
},
|
|
2179
|
-
files: { read: async (input) => await send2("files.read", input) }
|
|
2180
|
-
};
|
|
2181
|
-
|
|
2182
|
-
var sources = /* @__PURE__ */ new WeakMap();
|
|
2183
|
-
function registerBrowserAuth(handle2, source) {
|
|
2184
|
-
sources.set(handle2, source);
|
|
2185
|
-
}
|
|
2186
|
-
function browserAuthSource(handle2) {
|
|
2187
|
-
return sources.get(handle2);
|
|
2138
|
+
settled = Math.max(settled, started);
|
|
2139
|
+
let current2 = revision;
|
|
2140
|
+
return Object.freeze({ context: context2, isCurrent: () => host.isCurrent() && host.expiresAt > Date.now() && current2 === revision });
|
|
2141
|
+
} finally {
|
|
2142
|
+
response2.body?.cancel().catch(() => {
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
};
|
|
2188
2146
|
}
|
|
2189
2147
|
|
|
2190
2148
|
var sessionKey = "_os.app.session", responseChecks = /* @__PURE__ */ new WeakMap(), AppResponseReadError = class extends Error {
|
|
2191
2149
|
}, AppContextDenied = class extends Error {
|
|
2192
2150
|
}, AppRenewalUnavailable = class extends Error {
|
|
2193
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
|
+
}
|
|
2194
2165
|
async function appResponse(response2, maximum, signal) {
|
|
2195
2166
|
if (signal.aborted || !response2.body || response2.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() !== "application/json") throw new Error();
|
|
2196
2167
|
let reader = response2.body.getReader(), abort = () => {
|
|
@@ -2230,159 +2201,164 @@ function isAppOrigin(value) {
|
|
|
2230
2201
|
}
|
|
2231
2202
|
}
|
|
2232
2203
|
function appContext(origin, active2) {
|
|
2233
|
-
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 = () => {
|
|
2234
2205
|
try {
|
|
2235
|
-
return !denied && !disposed && active2() && globalThis.location.origin === origin
|
|
2206
|
+
return !denied && !disposed && active2() && globalThis.location.origin === origin;
|
|
2236
2207
|
} catch {
|
|
2237
2208
|
return !1;
|
|
2238
2209
|
}
|
|
2239
2210
|
}, cancel = () => {
|
|
2240
|
-
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);
|
|
2241
2213
|
}, invalidate = () => {
|
|
2242
2214
|
denied = !0, cancel();
|
|
2243
2215
|
try {
|
|
2244
|
-
!disposed && active2() && globalThis.location.origin === origin && (!
|
|
2216
|
+
!disposed && active2() && globalThis.location.origin === origin && (!serialized || globalThis.localStorage.getItem(sessionKey) === serialized) && globalThis.localStorage.removeItem(sessionKey);
|
|
2245
2217
|
} catch {
|
|
2246
2218
|
}
|
|
2247
2219
|
}, current2 = () => {
|
|
2248
2220
|
try {
|
|
2249
|
-
return alive() && stored() ===
|
|
2221
|
+
return alive() && !!binding && binding.expiresAt > Date.now() && stored() === serialized;
|
|
2250
2222
|
} catch {
|
|
2251
2223
|
return !1;
|
|
2252
2224
|
}
|
|
2253
|
-
}, sameSession = (value) => !binding ||
|
|
2254
|
-
|
|
2255
|
-
if (!
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
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
|
+
}
|
|
2264
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);
|
|
2265
2256
|
if (response2.status === 401 || response2.status === 403) throw new AppContextDenied();
|
|
2257
|
+
if (response2.status >= 500) throw new AppRenewalUnavailable();
|
|
2266
2258
|
if (!response2.ok) throw new Error();
|
|
2267
2259
|
let value = await appResponse(response2, 4096, signal);
|
|
2268
2260
|
if (!alive() || !bounded(value)) throw new Error();
|
|
2269
2261
|
return value;
|
|
2270
2262
|
}
|
|
2271
|
-
function install(value, candidate) {
|
|
2272
|
-
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);
|
|
2273
2265
|
let remaining = binding.expiresAt - Date.now();
|
|
2274
|
-
expiry = setTimeout(
|
|
2275
|
-
renew()
|
|
2266
|
+
expiry = setTimeout(expireAccess, remaining), renewalTimer = setTimeout(() => {
|
|
2267
|
+
renew().catch(() => {
|
|
2268
|
+
});
|
|
2276
2269
|
}, remaining - Math.min(6e4, remaining / 5));
|
|
2277
2270
|
}
|
|
2278
|
-
async function synchronize() {
|
|
2271
|
+
async function synchronize(signal = controller.signal) {
|
|
2279
2272
|
if (!alive()) throw new Error();
|
|
2280
|
-
if (
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
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;
|
|
2298
2292
|
}
|
|
2299
|
-
throw new Error();
|
|
2300
|
-
})();
|
|
2301
|
-
try {
|
|
2302
|
-
await observation;
|
|
2303
|
-
} catch {
|
|
2304
|
-
throw invalidate(), new Error("Local app context unavailable.");
|
|
2305
|
-
} finally {
|
|
2306
|
-
observation = void 0;
|
|
2307
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);
|
|
2308
2303
|
}
|
|
2309
2304
|
}
|
|
2310
2305
|
async function renew() {
|
|
2311
|
-
if (
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
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 });
|
|
2328
2326
|
});
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
});
|
|
2346
|
-
if (requestController.signal.aborted) throw new Error();
|
|
2347
|
-
await synchronize();
|
|
2348
|
-
return;
|
|
2349
|
-
}
|
|
2350
|
-
if (!response2.ok) throw new Error();
|
|
2351
|
-
if (!alive() || Date.now() >= deadline || !value || typeof value != "object" || Array.isArray(value) || Object.keys(value).sort().join(",") !== "context,credential") throw new Error();
|
|
2352
|
-
let result2 = value;
|
|
2353
|
-
if (!bounded(result2.context) || typeof result2.credential != "string" || !/^[A-Za-z0-9_-]{43}$/.test(result2.credential) || result2.credential === previous) throw new Error();
|
|
2354
|
-
if (stored() !== previous) {
|
|
2355
|
-
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);
|
|
2356
2343
|
return;
|
|
2357
2344
|
}
|
|
2358
|
-
|
|
2359
|
-
} catch (error) {
|
|
2360
|
-
try {
|
|
2361
|
-
if (alive() && stored() && stored() !== previous) {
|
|
2362
|
-
await synchronize();
|
|
2363
|
-
return;
|
|
2364
|
-
}
|
|
2365
|
-
} catch {
|
|
2366
|
-
}
|
|
2367
|
-
try {
|
|
2368
|
-
if (alive() && stored() && stored() !== previous) {
|
|
2369
|
-
await synchronize();
|
|
2370
|
-
return;
|
|
2371
|
-
}
|
|
2372
|
-
} catch {
|
|
2373
|
-
}
|
|
2374
|
-
(error instanceof AppRenewalUnavailable || error instanceof AppResponseReadError || requestController.signal.aborted) && current2() && Date.now() < deadline ? renewalTimer = setTimeout(() => {
|
|
2375
|
-
renew();
|
|
2376
|
-
}, Math.min(5e3, (deadline - Date.now()) / 5)) : invalidate();
|
|
2377
|
-
} finally {
|
|
2378
|
-
clearTimeout(timeout), controller.signal.removeEventListener("abort", abort);
|
|
2345
|
+
} catch {
|
|
2379
2346
|
}
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
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();
|
|
2383
2354
|
} finally {
|
|
2384
|
-
|
|
2355
|
+
clearTimeout(timeout), controller.signal.removeEventListener("abort", abort);
|
|
2385
2356
|
}
|
|
2357
|
+
})();
|
|
2358
|
+
try {
|
|
2359
|
+
await renewal;
|
|
2360
|
+
} finally {
|
|
2361
|
+
renewal = void 0;
|
|
2386
2362
|
}
|
|
2387
2363
|
}
|
|
2388
2364
|
let storageChanged = () => {
|
|
@@ -2391,101 +2367,102 @@ function appContext(origin, active2) {
|
|
|
2391
2367
|
invalidate();
|
|
2392
2368
|
return;
|
|
2393
2369
|
}
|
|
2394
|
-
synchronize().catch(
|
|
2370
|
+
expireAccess(), synchronize().catch(() => {
|
|
2371
|
+
});
|
|
2395
2372
|
}
|
|
2396
2373
|
}, monitor = setInterval(() => {
|
|
2397
2374
|
storageChanged();
|
|
2398
2375
|
}, 100);
|
|
2399
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);
|
|
2400
2382
|
let dispose = () => {
|
|
2401
2383
|
disposed = !0, cancel();
|
|
2402
2384
|
};
|
|
2385
|
+
async function settledAccess(signal) {
|
|
2386
|
+
for (await synchronize(); alive() && stored() !== serialized; ) await synchronize();
|
|
2387
|
+
if (signal.aborted || !current2()) throw new Error();
|
|
2388
|
+
}
|
|
2403
2389
|
async function requestData(operation2, input) {
|
|
2404
2390
|
try {
|
|
2405
2391
|
if (operation2 !== "data/query" || !current2()) throw new Error();
|
|
2406
|
-
let
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
referrerPolicy: "no-referrer",
|
|
2412
|
-
signal: controller.signal,
|
|
2413
|
-
headers: { "content-type": "application/json", authorization: `Bearer ${credential}` },
|
|
2414
|
-
body: JSON.stringify(input)
|
|
2415
|
-
});
|
|
2416
|
-
for (await synchronize(); alive() && stored() !== credential; ) await synchronize();
|
|
2417
|
-
if (!current2() || response2.redirected || response2.url && response2.url !== url) throw new Error();
|
|
2418
|
-
if (response2.status === 401 || response2.status === 403)
|
|
2419
|
-
throw admitted === credential && invalidate(), new DataOperationError("access_denied");
|
|
2420
|
-
let result2 = await appResponse(response2, Number.MAX_SAFE_INTEGER, controller.signal);
|
|
2421
|
-
for (await synchronize(); alive() && stored() !== credential; ) await synchronize();
|
|
2422
|
-
if (!current2()) throw new Error();
|
|
2423
|
-
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);
|
|
2424
2397
|
return result2;
|
|
2425
2398
|
} catch (error) {
|
|
2426
2399
|
throw error instanceof DataOperationError ? error : !current2() || controller.signal.aborted ? new DataOperationError("context_unavailable") : new DataOperationError("unavailable", !0);
|
|
2427
2400
|
}
|
|
2428
2401
|
}
|
|
2402
|
+
async function requestInbox(operation2, input) {
|
|
2403
|
+
if (!["questions.list", "questions.answer", "questions.searchRecords"].includes(operation2)) throw new Error("Inbox operation unavailable");
|
|
2404
|
+
return requestChecked("inbox", { method: "POST", body: JSON.stringify({ operation: operation2, input }) }, !0);
|
|
2405
|
+
}
|
|
2429
2406
|
async function requestRoutine(key, suffix, init2 = {}) {
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
referrerPolicy: "no-referrer",
|
|
2438
|
-
signal: controller.signal,
|
|
2439
|
-
headers: { ...init2.body === void 0 ? {} : { "content-type": "application/json" }, authorization: `Bearer ${credential}` }
|
|
2440
|
-
});
|
|
2441
|
-
for (await synchronize(); alive() && stored() !== credential; ) await synchronize();
|
|
2442
|
-
if (!current2() || response2.redirected || response2.url && response2.url !== url)
|
|
2443
|
-
throw invalidate(), new Error("Local app context unavailable.");
|
|
2444
|
-
return (response2.status === 401 || response2.status === 403) && admitted === credential && invalidate(), responseChecks.set(response2, async (value) => {
|
|
2445
|
-
for (await synchronize(); alive() && stored() !== credential; ) await synchronize();
|
|
2446
|
-
admitted === credential && value && typeof value == "object" && "error" in value && value.error === "authority_unavailable" && invalidate();
|
|
2407
|
+
return requestChecked(`routines/${encodeURIComponent(key)}/${suffix}`, init2);
|
|
2408
|
+
}
|
|
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();
|
|
2447
2414
|
}), response2;
|
|
2448
2415
|
}
|
|
2449
2416
|
function context2() {
|
|
2450
|
-
let issued = credential;
|
|
2417
|
+
let issued = credential, signal = access.signal;
|
|
2451
2418
|
return {
|
|
2452
2419
|
kind: "local",
|
|
2453
2420
|
...binding,
|
|
2454
2421
|
get expiresAt() {
|
|
2455
2422
|
return binding.expiresAt;
|
|
2456
2423
|
},
|
|
2457
|
-
isCurrent: current2,
|
|
2458
|
-
signal
|
|
2424
|
+
isCurrent: () => !signal.aborted && current2(),
|
|
2425
|
+
signal,
|
|
2459
2426
|
invalidate: () => {
|
|
2460
|
-
issued === credential && invalidate();
|
|
2427
|
+
issued === credential && current2() && invalidate();
|
|
2461
2428
|
},
|
|
2462
2429
|
requestRoutine,
|
|
2463
2430
|
requestData,
|
|
2431
|
+
requestInbox,
|
|
2464
2432
|
requestAvailability: (key) => requestRoutine(key, "availability", { method: "GET" })
|
|
2465
2433
|
};
|
|
2466
2434
|
}
|
|
2467
2435
|
let resolveOnce = async () => {
|
|
2468
2436
|
let attempted;
|
|
2469
2437
|
try {
|
|
2470
|
-
if (
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
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();
|
|
2478
2453
|
if (!current2()) throw new Error();
|
|
2479
|
-
if (binding && value.expiresAt > binding.expiresAt) throw new Error();
|
|
2480
|
-
return (!
|
|
2454
|
+
if (expiry && binding && value.expiresAt > binding.expiresAt) throw new Error();
|
|
2455
|
+
return (!expiry || value.expiresAt !== binding.expiresAt) && install(value, retained, candidate), context2();
|
|
2481
2456
|
} catch (error) {
|
|
2457
|
+
if (alive() && error instanceof AppRenewalUnavailable)
|
|
2458
|
+
throw new Error();
|
|
2482
2459
|
try {
|
|
2483
|
-
if (binding && current2() && attempted && attempted !==
|
|
2484
|
-
if (binding && alive() && stored() && stored() !==
|
|
2460
|
+
if (binding && current2() && attempted && attempted !== serialized) return context2();
|
|
2461
|
+
if (binding && alive() && stored() && stored() !== serialized)
|
|
2485
2462
|
return await synchronize(), context2();
|
|
2486
2463
|
} catch {
|
|
2487
2464
|
}
|
|
2488
|
-
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());
|
|
2489
2466
|
}
|
|
2490
2467
|
}, resolve = () => resolution2 || (resolution2 = resolveOnce().finally(() => {
|
|
2491
2468
|
resolution2 = void 0;
|
|
@@ -2497,10 +2474,205 @@ function appContext(origin, active2) {
|
|
|
2497
2474
|
}, 0);
|
|
2498
2475
|
}, invalidate, dispose };
|
|
2499
2476
|
}
|
|
2477
|
+
function validProof(value) {
|
|
2478
|
+
return typeof value == "string" && /^[A-Za-z0-9_-]{43}$/.test(value);
|
|
2479
|
+
}
|
|
2500
2480
|
function validBinding(value) {
|
|
2501
2481
|
if (!value || typeof value != "object" || Array.isArray(value) || Object.keys(value).sort().join(",") !== "appId,expiresAt,memberId,sessionId,workspace") return !1;
|
|
2502
2482
|
let binding = value;
|
|
2503
|
-
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);
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
var unavailable2 = () => new InboxOperationError(503, "unavailable"), stale = () => new InboxOperationError(401, "authority_unavailable");
|
|
2492
|
+
function hostFailure(error, context2) {
|
|
2493
|
+
return !context2.isCurrent() || context2.expiresAt <= Date.now() || error instanceof InboxContextError && error.status === 401 ? stale() : error instanceof InboxContextError && error.status === 403 ? new InboxOperationError(403, "access_denied") : unavailable2();
|
|
2494
|
+
}
|
|
2495
|
+
async function send2(operation2, input) {
|
|
2496
|
+
let envelope = parseInboxRequest({ operation: operation2, input }), context2;
|
|
2497
|
+
try {
|
|
2498
|
+
context2 = await resolveAppContext();
|
|
2499
|
+
} catch {
|
|
2500
|
+
throw stale();
|
|
2501
|
+
}
|
|
2502
|
+
if (context2.kind === "local") {
|
|
2503
|
+
if (!isAppQuestionOperation(operation2)) throw new InboxOperationError(403, "access_denied");
|
|
2504
|
+
let check2 = () => {
|
|
2505
|
+
if (!context2.isCurrent() || context2.signal.aborted || context2.expiresAt <= Date.now()) throw stale();
|
|
2506
|
+
};
|
|
2507
|
+
try {
|
|
2508
|
+
let response2 = await context2.requestInbox(operation2, envelope.input), value = await appResponse(response2, INBOX_RESULT_BYTES, context2.signal);
|
|
2509
|
+
if (check2(), !response2.ok) throw new InboxOperationError(
|
|
2510
|
+
[400, 401, 403, 409].includes(response2.status) ? response2.status : 503,
|
|
2511
|
+
response2.status === 400 ? "invalid_input" : response2.status === 401 ? "authority_unavailable" : response2.status === 403 ? "access_denied" : response2.status === 409 ? "conflict" : "unavailable"
|
|
2512
|
+
);
|
|
2513
|
+
if (response2.status !== 200) throw unavailable2();
|
|
2514
|
+
let parsed = parseInboxResult(operation2, value);
|
|
2515
|
+
if (check2(), operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw unavailable2();
|
|
2516
|
+
return parsed;
|
|
2517
|
+
} catch (error) {
|
|
2518
|
+
throw check2(), error instanceof InboxOperationError ? error : unavailable2();
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
if (context2.endpoint !== `https://${context2.workspace}.oddington.ai` || ["auth", "www", "api", "os"].includes(context2.workspace)) throw stale();
|
|
2522
|
+
let host;
|
|
2523
|
+
try {
|
|
2524
|
+
host = await resolveHostedInboxContext(context2);
|
|
2525
|
+
} catch (error) {
|
|
2526
|
+
throw hostFailure(error, context2);
|
|
2527
|
+
}
|
|
2528
|
+
if (!host) throw unavailable2();
|
|
2529
|
+
let check = () => {
|
|
2530
|
+
if (!context2.isCurrent() || !host.isCurrent() || !Number.isFinite(context2.expiresAt) || context2.expiresAt <= Date.now()) throw stale();
|
|
2531
|
+
};
|
|
2532
|
+
if (check(), host.context.kind === "focused" && !isAppQuestionOperation(operation2))
|
|
2533
|
+
throw new InboxOperationError(403, "access_denied");
|
|
2534
|
+
try {
|
|
2535
|
+
let response2 = await fetch(`${context2.endpoint}/api/inbox`, {
|
|
2536
|
+
method: "POST",
|
|
2537
|
+
headers: { authorization: `Bearer ${context2.accessToken}`, "content-type": "application/json" },
|
|
2538
|
+
body: JSON.stringify(envelope),
|
|
2539
|
+
redirect: "error",
|
|
2540
|
+
cache: "no-store",
|
|
2541
|
+
signal: AbortSignal.timeout(3e4)
|
|
2542
|
+
});
|
|
2543
|
+
try {
|
|
2544
|
+
check();
|
|
2545
|
+
} catch (error) {
|
|
2546
|
+
throw response2.body?.cancel().catch(() => {
|
|
2547
|
+
}), error;
|
|
2548
|
+
}
|
|
2549
|
+
if (!response2.ok)
|
|
2550
|
+
throw response2.body?.cancel().catch(() => {
|
|
2551
|
+
}), new InboxOperationError(
|
|
2552
|
+
[400, 401, 403, 409].includes(response2.status) ? response2.status : 503,
|
|
2553
|
+
response2.status === 400 ? "invalid_input" : response2.status === 401 ? "authority_unavailable" : response2.status === 403 ? "access_denied" : response2.status === 409 ? "conflict" : "unavailable"
|
|
2554
|
+
);
|
|
2555
|
+
if (response2.status !== 200)
|
|
2556
|
+
throw response2.body?.cancel().catch(() => {
|
|
2557
|
+
}), unavailable2();
|
|
2558
|
+
if (operation2 === "files.read") {
|
|
2559
|
+
if (!response2.body) throw unavailable2();
|
|
2560
|
+
let source = response2.body, reader, size = 0, cancel = async (reason) => {
|
|
2561
|
+
try {
|
|
2562
|
+
await (reader ? reader.cancel(reason) : source.cancel(reason));
|
|
2563
|
+
} finally {
|
|
2564
|
+
reader?.releaseLock();
|
|
2565
|
+
}
|
|
2566
|
+
}, body2 = new ReadableStream({
|
|
2567
|
+
async pull(controller) {
|
|
2568
|
+
try {
|
|
2569
|
+
check(), reader ??= source.getReader();
|
|
2570
|
+
let next = await reader.read();
|
|
2571
|
+
if (check(), next.done) {
|
|
2572
|
+
reader.releaseLock(), controller.close();
|
|
2573
|
+
return;
|
|
2574
|
+
}
|
|
2575
|
+
if (size += next.value.byteLength, size > 25 * 1024 * 1024) throw unavailable2();
|
|
2576
|
+
controller.enqueue(next.value);
|
|
2577
|
+
} catch (error) {
|
|
2578
|
+
controller.error(error), await cancel(error).catch(() => {
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2581
|
+
},
|
|
2582
|
+
cancel
|
|
2583
|
+
}, { highWaterMark: 0 });
|
|
2584
|
+
return new Response(body2, { status: response2.status, headers: response2.headers });
|
|
2585
|
+
}
|
|
2586
|
+
let bytes = await limitedBody(response2, INBOX_RESULT_BYTES);
|
|
2587
|
+
if (check(), !bytes) throw unavailable2();
|
|
2588
|
+
let value = JSON.parse(new TextDecoder("utf-8", { fatal: !0 }).decode(bytes)), parsed = parseInboxResult(operation2, value);
|
|
2589
|
+
if (check(), operation2 === "current" && parsed.workspace.slug !== context2.workspace) throw unavailable2();
|
|
2590
|
+
if ("itemId" in envelope.input) {
|
|
2591
|
+
let item = operation2 === "items.read" ? parsed : operation2 === "items.rename" || operation2 === "items.setLifecycle" || operation2 === "items.addRecipient" ? parsed.item : void 0;
|
|
2592
|
+
if (item && (item.id !== envelope.input.itemId || "revision" in envelope.input && item.revision !== envelope.input.revision) || operation2 === "items.addRecipient" && parsed.addedPersonId !== envelope.input.personId || operation2 === "questions.answer" && typeof envelope.input.response.selection == "object" && !parsed.label?.trim()) throw unavailable2();
|
|
2593
|
+
}
|
|
2594
|
+
return parsed;
|
|
2595
|
+
} catch (error) {
|
|
2596
|
+
throw check(), error instanceof InboxOperationError ? error : unavailable2();
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
var inbox = {
|
|
2600
|
+
current: async () => await send2("current", {}),
|
|
2601
|
+
items: {
|
|
2602
|
+
async list() {
|
|
2603
|
+
let items = [], beforeNumber, initial;
|
|
2604
|
+
try {
|
|
2605
|
+
initial = await resolveAppContext();
|
|
2606
|
+
} catch {
|
|
2607
|
+
throw stale();
|
|
2608
|
+
}
|
|
2609
|
+
let host;
|
|
2610
|
+
try {
|
|
2611
|
+
host = initial.kind !== "local" && await resolveHostedInboxContext(initial);
|
|
2612
|
+
} catch (error) {
|
|
2613
|
+
throw hostFailure(error, initial);
|
|
2614
|
+
}
|
|
2615
|
+
if (initial.kind === "local") throw new InboxOperationError(403, "access_denied");
|
|
2616
|
+
if (!host) throw unavailable2();
|
|
2617
|
+
let check = () => {
|
|
2618
|
+
if (!initial.isCurrent() || !host.isCurrent() || initial.expiresAt <= Date.now()) throw stale();
|
|
2619
|
+
};
|
|
2620
|
+
do {
|
|
2621
|
+
check();
|
|
2622
|
+
let page = await send2("items.list", beforeNumber === void 0 ? {} : { beforeNumber });
|
|
2623
|
+
if (check(), beforeNumber !== void 0 && (page.items.some((item) => item.number >= beforeNumber) || page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber)) throw unavailable2();
|
|
2624
|
+
if (items.push(...page.items), page.nextBeforeNumber === null) return items;
|
|
2625
|
+
beforeNumber = page.nextBeforeNumber;
|
|
2626
|
+
} while (!0);
|
|
2627
|
+
},
|
|
2628
|
+
read: async (itemId) => await send2("items.read", { itemId }),
|
|
2629
|
+
see: async (itemId) => {
|
|
2630
|
+
await send2("items.see", { itemId });
|
|
2631
|
+
},
|
|
2632
|
+
markDigestRead: async (itemId) => await send2("items.markDigestRead", { itemId }),
|
|
2633
|
+
rename: async (input) => await send2("items.rename", input),
|
|
2634
|
+
setLifecycle: async (input) => await send2("items.setLifecycle", input),
|
|
2635
|
+
listRecipientCandidates: async (itemId) => await send2("items.listRecipientCandidates", { itemId }),
|
|
2636
|
+
addRecipient: async (input) => await send2("items.addRecipient", input)
|
|
2637
|
+
},
|
|
2638
|
+
questions: {
|
|
2639
|
+
async list() {
|
|
2640
|
+
let questions = [], beforeNumber, initial;
|
|
2641
|
+
try {
|
|
2642
|
+
initial = await resolveAppContext();
|
|
2643
|
+
} catch {
|
|
2644
|
+
throw stale();
|
|
2645
|
+
}
|
|
2646
|
+
let host;
|
|
2647
|
+
try {
|
|
2648
|
+
host = initial.kind !== "local" && await resolveHostedInboxContext(initial);
|
|
2649
|
+
} catch (error) {
|
|
2650
|
+
throw hostFailure(error, initial);
|
|
2651
|
+
}
|
|
2652
|
+
if (initial.kind !== "local" && !host) throw unavailable2();
|
|
2653
|
+
let check = () => {
|
|
2654
|
+
if (!initial.isCurrent() || host && !host.isCurrent() || initial.expiresAt <= Date.now()) throw stale();
|
|
2655
|
+
};
|
|
2656
|
+
do {
|
|
2657
|
+
check();
|
|
2658
|
+
let page = await send2("questions.list", beforeNumber === void 0 ? {} : { beforeNumber });
|
|
2659
|
+
if (check(), page.questions.some((question2) => question2.item.href !== `https://${initial.workspace}.oddington.ai/inbox/${question2.item.id}`) || beforeNumber !== void 0 && (page.questions.some((question2) => question2.item.number >= beforeNumber) || page.nextBeforeNumber !== null && page.nextBeforeNumber >= beforeNumber)) throw unavailable2();
|
|
2660
|
+
if (questions.push(...page.questions), page.nextBeforeNumber === null) return questions;
|
|
2661
|
+
beforeNumber = page.nextBeforeNumber;
|
|
2662
|
+
} while (!0);
|
|
2663
|
+
},
|
|
2664
|
+
answer: async (input) => await send2("questions.answer", input),
|
|
2665
|
+
searchRecords: async (input) => await send2("questions.searchRecords", input)
|
|
2666
|
+
},
|
|
2667
|
+
files: { read: async (input) => await send2("files.read", input) }
|
|
2668
|
+
};
|
|
2669
|
+
|
|
2670
|
+
var sources = /* @__PURE__ */ new WeakMap();
|
|
2671
|
+
function registerBrowserAuth(handle2, source) {
|
|
2672
|
+
sources.set(handle2, source);
|
|
2673
|
+
}
|
|
2674
|
+
function browserAuthSource(handle2) {
|
|
2675
|
+
return sources.get(handle2);
|
|
2504
2676
|
}
|
|
2505
2677
|
|
|
2506
2678
|
var installedDispose;
|
|
@@ -2521,7 +2693,7 @@ function init({ auth: input }) {
|
|
|
2521
2693
|
url.protocol === "https:" && !url.port && !url.username && !url.password && !url.search && !url.hash && url.pathname === "/" && /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(slug) && slug !== "auth" && (endpoint = url.origin, workspace = slug);
|
|
2522
2694
|
} catch {
|
|
2523
2695
|
}
|
|
2524
|
-
let active2 = !0, revision = 0, person, token, local = localOrigin ? appContext(localOrigin, () => active2) : void 0, subscription, stopDisposal, uninstall = installMemberContext(async () => {
|
|
2696
|
+
let active2 = !0, revision = 0, person, token, binding = {}, local = localOrigin ? appContext(localOrigin, () => active2) : void 0, subscription, stopDisposal, uninstall = installMemberContext(async () => {
|
|
2525
2697
|
if (local) return local.resolve();
|
|
2526
2698
|
if (!active2 || !endpoint || !workspace || globalThis.location.origin !== endpoint) throw new Error("Hosted Data context unavailable.");
|
|
2527
2699
|
let started = revision, { data: { session }, error } = await auth2.getSession();
|
|
@@ -2530,12 +2702,16 @@ function init({ auth: input }) {
|
|
|
2530
2702
|
let expiresAt = (session.expires_at ?? 0) * 1e3;
|
|
2531
2703
|
if (!Number.isFinite(expiresAt) || expiresAt <= Date.now() || !session.user.id)
|
|
2532
2704
|
throw new Error("Hosted Data context unavailable.");
|
|
2533
|
-
|
|
2705
|
+
person = session.user.id;
|
|
2706
|
+
let isCurrent = () => active2 && globalThis.location.origin === endpoint && revision === started && person === session.user.id;
|
|
2707
|
+
return {
|
|
2534
2708
|
workspace,
|
|
2535
2709
|
endpoint,
|
|
2536
2710
|
accessToken: session.access_token,
|
|
2537
2711
|
expiresAt,
|
|
2538
|
-
isCurrent
|
|
2712
|
+
isCurrent,
|
|
2713
|
+
memberId: session.user.id,
|
|
2714
|
+
binding
|
|
2539
2715
|
};
|
|
2540
2716
|
}), dispose = () => {
|
|
2541
2717
|
active2 && (active2 = !1, local?.dispose(), revision++, subscription?.unsubscribe(), stopDisposal?.(), uninstall(), installedDispose === dispose && (installedDispose = void 0));
|