@examplary/cli 1.6.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/preview.d.ts +5 -0
  3. package/dist/commands/preview.js +174 -0
  4. package/dist/commands/upload.d.ts +5 -0
  5. package/dist/commands/upload.js +138 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +37 -0
  8. package/dist/lib/api.d.ts +5 -0
  9. package/dist/lib/api.js +47 -0
  10. package/dist/lib/bundle.d.ts +4 -0
  11. package/dist/lib/bundle.js +27 -0
  12. package/dist/lib/jsonata.d.ts +1 -0
  13. package/dist/lib/jsonata.js +26 -0
  14. package/dist/lib/read-meta.d.ts +16 -0
  15. package/dist/lib/read-meta.js +36 -0
  16. package/dist/lib/styles.d.ts +1 -0
  17. package/dist/lib/styles.js +24 -0
  18. package/dist/preview-ui/assets/icon-nodes-Ds7bJID4.js +2 -0
  19. package/dist/preview-ui/assets/icon-nodes-Ds7bJID4.js.map +1 -0
  20. package/dist/preview-ui/assets/index-DcEcr1Zm.css +1 -0
  21. package/dist/preview-ui/assets/index-NlxMWEJQ.js +3629 -0
  22. package/dist/preview-ui/assets/index-NlxMWEJQ.js.map +1 -0
  23. package/dist/preview-ui/assets/tags-DZBm0mOh.js +2 -0
  24. package/dist/preview-ui/assets/tags-DZBm0mOh.js.map +1 -0
  25. package/{src → dist}/preview-ui/index.html +2 -1
  26. package/package.json +26 -25
  27. package/bin/index.js +0 -37
  28. package/src/commands/preview.js +0 -220
  29. package/src/commands/upload.js +0 -179
  30. package/src/lib/api.js +0 -53
  31. package/src/lib/bundle.js +0 -35
  32. package/src/lib/jsonata.js +0 -31
  33. package/src/lib/middleware.js +0 -16
  34. package/src/lib/read-meta.js +0 -40
  35. package/src/lib/styles.js +0 -32
  36. package/src/preview-ui/App.tsx +0 -148
  37. package/src/preview-ui/components/json-editor.tsx +0 -27
  38. package/src/preview-ui/components/preview-assessment.tsx +0 -43
  39. package/src/preview-ui/components/preview-print.tsx +0 -38
  40. package/src/preview-ui/components/preview-results.tsx +0 -38
  41. package/src/preview-ui/components/preview-settings-area.tsx +0 -98
  42. package/src/preview-ui/components/question-component.tsx +0 -75
  43. package/src/preview-ui/index.css +0 -11
  44. package/src/preview-ui/lib/demo-api.ts +0 -29
  45. package/src/preview-ui/lib/i18n.ts +0 -15
  46. package/src/preview-ui/main.tsx +0 -8
@@ -11,10 +11,11 @@
11
11
  href="https://fonts.googleapis.com/css2?family=Epunda+Sans:ital,wght@0,300..900;1,300..900&family=Epunda+Slab:ital,wght@0,300..900;1,300..900&family=Inconsolata:wght@200..900&display=swap"
12
12
  rel="stylesheet"
13
13
  />
14
+ <script type="module" crossorigin src="/assets/index-NlxMWEJQ.js"></script>
15
+ <link rel="stylesheet" crossorigin href="/assets/index-DcEcr1Zm.css">
14
16
  </head>
15
17
  <body class="bg-app-bg font-sans">
16
18
  <div id="root"></div>
17
- <script type="module" src="/main.tsx"></script>
18
19
  <link href="/api/stylesheet" rel="stylesheet" />
19
20
  </body>
20
21
  </html>
package/package.json CHANGED
@@ -2,56 +2,57 @@
2
2
  "name": "@examplary/cli",
3
3
  "description": "Command-line tools for building and publishing Examplary question types.",
4
4
  "packageManager": "yarn@4.8.1",
5
- "version": "1.6.0",
6
- "type": "module",
5
+ "version": "1.9.0",
7
6
  "bin": {
8
- "exp": "./bin/index.js"
7
+ "exp": "./dist/index.js"
9
8
  },
10
9
  "scripts": {
11
- "release": "semantic-release -e semantic-release-monorepo"
12
- },
13
- "installConfig": {
14
- "hoistingLimits": "dependencies"
10
+ "release": "semantic-release -e semantic-release-monorepo",
11
+ "build:preview-ui": "vite build",
12
+ "build:js": "tsc --project tsconfig.json",
13
+ "build": "yarn build:js && yarn build:preview-ui",
14
+ "dev": "tsx scripts/dev.ts"
15
15
  },
