@jsnote-zeina/local-api 1.0.1 → 1.0.3
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/routes/cells.js +49 -23
- package/package.json +3 -4
package/dist/routes/cells.js
CHANGED
|
@@ -18,7 +18,7 @@ const promises_1 = __importDefault(require("fs/promises"));
|
|
|
18
18
|
const path_1 = __importDefault(require("path"));
|
|
19
19
|
const defaultCells = [
|
|
20
20
|
{
|
|
21
|
-
content: 'JSNote-Zeina\n----------\nThis is an interactive coding environment. You can write Javascript, see it executed, and write
|
|
21
|
+
content: 'JSNote-Zeina\n----------\nThis is an interactive coding environment. You can write Javascript, see it executed, and write comprehensive documentation using markdown.\n\n- Click any text cell (including this one) to edit it\n- The code in each code editor is all joined into one file. If you define a variable in cell #1, you can refer to it in any following code cell!\n- You can show any React component, string, number, or anything else by calling the `show `function. This is a function built into this environment. Call show multiple times to show multiple values\n- Re-order or delete cells using the buttons on the top right \n- Add new cells by hovering on the divider between each cell\n\nAll of your changes get saved to the file you opened Jbook with. So if you ran `npx jsnote-zeina serve test.js` , all of the text and code you write will be saved to the `test.js` file.',
|
|
22
22
|
type: 'text',
|
|
23
23
|
id: 'ohbrr',
|
|
24
24
|
},
|
|
@@ -37,39 +37,65 @@ const createCellsRouter = (filename, dir) => {
|
|
|
37
37
|
const router = express_1.default.Router();
|
|
38
38
|
router.use(express_1.default.json());
|
|
39
39
|
const fullPath = path_1.default.join(dir, filename);
|
|
40
|
+
const isLocalApiError = (err) => {
|
|
41
|
+
return typeof err === 'object' && err !== null && typeof err.code === 'string';
|
|
42
|
+
};
|
|
43
|
+
const isCell = (value) => {
|
|
44
|
+
if (typeof value !== 'object' || value === null)
|
|
45
|
+
return false;
|
|
46
|
+
const c = value;
|
|
47
|
+
return (typeof c.id === 'string' &&
|
|
48
|
+
typeof c.content === 'string' &&
|
|
49
|
+
(c.type === 'text' || c.type === 'code'));
|
|
50
|
+
};
|
|
51
|
+
const isCellArray = (value) => {
|
|
52
|
+
return Array.isArray(value) && value.every(isCell);
|
|
53
|
+
};
|
|
40
54
|
router.get('/cells', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
41
|
-
const isLocalApiError = (err) => {
|
|
42
|
-
return typeof err.code === 'string';
|
|
43
|
-
};
|
|
44
55
|
try {
|
|
45
|
-
// Read the file
|
|
46
56
|
const result = yield promises_1.default.readFile(fullPath, { encoding: 'utf-8' });
|
|
47
|
-
|
|
57
|
+
let parsed;
|
|
58
|
+
try {
|
|
59
|
+
parsed = JSON.parse(result);
|
|
60
|
+
}
|
|
61
|
+
catch (parseErr) {
|
|
62
|
+
console.error(`Notebook file ${fullPath} contains invalid JSON; serving defaults:`, parseErr);
|
|
63
|
+
res.send(defaultCells);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!isCellArray(parsed)) {
|
|
67
|
+
console.error(`Notebook file ${fullPath} does not match expected cell schema; serving defaults.`);
|
|
68
|
+
res.send(defaultCells);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
res.send(parsed);
|
|
48
72
|
}
|
|
49
73
|
catch (err) {
|
|
50
|
-
if (isLocalApiError(err)) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
res.send(JSON.stringify(defaultCells));
|
|
74
|
+
if (isLocalApiError(err) && err.code === 'ENOENT') {
|
|
75
|
+
try {
|
|
76
|
+
yield promises_1.default.writeFile(fullPath, JSON.stringify(defaultCells), 'utf-8');
|
|
77
|
+
res.send(defaultCells);
|
|
55
78
|
}
|
|
56
|
-
|
|
57
|
-
|
|
79
|
+
catch (writeErr) {
|
|
80
|
+
console.error('Failed to seed notebook file:', writeErr);
|
|
81
|
+
res.status(500).send({ error: 'Failed to create notebook file' });
|
|
58
82
|
}
|
|
83
|
+
return;
|
|
59
84
|
}
|
|
85
|
+
console.error('Failed to read notebook file:', err);
|
|
86
|
+
res.status(500).send({ error: 'Failed to read notebook file' });
|
|
60
87
|
}
|
|
61
|
-
// If read throws an error
|
|
62
|
-
// Insprect the error, see if it says that file doesn't exist
|
|
63
|
-
// Parse a list of cells out of it
|
|
64
|
-
// Send list of cells back to browser
|
|
65
88
|
}));
|
|
66
89
|
router.post('/cells', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
90
|
+
try {
|
|
91
|
+
const { cells } = req.body;
|
|
92
|
+
yield promises_1.default.writeFile(fullPath, JSON.stringify(cells), 'utf-8');
|
|
93
|
+
res.send({ status: 'ok' });
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
console.error('Failed to write notebook file:', err);
|
|
97
|
+
res.status(500).send({ error: 'Failed to save notebook file' });
|
|
98
|
+
}
|
|
73
99
|
}));
|
|
74
100
|
return router;
|
|
75
101
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsnote-zeina/local-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -23,10 +23,9 @@
|
|
|
23
23
|
"typescript": "^5.4.5"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@jsnote-zeina/local-client": "^1.0.
|
|
26
|
+
"@jsnote-zeina/local-client": "^1.0.3",
|
|
27
27
|
"cors": "^2.8.5",
|
|
28
28
|
"express": "^4.19.2",
|
|
29
29
|
"http-proxy-middleware": "^3.0.0"
|
|
30
|
-
}
|
|
31
|
-
"gitHead": "c917f9837ac91b26442e0c1b41444228d240e5af"
|
|
30
|
+
}
|
|
32
31
|
}
|