oc-server 1.1.4 → 1.1.6
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/cli/cli.d.ts +1 -0
- package/dist/cli/cli.js +67 -0
- package/dist/cli/get-mocked-plugins.d.ts +8 -0
- package/dist/cli/get-mocked-plugins.js +79 -0
- package/dist/cli/index.js +6 -0
- package/dist/cli/oc.d.ts +52 -0
- package/dist/cli/oc.js +69 -0
- package/dist/cli/server.d.ts +13 -0
- package/dist/cli/server.js +164 -0
- package/package.json +7 -6
- package/dist/cli.js +0 -272
- /package/dist/{cli.d.ts → cli/index.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cli(): void;
|
package/dist/cli/cli.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cli = void 0;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const node_util_1 = require("node:util");
|
|
9
|
+
const oc_1 = require("./oc");
|
|
10
|
+
const server_1 = require("./server");
|
|
11
|
+
const pkg = require(node_path_1.default.join(process.cwd(), 'package.json'));
|
|
12
|
+
const { templateType } = (0, oc_1.parsePkg)(pkg);
|
|
13
|
+
function cli() {
|
|
14
|
+
const { positionals: [command], values: { help, port = '5000' }, } = (0, node_util_1.parseArgs)({
|
|
15
|
+
allowPositionals: true,
|
|
16
|
+
options: {
|
|
17
|
+
port: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
default: '5000',
|
|
20
|
+
short: 'p',
|
|
21
|
+
},
|
|
22
|
+
help: {
|
|
23
|
+
type: 'boolean',
|
|
24
|
+
default: false,
|
|
25
|
+
short: 'h',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
if (help || !command) {
|
|
30
|
+
console.log(`
|
|
31
|
+
Usage:
|
|
32
|
+
$ oc-server <command> [options]
|
|
33
|
+
|
|
34
|
+
Commands:
|
|
35
|
+
dev Start the development server
|
|
36
|
+
|
|
37
|
+
Options:
|
|
38
|
+
-h, --help Display this message
|
|
39
|
+
`);
|
|
40
|
+
if (help && command === 'dev') {
|
|
41
|
+
console.log(`
|
|
42
|
+
Usage:
|
|
43
|
+
$ oc-server <command> [options]
|
|
44
|
+
|
|
45
|
+
Commands:
|
|
46
|
+
dev Start the development server
|
|
47
|
+
|
|
48
|
+
Options:
|
|
49
|
+
-h, --help Display this message
|
|
50
|
+
-p, --port Port to use (default: 5000)
|
|
51
|
+
`);
|
|
52
|
+
}
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
let template;
|
|
56
|
+
try {
|
|
57
|
+
template = require(`${templateType}-compiler/dist/lib/hmr`);
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
console.error(`The template ${templateType} is not supported. Try updating to the last version`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
if (command === 'dev') {
|
|
64
|
+
(0, server_1.createServer)({ template, port });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.cli = cli;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface PluginMock {
|
|
2
|
+
name: string;
|
|
3
|
+
register: {
|
|
4
|
+
register: (options: unknown, dependencies: unknown, next: () => void) => void;
|
|
5
|
+
execute: (...args: unknown[]) => unknown;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export default function getMockedPlugins(componentsDir: string): PluginMock[];
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const path_1 = __importDefault(require("path"));
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const readJsonSync = (path) => JSON.parse(fs_1.default.readFileSync(path, 'utf-8'));
|
|
9
|
+
const isMockValid = (plugin) => {
|
|
10
|
+
const isFunction = typeof plugin === 'function';
|
|
11
|
+
const isValidObject = !!plugin &&
|
|
12
|
+
typeof plugin === 'object' &&
|
|
13
|
+
typeof plugin.register === 'function' &&
|
|
14
|
+
typeof plugin.execute === 'function';
|
|
15
|
+
return isFunction || isValidObject;
|
|
16
|
+
};
|
|
17
|
+
const defaultRegister = (_options, _dependencies, next) => {
|
|
18
|
+
next();
|
|
19
|
+
};
|
|
20
|
+
const registerStaticMocks = (mocks) => Object.entries(mocks).map(([pluginName, mockedValue]) => {
|
|
21
|
+
return {
|
|
22
|
+
name: pluginName,
|
|
23
|
+
register: {
|
|
24
|
+
register: defaultRegister,
|
|
25
|
+
execute: () => mockedValue,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
const registerDynamicMocks = (ocJsonLocation, mocks) => Object.entries(mocks)
|
|
30
|
+
.map(([pluginName, source]) => {
|
|
31
|
+
let pluginMock;
|
|
32
|
+
try {
|
|
33
|
+
pluginMock = require(path_1.default.resolve(ocJsonLocation, source));
|
|
34
|
+
}
|
|
35
|
+
catch (er) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!isMockValid(pluginMock)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const register = pluginMock.register || defaultRegister;
|
|
42
|
+
const execute = pluginMock.execute || pluginMock;
|
|
43
|
+
return {
|
|
44
|
+
name: pluginName,
|
|
45
|
+
register: { execute, register },
|
|
46
|
+
};
|
|
47
|
+
})
|
|
48
|
+
.filter((pluginMock) => !!pluginMock);
|
|
49
|
+
const findPath = (pathToResolve, fileName) => {
|
|
50
|
+
const rootDir = fs_1.default.realpathSync('.');
|
|
51
|
+
const fileToResolve = path_1.default.join(pathToResolve, fileName);
|
|
52
|
+
if (!fs_1.default.existsSync(fileToResolve)) {
|
|
53
|
+
if (pathToResolve === rootDir) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const getParent = (pathToResolve) => pathToResolve.split('/').slice(0, -1).join('/');
|
|
57
|
+
const parentDir = pathToResolve ? getParent(pathToResolve) : rootDir;
|
|
58
|
+
return findPath(parentDir, fileName);
|
|
59
|
+
}
|
|
60
|
+
return fileToResolve;
|
|
61
|
+
};
|
|
62
|
+
function getMockedPlugins(componentsDir) {
|
|
63
|
+
componentsDir = path_1.default.resolve(componentsDir || '.');
|
|
64
|
+
let plugins = [];
|
|
65
|
+
const ocJsonFileName = 'oc.json';
|
|
66
|
+
const ocJsonPath = findPath(componentsDir, ocJsonFileName);
|
|
67
|
+
if (!ocJsonPath) {
|
|
68
|
+
return plugins;
|
|
69
|
+
}
|
|
70
|
+
const content = readJsonSync(ocJsonPath);
|
|
71
|
+
const ocJsonLocation = ocJsonPath.slice(0, -ocJsonFileName.length);
|
|
72
|
+
if (!content.mocks || !content.mocks.plugins) {
|
|
73
|
+
return plugins;
|
|
74
|
+
}
|
|
75
|
+
plugins = plugins.concat(registerStaticMocks(content.mocks.plugins.static ?? {}));
|
|
76
|
+
plugins = plugins.concat(registerDynamicMocks(ocJsonLocation, content.mocks.plugins.dynamic ?? {}));
|
|
77
|
+
return plugins;
|
|
78
|
+
}
|
|
79
|
+
exports.default = getMockedPlugins;
|
package/dist/cli/oc.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { FastifyRequest } from 'fastify';
|
|
3
|
+
import { PluginMock } from './get-mocked-plugins';
|
|
4
|
+
interface Package {
|
|
5
|
+
name: string;
|
|
6
|
+
version: string;
|
|
7
|
+
oc?: {
|
|
8
|
+
parameters?: Record<string, {
|
|
9
|
+
mandatory: boolean;
|
|
10
|
+
example: string | number | boolean;
|
|
11
|
+
}>;
|
|
12
|
+
files: {
|
|
13
|
+
data?: string;
|
|
14
|
+
template?: {
|
|
15
|
+
type?: string;
|
|
16
|
+
src?: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare function parsePkg(pkg: Package): {
|
|
22
|
+
name: string;
|
|
23
|
+
version: string;
|
|
24
|
+
defaultParams: {};
|
|
25
|
+
serverEntry: string | undefined;
|
|
26
|
+
appEntry: string;
|
|
27
|
+
templateType: string;
|
|
28
|
+
};
|
|
29
|
+
export declare function getContext(plugins: PluginMock[], req: FastifyRequest, params: any, action?: any): {
|
|
30
|
+
context: {
|
|
31
|
+
action: any;
|
|
32
|
+
acceptLanguage: string | undefined;
|
|
33
|
+
easeUrl: string;
|
|
34
|
+
env: {
|
|
35
|
+
name: string;
|
|
36
|
+
};
|
|
37
|
+
params: any;
|
|
38
|
+
plugins: {
|
|
39
|
+
[k: string]: (...args: unknown[]) => unknown;
|
|
40
|
+
};
|
|
41
|
+
renderComponent: () => never;
|
|
42
|
+
renderComponents: () => never;
|
|
43
|
+
requestHeaders: import("http").IncomingHttpHeaders;
|
|
44
|
+
requestIp: string;
|
|
45
|
+
setEmptyResponse: null;
|
|
46
|
+
staticPath: string;
|
|
47
|
+
setHeader: (header: string, value: string) => void;
|
|
48
|
+
templates: string;
|
|
49
|
+
};
|
|
50
|
+
responseHeaders: Record<string, string>;
|
|
51
|
+
};
|
|
52
|
+
export {};
|
package/dist/cli/oc.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getContext = exports.parsePkg = void 0;
|
|
4
|
+
function parsePkg(pkg) {
|
|
5
|
+
const serverEntry = pkg.oc?.files?.data;
|
|
6
|
+
let appEntry = pkg.oc?.files?.template?.src || '';
|
|
7
|
+
if (!appEntry) {
|
|
8
|
+
throw new Error('Missing an entry on your package.json under oc.files.template.src');
|
|
9
|
+
}
|
|
10
|
+
if (!appEntry.startsWith('/')) {
|
|
11
|
+
appEntry = `/${appEntry}`;
|
|
12
|
+
}
|
|
13
|
+
const defaultParams = (() => {
|
|
14
|
+
let params = {};
|
|
15
|
+
if (pkg.oc?.parameters) {
|
|
16
|
+
params = Object.fromEntries(Object.entries(pkg.oc.parameters || {})
|
|
17
|
+
.filter(([, param]) => {
|
|
18
|
+
return !!param.mandatory && 'example' in param;
|
|
19
|
+
})
|
|
20
|
+
.map(([paramName, param]) => [paramName, param.example]));
|
|
21
|
+
}
|
|
22
|
+
return params;
|
|
23
|
+
})();
|
|
24
|
+
const templateType = pkg.oc?.files?.template?.type;
|
|
25
|
+
if (!templateType) {
|
|
26
|
+
throw new Error('Missing an entry on your package.json under oc.files.template.type');
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
name: pkg.name,
|
|
30
|
+
version: pkg.version,
|
|
31
|
+
defaultParams,
|
|
32
|
+
serverEntry,
|
|
33
|
+
appEntry,
|
|
34
|
+
templateType,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
exports.parsePkg = parsePkg;
|
|
38
|
+
function getContext(plugins, req, params, action) {
|
|
39
|
+
const responseHeaders = {};
|
|
40
|
+
const context = {
|
|
41
|
+
action,
|
|
42
|
+
acceptLanguage: req.headers['accept-language'],
|
|
43
|
+
easeUrl: '/',
|
|
44
|
+
env: { name: 'local' },
|
|
45
|
+
params,
|
|
46
|
+
plugins: Object.fromEntries(plugins.map((plugin) => [plugin.name, plugin.register.execute])),
|
|
47
|
+
renderComponent: () => {
|
|
48
|
+
throw new Error('renderComponent is not implemented in the server context');
|
|
49
|
+
},
|
|
50
|
+
renderComponents: () => {
|
|
51
|
+
throw new Error('renderComponents is not implemented in the server context');
|
|
52
|
+
},
|
|
53
|
+
requestHeaders: req.headers,
|
|
54
|
+
requestIp: req.ip,
|
|
55
|
+
setEmptyResponse: null,
|
|
56
|
+
staticPath: '/',
|
|
57
|
+
setHeader: (header, value) => {
|
|
58
|
+
if (!(typeof header === 'string' && typeof value === 'string')) {
|
|
59
|
+
throw new Error('context.setHeader parameters must be strings');
|
|
60
|
+
}
|
|
61
|
+
if (header && value) {
|
|
62
|
+
responseHeaders[header.toLowerCase()] = value;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
templates: 'repository.getTemplatesInfo()',
|
|
66
|
+
};
|
|
67
|
+
return { context, responseHeaders };
|
|
68
|
+
}
|
|
69
|
+
exports.getContext = getContext;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function createServer({ template, port, }: {
|
|
2
|
+
template: Template;
|
|
3
|
+
port: string;
|
|
4
|
+
}): Promise<void>;
|
|
5
|
+
interface Template {
|
|
6
|
+
appBlock: (opts: {
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
entry: string;
|
|
10
|
+
}) => string;
|
|
11
|
+
plugin?: () => any;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createServer = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const node_vm_1 = __importDefault(require("node:vm"));
|
|
10
|
+
const fastify_1 = __importDefault(require("fastify"));
|
|
11
|
+
const express_1 = __importDefault(require("@fastify/express"));
|
|
12
|
+
const vite_1 = require("vite");
|
|
13
|
+
const esbuild_1 = __importDefault(require("esbuild"));
|
|
14
|
+
const oc_client_browser_1 = __importDefault(require("oc-client-browser"));
|
|
15
|
+
const cssModulesPlugin_1 = __importDefault(require("oc-vite-compiler/dist/lib/cssModulesPlugin"));
|
|
16
|
+
const oc_1 = require("./oc");
|
|
17
|
+
const get_mocked_plugins_1 = __importDefault(require("./get-mocked-plugins"));
|
|
18
|
+
const promisify = (fn) => (...args) => new Promise((resolve, reject) => fn(...args, (err, data) => (err ? reject(err) : resolve(data))));
|
|
19
|
+
const pk = require(node_path_1.default.join(process.cwd(), 'package.json'));
|
|
20
|
+
const { name, version, appEntry, serverEntry, defaultParams } = (0, oc_1.parsePkg)(pk);
|
|
21
|
+
function getDataProvider() {
|
|
22
|
+
if (!serverEntry) {
|
|
23
|
+
return async (context) => ({ ...(context.params ?? {}) });
|
|
24
|
+
}
|
|
25
|
+
const result = esbuild_1.default.buildSync({
|
|
26
|
+
entryPoints: [serverEntry],
|
|
27
|
+
bundle: true,
|
|
28
|
+
format: 'cjs',
|
|
29
|
+
write: false,
|
|
30
|
+
});
|
|
31
|
+
const code = result.outputFiles[0].text;
|
|
32
|
+
const backend = node_vm_1.default.runInNewContext(code, {
|
|
33
|
+
...globalThis,
|
|
34
|
+
exports: {},
|
|
35
|
+
module: { exports: {} },
|
|
36
|
+
});
|
|
37
|
+
const dataProvider = backend.data || backend.server.getData();
|
|
38
|
+
return promisify(dataProvider);
|
|
39
|
+
}
|
|
40
|
+
function getBaseTemplate(appBlock) {
|
|
41
|
+
const baseTemplate = `
|
|
42
|
+
<!DOCTYPE html>
|
|
43
|
+
<html>
|
|
44
|
+
<head>
|
|
45
|
+
<meta name="robots" content="index, follow" />
|
|
46
|
+
<meta charset="utf-8" />
|
|
47
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
48
|
+
<style>
|
|
49
|
+
html, body {
|
|
50
|
+
width: 100%;
|
|
51
|
+
height: 100%;
|
|
52
|
+
margin: 0;
|
|
53
|
+
};
|
|
54
|
+
</style>
|
|
55
|
+
</head>
|
|
56
|
+
<body>
|
|
57
|
+
<script src="/oc-client/client.js"></script>
|
|
58
|
+
${appBlock({ name, version, entry: appEntry })}
|
|
59
|
+
</body>
|
|
60
|
+
</html>
|
|
61
|
+
`;
|
|
62
|
+
return baseTemplate;
|
|
63
|
+
}
|
|
64
|
+
async function getHtmlTemplate(appBlock, filePath = 'index.html') {
|
|
65
|
+
let template;
|
|
66
|
+
try {
|
|
67
|
+
template = node_fs_1.default.readFileSync(node_path_1.default.resolve(process.cwd(), filePath), 'utf-8');
|
|
68
|
+
if (!template.includes('</body>')) {
|
|
69
|
+
throw new Error('If you use a custom html entry it has to have a closing body tag');
|
|
70
|
+
}
|
|
71
|
+
template = template.replace('</body>', `<script>
|
|
72
|
+
if (!window.oc?.status) {
|
|
73
|
+
const script = document.createElement('script');
|
|
74
|
+
script.src = '/oc-client/client.js';
|
|
75
|
+
document.body.appendChild(script);
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
78
|
+
${appBlock({
|
|
79
|
+
name,
|
|
80
|
+
version,
|
|
81
|
+
entry: appEntry,
|
|
82
|
+
})}</body>`);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
template = getBaseTemplate(appBlock);
|
|
86
|
+
}
|
|
87
|
+
return template;
|
|
88
|
+
}
|
|
89
|
+
async function createServer({ template, port, }) {
|
|
90
|
+
const { dev: clientJs } = oc_client_browser_1.default.compileSync();
|
|
91
|
+
const app = (0, fastify_1.default)({ logger: false });
|
|
92
|
+
await app.register(express_1.default);
|
|
93
|
+
const dataProvider = getDataProvider();
|
|
94
|
+
const plugins = (0, get_mocked_plugins_1.default)(node_path_1.default.join(process.cwd(), '..'));
|
|
95
|
+
for (const plugin of plugins) {
|
|
96
|
+
plugin.register.register(null, null, () => { });
|
|
97
|
+
}
|
|
98
|
+
const vite = await (0, vite_1.createServer)({
|
|
99
|
+
server: { middlewareMode: true },
|
|
100
|
+
plugins: [(0, cssModulesPlugin_1.default)(), template.plugin?.()].filter(Boolean),
|
|
101
|
+
mode: 'development',
|
|
102
|
+
optimizeDeps: {
|
|
103
|
+
exclude: ['fsevents'],
|
|
104
|
+
},
|
|
105
|
+
appType: 'custom',
|
|
106
|
+
});
|
|
107
|
+
app.use(vite.middlewares);
|
|
108
|
+
app.get('/oc-client/client.js', (request, reply) => {
|
|
109
|
+
reply.status(200);
|
|
110
|
+
reply.header('Content-Type', 'text/javascript');
|
|
111
|
+
reply.send(clientJs);
|
|
112
|
+
});
|
|
113
|
+
app.post('/', async (request, reply) => {
|
|
114
|
+
try {
|
|
115
|
+
const { action, parameters } = request.body.components[0];
|
|
116
|
+
const { context, responseHeaders } = (0, oc_1.getContext)(plugins, request, parameters, action);
|
|
117
|
+
const props = await dataProvider(context);
|
|
118
|
+
const response = [
|
|
119
|
+
{
|
|
120
|
+
status: 200,
|
|
121
|
+
response: {
|
|
122
|
+
data: {
|
|
123
|
+
component: {
|
|
124
|
+
props,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
for (const [key, value] of Object.entries(responseHeaders)) {
|
|
131
|
+
reply.header(key, value);
|
|
132
|
+
}
|
|
133
|
+
return response;
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
vite.ssrFixStacktrace(e);
|
|
137
|
+
throw e;
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
app.get('*', async (request, reply) => {
|
|
141
|
+
const url = request.originalUrl;
|
|
142
|
+
try {
|
|
143
|
+
const params = defaultParams;
|
|
144
|
+
const { context, responseHeaders } = (0, oc_1.getContext)(plugins, request, params);
|
|
145
|
+
let htmlTemplate = await getHtmlTemplate(template.appBlock);
|
|
146
|
+
const data = await dataProvider(context);
|
|
147
|
+
htmlTemplate = htmlTemplate.replace('__INITIAL_DATA__', JSON.stringify(data));
|
|
148
|
+
htmlTemplate = await vite.transformIndexHtml(url, htmlTemplate);
|
|
149
|
+
for (const [key, value] of Object.entries(responseHeaders)) {
|
|
150
|
+
reply.header(key, value);
|
|
151
|
+
}
|
|
152
|
+
reply.status(200);
|
|
153
|
+
reply.header('Content-Type', 'text/html');
|
|
154
|
+
reply.send(htmlTemplate);
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
vite.ssrFixStacktrace(e);
|
|
158
|
+
throw e;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
await app.listen({ port: port });
|
|
162
|
+
console.log(`Listening on: http://localhost:${port}`);
|
|
163
|
+
}
|
|
164
|
+
exports.createServer = createServer;
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oc-server",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
-
"bin": "dist/cli.js",
|
|
7
|
+
"bin": "dist/cli/index.js",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "tsc",
|
|
10
10
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
|
@@ -21,10 +21,11 @@
|
|
|
21
21
|
"dist/**"
|
|
22
22
|
],
|
|
23
23
|
"license": "MIT",
|
|
24
|
-
"dependencies": {
|
|
25
|
-
"oc": "^0.49.57"
|
|
26
|
-
},
|
|
27
24
|
"devDependencies": {
|
|
28
25
|
"@types/express": "^4.17.21"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"express": "^4.19.2",
|
|
29
|
+
"oc-client-browser": "^1.8.0"
|
|
29
30
|
}
|
|
30
|
-
}
|
|
31
|
+
}
|
package/dist/cli.js
DELETED
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
-
};
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
process.env.VITE_CJS_IGNORE_WARNING = 'true';
|
|
8
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
-
const node_vm_1 = __importDefault(require("node:vm"));
|
|
11
|
-
const express_1 = __importDefault(require("express"));
|
|
12
|
-
const vite_1 = require("vite");
|
|
13
|
-
const esbuild_1 = __importDefault(require("esbuild"));
|
|
14
|
-
const oc_client_browser_1 = __importDefault(require("oc-client-browser"));
|
|
15
|
-
const cssModulesPlugin_1 = __importDefault(require("oc-vite-compiler/dist/lib/cssModulesPlugin"));
|
|
16
|
-
const get_mocked_plugins_js_1 = __importDefault(require("oc/dist/cli/domain/get-mocked-plugins.js"));
|
|
17
|
-
const node_util_1 = require("node:util");
|
|
18
|
-
const promisify = (fn) => (...args) => new Promise((resolve, reject) => fn(...args, (err, data) => (err ? reject(err) : resolve(data))));
|
|
19
|
-
const plugins = (0, get_mocked_plugins_js_1.default)({ err: () => { }, log: () => { }, ok: () => { }, warn: () => { } }, node_path_1.default.join(process.cwd(), '..'));
|
|
20
|
-
const pkg = require(node_path_1.default.join(process.cwd(), 'package.json'));
|
|
21
|
-
const serverEntry = pkg.oc?.files?.data;
|
|
22
|
-
let appEntry = pkg.oc?.files?.template?.src || '';
|
|
23
|
-
if (!appEntry) {
|
|
24
|
-
console.log('Missing an entry on your package.json under oc.files.template.src');
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
if (!appEntry.startsWith('/')) {
|
|
28
|
-
appEntry = `/${appEntry}`;
|
|
29
|
-
}
|
|
30
|
-
const defaultParams = (() => {
|
|
31
|
-
let params = {};
|
|
32
|
-
if (pkg.oc?.parameters) {
|
|
33
|
-
params = Object.fromEntries(Object.entries(pkg.oc.parameters || {})
|
|
34
|
-
.filter(([, param]) => {
|
|
35
|
-
return !!param.mandatory && 'example' in param;
|
|
36
|
-
})
|
|
37
|
-
.map(([paramName, param]) => [paramName, param.example]));
|
|
38
|
-
}
|
|
39
|
-
return params;
|
|
40
|
-
})();
|
|
41
|
-
function getDataProvider() {
|
|
42
|
-
if (!serverEntry) {
|
|
43
|
-
return async (context) => ({ ...(context.params ?? {}) });
|
|
44
|
-
}
|
|
45
|
-
const result = esbuild_1.default.buildSync({
|
|
46
|
-
entryPoints: [serverEntry],
|
|
47
|
-
bundle: true,
|
|
48
|
-
format: 'cjs',
|
|
49
|
-
write: false,
|
|
50
|
-
});
|
|
51
|
-
const code = result.outputFiles[0].text;
|
|
52
|
-
const backend = node_vm_1.default.runInNewContext(code, {
|
|
53
|
-
...globalThis,
|
|
54
|
-
exports: {},
|
|
55
|
-
module: { exports: {} },
|
|
56
|
-
});
|
|
57
|
-
const dataProvider = backend.data || backend.server.getData();
|
|
58
|
-
return promisify(dataProvider);
|
|
59
|
-
}
|
|
60
|
-
function getContext(req, params, action) {
|
|
61
|
-
const responseHeaders = {};
|
|
62
|
-
const context = {
|
|
63
|
-
action,
|
|
64
|
-
acceptLanguage: req.headers['accept-language'],
|
|
65
|
-
easeUrl: '/',
|
|
66
|
-
env: { name: 'local' },
|
|
67
|
-
params,
|
|
68
|
-
plugins: Object.fromEntries(plugins.map((plugin) => [plugin.name, plugin.register.execute])),
|
|
69
|
-
renderComponent: () => {
|
|
70
|
-
throw new Error('renderComponent is not implemented in the server context');
|
|
71
|
-
},
|
|
72
|
-
renderComponents: () => {
|
|
73
|
-
throw new Error('renderComponents is not implemented in the server context');
|
|
74
|
-
},
|
|
75
|
-
requestHeaders: req.headers,
|
|
76
|
-
requestIp: req.ip,
|
|
77
|
-
setEmptyResponse: null,
|
|
78
|
-
staticPath: '/',
|
|
79
|
-
setHeader: (header, value) => {
|
|
80
|
-
if (!(typeof header === 'string' && typeof value === 'string')) {
|
|
81
|
-
throw new Error('context.setHeader parameters must be strings');
|
|
82
|
-
}
|
|
83
|
-
if (header && value) {
|
|
84
|
-
responseHeaders[header.toLowerCase()] = value;
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
templates: 'repository.getTemplatesInfo()',
|
|
88
|
-
};
|
|
89
|
-
return { context, responseHeaders };
|
|
90
|
-
}
|
|
91
|
-
function getBaseTemplate(appBlock) {
|
|
92
|
-
const baseTemplate = `
|
|
93
|
-
<!DOCTYPE html>
|
|
94
|
-
<html>
|
|
95
|
-
<head>
|
|
96
|
-
<meta name="robots" content="index, follow" />
|
|
97
|
-
<meta charset="utf-8" />
|
|
98
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
99
|
-
<style>
|
|
100
|
-
html, body {
|
|
101
|
-
width: 100%;
|
|
102
|
-
height: 100%;
|
|
103
|
-
margin: 0;
|
|
104
|
-
};
|
|
105
|
-
</style>
|
|
106
|
-
</head>
|
|
107
|
-
<body>
|
|
108
|
-
<script src="/oc-client/client.js"></script>
|
|
109
|
-
${appBlock({ name: pkg.name, version: pkg.version, entry: appEntry })}
|
|
110
|
-
</body>
|
|
111
|
-
</html>
|
|
112
|
-
`;
|
|
113
|
-
return baseTemplate;
|
|
114
|
-
}
|
|
115
|
-
async function getHtmlTemplate(appBlock, filePath = 'index.html') {
|
|
116
|
-
let template;
|
|
117
|
-
try {
|
|
118
|
-
template = node_fs_1.default.readFileSync(node_path_1.default.resolve(process.cwd(), filePath), 'utf-8');
|
|
119
|
-
if (!template.includes('</body>')) {
|
|
120
|
-
throw new Error('If you use a custom html entry it has to have a closing body tag');
|
|
121
|
-
}
|
|
122
|
-
template = template.replace('</body>', `<script>
|
|
123
|
-
if (!window.oc?.status) {
|
|
124
|
-
const script = document.createElement('script');
|
|
125
|
-
script.src = '/oc-client/client.js';
|
|
126
|
-
document.body.appendChild(script);
|
|
127
|
-
}
|
|
128
|
-
</script>
|
|
129
|
-
${appBlock({
|
|
130
|
-
name: pkg.name,
|
|
131
|
-
version: pkg.version,
|
|
132
|
-
entry: appEntry,
|
|
133
|
-
})}</body>`);
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
template = getBaseTemplate(appBlock);
|
|
137
|
-
}
|
|
138
|
-
return template;
|
|
139
|
-
}
|
|
140
|
-
async function createServer({ template, port, }) {
|
|
141
|
-
const { dev: clientJs } = oc_client_browser_1.default.compileSync();
|
|
142
|
-
const app = (0, express_1.default)();
|
|
143
|
-
const dataProvider = getDataProvider();
|
|
144
|
-
for (const plugin of plugins) {
|
|
145
|
-
plugin.register.register(null, null, () => { });
|
|
146
|
-
}
|
|
147
|
-
app.use(express_1.default.json());
|
|
148
|
-
const vite = await (0, vite_1.createServer)({
|
|
149
|
-
server: { middlewareMode: true },
|
|
150
|
-
plugins: [(0, cssModulesPlugin_1.default)(), template.plugin?.()].filter(Boolean),
|
|
151
|
-
mode: 'development',
|
|
152
|
-
optimizeDeps: {
|
|
153
|
-
exclude: ['fsevents'],
|
|
154
|
-
},
|
|
155
|
-
appType: 'custom',
|
|
156
|
-
});
|
|
157
|
-
app.use(vite.middlewares);
|
|
158
|
-
app.get('/oc-client/client.js', (req, res) => {
|
|
159
|
-
res.status(200).set({ 'Content-Type': 'text/javascript' }).send(clientJs);
|
|
160
|
-
});
|
|
161
|
-
app.post('/', async (req, res, next) => {
|
|
162
|
-
try {
|
|
163
|
-
const { action, parameters } = req.body.components[0];
|
|
164
|
-
const { context, responseHeaders } = getContext(req, parameters, action);
|
|
165
|
-
const props = await dataProvider(context);
|
|
166
|
-
const response = [
|
|
167
|
-
{
|
|
168
|
-
status: 200,
|
|
169
|
-
response: {
|
|
170
|
-
data: {
|
|
171
|
-
component: {
|
|
172
|
-
props,
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
},
|
|
176
|
-
},
|
|
177
|
-
];
|
|
178
|
-
if (Object.keys(responseHeaders).length) {
|
|
179
|
-
res.set(responseHeaders);
|
|
180
|
-
}
|
|
181
|
-
res
|
|
182
|
-
.status(200)
|
|
183
|
-
.set({ 'Content-Type': 'application/json' })
|
|
184
|
-
.send(response);
|
|
185
|
-
}
|
|
186
|
-
catch (e) {
|
|
187
|
-
vite.ssrFixStacktrace(e);
|
|
188
|
-
next(e);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
app.use('*', async (req, res, next) => {
|
|
192
|
-
const url = req.originalUrl;
|
|
193
|
-
try {
|
|
194
|
-
const params = defaultParams;
|
|
195
|
-
const { context, responseHeaders } = getContext(req, params);
|
|
196
|
-
let htmlTemplate = await getHtmlTemplate(template.appBlock);
|
|
197
|
-
const data = await dataProvider(context);
|
|
198
|
-
htmlTemplate = htmlTemplate.replace('__INITIAL_DATA__', JSON.stringify(data));
|
|
199
|
-
htmlTemplate = await vite.transformIndexHtml(url, htmlTemplate);
|
|
200
|
-
if (Object.keys(responseHeaders).length) {
|
|
201
|
-
res.set(responseHeaders);
|
|
202
|
-
}
|
|
203
|
-
res.status(200).set({ 'Content-Type': 'text/html' }).end(htmlTemplate);
|
|
204
|
-
}
|
|
205
|
-
catch (e) {
|
|
206
|
-
vite.ssrFixStacktrace(e);
|
|
207
|
-
next(e);
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
app.listen(port);
|
|
211
|
-
console.log(`Listening on: http://localhost:${port}`);
|
|
212
|
-
}
|
|
213
|
-
const major = Number(process.versions.node.split('.')[0]) || 0;
|
|
214
|
-
if (major < 22) {
|
|
215
|
-
console.error('This script requires Node.js v22 or higher');
|
|
216
|
-
process.exit(1);
|
|
217
|
-
}
|
|
218
|
-
function cli(template) {
|
|
219
|
-
const { positionals: [command], values: { help, port = '5000' }, } = (0, node_util_1.parseArgs)({
|
|
220
|
-
allowPositionals: true,
|
|
221
|
-
options: {
|
|
222
|
-
port: {
|
|
223
|
-
type: 'string',
|
|
224
|
-
default: '5000',
|
|
225
|
-
short: 'p',
|
|
226
|
-
},
|
|
227
|
-
help: {
|
|
228
|
-
type: 'boolean',
|
|
229
|
-
default: false,
|
|
230
|
-
short: 'h',
|
|
231
|
-
},
|
|
232
|
-
},
|
|
233
|
-
});
|
|
234
|
-
if (help || !command) {
|
|
235
|
-
console.log(`
|
|
236
|
-
Usage:
|
|
237
|
-
$ oc-server <command> [options]
|
|
238
|
-
|
|
239
|
-
Commands:
|
|
240
|
-
dev Start the development server
|
|
241
|
-
|
|
242
|
-
Options:
|
|
243
|
-
-h, --help Display this message
|
|
244
|
-
`);
|
|
245
|
-
if (help && command === 'dev') {
|
|
246
|
-
console.log(`
|
|
247
|
-
Usage:
|
|
248
|
-
$ oc-server <command> [options]
|
|
249
|
-
|
|
250
|
-
Commands:
|
|
251
|
-
dev Start the development server
|
|
252
|
-
|
|
253
|
-
Options:
|
|
254
|
-
-h, --help Display this message
|
|
255
|
-
-p, --port Port to use (default: 5000)
|
|
256
|
-
`);
|
|
257
|
-
}
|
|
258
|
-
process.exit(0);
|
|
259
|
-
}
|
|
260
|
-
if (command === 'dev') {
|
|
261
|
-
createServer({ template, port });
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
let template;
|
|
265
|
-
try {
|
|
266
|
-
template = require(`${pkg.oc?.files?.template?.type}-compiler/dist/lib/hmr`);
|
|
267
|
-
}
|
|
268
|
-
catch (e) {
|
|
269
|
-
console.error(`The template ${pkg.oc?.files?.template?.type} is not supported. Try updating to the last version`);
|
|
270
|
-
process.exit(1);
|
|
271
|
-
}
|
|
272
|
-
cli(template);
|
|
File without changes
|