@mongoosejs/studio 0.5.6 → 0.5.7
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/README.md +35 -3
- package/express.js +8 -1
- package/frontend/public/app.js +37 -15
- package/nest.d.ts +27 -0
- package/nest.js +134 -0
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Mongoose Studio
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An AI-Powered Data Workspace for MongoDB: Turn your MongoDB data into dashboards, maps, and interactive workflows - powered by your Mongoose models.
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
7
|
## Getting Started
|
|
8
8
|
|
|
9
9
|
Mongoose Studio is meant to run as a [sidecar](https://learn.microsoft.com/en-us/azure/architecture/patterns/sidecar) to your Node.js application, using the same Mongoose connection config.
|
|
10
|
-
If your app runs on `acme.app`, Studio will be on `acme.app/studio` or whichever path you prefer.
|
|
11
|
-
For local dev, if your app runs on `localhost:3000`, Studio will be on `localhost:3000/studio`.
|
|
10
|
+
If your app runs on `acme.app`, Mongoose Studio will be on `acme.app/studio` or whichever path you prefer.
|
|
11
|
+
For local dev, if your app runs on `localhost:3000`, Mongoose Studio will be on `localhost:3000/studio`.
|
|
12
12
|
|
|
13
13
|
By default, Mongoose Studio does **not** provide any authentication or authorization.
|
|
14
14
|
You can use Mongoose Studio for free for local development, but we recommend [Mongoose Studio Pro](https://studio.mongoosejs.io/#pricing) for when you want to go into production.
|
|
@@ -85,6 +85,38 @@ const handler = studio(
|
|
|
85
85
|
export default handler;
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
### Nest.js
|
|
89
|
+
|
|
90
|
+
Add `MongooseStudioModule` to your app module as follows.
|
|
91
|
+
Use `getConnectionToken()` so Mongoose Studio uses the same connection that `MongooseModule.forRoot()` creates.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { Module } from '@nestjs/common';
|
|
95
|
+
import { MongooseModule, getConnectionToken } from '@nestjs/mongoose';
|
|
96
|
+
import { MongooseStudioModule } from '@mongoosejs/studio/nest';
|
|
97
|
+
|
|
98
|
+
@Module({
|
|
99
|
+
imports: [
|
|
100
|
+
MongooseModule.forRoot(process.env.MONGODB_URI),
|
|
101
|
+
MongooseStudioModule.forRoot({
|
|
102
|
+
connectionToken: getConnectionToken(),
|
|
103
|
+
apiKey: process.env.MONGOOSE_STUDIO_API_KEY // optional
|
|
104
|
+
})
|
|
105
|
+
]
|
|
106
|
+
})
|
|
107
|
+
export class AppModule {}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
With this setup, Mongoose Studio is available at `/studio`.
|
|
111
|
+
If you mount Mongoose Studio on a different path, update the `path` option as follows.
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
MongooseStudioModule.forRoot({
|
|
115
|
+
path: '/__studio', // Serve on `/__studio` rather than `/studio`
|
|
116
|
+
connectionToken: getConnectionToken()
|
|
117
|
+
})
|
|
118
|
+
```
|
|
119
|
+
|
|
88
120
|
### Netlify
|
|
89
121
|
|
|
90
122
|
[Here is a full example of how to add Mongoose Studio to a Netlify repo](https://github.com/mongoosejs/studio.mongoosejs.io/commit/8b02ea367c8a1b7b4bcab290708f57d58f08210b).
|
package/express.js
CHANGED
|
@@ -9,6 +9,8 @@ const normalizeBindIPOption = require('./backend/helpers/normalizeBindIPOption')
|
|
|
9
9
|
const { toRoute, objectRouter } = require('extrovert');
|
|
10
10
|
const { defaultMothershipURL } = require('./constants');
|
|
11
11
|
|
|
12
|
+
const jsonParser = express.json();
|
|
13
|
+
|
|
12
14
|
module.exports = async function mongooseStudioExpressApp(apiUrl, conn, options) {
|
|
13
15
|
const router = express.Router();
|
|
14
16
|
options = options ? { changeStream: true, ...options } : { changeStream: true };
|
|
@@ -95,7 +97,12 @@ module.exports = async function mongooseStudioExpressApp(apiUrl, conn, options)
|
|
|
95
97
|
return res.status(500).json({ message: err.message });
|
|
96
98
|
});
|
|
97
99
|
},
|
|
98
|
-
|
|
100
|
+
function parseJson(req, res, next) {
|
|
101
|
+
if (req.body !== undefined || req.readable === false) {
|
|
102
|
+
return next();
|
|
103
|
+
}
|
|
104
|
+
return jsonParser(req, res, next);
|
|
105
|
+
},
|
|
99
106
|
objectRouter(backend, toRoute)
|
|
100
107
|
);
|
|
101
108
|
|
package/frontend/public/app.js
CHANGED
|
@@ -12699,7 +12699,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
12699
12699
|
/* harmony export */ });
|
|
12700
12700
|
/* harmony import */ var _vue_shared__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @vue/shared */ "./node_modules/@vue/shared/dist/shared.esm-bundler.js");
|
|
12701
12701
|
/**
|
|
12702
|
-
* @vue/reactivity v3.5.
|
|
12702
|
+
* @vue/reactivity v3.5.38
|
|
12703
12703
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
12704
12704
|
* @license MIT
|
|
12705
12705
|
**/
|
|
@@ -14596,8 +14596,9 @@ function watch(source, cb, options = _vue_shared__WEBPACK_IMPORTED_MODULE_0__.EM
|
|
|
14596
14596
|
if (once && cb) {
|
|
14597
14597
|
const _cb = cb;
|
|
14598
14598
|
cb = (...args) => {
|
|
14599
|
-
_cb(...args);
|
|
14599
|
+
const res = _cb(...args);
|
|
14600
14600
|
watchHandle();
|
|
14601
|
+
return res;
|
|
14601
14602
|
};
|
|
14602
14603
|
}
|
|
14603
14604
|
let oldValue = isMultiSource ? new Array(source.length).fill(INITIAL_WATCHER_VALUE) : INITIAL_WATCHER_VALUE;
|
|
@@ -14607,7 +14608,7 @@ function watch(source, cb, options = _vue_shared__WEBPACK_IMPORTED_MODULE_0__.EM
|
|
|
14607
14608
|
}
|
|
14608
14609
|
if (cb) {
|
|
14609
14610
|
const newValue = effect.run();
|
|
14610
|
-
if (deep || forceTrigger || (isMultiSource ? newValue.some((v, i) => (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.hasChanged)(v, oldValue[i])) : (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.hasChanged)(newValue, oldValue))) {
|
|
14611
|
+
if (immediateFirstRun || deep || forceTrigger || (isMultiSource ? newValue.some((v, i) => (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.hasChanged)(v, oldValue[i])) : (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.hasChanged)(newValue, oldValue))) {
|
|
14611
14612
|
if (cleanup) {
|
|
14612
14613
|
cleanup();
|
|
14613
14614
|
}
|
|
@@ -14867,7 +14868,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
14867
14868
|
/* harmony import */ var _vue_reactivity__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @vue/reactivity */ "./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js");
|
|
14868
14869
|
/* harmony import */ var _vue_shared__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @vue/shared */ "./node_modules/@vue/shared/dist/shared.esm-bundler.js");
|
|
14869
14870
|
/**
|
|
14870
|
-
* @vue/runtime-core v3.5.
|
|
14871
|
+
* @vue/runtime-core v3.5.38
|
|
14871
14872
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
14872
14873
|
* @license MIT
|
|
14873
14874
|
**/
|
|
@@ -17599,13 +17600,21 @@ function defineAsyncComponent(source) {
|
|
|
17599
17600
|
const loaded = (0,_vue_reactivity__WEBPACK_IMPORTED_MODULE_0__.ref)(false);
|
|
17600
17601
|
const error = (0,_vue_reactivity__WEBPACK_IMPORTED_MODULE_0__.ref)();
|
|
17601
17602
|
const delayed = (0,_vue_reactivity__WEBPACK_IMPORTED_MODULE_0__.ref)(!!delay);
|
|
17603
|
+
let timeoutTimer;
|
|
17604
|
+
let delayTimer;
|
|
17605
|
+
onUnmounted(() => {
|
|
17606
|
+
if (timeoutTimer != null) clearTimeout(timeoutTimer);
|
|
17607
|
+
if (delayTimer != null) clearTimeout(delayTimer);
|
|
17608
|
+
});
|
|
17602
17609
|
if (delay) {
|
|
17603
|
-
setTimeout(() => {
|
|
17610
|
+
delayTimer = setTimeout(() => {
|
|
17611
|
+
if (instance.isUnmounted) return;
|
|
17604
17612
|
delayed.value = false;
|
|
17605
17613
|
}, delay);
|
|
17606
17614
|
}
|
|
17607
17615
|
if (timeout != null) {
|
|
17608
|
-
setTimeout(() => {
|
|
17616
|
+
timeoutTimer = setTimeout(() => {
|
|
17617
|
+
if (instance.isUnmounted) return;
|
|
17609
17618
|
if (!loaded.value && !error.value) {
|
|
17610
17619
|
const err = new Error(
|
|
17611
17620
|
`Async component timed out after ${timeout}ms.`
|
|
@@ -17616,11 +17625,16 @@ function defineAsyncComponent(source) {
|
|
|
17616
17625
|
}, timeout);
|
|
17617
17626
|
}
|
|
17618
17627
|
load().then(() => {
|
|
17628
|
+
if (instance.isUnmounted) return;
|
|
17619
17629
|
loaded.value = true;
|
|
17620
17630
|
if (instance.parent && isKeepAlive(instance.parent.vnode)) {
|
|
17621
17631
|
instance.parent.update();
|
|
17622
17632
|
}
|
|
17623
17633
|
}).catch((err) => {
|
|
17634
|
+
if (instance.isUnmounted) {
|
|
17635
|
+
pendingRequest = null;
|
|
17636
|
+
return;
|
|
17637
|
+
}
|
|
17624
17638
|
onError(err);
|
|
17625
17639
|
error.value = err;
|
|
17626
17640
|
});
|
|
@@ -19202,13 +19216,20 @@ function useModel(props, name, options = _vue_shared__WEBPACK_IMPORTED_MODULE_1_
|
|
|
19202
19216
|
return;
|
|
19203
19217
|
}
|
|
19204
19218
|
const rawProps = i.vnode.props;
|
|
19205
|
-
|
|
19206
|
-
(name in rawProps || camelizedName in rawProps || hyphenatedName in rawProps) && (`onUpdate:${name}` in rawProps || `onUpdate:${camelizedName}` in rawProps || `onUpdate:${hyphenatedName}` in rawProps))
|
|
19219
|
+
const hasVModel = !!(rawProps && // check if parent has passed v-model
|
|
19220
|
+
(name in rawProps || camelizedName in rawProps || hyphenatedName in rawProps) && (`onUpdate:${name}` in rawProps || `onUpdate:${camelizedName}` in rawProps || `onUpdate:${hyphenatedName}` in rawProps));
|
|
19221
|
+
if (!hasVModel) {
|
|
19207
19222
|
localValue = value;
|
|
19208
19223
|
trigger();
|
|
19209
19224
|
}
|
|
19210
19225
|
i.emit(`update:${name}`, emittedValue);
|
|
19211
|
-
if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.hasChanged)(value,
|
|
19226
|
+
if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.hasChanged)(value, prevSetValue) && ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.hasChanged)(value, emittedValue) && !(0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.hasChanged)(emittedValue, prevEmittedValue) || // #13524: browsers differ in when they flush microtasks between
|
|
19227
|
+
// event listeners. If a v-model listener emits an intermediate value
|
|
19228
|
+
// and a following listener restores the model to its previous prop
|
|
19229
|
+
// value before parent updates are flushed, the parent render can be
|
|
19230
|
+
// deduped as having no prop change. Force a local update so DOM state
|
|
19231
|
+
// such as an input's value is synchronized back to the current model.
|
|
19232
|
+
hasVModel && prevSetValue !== _vue_shared__WEBPACK_IMPORTED_MODULE_1__.EMPTY_OBJ && !(0,_vue_shared__WEBPACK_IMPORTED_MODULE_1__.hasChanged)(emittedValue, localValue))) {
|
|
19212
19233
|
trigger();
|
|
19213
19234
|
}
|
|
19214
19235
|
prevSetValue = value;
|
|
@@ -23470,7 +23491,7 @@ function isMemoSame(cached, memo) {
|
|
|
23470
23491
|
return true;
|
|
23471
23492
|
}
|
|
23472
23493
|
|
|
23473
|
-
const version = "3.5.
|
|
23494
|
+
const version = "3.5.38";
|
|
23474
23495
|
const warn = true ? warn$1 : 0;
|
|
23475
23496
|
const ErrorTypeStrings = ErrorTypeStrings$1 ;
|
|
23476
23497
|
const devtools = true ? devtools$1 : 0;
|
|
@@ -23681,7 +23702,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
23681
23702
|
/* harmony import */ var _vue_runtime_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @vue/runtime-core */ "./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js");
|
|
23682
23703
|
/* harmony import */ var _vue_runtime_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @vue/shared */ "./node_modules/@vue/shared/dist/shared.esm-bundler.js");
|
|
23683
23704
|
/**
|
|
23684
|
-
* @vue/runtime-dom v3.5.
|
|
23705
|
+
* @vue/runtime-dom v3.5.38
|
|
23685
23706
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
23686
23707
|
* @license MIT
|
|
23687
23708
|
**/
|
|
@@ -25143,7 +25164,8 @@ const TransitionGroupImpl = /* @__PURE__ */ decorate({
|
|
|
25143
25164
|
if (children) {
|
|
25144
25165
|
for (let i = 0; i < children.length; i++) {
|
|
25145
25166
|
const child = children[i];
|
|
25146
|
-
if (child.el && child.el instanceof Element
|
|
25167
|
+
if (child.el && child.el instanceof Element && // Hidden v-show nodes have no previous layout box to animate from.
|
|
25168
|
+
!child.el[vShowHidden]) {
|
|
25147
25169
|
prevChildren.push(child);
|
|
25148
25170
|
(0,_vue_runtime_core__WEBPACK_IMPORTED_MODULE_0__.setTransitionHooks)(
|
|
25149
25171
|
child,
|
|
@@ -25779,7 +25801,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
25779
25801
|
/* harmony export */ toTypeString: () => (/* binding */ toTypeString)
|
|
25780
25802
|
/* harmony export */ });
|
|
25781
25803
|
/**
|
|
25782
|
-
* @vue/shared v3.5.
|
|
25804
|
+
* @vue/shared v3.5.38
|
|
25783
25805
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
25784
25806
|
* @license MIT
|
|
25785
25807
|
**/
|
|
@@ -51610,7 +51632,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
51610
51632
|
/* harmony import */ var _vue_runtime_dom__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @vue/runtime-dom */ "./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js");
|
|
51611
51633
|
/* harmony import */ var _vue_runtime_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @vue/runtime-dom */ "./node_modules/@vue/runtime-dom/dist/runtime-dom.esm-bundler.js");
|
|
51612
51634
|
/**
|
|
51613
|
-
* vue v3.5.
|
|
51635
|
+
* vue v3.5.38
|
|
51614
51636
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
51615
51637
|
* @license MIT
|
|
51616
51638
|
**/
|
|
@@ -64953,7 +64975,7 @@ var src_default = VueToastificationPlugin;
|
|
|
64953
64975
|
(module) {
|
|
64954
64976
|
|
|
64955
64977
|
"use strict";
|
|
64956
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.5.
|
|
64978
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@mongoosejs/studio","version":"0.5.7","description":"AI-Powered Data Workspace for MongoDB: Turn your MongoDB data into dashboards, maps, and interactive workflows - powered by your Mongoose models and AI.","homepage":"https://mongoosestudio.app/","repository":{"type":"git","url":"https://github.com/mongoosejs/studio"},"license":"Apache-2.0","dependencies":{"@ai-sdk/anthropic":"2.x","@ai-sdk/google":"2.x","@ai-sdk/openai":"2.x","ace-builds":"^1.43.6","ai":"5.x","archetype":"0.13.1","csv-stringify":"6.3.0","ejson":"^2.2.3","extrovert":"^0.2.0","marked":"15.0.12","mpath":"^0.9.0","node-inspect-extracted":"3.x","regexp.escape":"^2.0.1","tailwindcss":"3.4.0","time-commando":"1.0.1","typescript":"^6.0.2","vue":"3.x","vue-toastification":"^2.0.0-rc.5","webpack":"5.x","xss":"^1.0.15"},"peerDependencies":{"@nestjs/common":"10.x || 11.x","mongoose":"7.x || 8.x || ^9.0.0"},"peerDependenciesMeta":{"@nestjs/common":{"optional":true}},"optionalPeerDependencies":{"@mongoosejs/task":"0.5.x || 0.6.x"},"devDependencies":{"@masteringjs/eslint-config":"0.1.1","axios":"1.2.2","dedent":"^1.6.0","eslint":"9.30.0","@nestjs/common":"^11.1.9","express":"4.x","mocha":"10.2.0","mongodb-memory-server":"^11.0.1","mongoose":"9.x","sinon":"^21.0.1"},"scripts":{"lint":"eslint .","seed":"node seed/index.js","start":"node ./local.js","tailwind":"tailwindcss -o ./frontend/public/tw.css","tailwind:watch":"tailwindcss -o ./frontend/public/tw.css --watch","test":"mocha test/*.test.js","test:frontend":"mocha test/frontend/*.test.js","eval:agent":"node eval/agent/run.js"}}');
|
|
64957
64979
|
|
|
64958
64980
|
/***/ }
|
|
64959
64981
|
|
package/nest.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
declare module '@mongoosejs/studio/nest' {
|
|
2
|
+
import { DynamicModule, MiddlewareConsumer, NestModule } from '@nestjs/common';
|
|
3
|
+
import { Connection, Mongoose } from 'mongoose';
|
|
4
|
+
|
|
5
|
+
export interface MongooseStudioModuleOptions {
|
|
6
|
+
path?: string;
|
|
7
|
+
apiPath?: string;
|
|
8
|
+
connection?: Connection | Mongoose;
|
|
9
|
+
connectionToken?: string | symbol | Function;
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
bindIp?: string | string[] | null;
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface MongooseStudioModuleAsyncOptions {
|
|
16
|
+
imports?: any[];
|
|
17
|
+
inject?: any[];
|
|
18
|
+
connectionToken?: string | symbol | Function;
|
|
19
|
+
useFactory: (...args: any[]) => Promise<MongooseStudioModuleOptions> | MongooseStudioModuleOptions;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class MongooseStudioModule implements NestModule {
|
|
23
|
+
configure(consumer: MiddlewareConsumer): void;
|
|
24
|
+
static forRoot(options?: MongooseStudioModuleOptions): DynamicModule;
|
|
25
|
+
static forRootAsync(options: MongooseStudioModuleAsyncOptions): DynamicModule;
|
|
26
|
+
}
|
|
27
|
+
}
|
package/nest.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Inject, Module, RequestMethod } = require('@nestjs/common');
|
|
4
|
+
const mongoose = require('mongoose');
|
|
5
|
+
const createExpressRouter = require('./express');
|
|
6
|
+
|
|
7
|
+
const MONGOOSE_STUDIO_OPTIONS = Symbol('MONGOOSE_STUDIO_OPTIONS');
|
|
8
|
+
const MONGOOSE_STUDIO_CONNECTION = Symbol('MONGOOSE_STUDIO_CONNECTION');
|
|
9
|
+
const MONGOOSE_STUDIO_EXPRESS_ROUTER = Symbol('MONGOOSE_STUDIO_EXPRESS_ROUTER');
|
|
10
|
+
|
|
11
|
+
class MongooseStudioModule {
|
|
12
|
+
constructor(options, expressRouter) {
|
|
13
|
+
this.options = options || {};
|
|
14
|
+
this.expressRouter = expressRouter;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
configure(consumer) {
|
|
18
|
+
const mountPath = this.options.path || '/studio';
|
|
19
|
+
|
|
20
|
+
consumer
|
|
21
|
+
.apply((req, res, next) => {
|
|
22
|
+
if (!isMountedStudioRequest(req, mountPath)) {
|
|
23
|
+
return next();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const originalUrl = req.url;
|
|
27
|
+
req.url = req.url.slice(normalizeExpressMountPath(mountPath).length) || '/';
|
|
28
|
+
try {
|
|
29
|
+
return this.expressRouter(req, res, err => {
|
|
30
|
+
req.url = originalUrl;
|
|
31
|
+
next(err);
|
|
32
|
+
});
|
|
33
|
+
} finally {
|
|
34
|
+
req.url = originalUrl;
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
.forRoutes({
|
|
38
|
+
path: '*path',
|
|
39
|
+
method: RequestMethod.ALL
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static forRoot(options) {
|
|
44
|
+
options = options || {};
|
|
45
|
+
const providers = [
|
|
46
|
+
{ provide: MONGOOSE_STUDIO_OPTIONS, useValue: options },
|
|
47
|
+
createExpressRouterProvider()
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
if (options.connectionToken) {
|
|
51
|
+
providers.push({ provide: MONGOOSE_STUDIO_CONNECTION, useExisting: options.connectionToken });
|
|
52
|
+
} else if (options.connection) {
|
|
53
|
+
providers.push({ provide: MONGOOSE_STUDIO_CONNECTION, useValue: options.connection });
|
|
54
|
+
} else {
|
|
55
|
+
providers.push({ provide: MONGOOSE_STUDIO_CONNECTION, useValue: mongoose });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
module: MongooseStudioModule,
|
|
60
|
+
providers,
|
|
61
|
+
exports: providers
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static forRootAsync(options) {
|
|
66
|
+
options = options || {};
|
|
67
|
+
const providers = [
|
|
68
|
+
{
|
|
69
|
+
provide: MONGOOSE_STUDIO_OPTIONS,
|
|
70
|
+
useFactory: options.useFactory,
|
|
71
|
+
inject: options.inject || []
|
|
72
|
+
},
|
|
73
|
+
createExpressRouterProvider()
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
if (options.connectionToken) {
|
|
77
|
+
providers.push({ provide: MONGOOSE_STUDIO_CONNECTION, useExisting: options.connectionToken });
|
|
78
|
+
} else if (options.connection) {
|
|
79
|
+
providers.push({ provide: MONGOOSE_STUDIO_CONNECTION, useValue: options.connection });
|
|
80
|
+
} else {
|
|
81
|
+
providers.push({ provide: MONGOOSE_STUDIO_CONNECTION, useValue: mongoose });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
module: MongooseStudioModule,
|
|
86
|
+
imports: options.imports || [],
|
|
87
|
+
providers,
|
|
88
|
+
exports: providers
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function createExpressRouterProvider() {
|
|
94
|
+
return {
|
|
95
|
+
provide: MONGOOSE_STUDIO_EXPRESS_ROUTER,
|
|
96
|
+
useFactory: async(options, connection) => {
|
|
97
|
+
options = options || {};
|
|
98
|
+
const mountPath = options.path || '/studio';
|
|
99
|
+
const apiPath = options.apiPath || `${mountPath}/api`;
|
|
100
|
+
const studioOptions = { ...options };
|
|
101
|
+
delete studioOptions.path;
|
|
102
|
+
delete studioOptions.apiPath;
|
|
103
|
+
delete studioOptions.connection;
|
|
104
|
+
delete studioOptions.connectionToken;
|
|
105
|
+
|
|
106
|
+
return createExpressRouter(apiPath, options.connection || connection || mongoose, studioOptions);
|
|
107
|
+
},
|
|
108
|
+
inject: [MONGOOSE_STUDIO_OPTIONS, MONGOOSE_STUDIO_CONNECTION]
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isMountedStudioRequest(req, mountPath) {
|
|
113
|
+
const normalizedMountPath = normalizeExpressMountPath(mountPath);
|
|
114
|
+
return req.url === normalizedMountPath ||
|
|
115
|
+
req.url.startsWith(`${normalizedMountPath}/`) ||
|
|
116
|
+
req.url.startsWith(`${normalizedMountPath}?`) ||
|
|
117
|
+
req.url.startsWith(`${normalizedMountPath}#`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function normalizeExpressMountPath(path) {
|
|
121
|
+
path = `/${path.replace(/^\/+/, '').replace(/\/+$/, '')}`;
|
|
122
|
+
return path === '/' ? '' : path;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
Inject(MONGOOSE_STUDIO_OPTIONS)(MongooseStudioModule, undefined, 0);
|
|
126
|
+
Inject(MONGOOSE_STUDIO_EXPRESS_ROUTER)(MongooseStudioModule, undefined, 1);
|
|
127
|
+
Module({})(MongooseStudioModule);
|
|
128
|
+
|
|
129
|
+
module.exports = {
|
|
130
|
+
MONGOOSE_STUDIO_CONNECTION,
|
|
131
|
+
MONGOOSE_STUDIO_EXPRESS_ROUTER,
|
|
132
|
+
MONGOOSE_STUDIO_OPTIONS,
|
|
133
|
+
MongooseStudioModule
|
|
134
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mongoosejs/studio",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.7",
|
|
4
4
|
"description": "AI-Powered Data Workspace for MongoDB: Turn your MongoDB data into dashboards, maps, and interactive workflows - powered by your Mongoose models and AI.",
|
|
5
5
|
"homepage": "https://mongoosestudio.app/",
|
|
6
6
|
"repository": {
|
|
@@ -31,8 +31,14 @@
|
|
|
31
31
|
"xss": "^1.0.15"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
+
"@nestjs/common": "10.x || 11.x",
|
|
34
35
|
"mongoose": "7.x || 8.x || ^9.0.0"
|
|
35
36
|
},
|
|
37
|
+
"peerDependenciesMeta": {
|
|
38
|
+
"@nestjs/common": {
|
|
39
|
+
"optional": true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
36
42
|
"optionalPeerDependencies": {
|
|
37
43
|
"@mongoosejs/task": "0.5.x || 0.6.x"
|
|
38
44
|
},
|
|
@@ -41,6 +47,7 @@
|
|
|
41
47
|
"axios": "1.2.2",
|
|
42
48
|
"dedent": "^1.6.0",
|
|
43
49
|
"eslint": "9.30.0",
|
|
50
|
+
"@nestjs/common": "^11.1.9",
|
|
44
51
|
"express": "4.x",
|
|
45
52
|
"mocha": "10.2.0",
|
|
46
53
|
"mongodb-memory-server": "^11.0.1",
|