jxp 3.0.0 → 4.1.0
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 +43 -6
- package/README.md +27 -13
- package/dist/bin/init_db.d.ts +3 -0
- package/dist/bin/init_db.d.ts.map +1 -0
- package/dist/bin/init_db.js +48 -0
- package/dist/bin/init_db.js.map +1 -0
- package/dist/bin/server.d.ts +4 -0
- package/dist/bin/server.d.ts.map +1 -0
- package/dist/bin/server.js +132 -0
- package/dist/bin/server.js.map +1 -0
- package/dist/bin/setup.d.ts +3 -0
- package/dist/bin/setup.d.ts.map +1 -0
- package/dist/bin/setup.js +185 -0
- package/dist/bin/setup.js.map +1 -0
- package/dist/globals.d.ts +14 -0
- package/dist/globals.d.ts.map +1 -0
- package/dist/globals.js +3 -0
- package/dist/globals.js.map +1 -0
- package/dist/libs/aggregate_guard.d.ts +5 -0
- package/dist/libs/aggregate_guard.d.ts.map +1 -0
- package/dist/libs/aggregate_guard.js +58 -0
- package/dist/libs/aggregate_guard.js.map +1 -0
- package/dist/libs/bulkwrite_guard.d.ts +5 -0
- package/dist/libs/bulkwrite_guard.d.ts.map +1 -0
- package/dist/libs/bulkwrite_guard.js +44 -0
- package/dist/libs/bulkwrite_guard.js.map +1 -0
- package/dist/libs/cache.d.ts +2 -0
- package/dist/libs/cache.d.ts.map +1 -0
- package/dist/libs/cache.js +94 -0
- package/dist/libs/cache.js.map +1 -0
- package/dist/libs/call_guard.d.ts +3 -0
- package/dist/libs/call_guard.d.ts.map +1 -0
- package/dist/libs/call_guard.js +17 -0
- package/dist/libs/call_guard.js.map +1 -0
- package/dist/libs/connection_string.d.ts +3 -0
- package/dist/libs/connection_string.d.ts.map +1 -0
- package/dist/libs/connection_string.js +4 -0
- package/dist/libs/connection_string.js.map +1 -0
- package/dist/libs/datamunging.d.ts +2 -0
- package/dist/libs/datamunging.d.ts.map +1 -0
- package/dist/libs/datamunging.js +320 -0
- package/dist/libs/datamunging.js.map +1 -0
- 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.d.ts +2 -0
- package/dist/libs/docs.d.ts.map +1 -0
- package/dist/libs/docs.js +328 -0
- package/dist/libs/docs.js.map +1 -0
- package/dist/libs/groups.d.ts +2 -0
- package/dist/libs/groups.d.ts.map +1 -0
- package/dist/libs/groups.js +136 -0
- package/dist/libs/groups.js.map +1 -0
- package/dist/libs/jxp.d.ts +4 -0
- package/dist/libs/jxp.d.ts.map +1 -0
- package/dist/libs/jxp.js +1176 -0
- package/dist/libs/jxp.js.map +1 -0
- package/dist/libs/link_index.d.ts +14 -0
- package/dist/libs/link_index.d.ts.map +1 -0
- package/dist/libs/link_index.js +37 -0
- package/dist/libs/link_index.js.map +1 -0
- package/dist/libs/load-config.d.ts +16 -0
- package/dist/libs/load-config.d.ts.map +1 -0
- package/dist/libs/load-config.js +166 -0
- package/dist/libs/load-config.js.map +1 -0
- package/dist/libs/login.d.ts +2 -0
- package/dist/libs/login.d.ts.map +1 -0
- package/dist/libs/login.js +244 -0
- package/dist/libs/login.js.map +1 -0
- 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/modeldir.d.ts +5 -0
- package/dist/libs/modeldir.d.ts.map +1 -0
- package/dist/libs/modeldir.js +15 -0
- package/dist/libs/modeldir.js.map +1 -0
- package/dist/libs/query_limits.d.ts +2 -0
- package/dist/libs/query_limits.d.ts.map +1 -0
- package/dist/libs/query_limits.js +84 -0
- package/dist/libs/query_limits.js.map +1 -0
- package/dist/libs/query_manipulation.d.ts +3 -0
- package/dist/libs/query_manipulation.d.ts.map +1 -0
- package/{libs → dist/libs}/query_manipulation.js +22 -21
- package/dist/libs/query_manipulation.js.map +1 -0
- package/dist/libs/query_sanitize.d.ts +5 -0
- package/dist/libs/query_sanitize.d.ts.map +1 -0
- package/dist/libs/query_sanitize.js +109 -0
- package/dist/libs/query_sanitize.js.map +1 -0
- package/dist/libs/response_sanitize.d.ts +7 -0
- package/dist/libs/response_sanitize.d.ts.map +1 -0
- package/dist/libs/response_sanitize.js +57 -0
- package/dist/libs/response_sanitize.js.map +1 -0
- package/dist/libs/safe_error.d.ts +3 -0
- package/dist/libs/safe_error.d.ts.map +1 -0
- package/dist/libs/safe_error.js +14 -0
- package/dist/libs/safe_error.js.map +1 -0
- package/dist/libs/schema.d.ts +14 -0
- package/dist/libs/schema.d.ts.map +1 -0
- package/dist/libs/schema.js +98 -0
- package/dist/libs/schema.js.map +1 -0
- package/dist/libs/schema_description.d.ts +3 -0
- package/dist/libs/schema_description.d.ts.map +1 -0
- package/{libs → dist/libs}/schema_description.js +12 -21
- package/dist/libs/schema_description.js.map +1 -0
- package/dist/libs/security.d.ts +2 -0
- package/dist/libs/security.d.ts.map +1 -0
- package/dist/libs/security.js +428 -0
- package/dist/libs/security.js.map +1 -0
- package/dist/libs/setup.d.ts +2 -0
- package/dist/libs/setup.d.ts.map +1 -0
- package/dist/libs/setup.js +87 -0
- package/dist/libs/setup.js.map +1 -0
- package/dist/libs/startup-deprecations.d.ts +2 -0
- package/dist/libs/startup-deprecations.d.ts.map +1 -0
- package/dist/libs/startup-deprecations.js +21 -0
- package/dist/libs/startup-deprecations.js.map +1 -0
- package/dist/libs/startup.d.ts +16 -0
- package/dist/libs/startup.d.ts.map +1 -0
- package/dist/libs/startup.js +63 -0
- package/dist/libs/startup.js.map +1 -0
- package/dist/libs/ws.d.ts +2 -0
- package/dist/libs/ws.d.ts.map +1 -0
- package/{libs → dist/libs}/ws.js +91 -73
- package/dist/libs/ws.js.map +1 -0
- package/dist/models/apikey_model.d.ts +10 -0
- package/dist/models/apikey_model.d.ts.map +1 -0
- package/dist/models/apikey_model.js +14 -0
- package/dist/models/apikey_model.js.map +1 -0
- package/dist/models/link_model.d.ts +9 -0
- package/dist/models/link_model.d.ts.map +1 -0
- package/dist/models/link_model.js +20 -0
- package/dist/models/link_model.js.map +1 -0
- package/dist/models/refreshtoken_model.d.ts +11 -0
- package/dist/models/refreshtoken_model.d.ts.map +1 -0
- package/dist/models/refreshtoken_model.js +22 -0
- package/dist/models/refreshtoken_model.js.map +1 -0
- package/dist/models/test_model.d.ts +24 -0
- package/dist/models/test_model.d.ts.map +1 -0
- package/dist/models/test_model.js +44 -0
- package/dist/models/test_model.js.map +1 -0
- package/dist/models/token_model.d.ts +14 -0
- package/dist/models/token_model.d.ts.map +1 -0
- package/dist/models/token_model.js +25 -0
- package/dist/models/token_model.js.map +1 -0
- package/dist/models/user_model.d.ts +15 -0
- package/dist/models/user_model.d.ts.map +1 -0
- package/dist/models/user_model.js +38 -0
- package/dist/models/user_model.js.map +1 -0
- package/dist/models/usergroups_model.d.ts +9 -0
- package/dist/models/usergroups_model.d.ts.map +1 -0
- package/dist/models/usergroups_model.js +18 -0
- package/dist/models/usergroups_model.js.map +1 -0
- package/dist/types/jxp-config.d.ts +151 -0
- package/dist/types/jxp-config.d.ts.map +1 -0
- package/dist/types/jxp-config.js +3 -0
- package/dist/types/jxp-config.js.map +1 -0
- package/dist/types/schema-fields.d.ts +43 -0
- package/dist/types/schema-fields.d.ts.map +1 -0
- package/dist/types/schema-fields.js +3 -0
- package/dist/types/schema-fields.js.map +1 -0
- package/docs/aggregations.md +40 -21
- package/docs/api.md +55 -15
- package/docs/authentication.md +60 -37
- package/docs/bulk_writes.md +11 -8
- package/docs/caching.md +28 -11
- package/docs/changelog.md +258 -31
- package/docs/configuration.md +126 -115
- package/docs/hooks.md +12 -8
- package/docs/index.md +17 -17
- package/docs/installation.md +23 -18
- package/docs/permissions.md +33 -19
- package/docs/queries.md +9 -5
- package/docs/schemas.md +21 -10
- package/docs/special.md +4 -4
- package/docs/typescript.md +86 -0
- package/docs/websocket.md +99 -1
- package/mkdocs.yml +1 -0
- package/package.json +121 -69
- package/templates/api.pug +32 -0
- package/templates/app-server.js +43 -0
- package/templates/app.env.sample +8 -0
- package/templates/assets/api-console.js +151 -0
- package/templates/assets/docs-login.js +66 -0
- package/templates/assets/docs.css +244 -0
- package/templates/index.pug +67 -2
- package/templates/layout.pug +21 -11
- package/templates/login.pug +39 -0
- package/templates/md.pug +1 -1
- package/templates/model.pug +117 -68
- package/templates/navbar.pug +25 -21
- package/templates/sidebar.pug +30 -0
- package/.env +0 -9
- package/.eslintrc.json +0 -20
- package/.jshintrc +0 -4
- package/.vscode/launch.json +0 -34
- package/.vscode/settings.json +0 -3
- package/Dockerfile +0 -7
- package/bin/init_db.js +0 -54
- package/bin/server.js +0 -131
- package/bin/setup.js +0 -190
- package/config_sample.json +0 -10
- package/docker-compose.yml +0 -32
- package/libs/cache.js +0 -92
- package/libs/connection_string.js +0 -24
- package/libs/datamunging.js +0 -335
- package/libs/docs.js +0 -162
- package/libs/groups.js +0 -133
- package/libs/jxp.js +0 -1208
- package/libs/login.js +0 -222
- package/libs/modeldir.js +0 -14
- package/libs/schema.js +0 -99
- package/libs/security.js +0 -410
- package/libs/setup.js +0 -90
- package/models/apikey_model.js +0 -10
- package/models/link_model.js +0 -17
- package/models/refreshtoken_model.js +0 -20
- package/models/test_model.js +0 -50
- package/models/token_model.js +0 -23
- package/models/user_model.js +0 -38
- package/models/usergroups_model.js +0 -15
- package/setup.sh +0 -3
- package/test/.eslintrc.json +0 -13
- package/test/auth.js +0 -190
- package/test/init.js +0 -92
- package/test/setup.test.js +0 -62
- package/test/test.js +0 -1527
- package/test/wstest.js.old +0 -124
package/package.json
CHANGED
|
@@ -1,70 +1,122 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
2
|
+
"name": "jxp",
|
|
3
|
+
"description": "An opinionated RESTful API library based on Mongoose and Restify. Make an API by just writing Mongoose models.",
|
|
4
|
+
"version": "4.1.0",
|
|
5
|
+
"private": false,
|
|
6
|
+
"main": "dist/libs/jxp.js",
|
|
7
|
+
"types": "dist/libs/jxp.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
".env.sample",
|
|
11
|
+
"templates",
|
|
12
|
+
"docs",
|
|
13
|
+
"mkdocs.yml"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/libs/jxp.d.ts",
|
|
18
|
+
"default": "./dist/libs/jxp.js"
|
|
19
|
+
},
|
|
20
|
+
"./libs/schema": {
|
|
21
|
+
"types": "./dist/libs/schema.d.ts",
|
|
22
|
+
"default": "./dist/libs/schema.js"
|
|
23
|
+
},
|
|
24
|
+
"./libs/query_manipulation": {
|
|
25
|
+
"types": "./dist/libs/query_manipulation.d.ts",
|
|
26
|
+
"default": "./dist/libs/query_manipulation.js"
|
|
27
|
+
},
|
|
28
|
+
"./globals": {
|
|
29
|
+
"types": "./dist/globals.d.ts",
|
|
30
|
+
"default": "./dist/globals.js"
|
|
31
|
+
},
|
|
32
|
+
"./libs/load-config": {
|
|
33
|
+
"types": "./dist/libs/load-config.d.ts",
|
|
34
|
+
"default": "./dist/libs/load-config.js"
|
|
35
|
+
},
|
|
36
|
+
"./libs/connection_string": {
|
|
37
|
+
"types": "./dist/libs/connection_string.d.ts",
|
|
38
|
+
"default": "./dist/libs/connection_string.js"
|
|
39
|
+
},
|
|
40
|
+
"./types/jxp-config": {
|
|
41
|
+
"types": "./dist/types/jxp-config.d.ts"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc -p tsconfig.build.json",
|
|
46
|
+
"prepublishOnly": "npm run build",
|
|
47
|
+
"prepare": "node -e \"require('fs').existsSync('src')&&require('child_process').execSync('npm run build',{stdio:'inherit'})\"",
|
|
48
|
+
"start": "node dist/bin/server.js",
|
|
49
|
+
"dev": "nodemon --watch src --ext ts --exec 'npm run build && node dist/bin/server.js'",
|
|
50
|
+
"test": "npm run build && mocha --require test/env.js --timeout 1000 -b --exit",
|
|
51
|
+
"setup": "node dist/bin/setup.js"
|
|
52
|
+
},
|
|
53
|
+
"bin": {
|
|
54
|
+
"jxp": "dist/bin/setup.js",
|
|
55
|
+
"jxp-setup": "dist/bin/setup.js",
|
|
56
|
+
"jxp-add-admin": "dist/bin/init_db.js"
|
|
57
|
+
},
|
|
58
|
+
"repository": {
|
|
59
|
+
"type": "git",
|
|
60
|
+
"url": "git://github.com/WorkSpaceMan/jxp.git"
|
|
61
|
+
},
|
|
62
|
+
"keywords": [
|
|
63
|
+
"api",
|
|
64
|
+
"mongoose",
|
|
65
|
+
"typescript"
|
|
66
|
+
],
|
|
67
|
+
"author": "Jason Norwood-Young <jason@10layer.com> (https://github.com/j-norwood-young/)",
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/WorkSpaceMan/jxp/issues"
|
|
71
|
+
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"bcryptjs": "^3.0.2",
|
|
74
|
+
"commander": "^13.1.0",
|
|
75
|
+
"dotenv": "^16.5.0",
|
|
76
|
+
"glob": "11.1.0",
|
|
77
|
+
"js-yaml": "4.1.1",
|
|
78
|
+
"@json2csv/plainjs": "^7.0.6",
|
|
79
|
+
"jsonwebtoken": "^9.0.2",
|
|
80
|
+
"markdown-it": "^14.1.1",
|
|
81
|
+
"jxp-helper": "^1.4.3",
|
|
82
|
+
"moment": "^2.30.1",
|
|
83
|
+
"mongoose": "6.13.9",
|
|
84
|
+
"mongoose-friendly": "^0.1.4",
|
|
85
|
+
"morgan": "^1.10.0",
|
|
86
|
+
"node-cache": "^5.1.2",
|
|
87
|
+
"nodemailer": "^8.0.7",
|
|
88
|
+
"pug": "^3.0.3",
|
|
89
|
+
"rand-token": "^1.0.1",
|
|
90
|
+
"readline-sync": "^1.4.10",
|
|
91
|
+
"restify": "^11.1.0",
|
|
92
|
+
"restify-cors-middleware2": "^2.2.1",
|
|
93
|
+
"restify-errors": "^8.0.2",
|
|
94
|
+
"traverse": "^0.6.11",
|
|
95
|
+
"underscore": "^1.13.8",
|
|
96
|
+
"ws": "^8.18.1"
|
|
97
|
+
},
|
|
98
|
+
"devDependencies": {
|
|
99
|
+
"@types/markdown-it": "^14.1.2",
|
|
100
|
+
"@types/bcryptjs": "^2.4.6",
|
|
101
|
+
"@types/jsonwebtoken": "^9.0.9",
|
|
102
|
+
"@types/morgan": "^1.9.9",
|
|
103
|
+
"@types/node": "^22.15.21",
|
|
104
|
+
"@types/underscore": "^1.13.0",
|
|
105
|
+
"@types/ws": "^8.18.1",
|
|
106
|
+
"chai": "^4.3.10",
|
|
107
|
+
"chai-http": "^4.4.0",
|
|
108
|
+
"mocha": "^11.7.5",
|
|
109
|
+
"nodemon": "^3.1.0",
|
|
110
|
+
"should": "^13.2.3",
|
|
111
|
+
"typescript": "^5.8.3"
|
|
112
|
+
},
|
|
113
|
+
"engines": {
|
|
114
|
+
"node": ">=22.0.0"
|
|
115
|
+
},
|
|
116
|
+
"overrides": {
|
|
117
|
+
"find-my-way": "^8.2.2",
|
|
118
|
+
"send": "^0.19.0",
|
|
119
|
+
"serialize-javascript": "^7.0.5",
|
|
120
|
+
"diff": "^8.0.3"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
extends layout
|
|
2
|
+
|
|
3
|
+
block content
|
|
4
|
+
h1.mb-1 API reference
|
|
5
|
+
p.text-muted.mb-4 Explore resources, try requests with your API key, and inspect schemas.
|
|
6
|
+
|
|
7
|
+
if model_summaries.length
|
|
8
|
+
.table-responsive
|
|
9
|
+
table.table.table-striped.table-hover.align-middle
|
|
10
|
+
thead
|
|
11
|
+
tr
|
|
12
|
+
th Resource
|
|
13
|
+
th Collection
|
|
14
|
+
th Permissions
|
|
15
|
+
th
|
|
16
|
+
tbody
|
|
17
|
+
each summary in model_summaries
|
|
18
|
+
tr
|
|
19
|
+
td
|
|
20
|
+
a.fw-semibold(href="/docs/model/" + summary.slug)= summary.slug
|
|
21
|
+
td
|
|
22
|
+
code.small= summary.collection
|
|
23
|
+
td
|
|
24
|
+
if summary.perms
|
|
25
|
+
each value, key in summary.perms
|
|
26
|
+
span.badge.text-bg-secondary.me-1(title=key)= key + ': ' + value
|
|
27
|
+
else
|
|
28
|
+
span.badge.text-bg-warning No perms
|
|
29
|
+
td.text-end
|
|
30
|
+
a.btn.btn-sm.btn-outline-primary(href="/docs/model/" + summary.slug) Open
|
|
31
|
+
else
|
|
32
|
+
.alert.alert-info No API resources are registered.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require("dotenv").config();
|
|
2
|
+
const mongoose = require("mongoose");
|
|
3
|
+
const JXP = require("jxp");
|
|
4
|
+
const { loadJxpConfig, getMongoConnectionString } = require("jxp/libs/load-config");
|
|
5
|
+
|
|
6
|
+
const apiconfig = loadJxpConfig();
|
|
7
|
+
|
|
8
|
+
apiconfig.callbacks = {
|
|
9
|
+
post: function () {},
|
|
10
|
+
put: function () {},
|
|
11
|
+
delete: function () {},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
apiconfig.pre_hooks = {
|
|
15
|
+
login: (req, res, next) => next(),
|
|
16
|
+
get: (req, res, next) => next(),
|
|
17
|
+
getOne: (req, res, next) => next(),
|
|
18
|
+
post: (req, res, next) => next(),
|
|
19
|
+
put: (req, res, next) => next(),
|
|
20
|
+
delete: (req, res, next) => next(),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
mongoose.Promise = Promise;
|
|
24
|
+
const mongo_options = Object.assign({}, apiconfig.mongo?.options || {}, {
|
|
25
|
+
useNewUrlParser: true,
|
|
26
|
+
useUnifiedTopology: true,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
mongoose.connect(getMongoConnectionString(), mongo_options);
|
|
30
|
+
|
|
31
|
+
mongoose.connection.on("error", console.error.bind(console, "connection error:"));
|
|
32
|
+
mongoose.connection.once("open", () => {
|
|
33
|
+
console.log(`Connected to Mongo at: ${new Date()}`);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const server = JXP(apiconfig);
|
|
37
|
+
const port = parseInt(process.env.PORT || String(apiconfig.port || 4001), 10);
|
|
38
|
+
|
|
39
|
+
server.listen(port, function () {
|
|
40
|
+
console.log("%s listening at %s", server.name, server.url);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
module.exports = server;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const STORAGE_KEY = "jxp_docs_api_key";
|
|
5
|
+
const STORAGE_REMEMBER = "jxp_docs_remember_key";
|
|
6
|
+
|
|
7
|
+
function getApiKey() {
|
|
8
|
+
const input = document.getElementById("docs-api-key");
|
|
9
|
+
return input ? input.value.trim() : "";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function loadStoredKey() {
|
|
13
|
+
if (localStorage.getItem(STORAGE_REMEMBER) !== "1") return;
|
|
14
|
+
const key = localStorage.getItem(STORAGE_KEY);
|
|
15
|
+
if (!key) return;
|
|
16
|
+
const input = document.getElementById("docs-api-key");
|
|
17
|
+
const remember = document.getElementById("docs-remember-key");
|
|
18
|
+
if (input) input.value = key;
|
|
19
|
+
if (remember) remember.checked = true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function saveKeyIfRemembered() {
|
|
23
|
+
const remember = document.getElementById("docs-remember-key");
|
|
24
|
+
const input = document.getElementById("docs-api-key");
|
|
25
|
+
if (!remember || !input) return;
|
|
26
|
+
if (remember.checked) {
|
|
27
|
+
localStorage.setItem(STORAGE_REMEMBER, "1");
|
|
28
|
+
localStorage.setItem(STORAGE_KEY, input.value.trim());
|
|
29
|
+
} else {
|
|
30
|
+
localStorage.removeItem(STORAGE_REMEMBER);
|
|
31
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function formatBody(text) {
|
|
36
|
+
if (!text) return "";
|
|
37
|
+
try {
|
|
38
|
+
return JSON.stringify(JSON.parse(text), null, 2);
|
|
39
|
+
} catch {
|
|
40
|
+
return text;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function formatResponse(text) {
|
|
45
|
+
if (!text) return "(empty)";
|
|
46
|
+
try {
|
|
47
|
+
return JSON.stringify(JSON.parse(text), null, 2);
|
|
48
|
+
} catch {
|
|
49
|
+
return text;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function sendRequest(panel) {
|
|
54
|
+
const method = panel.dataset.method;
|
|
55
|
+
const pathInput = panel.querySelector(".api-path-input");
|
|
56
|
+
const bodyInput = panel.querySelector(".api-body-input");
|
|
57
|
+
const responseEl = panel.querySelector(".api-response");
|
|
58
|
+
const metaEl = panel.querySelector(".api-response-meta");
|
|
59
|
+
const btn = panel.querySelector(".api-send-btn");
|
|
60
|
+
|
|
61
|
+
const path = pathInput ? pathInput.value.trim() : panel.dataset.defaultPath;
|
|
62
|
+
if (!path.startsWith("/")) {
|
|
63
|
+
responseEl.textContent = "Path must start with /";
|
|
64
|
+
responseEl.classList.remove("empty");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const headers = { Accept: "application/json" };
|
|
69
|
+
const apiKey = getApiKey();
|
|
70
|
+
if (apiKey) headers["X-API-Key"] = apiKey;
|
|
71
|
+
|
|
72
|
+
const opts = { method, headers };
|
|
73
|
+
if (bodyInput && (method === "POST" || method === "PUT")) {
|
|
74
|
+
const raw = bodyInput.value.trim();
|
|
75
|
+
if (raw) {
|
|
76
|
+
headers["Content-Type"] = "application/json";
|
|
77
|
+
opts.body = raw;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
btn.disabled = true;
|
|
82
|
+
responseEl.textContent = "Sending…";
|
|
83
|
+
responseEl.classList.remove("empty");
|
|
84
|
+
metaEl.textContent = "";
|
|
85
|
+
|
|
86
|
+
const start = performance.now();
|
|
87
|
+
try {
|
|
88
|
+
const res = await fetch(path, opts);
|
|
89
|
+
const elapsed = Math.round(performance.now() - start);
|
|
90
|
+
const text = await res.text();
|
|
91
|
+
responseEl.textContent = formatResponse(text);
|
|
92
|
+
metaEl.textContent = `HTTP ${res.status} ${res.statusText} · ${elapsed} ms`;
|
|
93
|
+
metaEl.className = "api-response-meta " + (res.ok ? "text-success" : "text-danger");
|
|
94
|
+
} catch (err) {
|
|
95
|
+
responseEl.textContent = String(err.message || err);
|
|
96
|
+
metaEl.textContent = "Request failed";
|
|
97
|
+
metaEl.className = "api-response-meta text-danger";
|
|
98
|
+
} finally {
|
|
99
|
+
btn.disabled = false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function initPanel(panel) {
|
|
104
|
+
const sendBtn = panel.querySelector(".api-send-btn");
|
|
105
|
+
if (sendBtn) {
|
|
106
|
+
sendBtn.addEventListener("click", function () {
|
|
107
|
+
saveKeyIfRemembered();
|
|
108
|
+
sendRequest(panel);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const bodyInput = panel.querySelector(".api-body-input");
|
|
112
|
+
if (bodyInput) {
|
|
113
|
+
bodyInput.addEventListener("blur", function () {
|
|
114
|
+
bodyInput.value = formatBody(bodyInput.value);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
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
|
+
|
|
134
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
135
|
+
const access = document.documentElement.dataset.docsAccess;
|
|
136
|
+
loadSessionApiKey().then(function () {
|
|
137
|
+
if (access !== "protected") loadStoredKey();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const keyInput = document.getElementById("docs-api-key");
|
|
141
|
+
const remember = document.getElementById("docs-remember-key");
|
|
142
|
+
if (keyInput) {
|
|
143
|
+
keyInput.addEventListener("change", saveKeyIfRemembered);
|
|
144
|
+
}
|
|
145
|
+
if (remember) {
|
|
146
|
+
remember.addEventListener("change", saveKeyIfRemembered);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
document.querySelectorAll(".api-try-panel").forEach(initPanel);
|
|
150
|
+
});
|
|
151
|
+
})();
|
|
@@ -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
|
+
})();
|