@transomjs/transom-scaffold 5.0.0 → 7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @transomjs/transom-scaffold change log
2
2
 
3
+ ## 7.0.1
4
+ - Fixed: the `@transomjs/transom-core` peer dependency was still `^5.0.1`, so npm refused to
5
+ install transom-scaffold 7 alongside transom-core 7. It's now `^7.0.0`.
6
+
7
+ ## 7.0.0
8
+ - Dev tools: mocha 12, chai 6, c8 12, sinon 22, cross-env 10, open-cli 9; tests run against
9
+ transom-core 7. The unused shelljs is removed. Express (and `@types/express`) stay on 4 to
10
+ match transom-core, which provides the Express app.
11
+ - **Requires Node.js 22 or newer** (`engines.node` is `>=22`). The compiled code targets ES2023,
12
+ and CI runs on Node 22 and 24.
13
+ - Rewritten in TypeScript, with type definitions. The compiled code is in `dist/`;
14
+ `require("@transomjs/transom-scaffold")` and `.../lib/scaffoldHandler` return the same
15
+ things as before, and static folders are still resolved from the application's root.
16
+ - Types: `Definition` (the `definition.scaffold` section), `StaticRoute`, `RedirectRoute`,
17
+ `TemplateRoute`, `Options` and `Handler`. `@types/express` is now a dependency, since the
18
+ types build on it.
19
+
3
20
  ## 2.0.0
4
21
  - **BREAKING CHANGE**: Updated for Transom Core v5+ Express compatibility
5
22
  - Replaced Restify dependencies with Express static middleware
package/README.md CHANGED
@@ -3,8 +3,7 @@ Add routes for static assets, redirects and template based content to your Trans
3
3
 
4
4
  **Version 2.0+ is compatible with Transom Core v5+ (Express-based) while maintaining backward compatibility.**
5
5
 
