@objectql/server 1.3.1 → 1.4.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 +19 -0
- package/LICENSE +21 -0
- package/dist/adapters/node.js +69 -9
- package/dist/adapters/node.js.map +1 -1
- package/dist/adapters/rest.d.ts +15 -0
- package/dist/adapters/rest.js +252 -0
- package/dist/adapters/rest.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/metadata.js +152 -11
- package/dist/metadata.js.map +1 -1
- package/dist/server.d.ts +8 -0
- package/dist/server.js +75 -15
- package/dist/server.js.map +1 -1
- package/dist/studio.d.ts +5 -0
- package/dist/{console.js → studio.js} +35 -23
- package/dist/studio.js.map +1 -0
- package/dist/types.d.ts +49 -1
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -1
- package/package.json +7 -5
- package/src/adapters/node.ts +72 -11
- package/src/adapters/rest.ts +271 -0
- package/src/index.ts +3 -1
- package/src/metadata.ts +166 -11
- package/src/server.ts +119 -16
- package/src/{console.ts → studio.ts} +35 -22
- package/src/types.ts +56 -2
- package/test/rest.test.ts +164 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/console.d.ts +0 -5
- package/dist/console.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @objectql/server
|
|
2
2
|
|
|
3
|
+
## 1.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Release version 1.4.0 with new features and enhancements:
|
|
8
|
+
- Added complete REST API implementation with CRUD operations
|
|
9
|
+
- Enhanced error handling with standardized error codes and HTTP status mapping
|
|
10
|
+
- Added AI context support for tracking intent and use cases
|
|
11
|
+
- Enhanced metadata API with detailed field information and action listing
|
|
12
|
+
- Improved JSON-RPC API with better error categorization
|
|
13
|
+
- Added hooks and actions validation and implementation
|
|
14
|
+
- Updated documentation and examples
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
- @objectql/core@1.4.0
|
|
20
|
+
- @objectql/types@1.4.0
|
|
21
|
+
|
|
3
22
|
## 1.3.1
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ObjectQL Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/adapters/node.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createNodeHandler = createNodeHandler;
|
|
4
4
|
const server_1 = require("../server");
|
|
5
|
+
const types_1 = require("../types");
|
|
5
6
|
const openapi_1 = require("../openapi");
|
|
6
7
|
/**
|
|
7
8
|
* Creates a standard Node.js HTTP request handler.
|
|
@@ -17,11 +18,6 @@ function createNodeHandler(app) {
|
|
|
17
18
|
res.end(JSON.stringify(spec));
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
20
|
-
if (req.method !== 'POST') {
|
|
21
|
-
res.statusCode = 405;
|
|
22
|
-
res.end('Method Not Allowed');
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
21
|
const handleRequest = async (json) => {
|
|
26
22
|
try {
|
|
27
23
|
// TODO: Parse user from header or request override
|
|
@@ -29,18 +25,77 @@ function createNodeHandler(app) {
|
|
|
29
25
|
op: json.op,
|
|
30
26
|
object: json.object,
|
|
31
27
|
args: json.args,
|
|
32
|
-
user: json.user // For dev/testing, allowing user injection
|
|
28
|
+
user: json.user, // For dev/testing, allowing user injection
|
|
29
|
+
ai_context: json.ai_context // Support AI context
|
|
33
30
|
};
|
|
34
31
|
const result = await server.handle(qlReq);
|
|
32
|
+
// Determine HTTP status code based on error
|
|
33
|
+
let statusCode = 200;
|
|
34
|
+
if (result.error) {
|
|
35
|
+
switch (result.error.code) {
|
|
36
|
+
case types_1.ErrorCode.INVALID_REQUEST:
|
|
37
|
+
case types_1.ErrorCode.VALIDATION_ERROR:
|
|
38
|
+
statusCode = 400;
|
|
39
|
+
break;
|
|
40
|
+
case types_1.ErrorCode.UNAUTHORIZED:
|
|
41
|
+
statusCode = 401;
|
|
42
|
+
break;
|
|
43
|
+
case types_1.ErrorCode.FORBIDDEN:
|
|
44
|
+
statusCode = 403;
|
|
45
|
+
break;
|
|
46
|
+
case types_1.ErrorCode.NOT_FOUND:
|
|
47
|
+
statusCode = 404;
|
|
48
|
+
break;
|
|
49
|
+
case types_1.ErrorCode.CONFLICT:
|
|
50
|
+
statusCode = 409;
|
|
51
|
+
break;
|
|
52
|
+
case types_1.ErrorCode.RATE_LIMIT_EXCEEDED:
|
|
53
|
+
statusCode = 429;
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
statusCode = 500;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
35
59
|
res.setHeader('Content-Type', 'application/json');
|
|
36
|
-
res.statusCode =
|
|
60
|
+
res.statusCode = statusCode;
|
|
37
61
|
res.end(JSON.stringify(result));
|
|
38
62
|
}
|
|
39
63
|
catch (e) {
|
|
40
64
|
res.statusCode = 500;
|
|
41
|
-
res.end(JSON.stringify({
|
|
65
|
+
res.end(JSON.stringify({
|
|
66
|
+
error: {
|
|
67
|
+
code: types_1.ErrorCode.INTERNAL_ERROR,
|
|
68
|
+
message: 'Internal Server Error'
|
|
69
|
+
}
|
|
70
|
+
}));
|
|
42
71
|
}
|
|
43
72
|
};
|
|
73
|
+
if (req.method !== 'POST') {
|
|
74
|
+
// Attempt to handle GET requests for simple queries like /api/objectql/table
|
|
75
|
+
// We map this to a find operation
|
|
76
|
+
// URL pattern: /api/objectql/:objectName
|
|
77
|
+
const match = req.url?.match(/\/([^\/?]+)(\?.*)?$/);
|
|
78
|
+
if (req.method === 'GET' && match) {
|
|
79
|
+
const objectName = match[1];
|
|
80
|
+
// Ignore special paths
|
|
81
|
+
if (objectName !== 'openapi.json' && objectName !== 'metadata') {
|
|
82
|
+
await handleRequest({
|
|
83
|
+
op: 'find',
|
|
84
|
+
object: objectName,
|
|
85
|
+
args: {} // TODO: Parse query params to args
|
|
86
|
+
});
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
res.statusCode = 405;
|
|
91
|
+
res.end(JSON.stringify({
|
|
92
|
+
error: {
|
|
93
|
+
code: types_1.ErrorCode.INVALID_REQUEST,
|
|
94
|
+
message: 'Method Not Allowed'
|
|
95
|
+
}
|
|
96
|
+
}));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
44
99
|
// 1. Check if body is already parsed (e.g. by express.json())
|
|
45
100
|
if (req.body && typeof req.body === 'object') {
|
|
46
101
|
await handleRequest(req.body);
|
|
@@ -56,7 +111,12 @@ function createNodeHandler(app) {
|
|
|
56
111
|
}
|
|
57
112
|
catch (e) {
|
|
58
113
|
res.statusCode = 400;
|
|
59
|
-
res.end(
|
|
114
|
+
res.end(JSON.stringify({
|
|
115
|
+
error: {
|
|
116
|
+
code: types_1.ErrorCode.INVALID_REQUEST,
|
|
117
|
+
message: 'Invalid JSON'
|
|
118
|
+
}
|
|
119
|
+
}));
|
|
60
120
|
}
|
|
61
121
|
});
|
|
62
122
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/adapters/node.ts"],"names":[],"mappings":";;AASA,
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/adapters/node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IObjectQL } from '@objectql/types';
|
|
2
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a REST-style HTTP request handler for ObjectQL
|
|
5
|
+
*
|
|
6
|
+
* Endpoints:
|
|
7
|
+
* - GET /api/data/:object - List records
|
|
8
|
+
* - GET /api/data/:object/:id - Get single record
|
|
9
|
+
* - POST /api/data/:object - Create record
|
|
10
|
+
* - PUT /api/data/:object/:id - Update record
|
|
11
|
+
* - DELETE /api/data/:object/:id - Delete record
|
|
12
|
+
*/
|
|
13
|
+
export declare function createRESTHandler(app: IObjectQL): (req: IncomingMessage & {
|
|
14
|
+
body?: any;
|
|
15
|
+
}, res: ServerResponse) => Promise<void>;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRESTHandler = createRESTHandler;
|
|
4
|
+
const server_1 = require("../server");
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
/**
|
|
7
|
+
* Parse query string parameters
|
|
8
|
+
*/
|
|
9
|
+
function parseQueryParams(url) {
|
|
10
|
+
const params = {};
|
|
11
|
+
const queryIndex = url.indexOf('?');
|
|
12
|
+
if (queryIndex === -1)
|
|
13
|
+
return params;
|
|
14
|
+
const queryString = url.substring(queryIndex + 1);
|
|
15
|
+
const pairs = queryString.split('&');
|
|
16
|
+
for (const pair of pairs) {
|
|
17
|
+
const [key, value] = pair.split('=');
|
|
18
|
+
if (!key)
|
|
19
|
+
continue;
|
|
20
|
+
const decodedKey = decodeURIComponent(key);
|
|
21
|
+
const decodedValue = decodeURIComponent(value || '');
|
|
22
|
+
// Try to parse JSON values
|
|
23
|
+
try {
|
|
24
|
+
params[decodedKey] = JSON.parse(decodedValue);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
params[decodedKey] = decodedValue;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return params;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Read request body as JSON
|
|
34
|
+
*/
|
|
35
|
+
function readBody(req) {
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
let body = '';
|
|
38
|
+
req.on('data', chunk => body += chunk.toString());
|
|
39
|
+
req.on('end', () => {
|
|
40
|
+
if (!body)
|
|
41
|
+
return resolve({});
|
|
42
|
+
try {
|
|
43
|
+
resolve(JSON.parse(body));
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
reject(new Error('Invalid JSON'));
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
req.on('error', reject);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Send JSON response
|
|
54
|
+
*/
|
|
55
|
+
function sendJSON(res, statusCode, data) {
|
|
56
|
+
res.setHeader('Content-Type', 'application/json');
|
|
57
|
+
res.statusCode = statusCode;
|
|
58
|
+
res.end(JSON.stringify(data));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Creates a REST-style HTTP request handler for ObjectQL
|
|
62
|
+
*
|
|
63
|
+
* Endpoints:
|
|
64
|
+
* - GET /api/data/:object - List records
|
|
65
|
+
* - GET /api/data/:object/:id - Get single record
|
|
66
|
+
* - POST /api/data/:object - Create record
|
|
67
|
+
* - PUT /api/data/:object/:id - Update record
|
|
68
|
+
* - DELETE /api/data/:object/:id - Delete record
|
|
69
|
+
*/
|
|
70
|
+
function createRESTHandler(app) {
|
|
71
|
+
const server = new server_1.ObjectQLServer(app);
|
|
72
|
+
return async (req, res) => {
|
|
73
|
+
try {
|
|
74
|
+
// CORS headers
|
|
75
|
+
const requestOrigin = req.headers.origin;
|
|
76
|
+
const configuredOrigin = process.env.OBJECTQL_CORS_ORIGIN;
|
|
77
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
78
|
+
// In development, allow all origins by default (or use configured override).
|
|
79
|
+
// In production, require an explicit OBJECTQL_CORS_ORIGIN to be set.
|
|
80
|
+
if (!isProduction) {
|
|
81
|
+
res.setHeader('Access-Control-Allow-Origin', configuredOrigin || '*');
|
|
82
|
+
}
|
|
83
|
+
else if (configuredOrigin && (!requestOrigin || requestOrigin === configuredOrigin)) {
|
|
84
|
+
res.setHeader('Access-Control-Allow-Origin', configuredOrigin);
|
|
85
|
+
}
|
|
86
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
87
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
88
|
+
if (req.method === 'OPTIONS') {
|
|
89
|
+
res.statusCode = 200;
|
|
90
|
+
res.end();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const url = req.url || '';
|
|
94
|
+
const method = req.method || 'GET';
|
|
95
|
+
// Parse URL: /api/data/:object or /api/data/:object/:id
|
|
96
|
+
const match = url.match(/^\/api\/data\/([^\/\?]+)(?:\/([^\/\?]+))?(\?.*)?$/);
|
|
97
|
+
if (!match) {
|
|
98
|
+
sendJSON(res, 404, {
|
|
99
|
+
error: {
|
|
100
|
+
code: types_1.ErrorCode.NOT_FOUND,
|
|
101
|
+
message: 'Invalid REST API endpoint'
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const [, objectName, id, queryString] = match;
|
|
107
|
+
const queryParams = queryString ? parseQueryParams(queryString) : {};
|
|
108
|
+
let qlRequest;
|
|
109
|
+
switch (method) {
|
|
110
|
+
case 'GET':
|
|
111
|
+
if (id) {
|
|
112
|
+
// GET /api/data/:object/:id - Get single record
|
|
113
|
+
qlRequest = {
|
|
114
|
+
op: 'findOne',
|
|
115
|
+
object: objectName,
|
|
116
|
+
args: id
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// GET /api/data/:object - List records
|
|
121
|
+
const args = {};
|
|
122
|
+
// Parse query parameters
|
|
123
|
+
if (queryParams.filter) {
|
|
124
|
+
args.filters = queryParams.filter;
|
|
125
|
+
}
|
|
126
|
+
if (queryParams.fields) {
|
|
127
|
+
args.fields = queryParams.fields;
|
|
128
|
+
}
|
|
129
|
+
if (queryParams.sort) {
|
|
130
|
+
args.sort = Array.isArray(queryParams.sort)
|
|
131
|
+
? queryParams.sort
|
|
132
|
+
: [[queryParams.sort, 'asc']];
|
|
133
|
+
}
|
|
134
|
+
if (queryParams.top || queryParams.limit) {
|
|
135
|
+
args.top = queryParams.top || queryParams.limit;
|
|
136
|
+
}
|
|
137
|
+
if (queryParams.skip || queryParams.offset) {
|
|
138
|
+
args.skip = queryParams.skip || queryParams.offset;
|
|
139
|
+
}
|
|
140
|
+
if (queryParams.expand) {
|
|
141
|
+
args.expand = queryParams.expand;
|
|
142
|
+
}
|
|
143
|
+
qlRequest = {
|
|
144
|
+
op: 'find',
|
|
145
|
+
object: objectName,
|
|
146
|
+
args
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
case 'POST':
|
|
151
|
+
// POST /api/data/:object - Create record
|
|
152
|
+
const createBody = req.body || await readBody(req);
|
|
153
|
+
qlRequest = {
|
|
154
|
+
op: 'create',
|
|
155
|
+
object: objectName,
|
|
156
|
+
args: createBody
|
|
157
|
+
};
|
|
158
|
+
break;
|
|
159
|
+
case 'PUT':
|
|
160
|
+
case 'PATCH':
|
|
161
|
+
// PUT /api/data/:object/:id - Update record
|
|
162
|
+
if (!id) {
|
|
163
|
+
sendJSON(res, 400, {
|
|
164
|
+
error: {
|
|
165
|
+
code: types_1.ErrorCode.INVALID_REQUEST,
|
|
166
|
+
message: 'ID is required for update operation'
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const updateBody = req.body || await readBody(req);
|
|
172
|
+
qlRequest = {
|
|
173
|
+
op: 'update',
|
|
174
|
+
object: objectName,
|
|
175
|
+
args: {
|
|
176
|
+
id,
|
|
177
|
+
data: updateBody
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
break;
|
|
181
|
+
case 'DELETE':
|
|
182
|
+
// DELETE /api/data/:object/:id - Delete record
|
|
183
|
+
if (!id) {
|
|
184
|
+
sendJSON(res, 400, {
|
|
185
|
+
error: {
|
|
186
|
+
code: types_1.ErrorCode.INVALID_REQUEST,
|
|
187
|
+
message: 'ID is required for delete operation'
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
qlRequest = {
|
|
193
|
+
op: 'delete',
|
|
194
|
+
object: objectName,
|
|
195
|
+
args: { id }
|
|
196
|
+
};
|
|
197
|
+
break;
|
|
198
|
+
default:
|
|
199
|
+
sendJSON(res, 405, {
|
|
200
|
+
error: {
|
|
201
|
+
code: types_1.ErrorCode.INVALID_REQUEST,
|
|
202
|
+
message: 'Method not allowed'
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
// Execute the request
|
|
208
|
+
const result = await server.handle(qlRequest);
|
|
209
|
+
// Determine HTTP status code
|
|
210
|
+
let statusCode = 200;
|
|
211
|
+
if (result.error) {
|
|
212
|
+
switch (result.error.code) {
|
|
213
|
+
case types_1.ErrorCode.INVALID_REQUEST:
|
|
214
|
+
case types_1.ErrorCode.VALIDATION_ERROR:
|
|
215
|
+
statusCode = 400;
|
|
216
|
+
break;
|
|
217
|
+
case types_1.ErrorCode.UNAUTHORIZED:
|
|
218
|
+
statusCode = 401;
|
|
219
|
+
break;
|
|
220
|
+
case types_1.ErrorCode.FORBIDDEN:
|
|
221
|
+
statusCode = 403;
|
|
222
|
+
break;
|
|
223
|
+
case types_1.ErrorCode.NOT_FOUND:
|
|
224
|
+
statusCode = 404;
|
|
225
|
+
break;
|
|
226
|
+
case types_1.ErrorCode.CONFLICT:
|
|
227
|
+
statusCode = 409;
|
|
228
|
+
break;
|
|
229
|
+
case types_1.ErrorCode.RATE_LIMIT_EXCEEDED:
|
|
230
|
+
statusCode = 429;
|
|
231
|
+
break;
|
|
232
|
+
default:
|
|
233
|
+
statusCode = 500;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else if (method === 'POST') {
|
|
237
|
+
statusCode = 201; // Created
|
|
238
|
+
}
|
|
239
|
+
sendJSON(res, statusCode, result);
|
|
240
|
+
}
|
|
241
|
+
catch (e) {
|
|
242
|
+
console.error('[REST Handler] Error:', e);
|
|
243
|
+
sendJSON(res, 500, {
|
|
244
|
+
error: {
|
|
245
|
+
code: types_1.ErrorCode.INTERNAL_ERROR,
|
|
246
|
+
message: 'Internal server error'
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=rest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../../src/adapters/rest.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -18,8 +18,10 @@ __exportStar(require("./types"), exports);
|
|
|
18
18
|
__exportStar(require("./openapi"), exports);
|
|
19
19
|
__exportStar(require("./server"), exports);
|
|
20
20
|
__exportStar(require("./metadata"), exports);
|
|
21
|
-
__exportStar(require("./
|
|
21
|
+
__exportStar(require("./studio"), exports);
|
|
22
22
|
// We export createNodeHandler from root for convenience,
|
|
23
23
|
// but in the future we might encourage 'import ... from @objectql/server/node'
|
|
24
24
|
__exportStar(require("./adapters/node"), exports);
|
|
25
|
+
// Export REST adapter
|
|
26
|
+
__exportStar(require("./adapters/rest"), exports);
|
|
25
27
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,4CAA0B;AAC1B,2CAAyB;AACzB,6CAA2B;AAC3B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,4CAA0B;AAC1B,2CAAyB;AACzB,6CAA2B;AAC3B,2CAAyB;AACzB,0DAA0D;AAC1D,+EAA+E;AAC/E,kDAAgC;AAChC,sBAAsB;AACtB,kDAAgC"}
|