jxp 4.0.0 → 4.1.1
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/.env.sample +12 -0
- package/dist/libs/bulkwrite_guard.d.ts +1 -0
- package/dist/libs/bulkwrite_guard.d.ts.map +1 -1
- package/dist/libs/bulkwrite_guard.js +43 -0
- package/dist/libs/bulkwrite_guard.js.map +1 -1
- package/dist/libs/docs-auth.d.ts +25 -0
- package/dist/libs/docs-auth.d.ts.map +1 -0
- package/dist/libs/docs-auth.js +205 -0
- package/dist/libs/docs-auth.js.map +1 -0
- package/dist/libs/docs.js +26 -5
- package/dist/libs/docs.js.map +1 -1
- package/dist/libs/jxp.d.ts.map +1 -1
- package/dist/libs/jxp.js +118 -53
- package/dist/libs/jxp.js.map +1 -1
- package/dist/libs/load-config.d.ts.map +1 -1
- package/dist/libs/load-config.js +11 -0
- package/dist/libs/load-config.js.map +1 -1
- package/dist/libs/login_rate_limit.d.ts +16 -0
- package/dist/libs/login_rate_limit.d.ts.map +1 -0
- package/dist/libs/login_rate_limit.js +49 -0
- package/dist/libs/login_rate_limit.js.map +1 -0
- package/dist/libs/query_limits.js +9 -3
- package/dist/libs/query_limits.js.map +1 -1
- package/dist/libs/request_log.d.ts +44 -0
- package/dist/libs/request_log.d.ts.map +1 -0
- package/dist/libs/request_log.js +229 -0
- package/dist/libs/request_log.js.map +1 -0
- package/dist/libs/security.js +18 -9
- package/dist/libs/security.js.map +1 -1
- package/dist/models/test_model.js +1 -1
- package/dist/models/test_model.js.map +1 -1
- package/dist/types/jxp-config.d.ts +17 -0
- package/dist/types/jxp-config.d.ts.map +1 -1
- package/docs/bulk_writes.md +9 -2
- package/docs/changelog.md +76 -1
- package/docs/configuration.md +30 -0
- package/package.json +2 -2
- package/templates/assets/api-console.js +19 -1
- package/templates/assets/docs-login.js +66 -0
- package/templates/assets/docs.css +17 -0
- package/templates/index.pug +9 -4
- package/templates/layout.pug +8 -4
- package/templates/login.pug +39 -0
- package/templates/navbar.pug +18 -7
|
@@ -116,8 +116,26 @@
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
async function loadSessionApiKey() {
|
|
120
|
+
const access = document.documentElement.dataset.docsAccess;
|
|
121
|
+
if (access !== "protected") return;
|
|
122
|
+
try {
|
|
123
|
+
const res = await fetch("/docs/session", { credentials: "same-origin" });
|
|
124
|
+
if (!res.ok) return;
|
|
125
|
+
const data = await res.json();
|
|
126
|
+
if (!data.apikey) return;
|
|
127
|
+
const input = document.getElementById("docs-api-key");
|
|
128
|
+
if (input) input.value = data.apikey;
|
|
129
|
+
} catch {
|
|
130
|
+
/* ignore */
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
119
134
|
document.addEventListener("DOMContentLoaded", function () {
|
|
120
|
-
|
|
135
|
+
const access = document.documentElement.dataset.docsAccess;
|
|
136
|
+
loadSessionApiKey().then(function () {
|
|
137
|
+
if (access !== "protected") loadStoredKey();
|
|
138
|
+
});
|
|
121
139
|
|
|
122
140
|
const keyInput = document.getElementById("docs-api-key");
|
|
123
141
|
const remember = document.getElementById("docs-remember-key");
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
5
|
+
const form = document.getElementById("docs-login-form");
|
|
6
|
+
const errEl = document.getElementById("docs-login-error");
|
|
7
|
+
if (!form || !errEl) return;
|
|
8
|
+
|
|
9
|
+
form.addEventListener("submit", async function (e) {
|
|
10
|
+
e.preventDefault();
|
|
11
|
+
errEl.hidden = true;
|
|
12
|
+
const email = form.email.value.trim();
|
|
13
|
+
const password = form.password.value;
|
|
14
|
+
const next =
|
|
15
|
+
form.next && form.next.value && form.next.value.startsWith("/")
|
|
16
|
+
? form.next.value
|
|
17
|
+
: "/docs/api";
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const loginRes = await fetch("/login", {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: {
|
|
23
|
+
"Content-Type": "application/json",
|
|
24
|
+
Accept: "application/json",
|
|
25
|
+
},
|
|
26
|
+
body: JSON.stringify({ email, password }),
|
|
27
|
+
});
|
|
28
|
+
const loginBody = await loginRes.json().catch(function () {
|
|
29
|
+
return {};
|
|
30
|
+
});
|
|
31
|
+
if (loginRes.status === 429) {
|
|
32
|
+
errEl.textContent =
|
|
33
|
+
"Too many login attempts. Please wait a minute and try again.";
|
|
34
|
+
errEl.hidden = false;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (!loginRes.ok || !loginBody.apikey) {
|
|
38
|
+
errEl.textContent =
|
|
39
|
+
loginBody.message || "Incorrect email or password";
|
|
40
|
+
errEl.hidden = false;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const sessRes = await fetch("/docs/session", {
|
|
45
|
+
method: "POST",
|
|
46
|
+
headers: {
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
Accept: "application/json",
|
|
49
|
+
},
|
|
50
|
+
credentials: "same-origin",
|
|
51
|
+
body: JSON.stringify({ apikey: loginBody.apikey }),
|
|
52
|
+
});
|
|
53
|
+
if (!sessRes.ok) {
|
|
54
|
+
errEl.textContent = "Signed in but could not start docs session";
|
|
55
|
+
errEl.hidden = false;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
window.location.href = next;
|
|
60
|
+
} catch {
|
|
61
|
+
errEl.textContent = "Login request failed";
|
|
62
|
+
errEl.hidden = false;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
})();
|
|
@@ -225,3 +225,20 @@ body.docs-body {
|
|
|
225
225
|
.docs-security-note {
|
|
226
226
|
font-size: 0.8rem;
|
|
227
227
|
}
|
|
228
|
+
|
|
229
|
+
.docs-main-full {
|
|
230
|
+
max-width: 480px;
|
|
231
|
+
margin: 0 auto;
|
|
232
|
+
padding-top: 2rem;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.docs-login-wrap {
|
|
236
|
+
display: flex;
|
|
237
|
+
justify-content: center;
|
|
238
|
+
padding: 1rem 0 3rem;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.docs-login-card {
|
|
242
|
+
width: 100%;
|
|
243
|
+
max-width: 400px;
|
|
244
|
+
}
|
package/templates/index.pug
CHANGED
|
@@ -18,15 +18,20 @@ block content
|
|
|
18
18
|
.card.h-100
|
|
19
19
|
.card-header.fw-semibold Quick start
|
|
20
20
|
.card-body
|
|
21
|
-
p.mb-2 Authenticate with an API key header (optional for exploring docs; required for live calls):
|
|
21
|
+
p.mb-2 Authenticate with an API key header#{docs_access === 'public' ? ' (optional for exploring docs; required for live calls)' : ''}:
|
|
22
22
|
pre.mb-3
|
|
23
23
|
code.
|
|
24
24
|
curl -H "X-API-Key: YOUR_KEY" \
|
|
25
25
|
"#{base_url}/api/MODEL?limit=5"
|
|
26
26
|
p.mb-0.small.text-muted
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
if docs_access === 'protected'
|
|
28
|
+
| After signing in, your API key is filled in automatically for
|
|
29
|
+
strong Try it
|
|
30
|
+
| panels on API resource pages.
|
|
31
|
+
else
|
|
32
|
+
| Set your key in the top bar to use
|
|
33
|
+
strong Try it
|
|
34
|
+
| panels on API resource pages. Keys are stored in the browser only when “Remember” is checked.
|
|
30
35
|
.col-md-6
|
|
31
36
|
.card.h-100
|
|
32
37
|
.card-header.fw-semibold API at a glance
|
package/templates/layout.pug
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
doctype html
|
|
2
|
-
html(lang="en")
|
|
2
|
+
html(lang="en" data-docs-access=docs_access)
|
|
3
3
|
head
|
|
4
4
|
meta(charset="utf-8")
|
|
5
5
|
meta(name="viewport" content="width=device-width, initial-scale=1")
|
|
@@ -9,10 +9,14 @@ html(lang="en")
|
|
|
9
9
|
link(rel="stylesheet" href="/docs/assets/docs.css")
|
|
10
10
|
body.docs-body
|
|
11
11
|
include navbar
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
main.docs-main
|
|
12
|
+
if hide_sidebar
|
|
13
|
+
main.docs-main.docs-main-full
|
|
15
14
|
block content
|
|
15
|
+
else
|
|
16
|
+
.docs-shell
|
|
17
|
+
include sidebar
|
|
18
|
+
main.docs-main
|
|
19
|
+
block content
|
|
16
20
|
script(src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous")
|
|
17
21
|
script(src="/docs/assets/api-console.js" defer)
|
|
18
22
|
block javascripts
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
extends layout
|
|
2
|
+
|
|
3
|
+
block content
|
|
4
|
+
.docs-login-wrap
|
|
5
|
+
.card.docs-login-card.shadow-sm
|
|
6
|
+
.card-body.p-4
|
|
7
|
+
h1.h4.mb-1 Sign in to explore the API
|
|
8
|
+
p.text-muted.small.mb-4
|
|
9
|
+
| Use your normal API account (
|
|
10
|
+
code POST /login
|
|
11
|
+
| ). Guides and this site stay open; model pages and “Try it” need a session.
|
|
12
|
+
#docs-login-error.alert.alert-danger(role="alert" hidden)
|
|
13
|
+
form#docs-login-form
|
|
14
|
+
input(type="hidden" name="next" value=docs_next)
|
|
15
|
+
.mb-3
|
|
16
|
+
label.form-label(for="docs-login-email") Email
|
|
17
|
+
input#docs-login-email.form-control(
|
|
18
|
+
type="email"
|
|
19
|
+
name="email"
|
|
20
|
+
value=docs_user_email
|
|
21
|
+
required
|
|
22
|
+
autocomplete="username"
|
|
23
|
+
)
|
|
24
|
+
.mb-3
|
|
25
|
+
label.form-label(for="docs-login-password") Password
|
|
26
|
+
input#docs-login-password.form-control(
|
|
27
|
+
type="password"
|
|
28
|
+
name="password"
|
|
29
|
+
required
|
|
30
|
+
autocomplete="current-password"
|
|
31
|
+
)
|
|
32
|
+
button.btn.btn-primary.w-100(type="submit") Sign in
|
|
33
|
+
p.mt-3.mb-0.small.text-muted
|
|
34
|
+
a(href="/") Back to home
|
|
35
|
+
| ·
|
|
36
|
+
a(href="/docs/md/api.md") Read API docs without signing in
|
|
37
|
+
|
|
38
|
+
block javascripts
|
|
39
|
+
script(src="/docs/assets/docs-login.js" defer)
|
package/templates/navbar.pug
CHANGED
|
@@ -5,10 +5,21 @@ header.docs-topbar.navbar.navbar-expand-lg.sticky-top
|
|
|
5
5
|
a.docs-brand.navbar-brand.mb-0(href="/")= name
|
|
6
6
|
span.badge.bg-secondary.ms-2.align-self-center v#{version}
|
|
7
7
|
.ms-auto.d-flex.align-items-center.gap-2.flex-wrap
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
if docs_access === 'protected' && !docs_authenticated
|
|
9
|
+
a.btn.btn-sm.btn-outline-primary(href="/docs/login?next=/docs/api") Explore API
|
|
10
|
+
if docs_access !== 'disabled' && (docs_access !== 'protected' || docs_authenticated)
|
|
11
|
+
.docs-api-key-wrap
|
|
12
|
+
label.visually-hidden(for="docs-api-key") API Key
|
|
13
|
+
input#docs-api-key.form-control.form-control-sm(
|
|
14
|
+
type="password"
|
|
15
|
+
placeholder=docs_access === 'protected' ? "X-API-Key" : "X-API-Key (optional)"
|
|
16
|
+
autocomplete="off"
|
|
17
|
+
)
|
|
18
|
+
.form-check.form-check-inline.mb-0.docs-security-note
|
|
19
|
+
input#docs-remember-key.form-check-input(type="checkbox")
|
|
20
|
+
label.form-check-label(for="docs-remember-key") Remember
|
|
21
|
+
if docs_access === 'protected'
|
|
22
|
+
form.d-inline(method="post" action="/docs/logout")
|
|
23
|
+
button.btn.btn-sm.btn-link.text-muted(type="submit") Sign out
|
|
24
|
+
else
|
|
25
|
+
span.docs-security-note.text-muted.d-none.d-md-inline Dev only
|