16
16
  "publishConfig": {
17
17
  "access": "public"
18
18
  },
19
19
  "files": [
20
- "bin",
21
- "src"
20
+ "dist"
22
21
  ],
23
22
  "dependencies": {
24
23
  "@examplary/schemas": "*",
25
24
  "@examplary/ui": "*",
26
- "@hono/node-server": "^1.19.11",
25
+ "@hono/node-server": "^1.19.13",
27
26
  "@tailwindcss/postcss": "^4.1.14",
28
27
  "@tailwindcss/vite": "^4.2.1",
29
- "@vitejs/plugin-react": "^6.0.1",
30
28
  "esbuild": "^0.27.1",
31
- "hono": "^4.12.8",
32
- "i18next": "^25.3.2",
33
- "i18next-browser-languagedetector": "^8.2.0",
29
+ "hono": "^4.12.18",
34
30
  "jsonata": "^2.1.0",
35
31
  "lucide-react": "^0.535.0",
36
32
  "open": "^11.0.0",
37
- "postcss": "^8.5.6",
38
- "react": "^19.2.4",
39
- "react-dom": "^19.2.4",
40
- "react-error-boundary": "^6.0.3",
41
- "react-i18next": "^16.0.0",
42
- "swr": "^2.3.6",
43
33
  "tailwindcss": "^4.2.1",
44
- "use-local-storage": "^3.0.0",
45
- "vite": "^8.0.0",
46
34
  "ws": "^8.18.3",
47
- "yaml": "^2.8.2",
35
+ "yaml": "^2.8.3",
48
36
  "yargs": "^18.0.0"
49
37
  },
50
38
  "devDependencies": {
51
39
  "@types/node": "^24.1.0",
52
- "typescript": "^5.9.3"
40
+ "@types/yargs": "^17.0.35",
41
+ "@vitejs/plugin-react": "^6.0.1",
42
+ "i18next": "^26.2.0",
43
+ "i18next-browser-languagedetector": "^8.2.0",
44
+ "postcss": "^8.5.10",
45
+ "react": "^19.2.6",
46
+ "react-dom": "^19.2.6",
47
+ "react-error-boundary": "^6.0.3",
48
+ "react-i18next": "^17.0.8",
49
+ "swr": "^2.3.6",
50
+ "tsx": "^4.22.1",
51
+ "typescript": "^6.0.3",
52
+ "use-local-storage": "^3.0.0",
53
+ "vite": "^8.0.5"
53
54
  },
