jxp 2.16.0 → 4.0.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 +31 -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.d.ts +2 -0
- package/dist/libs/docs.d.ts.map +1 -0
- package/dist/libs/docs.js +307 -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 +1157 -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 +155 -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/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 +114 -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 +134 -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 +237 -31
- package/docs/configuration.md +99 -118
- 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 +133 -0
- package/templates/assets/docs.css +227 -0
- package/templates/index.pug +62 -2
- package/templates/layout.pug +17 -11
- package/templates/md.pug +1 -1
- package/templates/model.pug +117 -68
- package/templates/navbar.pug +14 -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 -29
- package/.vscode/settings.json +0 -3
- package/Dockerfile +0 -7
- package/bin/init_db.js +0 -54
- package/bin/server.js +0 -84
- 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 -218
- 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/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.0.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,133 @@
|
|
|
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
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
120
|
+
loadStoredKey();
|
|
121
|
+
|
|
122
|
+
const keyInput = document.getElementById("docs-api-key");
|
|
123
|
+
const remember = document.getElementById("docs-remember-key");
|
|
124
|
+
if (keyInput) {
|
|
125
|
+
keyInput.addEventListener("change", saveKeyIfRemembered);
|
|
126
|
+
}
|
|
127
|
+
if (remember) {
|
|
128
|
+
remember.addEventListener("change", saveKeyIfRemembered);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
document.querySelectorAll(".api-try-panel").forEach(initPanel);
|
|
132
|
+
});
|
|
133
|
+
})();
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--docs-sidebar-width: 280px;
|
|
3
|
+
--docs-topbar-height: 56px;
|
|
4
|
+
--docs-accent: #0d6efd;
|
|
5
|
+
--docs-sidebar-bg: #f8f9fa;
|
|
6
|
+
--docs-border: #dee2e6;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
body.docs-body {
|
|
10
|
+
min-height: 100vh;
|
|
11
|
+
background: #fff;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.docs-topbar {
|
|
15
|
+
height: var(--docs-topbar-height);
|
|
16
|
+
border-bottom: 1px solid var(--docs-border);
|
|
17
|
+
background: #fff;
|
|
18
|
+
z-index: 1030;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.docs-brand {
|
|
22
|
+
font-weight: 600;
|
|
23
|
+
font-size: 1.1rem;
|
|
24
|
+
color: #212529;
|
|
25
|
+
text-decoration: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.docs-brand:hover {
|
|
29
|
+
color: var(--docs-accent);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.docs-shell {
|
|
33
|
+
display: flex;
|
|
34
|
+
min-height: calc(100vh - var(--docs-topbar-height));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.docs-sidebar {
|
|
38
|
+
width: var(--docs-sidebar-width);
|
|
39
|
+
flex-shrink: 0;
|
|
40
|
+
border-right: 1px solid var(--docs-border);
|
|
41
|
+
background: var(--docs-sidebar-bg);
|
|
42
|
+
overflow-y: auto;
|
|
43
|
+
padding: 1rem 0;
|
|
44
|
+
position: sticky;
|
|
45
|
+
top: var(--docs-topbar-height);
|
|
46
|
+
height: calc(100vh - var(--docs-topbar-height));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.docs-main {
|
|
50
|
+
flex: 1;
|
|
51
|
+
min-width: 0;
|
|
52
|
+
padding: 1.5rem 2rem 3rem;
|
|
53
|
+
max-width: 960px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.docs-sidebar-section {
|
|
57
|
+
padding: 0 1rem;
|
|
58
|
+
margin-bottom: 1.25rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.docs-sidebar-title {
|
|
62
|
+
font-size: 0.7rem;
|
|
63
|
+
font-weight: 700;
|
|
64
|
+
text-transform: uppercase;
|
|
65
|
+
letter-spacing: 0.06em;
|
|
66
|
+
color: #6c757d;
|
|
67
|
+
margin-bottom: 0.5rem;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.docs-nav-link {
|
|
71
|
+
display: block;
|
|
72
|
+
padding: 0.35rem 0.75rem;
|
|
73
|
+
font-size: 0.875rem;
|
|
74
|
+
color: #495057;
|
|
75
|
+
text-decoration: none;
|
|
76
|
+
border-radius: 0.375rem;
|
|
77
|
+
border-left: 3px solid transparent;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.docs-nav-link:hover {
|
|
81
|
+
background: rgba(13, 110, 253, 0.08);
|
|
82
|
+
color: var(--docs-accent);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.docs-nav-link.active {
|
|
86
|
+
background: rgba(13, 110, 253, 0.12);
|
|
87
|
+
color: var(--docs-accent);
|
|
88
|
+
border-left-color: var(--docs-accent);
|
|
89
|
+
font-weight: 500;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.docs-api-key-wrap {
|
|
93
|
+
max-width: 220px;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.docs-api-key-wrap .form-control {
|
|
97
|
+
font-size: 0.8rem;
|
|
98
|
+
font-family: ui-monospace, monospace;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@media (max-width: 991.98px) {
|
|
102
|
+
.docs-sidebar {
|
|
103
|
+
display: none;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.docs-main {
|
|
107
|
+
padding: 1rem;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.docs-hero {
|
|
112
|
+
padding: 2.5rem 0 2rem;
|
|
113
|
+
border-bottom: 1px solid var(--docs-border);
|
|
114
|
+
margin-bottom: 2rem;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.docs-hero h1 {
|
|
118
|
+
font-size: 2.25rem;
|
|
119
|
+
font-weight: 700;
|
|
120
|
+
margin-bottom: 0.5rem;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.docs-hero .lead {
|
|
124
|
+
color: #6c757d;
|
|
125
|
+
max-width: 36rem;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.docs-content h1,
|
|
129
|
+
.docs-content h2,
|
|
130
|
+
.docs-content h3 {
|
|
131
|
+
margin-top: 1.5rem;
|
|
132
|
+
margin-bottom: 0.75rem;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.docs-content pre {
|
|
136
|
+
background: #f8f9fa;
|
|
137
|
+
border: 1px solid var(--docs-border);
|
|
138
|
+
border-radius: 0.375rem;
|
|
139
|
+
padding: 1rem;
|
|
140
|
+
overflow-x: auto;
|
|
141
|
+
font-size: 0.85rem;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.docs-content code {
|
|
145
|
+
font-size: 0.875em;
|
|
146
|
+
color: #d63384;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.docs-content pre code {
|
|
150
|
+
color: inherit;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.docs-content table {
|
|
154
|
+
margin: 1rem 0;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.method-badge {
|
|
158
|
+
font-family: ui-monospace, monospace;
|
|
159
|
+
font-size: 0.75rem;
|
|
160
|
+
font-weight: 700;
|
|
161
|
+
min-width: 4.5rem;
|
|
162
|
+
text-align: center;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.method-get { background-color: #198754 !important; }
|
|
166
|
+
.method-post { background-color: #0d6efd !important; }
|
|
167
|
+
.method-put { background-color: #fd7e14 !important; }
|
|
168
|
+
.method-delete { background-color: #dc3545 !important; }
|
|
169
|
+
|
|
170
|
+
.endpoint-path {
|
|
171
|
+
font-family: ui-monospace, monospace;
|
|
172
|
+
font-size: 0.9rem;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.api-try-panel {
|
|
176
|
+
border: 1px solid var(--docs-border);
|
|
177
|
+
border-radius: 0.375rem;
|
|
178
|
+
padding: 1rem;
|
|
179
|
+
background: #fafbfc;
|
|
180
|
+
margin-top: 0.75rem;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.api-response {
|
|
184
|
+
font-family: ui-monospace, monospace;
|
|
185
|
+
font-size: 0.8rem;
|
|
186
|
+
background: #212529;
|
|
187
|
+
color: #e9ecef;
|
|
188
|
+
border-radius: 0.375rem;
|
|
189
|
+
padding: 1rem;
|
|
190
|
+
max-height: 320px;
|
|
191
|
+
overflow: auto;
|
|
192
|
+
white-space: pre-wrap;
|
|
193
|
+
word-break: break-word;
|
|
194
|
+
margin-top: 0.75rem;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.api-response.empty {
|
|
198
|
+
background: #f8f9fa;
|
|
199
|
+
color: #6c757d;
|
|
200
|
+
border: 1px dashed var(--docs-border);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.api-response-meta {
|
|
204
|
+
font-size: 0.8rem;
|
|
205
|
+
color: #6c757d;
|
|
206
|
+
margin-top: 0.5rem;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.field-details pre {
|
|
210
|
+
font-size: 0.75rem;
|
|
211
|
+
max-height: 200px;
|
|
212
|
+
overflow: auto;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.feature-card {
|
|
216
|
+
height: 100%;
|
|
217
|
+
border: 1px solid var(--docs-border);
|
|
218
|
+
transition: box-shadow 0.15s ease;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.feature-card:hover {
|
|
222
|
+
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.08);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.docs-security-note {
|
|
226
|
+
font-size: 0.8rem;
|
|
227
|
+
}
|