@objectql/server 1.8.3 → 1.9.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/CHANGELOG.md +27 -0
- package/dist/adapters/graphql.js +25 -0
- package/dist/adapters/graphql.js.map +1 -1
- package/dist/adapters/node.d.ts +3 -1
- package/dist/adapters/node.js +52 -29
- package/dist/adapters/node.js.map +1 -1
- package/dist/adapters/rest.d.ts +20 -10
- package/dist/adapters/rest.js +39 -31
- package/dist/adapters/rest.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metadata.d.ts +12 -2
- package/dist/metadata.js +31 -23
- package/dist/metadata.js.map +1 -1
- package/dist/openapi.d.ts +2 -2
- package/dist/openapi.js +6 -4
- package/dist/openapi.js.map +1 -1
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +24 -0
- package/dist/utils.js.map +1 -0
- package/package.json +3 -3
- package/src/adapters/graphql.ts +28 -0
- package/src/adapters/node.ts +44 -19
- package/src/adapters/rest.ts +34 -19
- package/src/index.ts +1 -1
- package/src/metadata.ts +29 -14
- package/src/openapi.ts +6 -5
- package/src/utils.ts +21 -0
- package/test/custom-routes.test.ts +297 -0
- package/test/metadata.test.ts +259 -0
- package/test/openapi.test.ts +354 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/studio.d.ts +0 -5
- package/dist/studio.js +0 -186
- package/dist/studio.js.map +0 -1
- package/src/studio.ts +0 -164
package/dist/studio.d.ts
DELETED
package/dist/studio.js
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.createStudioHandler = createStudioHandler;
|
|
37
|
-
const fs = __importStar(require("fs"));
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
/**
|
|
40
|
-
* Creates a handler to serve the Studio UI static files.
|
|
41
|
-
*/
|
|
42
|
-
function createStudioHandler() {
|
|
43
|
-
let distPath = null;
|
|
44
|
-
// 1. Try to resolve from installed package (Standard way)
|
|
45
|
-
try {
|
|
46
|
-
const studioPkg = require.resolve('@objectql/studio/package.json');
|
|
47
|
-
const candidate = path.join(path.dirname(studioPkg), 'dist');
|
|
48
|
-
if (fs.existsSync(candidate)) {
|
|
49
|
-
distPath = candidate;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
catch (e) {
|
|
53
|
-
// @objectql/studio might not be installed
|
|
54
|
-
}
|
|
55
|
-
// 2. Fallback for local development (Monorepo)
|
|
56
|
-
if (!distPath) {
|
|
57
|
-
const possiblePaths = [
|
|
58
|
-
path.join(__dirname, '../../studio/dist'),
|
|
59
|
-
path.join(process.cwd(), 'packages/studio/dist'),
|
|
60
|
-
path.join(process.cwd(), 'packages/tools/studio/dist'),
|
|
61
|
-
];
|
|
62
|
-
for (const p of possiblePaths) {
|
|
63
|
-
if (fs.existsSync(p)) {
|
|
64
|
-
distPath = p;
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return async (req, res) => {
|
|
70
|
-
if (!distPath) {
|
|
71
|
-
// Return placeholder page if studio is not built
|
|
72
|
-
const html = getPlaceholderPage();
|
|
73
|
-
res.setHeader('Content-Type', 'text/html');
|
|
74
|
-
res.statusCode = 200;
|
|
75
|
-
res.end(html);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
// Parse the URL and remove /studio prefix
|
|
79
|
-
let urlPath = (req.url || '').replace(/^\/studio/, '') || '/';
|
|
80
|
-
// Default to index.html for SPA routing
|
|
81
|
-
if (urlPath === '/' || !urlPath.includes('.')) {
|
|
82
|
-
urlPath = '/index.html';
|
|
83
|
-
}
|
|
84
|
-
const filePath = path.join(distPath, urlPath);
|
|
85
|
-
// Security check: ensure the file is within distPath
|
|
86
|
-
if (!filePath.startsWith(distPath)) {
|
|
87
|
-
res.statusCode = 403;
|
|
88
|
-
res.end('Forbidden');
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
// Check if file exists
|
|
92
|
-
if (!fs.existsSync(filePath)) {
|
|
93
|
-
// For SPA, return index.html for any non-existent routes
|
|
94
|
-
const indexPath = path.join(distPath, 'index.html');
|
|
95
|
-
if (fs.existsSync(indexPath)) {
|
|
96
|
-
const content = fs.readFileSync(indexPath);
|
|
97
|
-
res.setHeader('Content-Type', 'text/html');
|
|
98
|
-
res.statusCode = 200;
|
|
99
|
-
res.end(content);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
res.statusCode = 404;
|
|
103
|
-
res.end('Not Found');
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
// Read and serve the file
|
|
107
|
-
const content = fs.readFileSync(filePath);
|
|
108
|
-
const ext = path.extname(filePath);
|
|
109
|
-
const contentType = getContentType(ext);
|
|
110
|
-
res.setHeader('Content-Type', contentType);
|
|
111
|
-
res.statusCode = 200;
|
|
112
|
-
res.end(content);
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
function getContentType(ext) {
|
|
116
|
-
const types = {
|
|
117
|
-
'.html': 'text/html',
|
|
118
|
-
'.js': 'application/javascript',
|
|
119
|
-
'.css': 'text/css',
|
|
120
|
-
'.json': 'application/json',
|
|
121
|
-
'.png': 'image/png',
|
|
122
|
-
'.jpg': 'image/jpeg',
|
|
123
|
-
'.gif': 'image/gif',
|
|
124
|
-
'.svg': 'image/svg+xml',
|
|
125
|
-
'.ico': 'image/x-icon',
|
|
126
|
-
};
|
|
127
|
-
return types[ext] || 'application/octet-stream';
|
|
128
|
-
}
|
|
129
|
-
function getPlaceholderPage() {
|
|
130
|
-
return `<!DOCTYPE html>
|
|
131
|
-
<html lang="en">
|
|
132
|
-
<head>
|
|
133
|
-
<meta charset="UTF-8">
|
|
134
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
135
|
-
<title>ObjectQL Studio</title>
|
|
136
|
-
<style>
|
|
137
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
138
|
-
body {
|
|
139
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
140
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
141
|
-
min-height: 100vh;
|
|
142
|
-
display: flex;
|
|
143
|
-
align-items: center;
|
|
144
|
-
justify-content: center;
|
|
145
|
-
color: white;
|
|
146
|
-
}
|
|
147
|
-
.container {
|
|
148
|
-
text-align: center;
|
|
149
|
-
max-width: 600px;
|
|
150
|
-
padding: 2rem;
|
|
151
|
-
}
|
|
152
|
-
h1 { font-size: 3rem; margin-bottom: 1rem; }
|
|
153
|
-
p { font-size: 1.25rem; opacity: 0.9; line-height: 1.6; }
|
|
154
|
-
.info {
|
|
155
|
-
background: rgba(255, 255, 255, 0.1);
|
|
156
|
-
padding: 1.5rem;
|
|
157
|
-
border-radius: 8px;
|
|
158
|
-
margin-top: 2rem;
|
|
159
|
-
backdrop-filter: blur(10px);
|
|
160
|
-
}
|
|
161
|
-
code {
|
|
162
|
-
background: rgba(0, 0, 0, 0.2);
|
|
163
|
-
padding: 0.25rem 0.5rem;
|
|
164
|
-
border-radius: 4px;
|
|
165
|
-
font-family: monospace;
|
|
166
|
-
}
|
|
167
|
-
</style>
|
|
168
|
-
</head>
|
|
169
|
-
<body>
|
|
170
|
-
<div class="container">
|
|
171
|
-
<h1>ObjectQL Studio</h1>
|
|
172
|
-
<p>Web-based admin studio for database management</p>
|
|
173
|
-
<div class="info">
|
|
174
|
-
<p style="margin-bottom: 1rem;">
|
|
175
|
-
The studio is available but needs to be built separately.
|
|
176
|
-
</p>
|
|
177
|
-
<p style="font-size: 1rem;">
|
|
178
|
-
To use the full studio UI, run:<br>
|
|
179
|
-
<code>cd packages/studio && pnpm run build</code>
|
|
180
|
-
</p>
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
</body>
|
|
184
|
-
</html>`;
|
|
185
|
-
}
|
|
186
|
-
//# sourceMappingURL=studio.js.map
|
package/dist/studio.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"studio.js","sourceRoot":"","sources":["../src/studio.ts"],"names":[],"mappings":"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"}
|
package/src/studio.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { IncomingMessage, ServerResponse } from 'http';
|
|
2
|
-
import * as fs from 'fs';
|
|
3
|
-
import * as path from 'path';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Creates a handler to serve the Studio UI static files.
|
|
7
|
-
*/
|
|
8
|
-
export function createStudioHandler() {
|
|
9
|
-
let distPath: string | null = null;
|
|
10
|
-
|
|
11
|
-
// 1. Try to resolve from installed package (Standard way)
|
|
12
|
-
try {
|
|
13
|
-
const studioPkg = require.resolve('@objectql/studio/package.json');
|
|
14
|
-
const candidate = path.join(path.dirname(studioPkg), 'dist');
|
|
15
|
-
if (fs.existsSync(candidate)) {
|
|
16
|
-
distPath = candidate;
|
|
17
|
-
}
|
|
18
|
-
} catch (e) {
|
|
19
|
-
// @objectql/studio might not be installed
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// 2. Fallback for local development (Monorepo)
|
|
23
|
-
if (!distPath) {
|
|
24
|
-
const possiblePaths = [
|
|
25
|
-
path.join(__dirname, '../../studio/dist'),
|
|
26
|
-
path.join(process.cwd(), 'packages/studio/dist'),
|
|
27
|
-
path.join(process.cwd(), 'packages/tools/studio/dist'),
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
for (const p of possiblePaths) {
|
|
31
|
-
if (fs.existsSync(p)) {
|
|
32
|
-
distPath = p;
|
|
33
|
-
break;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return async (req: IncomingMessage, res: ServerResponse) => {
|
|
39
|
-
if (!distPath) {
|
|
40
|
-
// Return placeholder page if studio is not built
|
|
41
|
-
const html = getPlaceholderPage();
|
|
42
|
-
res.setHeader('Content-Type', 'text/html');
|
|
43
|
-
res.statusCode = 200;
|
|
44
|
-
res.end(html);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Parse the URL and remove /studio prefix
|
|
49
|
-
let urlPath = (req.url || '').replace(/^\/studio/, '') || '/';
|
|
50
|
-
|
|
51
|
-
// Default to index.html for SPA routing
|
|
52
|
-
if (urlPath === '/' || !urlPath.includes('.')) {
|
|
53
|
-
urlPath = '/index.html';
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const filePath = path.join(distPath, urlPath);
|
|
57
|
-
|
|
58
|
-
// Security check: ensure the file is within distPath
|
|
59
|
-
if (!filePath.startsWith(distPath)) {
|
|
60
|
-
res.statusCode = 403;
|
|
61
|
-
res.end('Forbidden');
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Check if file exists
|
|
66
|
-
if (!fs.existsSync(filePath)) {
|
|
67
|
-
// For SPA, return index.html for any non-existent routes
|
|
68
|
-
const indexPath = path.join(distPath, 'index.html');
|
|
69
|
-
if (fs.existsSync(indexPath)) {
|
|
70
|
-
const content = fs.readFileSync(indexPath);
|
|
71
|
-
res.setHeader('Content-Type', 'text/html');
|
|
72
|
-
res.statusCode = 200;
|
|
73
|
-
res.end(content);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
res.statusCode = 404;
|
|
78
|
-
res.end('Not Found');
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Read and serve the file
|
|
83
|
-
const content = fs.readFileSync(filePath);
|
|
84
|
-
const ext = path.extname(filePath);
|
|
85
|
-
const contentType = getContentType(ext);
|
|
86
|
-
|
|
87
|
-
res.setHeader('Content-Type', contentType);
|
|
88
|
-
res.statusCode = 200;
|
|
89
|
-
res.end(content);
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function getContentType(ext: string): string {
|
|
94
|
-
const types: Record<string, string> = {
|
|
95
|
-
'.html': 'text/html',
|
|
96
|
-
'.js': 'application/javascript',
|
|
97
|
-
'.css': 'text/css',
|
|
98
|
-
'.json': 'application/json',
|
|
99
|
-
'.png': 'image/png',
|
|
100
|
-
'.jpg': 'image/jpeg',
|
|
101
|
-
'.gif': 'image/gif',
|
|
102
|
-
'.svg': 'image/svg+xml',
|
|
103
|
-
'.ico': 'image/x-icon',
|
|
104
|
-
};
|
|
105
|
-
return types[ext] || 'application/octet-stream';
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function getPlaceholderPage(): string {
|
|
109
|
-
return `<!DOCTYPE html>
|
|
110
|
-
<html lang="en">
|
|
111
|
-
<head>
|
|
112
|
-
<meta charset="UTF-8">
|
|
113
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
114
|
-
<title>ObjectQL Studio</title>
|
|
115
|
-
<style>
|
|
116
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
117
|
-
body {
|
|
118
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
119
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
120
|
-
min-height: 100vh;
|
|
121
|
-
display: flex;
|
|
122
|
-
align-items: center;
|
|
123
|
-
justify-content: center;
|
|
124
|
-
color: white;
|
|
125
|
-
}
|
|
126
|
-
.container {
|
|
127
|
-
text-align: center;
|
|
128
|
-
max-width: 600px;
|
|
129
|
-
padding: 2rem;
|
|
130
|
-
}
|
|
131
|
-
h1 { font-size: 3rem; margin-bottom: 1rem; }
|
|
132
|
-
p { font-size: 1.25rem; opacity: 0.9; line-height: 1.6; }
|
|
133
|
-
.info {
|
|
134
|
-
background: rgba(255, 255, 255, 0.1);
|
|
135
|
-
padding: 1.5rem;
|
|
136
|
-
border-radius: 8px;
|
|
137
|
-
margin-top: 2rem;
|
|
138
|
-
backdrop-filter: blur(10px);
|
|
139
|
-
}
|
|
140
|
-
code {
|
|
141
|
-
background: rgba(0, 0, 0, 0.2);
|
|
142
|
-
padding: 0.25rem 0.5rem;
|
|
143
|
-
border-radius: 4px;
|
|
144
|
-
font-family: monospace;
|
|
145
|
-
}
|
|
146
|
-
</style>
|
|
147
|
-
</head>
|
|
148
|
-
<body>
|
|
149
|
-
<div class="container">
|
|
150
|
-
<h1>ObjectQL Studio</h1>
|
|
151
|
-
<p>Web-based admin studio for database management</p>
|
|
152
|
-
<div class="info">
|
|
153
|
-
<p style="margin-bottom: 1rem;">
|
|
154
|
-
The studio is available but needs to be built separately.
|
|
155
|
-
</p>
|
|
156
|
-
<p style="font-size: 1rem;">
|
|
157
|
-
To use the full studio UI, run:<br>
|
|
158
|
-
<code>cd packages/studio && pnpm run build</code>
|
|
159
|
-
</p>
|
|
160
|
-
</div>
|
|
161
|
-
</div>
|
|
162
|
-
</body>
|
|
163
|
-
</html>`;
|
|
164
|
-
}
|