54
- "homepage": "https://developers.examplary.ai/",
55
+ "homepage": "https://examplary.ai/developers",
55
56
  "author": {
56
57
  "name": "Examplary AI",
57
58
  "email": "hi@examplary.ai"
package/bin/index.js DELETED
@@ -1,37 +0,0 @@
1
- #! /usr/bin/env node
2
- import yargs from "yargs";
3
- import { hideBin } from "yargs/helpers";
4
-
5
- import { previewCommand } from "../src/commands/preview.js";
6
- import { uploadCommand } from "../src/commands/upload.js";
7
-
8
- yargs()
9
- .usage("examplary <cmd> [args]")
10
-
11
- .command(
12
- "upload",
13
- "Bundle and upload a question type definition",
14
- (yargs) => {
15
- yargs
16
- .option("key", {
17
- type: "string",
18
- description:
19
- "API key for authentication (uses EXAMPLARY_API_KEY env var if not provided)",
20
- default: process.env.EXAMPLARY_API_KEY || "",
21
- })
22
- .option("host", {
23
- type: "string",
24
- description: "API host to upload to",
25
- default: "https://api.examplary.ai",
26
- });
27
- },
28
- uploadCommand,
29
- )
30
-
31
- .command("preview", "Run local development server", previewCommand)
32
-
33
- .help()
34
- .recommendCommands()
35
- .demandCommand()
36
-
37
- .parse(hideBin(process.argv));
@@ -1,220 +0,0 @@
1
- #! /usr/bin/env node
2
- import { watch } from "fs";
3
- import { readFile } from "fs/promises";
4
- import { createServer as createHttpServer } from "http";
5
- import path, { resolve } from "path";
6
- import { cwd, exit } from "process";
7
-
8
- import { serve } from "@hono/node-server";
9
- import tailwindcss from "@tailwindcss/vite";
10
- import react from "@vitejs/plugin-react";
11
- import { Hono } from "hono";
12
- import open from "open";
13
- import { createServer } from "vite";
14
- import { WebSocketServer } from "ws";
15
-
16
- import { setApiHost, setApiKey } from "../lib/api.js";
17
- import { buildComponent } from "../lib/bundle.js";
18
- import { adaptExpressMiddleware } from "../lib/middleware.js";
19
- import { readMetaFile } from "../lib/read-meta.js";
20
- import { buildStyles } from "../lib/styles.js";
21
-
22
- export const previewCommand = async (argv) => {
23
- setApiHost(argv.host);
24
- setApiKey(argv.key);
25
-
26
- const dir = cwd();
27
-
28
- // Verify a question-type file exists (json or yml)
29
- try {
30
- await readMetaFile();
31
- } catch (e) {
32
- console.error(`🚫 ${e.message}`);
33
- exit(1);
34
- }
35
-
36
- // Let's start a Vite server to preview the question type
37
- const root = resolve(import.meta.dirname, "..", "preview-ui");
38
- const app = new Hono();
39
- const vite = await createServer({
40
- server: { middlewareMode: true },
41
- mode: "development",
42
- appType: "custom",
43
- root,
44
- plugins: [react(), tailwindcss()],
45
- resolve: {
46
- alias: {
47
- react: path.dirname(import.meta.resolve("react")),
48
- "react-dom": path.dirname(import.meta.resolve("react-dom")),
49
- },
50
- },
51
- });
52
-
53
- app.get("/api/bundle", async (c) => {
54
- const path = c.req.query("path");
55
- const sourcemap = c.req.query("sourcemap") === "1";
56
- const componentName = c.req.query("componentName");
57
-
58
- try {
59
- const componentOutput = await buildComponent(path);
60
-
61
- if (sourcemap) {
62
- return c.body(componentOutput.sourcemap, 200, {
63
- "Content-Type": "application/json",
64
- });
65
- } else {
66
- const sizeInKb = componentOutput.length / 1000;
67
- if (sizeInKb > 100) {
68
- console.warn(
69
- `⚠️ Component ${componentName} is larger than 100 kB! Consider optimizing it.`,
70
- );
71
- }
72
-
73
- let output = componentOutput.js;
74
- if (componentOutput.sourcemap) {
75
- output += `\n//# sourceMappingURL=/api/bundle?componentName=${componentName}&path=${encodeURIComponent(path || "")}&sourcemap=1`;
76
- }
77
-
78
- return c.body(output, 200, {
79
- "Content-Type": "application/javascript",
80
- });
81
- }
82
- } catch (error) {
83
- console.error(
84
- `🚫 Error bundling component ${componentName} from ${path}: ${error.message}`,
85
- );
86
- return c.text(
87
- `Error bundling component ${componentName}: ${error.message}`,
88
- 500,
89
- );
90
- }
91
- });
92
- app.get("/api/icon", async (c) => {
93
- const path = c.req.query("path") || "";
94
- const icon = await readFile(resolve(dir, path), "utf-8");
95
-
96
- return c.body(icon, 200, {
97
- "Content-Type": "image/svg+xml",
98
- });
99
- });
100
-
101
- app.get("/api/stylesheet", async (c) => {
102
- const componentName = c.req.query("componentName");
103
-
104
- try {
105
- const componentOutput = await buildStyles();
106
- return c.body(componentOutput || "", 200, {
107
- "Content-Type": "text/css",
108
- });
109
- } catch (error) {
110
- console.error(
111
- `🚫 Error building CSS for component ${componentName}: ${error.message}`,
112
- );
113
- return c.text(
114
- `Error building CSS for component ${componentName}: ${error.message}`,
115
- 500,
116
- );
117
- }
118
- });
119
-
120
- let wsPort; // WebSocket port will be set when server starts
121
-
122
- app.get("/", async (c) => {
123
- let questionType;
124
- try {
125
- ({ definition: questionType } = await readMetaFile());
126
- questionType.components = questionType.components
127
- ? Object.entries(questionType.components).reduce(
128
- (acc, [componentName, componentPath]) => ({
129
- ...acc,
130
- [componentName]: `/api/bundle?componentName=${componentName}&path=${encodeURIComponent(componentPath)}`,
131
- }),
132
- {},
133
- )
134
- : questionType.components;
135
- } catch (e) {
136
- return c.text(
137
- `Error reading question type definition: ${e.message}`,
138
- 500,
139
- );
140
- }
141
-
142
- let template = await readFile(resolve(root, "index.html"), "utf-8");
143
- template = await vite.transformIndexHtml("/", template);
144
-
145
- // Inject hot reload script
146
- const hotReloadScript = `
147
- <script>
148
- (function() {
149
- const wsPort = ${wsPort || "null"};
150
- if (wsPort) {
151
- const ws = new WebSocket('ws://localhost:' + wsPort);
152
- ws.onmessage = function(event) {
153
- const data = JSON.parse(event.data);
154
- if (data.type === 'reload') {
155
- console.log('🔄 Reloading page due to file change...');
156
- window.location.reload();
157
- }
158
- };
159
- ws.onopen = function() {
160
- console.log('🔗 Hot reload connected');
161
- };
162
- ws.onclose = function() {
163
- console.log('🔌 Hot reload disconnected');
164
- };
165
- ws.onerror = function(error) {
166
- console.log('❌ Hot reload error:', error);
167
- };
168
- }
169
- })();
170
- </script>
171
- `;
172
-
173
- template =
174
- "<script>window._questionType = " +
175
- JSON.stringify(questionType) +
176
- `;</script>${template}${hotReloadScript}`;
177
- return c.html(template);
178
- });
179
-
180
- app.use("*", adaptExpressMiddleware(vite.middlewares));
181
-
182
- // Set up file watcher
183
- const watchDir = cwd();
184
- console.log(`📁 Watching ${watchDir} for changes...`);
185
-
186
- let wss; // Will be initialized after server starts
187
-
188
- const watcher = watch(watchDir, { recursive: true }, (filename) => {
189
- if (filename && !filename.startsWith(".")) {
190
- // Broadcast reload message to all connected clients
191
- if (wss) {
192
- wss.clients.forEach((client) => {
193
- if (client.readyState === 1) {
194
- // WebSocket.OPEN
195
- client.send(JSON.stringify({ type: "reload" }));
196
- }
197
- });
198
- }
199
- }
200
- });
201
-
202
- // Clean up watcher on process exit
203
- process.on("SIGINT", () => {
204
- watcher.close();
205
- process.exit(0);
206
- });
207
-
208
- serve({ fetch: app.fetch }, (address) => {
209
- const port = address.port;
210
- wsPort = port + 1234;
211
-
212
- const wsServer = createHttpServer();
213
- wss = new WebSocketServer({ server: wsServer });
214
- wsServer.listen(wsPort);
215
-
216
- const url = `http://localhost:${port}`;
217
- console.log(`🚀 Preview server running at ${url}`);
218
- open(url);
219
- });
220
- };
@@ -1,179 +0,0 @@
1
- #! /usr/bin/env node
2
- import { readFile } from "fs/promises";
3
- import { resolve } from "path";
4
- import { cwd, exit } from "process";
5
-
6
- import { setApiHost, setApiKey, uploadFile } from "../lib/api.js";
7
- import { buildComponent } from "../lib/bundle.js";
8
- import { deepCompileJsonata } from "../lib/jsonata.js";
9
- import { readMetaFile } from "../lib/read-meta.js";
10
- import { buildStyles } from "../lib/styles.js";
11
-
12
- export const uploadCommand = async (argv) => {
13
- setApiHost(argv.host);
14
- setApiKey(argv.key);
15
-
16
- const dir = cwd();
17
- let definition = {};
18
- try {
19
- ({ definition } = await readMetaFile());
20
- } catch (e) {
21
- console.error(`🚫 ${e.message}`);
22
- exit(1);
23
- }
24
- console.log(`Uploading question type: ${definition.id}...`);
25
- if (!definition.id) {
26
- console.error(`🚫 Missing required field: id`);
27
- exit(1);
28
- }
29
- if (!definition.name) {
30
- console.error(`🚫 Missing required field: name`);
31
- exit(1);
32
- }
33
-
34
- // Validate JSONata expressions in the definition
35
- if (definition.export?.qti?.interaction?.options) {
36
- try {
37
- await deepCompileJsonata(definition.export.qti.interaction.options);
38
- } catch (e) {
39
- console.error(
40
- `🚫 Invalid JSONata expression in export.qti.interaction.options: ${e.message}`,
41
- );
42
- exit(1);
43
- }
44
- }
45
-
46
- // Bundle and upload components
47
- const components = {};
48
- const validComponentTypes = [
49
- "settings-area",
50
- "assessment",
51
- "print",
52
- "results",
53
- ];
54
- for (const [componentType, componentPath] of Object.entries(
55
- definition.components || {},
56
- )) {
57
- // Validation
58
- if (!validComponentTypes.includes(componentType)) {
59
- console.error(`🚫 Invalid component type specified: ${componentType}`);
60
- exit(1);
61
- }
62
- const realPath = resolve(dir, componentPath);
63
- if (!realPath) {
64
- console.error(`🚫 Missing required file: ${componentPath}`);
65
- exit(1);
66
- }
67
-
68
- // Bundle component
69
- let componentOutput = {};
70
- try {
71
- componentOutput = await buildComponent(realPath);
72
- const sizeInKb = componentOutput.js.length / 1000;
73
- const sizeHint = `(${sizeInKb.toFixed(2)} kB)`;
74
- console.log(
75
- `• Bundled component ${componentType} from ${componentPath} ${sizeHint}`,
76
- );
77
-
78
- if (sizeInKb > 100) {
79
- console.warn(
80
- ` ⚠️ Component ${componentType} is larger than 100 kB! Consider optimizing it.`,
81
- );
82
- if (process.env.GITHUB_ACTIONS) {
83
- console.log(
84
- `::warning file=${realPath},title=Large component size::Component ${
85
- componentType
86
- } is larger than 100 kB ${sizeHint}! Consider optimizing it.`,
87
- );
88
- }
89
- }
90
- } catch (error) {
91
- console.error(
92
- `🚫 Error bundling component ${componentType} from ${componentPath}: ${error.message}`,
93
- );
94
- exit(1);
95
- }
96
-
97
- // Upload source map first if it exists
98
- let sourceMapStatement = "";
99
- if (componentOutput.sourcemap) {
100
- const url = await uploadFile(
101
- `component-${componentType}.js.map`,
102
- componentOutput.sourcemap,
103
- "application/json",
104
- );
105
-
106
- sourceMapStatement = `\n//# sourceMappingURL=${url}`;
107
- }
108
-
109
- // Upload component
110
- components[componentType] = await uploadFile(
111
- `component-${componentType}.js`,
112
- componentOutput.js + sourceMapStatement,
113
- "application/javascript",
114
- );
115
-
116
- console.log(`• Uploaded component ${componentType}`);
117
- }
118
- definition.components = components;
119
-
120
- // Upload styles if present
121
- if (Object.keys(definition.components).length) {
122
- const styles = await buildStyles();
123
- if (styles) {
124
- definition.stylesheet = await uploadFile(
125
- "styles.css",
126
- styles,
127
- "text/css",
128
- );
129
- const sizeInKb = styles.length / 1000;
130
- const sizeHint = `(${sizeInKb.toFixed(2)} kB)`;
131
- console.log(`• Uploaded styles ${sizeHint}`);
132
- }
133
- }
134
-
135
- // Upload icon if specified
136
- if (definition.icon) {
137
- const iconPath = resolve(dir, definition.icon);
138
- let iconContents;
139
- try {
140
- iconContents = await readFile(iconPath, "utf-8");
141
- } catch (error) {
142
- console.error(`🚫 Error reading icon file: ${error.message}`);
143
- exit(1);
144
- }
145
- if (!iconContents) {
146
- console.error(`🚫 Icon file is empty: ${iconPath}`);
147
- exit(1);
148
- }
149
- definition.icon = await uploadFile(
150
- "icon.svg",
151
- iconContents,
152
- "image/svg+xml",
153
- );
154
- console.log(`• Uploaded icon`);
155
- }
156
-
157
- // Upload the main question type definition
158
- const res = await fetch(`${argv.host}/question-types`, {
159
- headers: {
160
- Authorization: `Bearer ${argv.key}`,
161
- "Content-Type": "application/json",
162
- },
163
- method: "POST",
164
- body: JSON.stringify(definition),
165
- });
166
-
167
- if (!res.ok) {
168
- console.error(`🚫 Uploading question type failed`);
169
- try {
170
- const errorResponse = await res.json();
171
- console.log(errorResponse);
172
- } catch (e) {
173
- console.log(e);
174
- }
175
- exit(1);
176
- }
177
-
178
- console.log(`• Finished uploading definition\n`);
179
- };
package/src/lib/api.js DELETED
@@ -1,53 +0,0 @@
1
- import { basename } from "path";
2
- import { exit } from "process";
3
-
4
- // These get overwritten by the CLI options
5
- export let API_HOST = "https://api.examplary.ai";
6
- export let API_KEY = process.env.EXAMPLARY_API_KEY || "";
7
-
8
- export const setApiKey = (key) => {
9
- if (!key) return;
10
- API_KEY = key;
11
- };
12
- export const setApiHost = (host) => {
13
- if (!host) return;
14
- API_HOST = host;
15
- };
16
-
17
- export const uploadFile = async (fileName, fileContents, contentType) => {
18
- const params = new URLSearchParams();
19
- params.append("filename", basename(fileName));
20
- params.append("contentType", contentType);
21
- params.append("type", "question-type");
22
-
23
- // Request the upload URL
24
- const res = await fetch(`${API_HOST}/media/upload?${params.toString()}`, {
25
- headers: {
26
- Authorization: `Bearer ${API_KEY}`,
27
- },
28
- });
29
-
30
- if (!res.ok) {
31
- const errorText = await res.text();
32
- console.error(`🚫 Upload failed: ${errorText}`);
33
- exit(1);
34
- }
35
-
36
- // Actually upload the file
37
- const { uploadUrl, publicUrl } = await res.json();
38
- const uploadRes = await fetch(uploadUrl, {
39
- method: "PUT",
40
- headers: {
41
- "Content-Type": contentType,
42
- },
43
- body: fileContents,
44
- });
45
-
46
- if (!uploadRes.ok) {
47
- const errorText = await uploadRes.text();
48
- console.error(`🚫 Upload failed: ${errorText}`);
49
- exit(1);
50
- }
51
-
52
- return publicUrl;
53
- };
package/src/lib/bundle.js DELETED
@@ -1,35 +0,0 @@
1
- import { build } from "esbuild";
2
-
3
- export const buildComponent = async (file) => {
4
- const res = await build({
5
- entryPoints: [file],
6
- bundle: true,
7
- write: false,
8
- minify: true,
9
- sourcemap: "inline",
10
- platform: "browser",
11
- format: "cjs",
12
- external: [
13
- "@examplary/ui",
14
- "react",
15
- "react-dom",
16
- "react/jsx-runtime",
17
- "react-dom/client",
18
- ],
19
- });
20
-
21
- let js = res.outputFiles[0].text;
22
- let sourcemap = "";
23
-
24
- const sourceMapStatement =
25
- "\n//# sourceMappingURL=data:application/json;base64,";
26
- if (js.includes(sourceMapStatement)) {
27
- sourcemap = Buffer.from(
28
- js.split(sourceMapStatement)[1].trim(),
29
- "base64",
30
- ).toString("utf-8");
31
- js = js.split(sourceMapStatement)[0].trim();
32
- }
33
-
34
- return { js, sourcemap };
35
- };
@@ -1,31 +0,0 @@
1
- import jsonata from "jsonata";
2
-
3
- export const deepCompileJsonata = async (expression) => {
4
- if (typeof expression === "string" && expression.startsWith("=")) {
5
- try {
6
- jsonata(expression.substring(1));
7
- } catch (error) {
8
- throw new Error(
9
- `JSONata evaluation failed for "${expression}": ${error.message}`,
10
- );
11
- }
12
- }
13
-
14
- if (Array.isArray(expression)) {
15
- const output = [];
16
- for (const o of expression) {
17
- output.push(await deepCompileJsonata(o));
18
- }
19
- return output;
20
- }
21
-
22
- if (typeof expression === "object" && expression !== null) {
23
- const result = {};
24
- for (const [key, value] of Object.entries(expression)) {
25
- result[key] = await deepCompileJsonata(value);
26
- }
27
- return result;
28
- }
29
-
30
- return expression;
31
- };
@@ -1,16 +0,0 @@
1
- import { createMiddleware } from "hono/factory";
2
-
3
- export const adaptExpressMiddleware = (middleware) =>
4
- createMiddleware(async (c, next) => {
5
- const req = c.env.incoming;
6
- const res = c.env.outgoing;
7
-
8
- await new Promise((resolve, reject) => {
9
- middleware(req, res, (err) => {
10
- if (err) reject(err);
11
- else resolve(c.res);
12
- });
13
- });
14
-
15
- await next();
16
- });