6
- [![Build Status](https://travis-ci.org/transomjs/transom-scaffold.svg?branch=master)](https://travis-ci.org/transomjs/transom-scaffold)
7
- [![Coverage Status](https://coveralls.io/repos/github/transomjs/transom-scaffold/badge.svg?branch=master)](https://coveralls.io/github/transomjs/transom-scaffold?branch=master)
6
+ [![CI](https://github.com/transomjs/transom-scaffold/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/transomjs/transom-scaffold/actions/workflows/ci.yml)
8
7
 
9
8
  ## Installation
10
9
 
@@ -0,0 +1,47 @@
1
+ import ScaffoldHandler = require("./lib/scaffoldHandler");
2
+ /** The parts of the transom-core server this plugin uses. Any transom-core server fits. */
3
+ interface ScaffoldPluginServer extends ScaffoldHandler.RouteServer {
4
+ registry: ScaffoldHandler.RouteServer["registry"] & {
5
+ get(key: string, defaultValue: object): unknown;
6
+ set(key: string, value: unknown): void;
7
+ };
8
+ }
9
+ /** Plugin options, from transom.configure(). */
10
+ interface ScaffoldOptions {
11
+ /** The registry key for the route helpers. Defaults to "transomScaffold". */
12
+ registryKey?: string;
13
+ /** The registry key of the template renderer. Defaults to "transomTemplate". */
14
+ templateHandler?: string;
15
+ /** Set by the plugin: a copy of the API definition's scaffold section. */
16
+ scaffold?: ScaffoldDefinition;
17
+ }
18
+ /**
19
+ * The API definition's `definition.scaffold` section. `staticRoutes` and `redirectRoutes`
20
+ * take one route or a list; every other entry is a template route named by its key.
21
+ */
22
+ interface ScaffoldDefinition {
23
+ staticRoutes?: ScaffoldHandler.StaticRoute | ScaffoldHandler.StaticRoute[];
24
+ redirectRoutes?: ScaffoldHandler.RedirectRoute | ScaffoldHandler.RedirectRoute[];
25
+ [templateRoute: string]: ScaffoldHandler.TemplateRouteDefinition | ScaffoldHandler.StaticRoute | ScaffoldHandler.StaticRoute[] | ScaffoldHandler.RedirectRoute | ScaffoldHandler.RedirectRoute[] | undefined;
26
+ }
27
+ /**
28
+ * Adds static asset, redirect and template routes from the API definition's
29
+ * `definition.scaffold` section, and registers the route helpers.
30
+ */
31
+ declare class TransomScaffold {
32
+ initialize: (server: ScaffoldPluginServer, options: ScaffoldOptions) => Promise<void>;
33
+ }
34
+ /** The plugin instance, as `require("@transomjs/transom-scaffold")` has always returned. */
35
+ declare const transomScaffold: TransomScaffold;
36
+ declare namespace transomScaffold {
37
+ type Options = ScaffoldOptions;
38
+ type Definition = ScaffoldDefinition;
39
+ type StaticRoute = ScaffoldHandler.StaticRoute;
40
+ type RedirectRoute = ScaffoldHandler.RedirectRoute;
41
+ type TemplateRoute = ScaffoldHandler.TemplateRouteDefinition;
42
+ type RestifyServeStatic = ScaffoldHandler.RestifyServeStatic;
43
+ type Handler = ScaffoldHandler.Handler;
44
+ type PluginServer = ScaffoldPluginServer;
45
+ }
46
+ export = transomScaffold;
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,eAAe,GAAG,QAAQ,uBAAuB,CAAC,CAAC;AAI1D,2FAA2F;AAC3F,UAAU,oBAAqB,SAAQ,eAAe,CAAC,WAAW;IAChE,QAAQ,EAAE,eAAe,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG;QAClD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAChD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;KACxC,CAAC;CACH;AAED,gDAAgD;AAChD,UAAU,eAAe;IACvB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;GAGG;AACH,UAAU,kBAAkB;IAC1B,YAAY,CAAC,EAAE,eAAe,CAAC,WAAW,GAAG,eAAe,CAAC,WAAW,EAAE,CAAC;IAC3E,cAAc,CAAC,EAAE,eAAe,CAAC,aAAa,GAAG,eAAe,CAAC,aAAa,EAAE,CAAC;IACjF,CAAC,aAAa,EAAE,MAAM,GAClB,eAAe,CAAC,uBAAuB,GACvC,eAAe,CAAC,WAAW,GAC3B,eAAe,CAAC,WAAW,EAAE,GAC7B,eAAe,CAAC,aAAa,GAC7B,eAAe,CAAC,aAAa,EAAE,GAC/B,SAAS,CAAC;CACf;AAMD;;;GAGG;AACH,cAAM,eAAe;IACnB,UAAU,WAAY,oBAAoB,WAAW,eAAe,KAAG,OAAO,CAAC,IAAI,CAAC,CA2ClF;CACH;AAED,4FAA4F;AAC5F,QAAA,MAAM,eAAe,iBAAwB,CAAC;AAE9C,OAAO,WAAW,eAAe,CAAC;IAChC,KAAK,OAAO,GAAG,eAAe,CAAC;IAC/B,KAAK,UAAU,GAAG,kBAAkB,CAAC;IACrC,KAAK,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC;IAC/C,KAAK,aAAa,GAAG,eAAe,CAAC,aAAa,CAAC;IACnD,KAAK,aAAa,GAAG,eAAe,CAAC,uBAAuB,CAAC;IAC7D,KAAK,kBAAkB,GAAG,eAAe,CAAC,kBAAkB,CAAC;IAC7D,KAAK,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC;IACvC,KAAK,YAAY,GAAG,oBAAoB,CAAC;CAC1C;SAEQ,eAAe"}
package/dist/index.js ADDED
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ const debug_1 = __importDefault(require("debug"));
6
+ const ScaffoldHandler = require("./lib/scaffoldHandler");
7
+ const debug = (0, debug_1.default)("transom:scaffold");
8
+ function asList(value) {
9
+ return Array.isArray(value) ? value : [value];
10
+ }
11
+ /**
12
+ * Adds static asset, redirect and template routes from the API definition's
13
+ * `definition.scaffold` section, and registers the route helpers.
14
+ */
15
+ class TransomScaffold {
16
+ initialize = (server, options) => {
17
+ return new Promise(function (resolve) {
18
+ // Boundary: the API definition's scaffold section.
19
+ const scaffoldDefn = server.registry.get("transom-config.definition.scaffold", {});
20
+ const scaffolds = Object.assign({}, scaffoldDefn);
21
+ options.scaffold = scaffolds;
22
+ const scaffoldHandler = ScaffoldHandler(server);
23
+ server.registry.set(options.registryKey || "transomScaffold", scaffoldHandler);
24
+ // Add simple get routes to fetch scaffolded content.
25
+ Object.keys(scaffolds).map(function (key) {
26
+ if (key === "staticRoutes") {
27
+ const staticRoutes = scaffolds.staticRoutes;
28
+ if (staticRoutes === undefined) {
29
+ return;
30
+ }
31
+ asList(staticRoutes).map(function (route) {
32
+ debug(`Setting up '${route.path}' as a static asset route`);
33
+ scaffoldHandler.addStaticAssetRoute(server, route);
34
+ });
35
+ }
36
+ else if (key === "redirectRoutes") {
37
+ const redirectRoutes = scaffolds.redirectRoutes;
38
+ if (redirectRoutes === undefined) {
39
+ return;
40
+ }
41
+ asList(redirectRoutes).map(function (route) {
42
+ debug(`Setting up '${route.path}' as a redirect route`);
43
+ scaffoldHandler.addRedirectRoute(server, route);
44
+ });
45
+ }
46
+ else {
47
+ // Boundary: every other key is a template route. Its defaults are filled in
48
+ // place, on the definition's own object, as before.
49
+ const scaffold = scaffolds[key];
50
+ scaffold.path = scaffold.path || `/${key.toLowerCase()}`;
51
+ scaffold.templateName = scaffold.templateName || key;
52
+ scaffold.templateHandler = options.templateHandler || "transomTemplate";
53
+ debug(`Setting up '${scaffold.path}' as a template route to ${scaffold.templateName}`);
54
+ scaffoldHandler.addTemplateRoute(server, scaffold);
55
+ }
56
+ });
57
+ resolve();
58
+ });
59
+ };
60
+ }
61
+ /** The plugin instance, as `require("@transomjs/transom-scaffold")` has always returned. */
62
+ const transomScaffold = new TransomScaffold();
63
+ module.exports = transomScaffold;
64
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,kDAAgC;AAChC,MAAO,eAAe,oCAAoC;AAE1D,MAAM,KAAK,GAAG,IAAA,eAAW,EAAC,kBAAkB,CAAC,CAAC;AAoC9C,SAAS,MAAM,CAAI,KAAc;IAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,eAAe;IACnB,UAAU,GAAG,CAAC,MAA4B,EAAE,OAAwB,EAAiB,EAAE;QACrF,OAAO,IAAI,OAAO,CAAO,UAAU,OAAO;YACxC,mDAAmD;YACnD,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,oCAAoC,EAAE,EAAE,CAAuB,CAAC;YACzG,MAAM,SAAS,GAAuB,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;YACtE,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;YAE7B,MAAM,eAAe,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,iBAAiB,EAAE,eAAe,CAAC,CAAC;YAE/E,qDAAqD;YACrD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,UAAU,GAAG;gBACtC,IAAI,GAAG,KAAK,cAAc,EAAE,CAAC;oBAC3B,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,CAAC;oBAC5C,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;wBAC/B,OAAO;oBACT,CAAC;oBACD,MAAM,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,UAAU,KAAK;wBACtC,KAAK,CAAC,eAAe,KAAK,CAAC,IAAI,2BAA2B,CAAC,CAAC;wBAC5D,eAAe,CAAC,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;oBACrD,CAAC,CAAC,CAAC;gBACL,CAAC;qBAAM,IAAI,GAAG,KAAK,gBAAgB,EAAE,CAAC;oBACpC,MAAM,cAAc,GAAG,SAAS,CAAC,cAAc,CAAC;oBAChD,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;wBACjC,OAAO;oBACT,CAAC;oBACD,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,UAAU,KAAK;wBACxC,KAAK,CAAC,eAAe,KAAK,CAAC,IAAI,uBAAuB,CAAC,CAAC;wBACxD,eAAe,CAAC,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;oBAClD,CAAC,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,4EAA4E;oBAC5E,oDAAoD;oBACpD,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAkC,CAAC;oBACjE,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;oBACzD,QAAQ,CAAC,YAAY,GAAG,QAAQ,CAAC,YAAY,IAAI,GAAG,CAAC;oBACrD,QAAQ,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,iBAAiB,CAAC;oBACxE,KAAK,CAAC,eAAe,QAAQ,CAAC,IAAI,4BAA4B,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;oBACvF,eAAe,CAAC,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC,CAAC,CAAC;YACH,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;CACH;AAED,4FAA4F;AAC5F,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;AAa9C,iBAAS,eAAe,CAAC"}
@@ -0,0 +1,76 @@
1
+ import express from "express";
2
+ import type { RequestHandler } from "express";
3
+ /**
4
+ * Builds the route helpers that transom-scaffold registers (as "transomScaffold" by default).
5
+ * A plain function, so existing `new ScaffoldHandler(...)` calls keep working.
6
+ */
7
+ declare function ScaffoldHandler(_server?: unknown, _options?: unknown): ScaffoldHandler.Handler;
8
+ declare namespace ScaffoldHandler {
9
+ /** The parts of the transom-core server the route helpers use. Any transom-core server fits. */
10
+ interface RouteServer {
11
+ registry: {
12
+ get(key: string): unknown;
13
+ };
14
+ get(path: string, ...handlers: RequestHandler[]): unknown;
15
+ use?(path: string, ...handlers: RequestHandler[]): unknown;
16
+ }
17
+ /** The options a custom (Restify-style) serveStatic receives. */
18
+ interface RestifyStaticOptions {
19
+ directory: string;
20
+ appendRequestPath: boolean;
21
+ default: string;
22
+ }
23
+ type RestifyServeStatic = (options: RestifyStaticOptions) => RequestHandler;
24
+ /** An entry in `staticRoutes`. */
25
+ interface StaticRoute {
26
+ /** The URL path to mount, e.g. "/html". */
27
+ path: string;
28
+ /** Folder under the application root. Defaults to the root itself. */
29
+ folder?: string;
30
+ /** Defaults to "index.html". */
31
+ defaultAsset?: string;
32
+ /** When false, folders don't serve the default asset. Defaults to true. */
33
+ appendRequestPath?: boolean;
34
+ /** Replace express.static, e.g. with a Restify-style serveStatic. */
35
+ serveStatic?: typeof express.static | RestifyServeStatic;
36
+ }
37
+ /** An entry in `redirectRoutes`. */
38
+ interface RedirectRoute {
39
+ path: string;
40
+ /** A URL (302), or a pathname with `permanent: true` for a 301. */
41
+ target: string | {
42
+ pathname: string;
43
+ permanent?: boolean;
44
+ };
45
+ }
46
+ /** A named entry in the scaffold definition, rendered with an HTML template. */
47
+ interface TemplateRouteDefinition {
48
+ /** Defaults to "/<name in lower case>". */
49
+ path?: string;
50
+ /** Defaults to the entry's name. */
51
+ templateName?: string;
52
+ /** Defaults to "text/html". */
53
+ contentType?: string;
54
+ /** Passed to the template, with the request's `headers` and `params` added. */
55
+ data?: Record<string, unknown>;
56
+ }
57
+ /** A template route once the plugin has filled in its defaults. */
58
+ interface TemplateRoute extends TemplateRouteDefinition {
59
+ path: string;
60
+ templateName: string;
61
+ /** The registry key of the template renderer. */
62
+ templateHandler: string;
63
+ }
64
+ /** The registered template renderer, as transom-ejs-template provides it. */
65
+ interface TemplateRenderer {
66
+ renderHtmlTemplate(templateName: string, data: object): string;
67
+ }
68
+ /** The registered helpers. */
69
+ interface Handler {
70
+ addStaticAssetRoute(server: RouteServer, scaffold: StaticRoute): void;
71
+ addRedirectRoute(server: RouteServer, scaffold: RedirectRoute): void;
72
+ addTemplateRoute(server: RouteServer, scaffold: TemplateRoute): void;
73
+ }
74
+ }
75
+ export = ScaffoldHandler;
76
+ //# sourceMappingURL=scaffoldHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffoldHandler.d.ts","sourceRoot":"","sources":["../../src/lib/scaffoldHandler.ts"],"names":[],"mappings":"AAGA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAyB,cAAc,EAAY,MAAM,SAAS,CAAC;AAkB/E;;;GAGG;AACH,iBAAS,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,eAAe,CAAC,OAAO,CAyGvF;AAED,OAAO,WAAW,eAAe,CAAC;IAChC,gGAAgG;IAChG,UAAU,WAAW;QACnB,QAAQ,EAAE;YACR,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SAC3B,CAAC;QACF,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;QAC1D,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;KAC5D;IAED,iEAAiE;IACjE,UAAU,oBAAoB;QAC5B,SAAS,EAAE,MAAM,CAAC;QAClB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,OAAO,EAAE,MAAM,CAAC;KACjB;IAED,KAAK,kBAAkB,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,cAAc,CAAC;IAE5E,kCAAkC;IAClC,UAAU,WAAW;QACnB,2CAA2C;QAC3C,IAAI,EAAE,MAAM,CAAC;QACb,sEAAsE;QACtE,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,gCAAgC;QAChC,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,2EAA2E;QAC3E,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,qEAAqE;QACrE,WAAW,CAAC,EAAE,OAAO,OAAO,CAAC,MAAM,GAAG,kBAAkB,CAAC;KAC1D;IAED,oCAAoC;IACpC,UAAU,aAAa;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,mEAAmE;QACnE,MAAM,EAAE,MAAM,GAAG;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;KAC5D;IAED,gFAAgF;IAChF,UAAU,uBAAuB;QAC/B,2CAA2C;QAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,oCAAoC;QACpC,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,+BAA+B;QAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,+EAA+E;QAC/E,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC;IAED,mEAAmE;IACnE,UAAU,aAAc,SAAQ,uBAAuB;QACrD,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,MAAM,CAAC;QACrB,iDAAiD;QACjD,eAAe,EAAE,MAAM,CAAC;KACzB;IAED,6EAA6E;IAC7E,UAAU,gBAAgB;QACxB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;KAChE;IAED,8BAA8B;IAC9B,UAAU,OAAO;QACf,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;QACtE,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;QACrE,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;KACtE;CACF;SAEQ,eAAe"}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ const assert_1 = __importDefault(require("assert"));
6
+ const path_1 = __importDefault(require("path"));
7
+ const debug_1 = __importDefault(require("debug"));
8
+ const express_1 = __importDefault(require("express"));
9
+ const debug = (0, debug_1.default)("transom:scaffold");
10
+ // This file runs from <package>/dist/lib.
11
+ const PACKAGE_ROOT = path_1.default.join(__dirname, "..", "..");
12
+ /**
13
+ * Where static folders are resolved from: the application's root, found by walking up
14
+ * out of node_modules/@transomjs/transom-scaffold. When NODE_ENV is "testing", the
15
+ * package root.
16
+ */
17
+ function assetRoot() {
18
+ return `${process.env.NODE_ENV}`.toUpperCase() === "TESTING"
19
+ ? PACKAGE_ROOT
20
+ : path_1.default.join(PACKAGE_ROOT, "..", "..", "..");
21
+ }
22
+ /**
23
+ * Builds the route helpers that transom-scaffold registers (as "transomScaffold" by default).
24
+ * A plain function, so existing `new ScaffoldHandler(...)` calls keep working.
25
+ */
26
+ function ScaffoldHandler(_server, _options) {
27
+ /**
28
+ * Serves static assets from a folder under the application root.
29
+ *
30
+ * @param server - The transom server.
31
+ * @param scaffold - An entry from `staticRoutes`.
32
+ */
33
+ function addStaticAssetRoute(server, scaffold) {
34
+ (0, assert_1.default)(scaffold.path, `TransomScaffold staticRoute requires "path" to be specified.`);
35
+ const contentFolder = scaffold.folder || path_1.default.sep;
36
+ const defaultAsset = scaffold.defaultAsset || "index.html";
37
+ const appendRequestPath = scaffold.appendRequestPath === false ? false : true; // default true
38
+ const directory = path_1.default.join(assetRoot(), contentFolder);
39
+ debug(`Path ${scaffold.path} is serving static assets from ${directory}`);
40
+ let staticMiddleware;
41
+ if (scaffold.serveStatic && scaffold.serveStatic !== express_1.default.static) {
42
+ // A custom serveStatic function (Restify style) gets Restify-style options.
43
+ // Boundary: it's documented as taking a single options object.
44
+ const restifyServeStatic = scaffold.serveStatic;
45
+ staticMiddleware = restifyServeStatic({
46
+ directory,
47
+ appendRequestPath,
48
+ default: defaultAsset,
49
+ });
50
+ }
51
+ else {
52
+ // Express static, with Express-style options.
53
+ staticMiddleware = express_1.default.static(directory, {
54
+ index: appendRequestPath ? defaultAsset : false,
55
+ });
56
+ }
57
+ // Use server.use if available (Express), otherwise fall back to server.get.
58
+ if (typeof server.use === "function") {
59
+ server.use(scaffold.path, staticMiddleware);
60
+ }
61
+ else {
62
+ server.get(scaffold.path, staticMiddleware);
63
+ }
64
+ }
65
+ /**
66
+ * Adds a GET route that redirects to another URI.
67
+ *
68
+ * @param server - The transom server.
69
+ * @param scaffold - An entry from `redirectRoutes`.
70
+ */
71
+ function addRedirectRoute(server, scaffold) {
72
+ (0, assert_1.default)(scaffold.path && scaffold.target, `TransomScaffold redirectRoute requires 'path' and 'target' to be specified.`);
73
+ server.get(scaffold.path, function (_req, res) {
74
+ // An object target can choose a permanent (301) redirect.
75
+ if (typeof scaffold.target === "object") {
76
+ const statusCode = scaffold.target.permanent ? 301 : 302;
77
+ res.redirect(statusCode, scaffold.target.pathname);
78
+ }
79
+ else {
80
+ res.redirect(scaffold.target);
81
+ }
82
+ });
83
+ }
84
+ /**
85
+ * Adds a GET route rendered with an HTML template from the registered template handler.
86
+ *
87
+ * @param server - The transom server.
88
+ * @param scaffold - A named entry from the scaffold definition, with its defaults applied.
89
+ */
90
+ function addTemplateRoute(server, scaffold) {
91
+ server.get(scaffold.path, function (req, res, next) {
92
+ // Boundary: the template handler registered under this key (transom-ejs-template's renderer).
93
+ const transomTemplate = server.registry.get(scaffold.templateHandler);
94
+ const contentType = scaffold.contentType || "text/html";
95
+ new Promise(function (resolve) {
96
+ // Push request headers and params into the data going to the template.
97
+ const data = scaffold.data || {};
98
+ data.headers = req.headers;
99
+ data.params = req.params;
100
+ resolve(transomTemplate.renderHtmlTemplate(scaffold.templateName, data));
101
+ })
102
+ .then(function (pageData) {
103
+ res.setHeader("content-type", contentType);
104
+ res.end(pageData);
105
+ // Call next() for test compatibility (tests expect it to be called).
106
+ if (typeof next === "function") {
107
+ // Use setTimeout to ensure the response is sent first.
108
+ setTimeout(() => next(), 0);
109
+ }
110
+ })
111
+ .catch(function (err) {
112
+ next(err);
113
+ });
114
+ });
115
+ }
116
+ return {
117
+ addStaticAssetRoute,
118
+ addRedirectRoute,
119
+ addTemplateRoute,
120
+ };
121
+ }
122
+ module.exports = ScaffoldHandler;
123
+ //# sourceMappingURL=scaffoldHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffoldHandler.js","sourceRoot":"","sources":["../../src/lib/scaffoldHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import ScaffoldHandler = require("../dist/lib/scaffoldHandler");
2
+ export = ScaffoldHandler;
@@ -1,116 +1,3 @@
1
- 'use strict';
2
- const debug = require('debug')('transom:scaffold');
3
- const express = require('express');
4
- const path = require('path');
5
- const assert = require('assert');
6
-
7
- module.exports = function ScaffoldHandler(server) {
8
-
9
- /**
10
- * Add a GET route to the server to handle static assets.
11
- *
12
- * @param {*} server - Express server instance
13
- * @param {*} scaffold - Object from the staticRoutes array.
14
- */
15
- function addStaticAssetRoute(server, scaffold) {
16
- assert(scaffold.path, `TransomScaffold staticRoute requires "path" to be specified.`);
17
-
18
- const contentFolder = scaffold.folder || path.sep;
19
- const serveStatic = scaffold.serveStatic || express.static;
20
- const defaultAsset = scaffold.defaultAsset || 'index.html';
21
- const appendRequestPath = (scaffold.appendRequestPath === false ? false : true); // default true
22
-
23
- // When we are running tests, the path to our assets will be different.
24
- // We create the path using NODE_ENV which should be set to TESTING.
25
- let directory = path.join(__dirname, '..', '..', '..', '..', contentFolder);
26
- if ((`${process.env.NODE_ENV}`).toUpperCase() === 'TESTING') {
27
- directory = path.join(__dirname, "..", contentFolder);
28
- }
29
- debug(`Path ${scaffold.path} is serving static assets from ${directory}`);
30
-
31
- // Create middleware function based on server type and static function
32
- let staticMiddleware;
33
-
34
- if (scaffold.serveStatic && scaffold.serveStatic !== express.static) {
35
- // Custom serveStatic function provided (like in tests)
36
- // Use Restify-style options for backward compatibility
37
- const restifyOptions = {
38
- directory,
39
- appendRequestPath,
40
- default: defaultAsset
41
- };
42
- staticMiddleware = serveStatic(restifyOptions);
43
- } else {
44
- // Use Express static with Express-style options
45
- const expressOptions = {
46
- index: appendRequestPath ? defaultAsset : false
47
- };
48
- staticMiddleware = serveStatic(directory, expressOptions);
49
- }
50
-
51
- // Use server.use if available (Express), otherwise fall back to server.get for compatibility
52
- if (typeof server.use === 'function') {
53
- server.use(scaffold.path, staticMiddleware);
54
- } else {
55
- server.get(scaffold.path, staticMiddleware);
56
- }
57
- }
58
-
59
- /**
60
- * Add a GET route that redirects to another URI.
61
- *
62
- * @param {*} server - Express server instance
63
- * @param {*} scaffold - Object from the redirectRoutes array.
64
- */
65
- function addRedirectRoute(server, scaffold) {
66
- assert(scaffold.path && scaffold.target, `TransomScaffold redirectRoute requires 'path' and 'target' to be specified.`);
67
-
68
- server.get(scaffold.path, function (req, res, next) {
69
- // Handle Express redirect - if target is object with pathname and permanent
70
- if (typeof scaffold.target === 'object') {
71
- const statusCode = scaffold.target.permanent ? 301 : 302;
72
- res.redirect(statusCode, scaffold.target.pathname);
73
- } else {
74
- res.redirect(scaffold.target);
75
- }
76
- });
77
- }
78
-
79
- /**
80
- * Add a GET route that is handled with a template.
81
- *
82
- * @param {*} server - Express server instance
83
- * @param {*} scaffold
84
- */
85
- function addTemplateRoute(server, scaffold) {
86
- server.get(scaffold.path, function (req, res, next) {
87
- const transomTemplate = server.registry.get(scaffold.templateHandler);
88
- const contentType = scaffold.contentType || 'text/html';
89
-
90
- const p = new Promise(function (resolve, reject) {
91
- // Push request headers and params into the data going to the template.
92
- const data = scaffold.data || {};
93
- data.headers = req.headers;
94
- data.params = req.params;
95
-
96
- resolve(transomTemplate.renderHtmlTemplate(scaffold.templateName, data));
97
- }).then(function (pageData) {
98
- res.setHeader('content-type', contentType);
99
- res.end(pageData);
100
- // Call next() for test compatibility (tests expect it to be called)
101
- if (typeof next === 'function') {
102
- // Use setTimeout to ensure response is sent first
103
- setTimeout(() => next(), 0);
104
- }
105
- }).catch(function (err) {
106
- next(err);
107
- });
108
- });
109
- }
110
-
111
- return {
112
- addStaticAssetRoute,
113
- addRedirectRoute,
114
- addTemplateRoute
115
- };
116
- };
1
+ "use strict";
2
+ // Kept so require("@transomjs/transom-scaffold/lib/scaffoldHandler") still works; the code is in dist/.
3
+ module.exports = require("../dist/lib/scaffoldHandler");
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "@transomjs/transom-scaffold",
3
- "version": "5.0.0",
3
+ "version": "7.0.1",
4
4
  "description": "Serve static assets and add redirect routes to a Transom REST API (Express compatible).",
5
- "main": "index.js",
5
+ "main": "dist/index.js",
6
6
  "scripts": {
7
+ "build": "tsc -p tsconfig.build.json",
8
+ "typecheck": "npm run build && tsc -p tsconfig.json",
9
+ "pretest": "npm run build",
7
10
  "deploy": "np",
8
- "test": "cross-env NODE_ENV=testing nyc mocha",
9
- "coveralls": "nyc report --reporter=text-lcov | coveralls",
10
- "cover": "nyc report --reporter=html && open-cli ./coverage/index.html"
11
+ "test": "cross-env NODE_ENV=testing c8 mocha",
12
+ "cover": "c8 report --reporter=html && open-cli ./coverage/index.html",
13
+ "prepublishOnly": "npm run typecheck && npm test"
11
14
  },
12
15
  "repository": {
13
16
  "type": "git",
@@ -26,24 +29,34 @@
26
29
  },
27
30
  "homepage": "https://github.com/transomjs/transom-scaffold#readme",
28
31
  "engines": {
29
- "node": ">=18"
32
+ "node": ">=22"
30
33
  },
31
34
  "devDependencies": {
32
- "@transomjs/transom-core": "^5.0.1",
33
- "chai": "^5.1.2",
34
- "coveralls": "^3.1.1",
35
- "cross-env": "^7.0.3",
35
+ "@transomjs/transom-core": "^7.0.0",
36
+ "@types/debug": "^4.1.13",
37
+ "@types/node": "^22.20.5",
38
+ "c8": "^12.0.0",
39
+ "chai": "^6.3.0",
40
+ "cross-env": "^10.1.0",
36
41
  "express": "^4.21.1",
37
- "mocha": "^10.8.2",
38
- "mocha-lcov-reporter": "^1.3.0",
39
- "open-cli": "^8.0.0",
40
- "np": "^10.0.10",
41
- "nyc": "^17.1.0",
42
- "shelljs": "^0.8.5",
43
- "sinon": "^19.0.2"
42
+ "mocha": "^12.0.3",
43
+ "np": "^12.1.1",
44
+ "open-cli": "^9.0.0",
45
+ "pocket-registry": "^3.0.0",
46
+ "sinon": "^22.1.0",
47
+ "typescript": "^7.0.2"
44
48
  },
45
49
  "peerDependencies": {
46
- "@transomjs/transom-core": "^5.0.1"
50
+ "@transomjs/transom-core": "^7.0.0"
47
51
  },
48
- "dependencies": {}
52
+ "dependencies": {
53
+ "@types/express": "^4.17.25"
54
+ },
55
+ "types": "dist/index.d.ts",
56
+ "files": [
57
+ "dist",
58
+ "src",
59
+ "lib",
60
+ "CHANGELOG.md"
61
+ ]
49
62
  }
package/src/index.ts ADDED
@@ -0,0 +1,109 @@
1
+ import createDebug from "debug";
2
+ import ScaffoldHandler = require("./lib/scaffoldHandler");
3
+
4
+ const debug = createDebug("transom:scaffold");
5
+
6
+ /** The parts of the transom-core server this plugin uses. Any transom-core server fits. */
7
+ interface ScaffoldPluginServer extends ScaffoldHandler.RouteServer {
8
+ registry: ScaffoldHandler.RouteServer["registry"] & {
9
+ get(key: string, defaultValue: object): unknown;
10
+ set(key: string, value: unknown): void;
11
+ };
12
+ }
13
+
14
+ /** Plugin options, from transom.configure(). */
15
+ interface ScaffoldOptions {
16
+ /** The registry key for the route helpers. Defaults to "transomScaffold". */
17
+ registryKey?: string;
18
+ /** The registry key of the template renderer. Defaults to "transomTemplate". */
19
+ templateHandler?: string;
20
+ /** Set by the plugin: a copy of the API definition's scaffold section. */
21
+ scaffold?: ScaffoldDefinition;
22
+ }
23
+
24
+ /**
25
+ * The API definition's `definition.scaffold` section. `staticRoutes` and `redirectRoutes`
26
+ * take one route or a list; every other entry is a template route named by its key.
27
+ */
28
+ interface ScaffoldDefinition {
29
+ staticRoutes?: ScaffoldHandler.StaticRoute | ScaffoldHandler.StaticRoute[];
30
+ redirectRoutes?: ScaffoldHandler.RedirectRoute | ScaffoldHandler.RedirectRoute[];
31
+ [templateRoute: string]:
32
+ | ScaffoldHandler.TemplateRouteDefinition
33
+ | ScaffoldHandler.StaticRoute
34
+ | ScaffoldHandler.StaticRoute[]
35
+ | ScaffoldHandler.RedirectRoute
36
+ | ScaffoldHandler.RedirectRoute[]
37
+ | undefined;
38
+ }
39
+
40
+ function asList<T>(value: T | T[]): T[] {
41
+ return Array.isArray(value) ? value : [value];
42
+ }
43
+
44
+ /**
45
+ * Adds static asset, redirect and template routes from the API definition's
46
+ * `definition.scaffold` section, and registers the route helpers.
47
+ */
48
+ class TransomScaffold {
49
+ initialize = (server: ScaffoldPluginServer, options: ScaffoldOptions): Promise<void> => {
50
+ return new Promise<void>(function (resolve) {
51
+ // Boundary: the API definition's scaffold section.
52
+ const scaffoldDefn = server.registry.get("transom-config.definition.scaffold", {}) as ScaffoldDefinition;
53
+ const scaffolds: ScaffoldDefinition = Object.assign({}, scaffoldDefn);
54
+ options.scaffold = scaffolds;
55
+
56
+ const scaffoldHandler = ScaffoldHandler(server);
57
+ server.registry.set(options.registryKey || "transomScaffold", scaffoldHandler);
58
+
59
+ // Add simple get routes to fetch scaffolded content.
60
+ Object.keys(scaffolds).map(function (key) {
61
+ if (key === "staticRoutes") {
62
+ const staticRoutes = scaffolds.staticRoutes;
63
+ if (staticRoutes === undefined) {
64
+ return;
65
+ }
66
+ asList(staticRoutes).map(function (route) {
67
+ debug(`Setting up '${route.path}' as a static asset route`);
68
+ scaffoldHandler.addStaticAssetRoute(server, route);
69
+ });
70
+ } else if (key === "redirectRoutes") {
71
+ const redirectRoutes = scaffolds.redirectRoutes;
72
+ if (redirectRoutes === undefined) {
73
+ return;
74
+ }
75
+ asList(redirectRoutes).map(function (route) {
76
+ debug(`Setting up '${route.path}' as a redirect route`);
77
+ scaffoldHandler.addRedirectRoute(server, route);
78
+ });
79
+ } else {
80
+ // Boundary: every other key is a template route. Its defaults are filled in
81
+ // place, on the definition's own object, as before.
82
+ const scaffold = scaffolds[key] as ScaffoldHandler.TemplateRoute;
83
+ scaffold.path = scaffold.path || `/${key.toLowerCase()}`;
84
+ scaffold.templateName = scaffold.templateName || key;
85
+ scaffold.templateHandler = options.templateHandler || "transomTemplate";
86
+ debug(`Setting up '${scaffold.path}' as a template route to ${scaffold.templateName}`);
87
+ scaffoldHandler.addTemplateRoute(server, scaffold);
88
+ }
89
+ });
90
+ resolve();
91
+ });
92
+ };
93
+ }
94
+
95
+ /** The plugin instance, as `require("@transomjs/transom-scaffold")` has always returned. */
96
+ const transomScaffold = new TransomScaffold();
97
+
98
+ declare namespace transomScaffold {
99
+ type Options = ScaffoldOptions;
100
+ type Definition = ScaffoldDefinition;
101
+ type StaticRoute = ScaffoldHandler.StaticRoute;
102
+ type RedirectRoute = ScaffoldHandler.RedirectRoute;
103
+ type TemplateRoute = ScaffoldHandler.TemplateRouteDefinition;
104
+ type RestifyServeStatic = ScaffoldHandler.RestifyServeStatic;
105
+ type Handler = ScaffoldHandler.Handler;
106
+ type PluginServer = ScaffoldPluginServer;
107
+ }
108
+
109
+ export = transomScaffold;
@@ -0,0 +1,207 @@
1
+ import assert from "assert";
2
+ import path from "path";
3
+ import createDebug from "debug";
4
+ import express from "express";
5
+ import type { NextFunction, Request, RequestHandler, Response } from "express";
6
+
7
+ const debug = createDebug("transom:scaffold");
8
+
9
+ // This file runs from <package>/dist/lib.
10
+ const PACKAGE_ROOT = path.join(__dirname, "..", "..");
11
+
12
+ /**
13
+ * Where static folders are resolved from: the application's root, found by walking up
14
+ * out of node_modules/@transomjs/transom-scaffold. When NODE_ENV is "testing", the
15
+ * package root.
16
+ */
17
+ function assetRoot(): string {
18
+ return `${process.env.NODE_ENV}`.toUpperCase() === "TESTING"
19
+ ? PACKAGE_ROOT
20
+ : path.join(PACKAGE_ROOT, "..", "..", "..");
21
+ }
22
+
23
+ /**
24
+ * Builds the route helpers that transom-scaffold registers (as "transomScaffold" by default).
25
+ * A plain function, so existing `new ScaffoldHandler(...)` calls keep working.
26
+ */
27
+ function ScaffoldHandler(_server?: unknown, _options?: unknown): ScaffoldHandler.Handler {
28
+ /**
29
+ * Serves static assets from a folder under the application root.
30
+ *
31
+ * @param server - The transom server.
32
+ * @param scaffold - An entry from `staticRoutes`.
33
+ */
34
+ function addStaticAssetRoute(server: ScaffoldHandler.RouteServer, scaffold: ScaffoldHandler.StaticRoute): void {
35
+ assert(scaffold.path, `TransomScaffold staticRoute requires "path" to be specified.`);
36
+
37
+ const contentFolder = scaffold.folder || path.sep;
38
+ const defaultAsset = scaffold.defaultAsset || "index.html";
39
+ const appendRequestPath = scaffold.appendRequestPath === false ? false : true; // default true
40
+
41
+ const directory = path.join(assetRoot(), contentFolder);
42
+ debug(`Path ${scaffold.path} is serving static assets from ${directory}`);
43
+
44
+ let staticMiddleware: RequestHandler;
45
+ if (scaffold.serveStatic && scaffold.serveStatic !== express.static) {
46
+ // A custom serveStatic function (Restify style) gets Restify-style options.
47
+ // Boundary: it's documented as taking a single options object.
48
+ const restifyServeStatic = scaffold.serveStatic as ScaffoldHandler.RestifyServeStatic;
49
+ staticMiddleware = restifyServeStatic({
50
+ directory,
51
+ appendRequestPath,
52
+ default: defaultAsset,
53
+ });
54
+ } else {
55
+ // Express static, with Express-style options.
56
+ staticMiddleware = express.static(directory, {
57
+ index: appendRequestPath ? defaultAsset : false,
58
+ });
59
+ }
60
+
61
+ // Use server.use if available (Express), otherwise fall back to server.get.
62
+ if (typeof server.use === "function") {
63
+ server.use(scaffold.path, staticMiddleware);
64
+ } else {
65
+ server.get(scaffold.path, staticMiddleware);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Adds a GET route that redirects to another URI.
71
+ *
72
+ * @param server - The transom server.
73
+ * @param scaffold - An entry from `redirectRoutes`.
74
+ */
75
+ function addRedirectRoute(server: ScaffoldHandler.RouteServer, scaffold: ScaffoldHandler.RedirectRoute): void {
76
+ assert(
77
+ scaffold.path && scaffold.target,
78
+ `TransomScaffold redirectRoute requires 'path' and 'target' to be specified.`,
79
+ );
80
+
81
+ server.get(scaffold.path, function (_req: Request, res: Response) {
82
+ // An object target can choose a permanent (301) redirect.
83
+ if (typeof scaffold.target === "object") {
84
+ const statusCode = scaffold.target.permanent ? 301 : 302;
85
+ res.redirect(statusCode, scaffold.target.pathname);
86
+ } else {
87
+ res.redirect(scaffold.target);
88
+ }
89
+ });
90
+ }
91
+
92
+ /**
93
+ * Adds a GET route rendered with an HTML template from the registered template handler.
94
+ *
95
+ * @param server - The transom server.
96
+ * @param scaffold - A named entry from the scaffold definition, with its defaults applied.
97
+ */
98
+ function addTemplateRoute(server: ScaffoldHandler.RouteServer, scaffold: ScaffoldHandler.TemplateRoute): void {
99
+ server.get(scaffold.path, function (req: Request, res: Response, next: NextFunction) {
100
+ // Boundary: the template handler registered under this key (transom-ejs-template's renderer).
101
+ const transomTemplate = server.registry.get(scaffold.templateHandler) as ScaffoldHandler.TemplateRenderer;
102
+ const contentType = scaffold.contentType || "text/html";
103
+
104
+ new Promise<string>(function (resolve) {
105
+ // Push request headers and params into the data going to the template.
106
+ const data = scaffold.data || {};
107
+ data.headers = req.headers;
108
+ data.params = req.params;
109
+
110
+ resolve(transomTemplate.renderHtmlTemplate(scaffold.templateName, data));
111
+ })
112
+ .then(function (pageData) {
113
+ res.setHeader("content-type", contentType);
114
+ res.end(pageData);
115
+ // Call next() for test compatibility (tests expect it to be called).
116
+ if (typeof next === "function") {
117
+ // Use setTimeout to ensure the response is sent first.
118
+ setTimeout(() => next(), 0);
119
+ }
120
+ })
121
+ .catch(function (err: unknown) {
122
+ next(err);
123
+ });
124
+ });
125
+ }
126
+
127
+ return {
128
+ addStaticAssetRoute,
129
+ addRedirectRoute,
130
+ addTemplateRoute,
131
+ };
132
+ }
133
+
134
+ declare namespace ScaffoldHandler {
135
+ /** The parts of the transom-core server the route helpers use. Any transom-core server fits. */
136
+ interface RouteServer {
137
+ registry: {
138
+ get(key: string): unknown;
139
+ };
140
+ get(path: string, ...handlers: RequestHandler[]): unknown;
141
+ use?(path: string, ...handlers: RequestHandler[]): unknown;
142
+ }
143
+
144
+ /** The options a custom (Restify-style) serveStatic receives. */
145
+ interface RestifyStaticOptions {
146
+ directory: string;
147
+ appendRequestPath: boolean;
148
+ default: string;
149
+ }
150
+
151
+ type RestifyServeStatic = (options: RestifyStaticOptions) => RequestHandler;
152
+
153
+ /** An entry in `staticRoutes`. */
154
+ interface StaticRoute {
155
+ /** The URL path to mount, e.g. "/html". */
156
+ path: string;
157
+ /** Folder under the application root. Defaults to the root itself. */
158
+ folder?: string;
159
+ /** Defaults to "index.html". */
160
+ defaultAsset?: string;
161
+ /** When false, folders don't serve the default asset. Defaults to true. */
162
+ appendRequestPath?: boolean;
163
+ /** Replace express.static, e.g. with a Restify-style serveStatic. */
164
+ serveStatic?: typeof express.static | RestifyServeStatic;
165
+ }
166
+
167
+ /** An entry in `redirectRoutes`. */
168
+ interface RedirectRoute {
169
+ path: string;
170
+ /** A URL (302), or a pathname with `permanent: true` for a 301. */
171
+ target: string | { pathname: string; permanent?: boolean };
172
+ }
173
+
174
+ /** A named entry in the scaffold definition, rendered with an HTML template. */
175
+ interface TemplateRouteDefinition {
176
+ /** Defaults to "/<name in lower case>". */
177
+ path?: string;
178
+ /** Defaults to the entry's name. */
179
+ templateName?: string;
180
+ /** Defaults to "text/html". */
181
+ contentType?: string;
182
+ /** Passed to the template, with the request's `headers` and `params` added. */
183
+ data?: Record<string, unknown>;
184
+ }
185
+
186
+ /** A template route once the plugin has filled in its defaults. */
187
+ interface TemplateRoute extends TemplateRouteDefinition {
188
+ path: string;
189
+ templateName: string;
190
+ /** The registry key of the template renderer. */
191
+ templateHandler: string;
192
+ }
193
+
194
+ /** The registered template renderer, as transom-ejs-template provides it. */
195
+ interface TemplateRenderer {
196
+ renderHtmlTemplate(templateName: string, data: object): string;
197
+ }
198
+
199
+ /** The registered helpers. */
200
+ interface Handler {
201
+ addStaticAssetRoute(server: RouteServer, scaffold: StaticRoute): void;
202
+ addRedirectRoute(server: RouteServer, scaffold: RedirectRoute): void;
203
+ addTemplateRoute(server: RouteServer, scaffold: TemplateRoute): void;
204
+ }
205
+ }
206
+
207
+ export = ScaffoldHandler;
package/index.js DELETED
@@ -1,43 +0,0 @@
1
- 'use strict';
2
- const debug = require('debug')('transom:scaffold');
3
- const ScaffoldHandler = require('./lib/scaffoldHandler');
4
-
5
- function TransomScaffold() {
6
- this.initialize = function (server, options) {
7
- return new Promise(function(resolve, reject){
8
- const scaffoldDefn = server.registry.get('transom-config.definition.scaffold', {});
9
- options.scaffold = Object.assign({}, scaffoldDefn);
10
-
11
- const scaffoldHandler = new ScaffoldHandler(server);
12
- server.registry.set(options.registryKey || 'transomScaffold', scaffoldHandler);
13
-
14
- // Add simple get routes to fetch scaffolded content.
15
- Object.keys(options.scaffold).map(function (key) {
16
- const scaffold = options.scaffold[key];
17
-
18
- if (key === 'staticRoutes') {
19
- const staticRoutes = Array.isArray(scaffold) ? scaffold : [scaffold];
20
- staticRoutes.map(function (route) {
21
- debug(`Setting up '${route.path}' as a static asset route`);
22
- scaffoldHandler.addStaticAssetRoute(server, route);
23
- });
24
- } else if (key === 'redirectRoutes') {
25
- const redirectRoutes = Array.isArray(scaffold) ? scaffold : [scaffold];
26
- redirectRoutes.map(function (route) {
27
- debug(`Setting up '${route.path}' as a redirect route`);
28
- scaffoldHandler.addRedirectRoute(server, route);
29
- });
30
- } else {
31
- scaffold.path = scaffold.path || `/${key.toLowerCase()}`;
32
- scaffold.templateName = scaffold.templateName || key;
33
- scaffold.templateHandler = options.templateHandler || 'transomTemplate';
34
- debug(`Setting up '${scaffold.path}' as a template route to ${scaffold.templateName}`);
35
- scaffoldHandler.addTemplateRoute(server, scaffold);
36
- }
37
- });
38
- resolve();
39
- });
40
- }
41
- }
42
-
43
- module.exports = new TransomScaffold();