@get-enlace/nest 0.0.1
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/dist/constants.d.ts +2 -0
- package/dist/constants.js +2 -0
- package/dist/enlace.controller.d.ts +15 -0
- package/dist/enlace.controller.js +44 -0
- package/dist/enlace.module.d.ts +36 -0
- package/dist/enlace.module.js +70 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/specLoader.d.ts +6 -0
- package/dist/specLoader.js +17 -0
- package/package.json +57 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EnlaceOptions } from './enlace.module.js';
|
|
2
|
+
/**
|
|
3
|
+
* Serves the raw OpenAPI document at `<mount>/api/spec`. Read fresh on each
|
|
4
|
+
* request, not cached — matches the "not stored, read fresh each load" rule
|
|
5
|
+
* from ARCHITECTURE.md §4, same as the express adapter's `/api/spec` route.
|
|
6
|
+
*
|
|
7
|
+
* This is the only route this adapter defines — per ARCHITECTURE.md's MVP
|
|
8
|
+
* model, execution runs entirely client-side in @get-enlace/ui, so there's
|
|
9
|
+
* no `/api/run` or `/api/credentials` here at all.
|
|
10
|
+
*/
|
|
11
|
+
export declare class EnlaceController {
|
|
12
|
+
private readonly options;
|
|
13
|
+
constructor(options: EnlaceOptions);
|
|
14
|
+
getSpec(): Record<string, any>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { Controller, Get, Inject } from '@nestjs/common';
|
|
14
|
+
import { ENLACE_OPTIONS } from './constants.js';
|
|
15
|
+
import { loadSpec } from './specLoader.js';
|
|
16
|
+
/**
|
|
17
|
+
* Serves the raw OpenAPI document at `<mount>/api/spec`. Read fresh on each
|
|
18
|
+
* request, not cached — matches the "not stored, read fresh each load" rule
|
|
19
|
+
* from ARCHITECTURE.md §4, same as the express adapter's `/api/spec` route.
|
|
20
|
+
*
|
|
21
|
+
* This is the only route this adapter defines — per ARCHITECTURE.md's MVP
|
|
22
|
+
* model, execution runs entirely client-side in @get-enlace/ui, so there's
|
|
23
|
+
* no `/api/run` or `/api/credentials` here at all.
|
|
24
|
+
*/
|
|
25
|
+
let EnlaceController = class EnlaceController {
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
}
|
|
29
|
+
getSpec() {
|
|
30
|
+
return loadSpec(this.options.spec);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
__decorate([
|
|
34
|
+
Get('spec'),
|
|
35
|
+
__metadata("design:type", Function),
|
|
36
|
+
__metadata("design:paramtypes", []),
|
|
37
|
+
__metadata("design:returntype", void 0)
|
|
38
|
+
], EnlaceController.prototype, "getSpec", null);
|
|
39
|
+
EnlaceController = __decorate([
|
|
40
|
+
Controller('api'),
|
|
41
|
+
__param(0, Inject(ENLACE_OPTIONS)),
|
|
42
|
+
__metadata("design:paramtypes", [Object])
|
|
43
|
+
], EnlaceController);
|
|
44
|
+
export { EnlaceController };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DynamicModule } from '@nestjs/common';
|
|
2
|
+
import type { SpecSource } from './specLoader.js';
|
|
3
|
+
export interface EnlaceOptions {
|
|
4
|
+
/** A file/URL path or an already-parsed object — the only input this needs is a valid OpenAPI 3.x document, however it's produced or served. */
|
|
5
|
+
spec: SpecSource;
|
|
6
|
+
/**
|
|
7
|
+
* Mount path for the canvas, e.g. `'enlace'` serves the UI at `/enlace`
|
|
8
|
+
* and the spec at `/enlace/api/spec`. Defaults to `'enlace'`.
|
|
9
|
+
*
|
|
10
|
+
* Nest controller prefixes are fixed at decorator time, so this can't
|
|
11
|
+
* vary per `forRoot()` call the way the express adapter's `app.use(path,
|
|
12
|
+
* enlace(...))` does — it's applied via `RouterModule.register()` instead,
|
|
13
|
+
* the standard Nest pattern for a dynamic module with a configurable
|
|
14
|
+
* route prefix.
|
|
15
|
+
*/
|
|
16
|
+
path?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Mounts the Enlace canvas.
|
|
20
|
+
*
|
|
21
|
+
* @Module({ imports: [EnlaceModule.forRoot({ spec })] })
|
|
22
|
+
* export class AppModule {}
|
|
23
|
+
*
|
|
24
|
+
* This adapter's job is deliberately small — per ARCHITECTURE.md's MVP
|
|
25
|
+
* model, execution runs entirely client-side in @get-enlace/ui, so there's
|
|
26
|
+
* no `/api/run` or `/api/credentials` here at all. All this does is:
|
|
27
|
+
* - serve the raw OpenAPI document (parsed into an Operation[] list
|
|
28
|
+
* client-side, not here — see @get-enlace/ui's engine/specParser.ts),
|
|
29
|
+
* via EnlaceController
|
|
30
|
+
* - serve the built UI bundle, via @nestjs/serve-static (platform-
|
|
31
|
+
* agnostic — works whether the host app runs Nest's Express or Fastify
|
|
32
|
+
* adapter, unlike @get-enlace/express's direct `express.static` use)
|
|
33
|
+
*/
|
|
34
|
+
export declare class EnlaceModule {
|
|
35
|
+
static forRoot(options: EnlaceOptions): DynamicModule;
|
|
36
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var EnlaceModule_1;
|
|
8
|
+
import { Module } from '@nestjs/common';
|
|
9
|
+
import { RouterModule } from '@nestjs/core';
|
|
10
|
+
import { ServeStaticModule } from '@nestjs/serve-static';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { createRequire } from 'node:module';
|
|
13
|
+
import { ENLACE_OPTIONS } from './constants.js';
|
|
14
|
+
import { EnlaceController } from './enlace.controller.js';
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
/**
|
|
17
|
+
* Mounts the Enlace canvas.
|
|
18
|
+
*
|
|
19
|
+
* @Module({ imports: [EnlaceModule.forRoot({ spec })] })
|
|
20
|
+
* export class AppModule {}
|
|
21
|
+
*
|
|
22
|
+
* This adapter's job is deliberately small — per ARCHITECTURE.md's MVP
|
|
23
|
+
* model, execution runs entirely client-side in @get-enlace/ui, so there's
|
|
24
|
+
* no `/api/run` or `/api/credentials` here at all. All this does is:
|
|
25
|
+
* - serve the raw OpenAPI document (parsed into an Operation[] list
|
|
26
|
+
* client-side, not here — see @get-enlace/ui's engine/specParser.ts),
|
|
27
|
+
* via EnlaceController
|
|
28
|
+
* - serve the built UI bundle, via @nestjs/serve-static (platform-
|
|
29
|
+
* agnostic — works whether the host app runs Nest's Express or Fastify
|
|
30
|
+
* adapter, unlike @get-enlace/express's direct `express.static` use)
|
|
31
|
+
*/
|
|
32
|
+
let EnlaceModule = EnlaceModule_1 = class EnlaceModule {
|
|
33
|
+
static forRoot(options) {
|
|
34
|
+
const mountPath = options.path ?? 'enlace';
|
|
35
|
+
// Resolved via Node's own module resolution against the installed
|
|
36
|
+
// `@get-enlace/ui` package (a real dependency, see package.json) — not a
|
|
37
|
+
// relative path into this monorepo — so this works identically whether
|
|
38
|
+
// `@get-enlace/ui` got here via an npm workspace symlink (local dev) or
|
|
39
|
+
// a real `node_modules` install (anyone who installs @get-enlace/nest on
|
|
40
|
+
// its own). There's nothing to copy or build into this package itself;
|
|
41
|
+
// the bundle lives wherever @get-enlace/ui's own "files" field ships it
|
|
42
|
+
// (dist/), and it must already be built (`npm run build --workspace
|
|
43
|
+
// @get-enlace/ui`) before this resolves.
|
|
44
|
+
const uiPackageJson = require.resolve('@get-enlace/ui/package.json');
|
|
45
|
+
const uiDist = path.join(path.dirname(uiPackageJson), 'dist');
|
|
46
|
+
return {
|
|
47
|
+
module: EnlaceModule_1,
|
|
48
|
+
imports: [
|
|
49
|
+
ServeStaticModule.forRoot({
|
|
50
|
+
rootPath: uiDist,
|
|
51
|
+
serveRoot: `/${mountPath}`,
|
|
52
|
+
// Keeps the static middleware from shadowing EnlaceController's
|
|
53
|
+
// `/api/spec` route. `{*splat}` is path-to-regexp v8's wildcard
|
|
54
|
+
// syntax (the version @nestjs/serve-static v5 bundles) — the
|
|
55
|
+
// older unnamed `(.*)` capture group it replaces silently 500s
|
|
56
|
+
// instead of matching, since it's now invalid syntax rather than
|
|
57
|
+
// just non-matching.
|
|
58
|
+
exclude: [`/${mountPath}/api/{*splat}`],
|
|
59
|
+
}),
|
|
60
|
+
RouterModule.register([{ path: mountPath, module: EnlaceModule_1 }]),
|
|
61
|
+
],
|
|
62
|
+
controllers: [EnlaceController],
|
|
63
|
+
providers: [{ provide: ENLACE_OPTIONS, useValue: options }],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
EnlaceModule = EnlaceModule_1 = __decorate([
|
|
68
|
+
Module({})
|
|
69
|
+
], EnlaceModule);
|
|
70
|
+
export { EnlaceModule };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EnlaceModule } from './enlace.module.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { extname } from 'node:path';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
/**
|
|
5
|
+
* Reads an OpenAPI 3.x document from a file/URL path or accepts an already-
|
|
6
|
+
* parsed object directly.
|
|
7
|
+
*/
|
|
8
|
+
export function loadSpec(source) {
|
|
9
|
+
if (typeof source !== 'string')
|
|
10
|
+
return source;
|
|
11
|
+
const raw = readFileSync(source, 'utf-8');
|
|
12
|
+
const ext = extname(source);
|
|
13
|
+
if (ext === '.yaml' || ext === '.yml') {
|
|
14
|
+
return yaml.load(raw);
|
|
15
|
+
}
|
|
16
|
+
return JSON.parse(raw);
|
|
17
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@get-enlace/nest",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"description": "Simple NestJS adapter for @get-enlace/ui. Early dev preview: no persistence yet (serves the spec + UI bundle only), install via the `dev` dist-tag on GitHub Packages.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/get-enlace/enlace-js.git",
|
|
10
|
+
"directory": "packages/enlace-nest"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"registry": "https://npm.pkg.github.com"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -p tsconfig.json",
|
|
29
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
30
|
+
"test": "vitest run"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
34
|
+
"@nestjs/core": "^10.0.0 || ^11.0.0",
|
|
35
|
+
"@nestjs/serve-static": "^4.0.0 || ^5.0.0",
|
|
36
|
+
"reflect-metadata": "^0.1.13 || ^0.2.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@get-enlace/ui": "0.0.1",
|
|
40
|
+
"js-yaml": "^4.1.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@nestjs/common": "^11.2.1",
|
|
44
|
+
"@nestjs/core": "^11.2.1",
|
|
45
|
+
"@nestjs/platform-express": "^11.2.1",
|
|
46
|
+
"@nestjs/serve-static": "^5.0.5",
|
|
47
|
+
"@nestjs/testing": "^11.2.1",
|
|
48
|
+
"@types/js-yaml": "^4.0.9",
|
|
49
|
+
"@types/node": "^20.19.43",
|
|
50
|
+
"@types/supertest": "^7.2.1",
|
|
51
|
+
"reflect-metadata": "^0.2.2",
|
|
52
|
+
"rxjs": "^7.8.2",
|
|
53
|
+
"supertest": "^7.2.2",
|
|
54
|
+
"typescript": "^5.5.4",
|
|
55
|
+
"vitest": "^4.1.11"
|
|
56
|
+
}
|
|
57
|
+
}
|