scorm-review 1.2.0 → 1.3.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.
- package/README.md +361 -0
- package/dist/cli.js +38 -5
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
# scorm-review
|
|
2
|
+
|
|
3
|
+
> Inject the **coreview** annotation tool into any SCORM package — no server, no browser extension, no setup needed on the reviewer's end.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [What it does](#what-it-does)
|
|
10
|
+
- [How it works](#how-it-works)
|
|
11
|
+
- [Requirements](#requirements)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Option A — Use with npx (no install)](#option-a--use-with-npx-no-install)
|
|
14
|
+
- [Option B — Install globally](#option-b--install-globally)
|
|
15
|
+
- [Usage](#usage)
|
|
16
|
+
- [Convert a SCORM zip](#convert-a-scorm-zip)
|
|
17
|
+
- [Convert a SCORM folder](#convert-a-scorm-folder)
|
|
18
|
+
- [Convert a plain HTML file](#convert-a-plain-html-file)
|
|
19
|
+
- [Specify a custom output path](#specify-a-custom-output-path)
|
|
20
|
+
- [Show help](#show-help)
|
|
21
|
+
- [Output explained](#output-explained)
|
|
22
|
+
- [What gets changed inside your package](#what-gets-changed-inside-your-package)
|
|
23
|
+
- [How to send to a reviewer](#how-to-send-to-a-reviewer)
|
|
24
|
+
- [CLI reference](#cli-reference)
|
|
25
|
+
- [How it works internally](#how-it-works-internally)
|
|
26
|
+
- [Entry point detection](#entry-point-detection)
|
|
27
|
+
- [Script injection](#script-injection)
|
|
28
|
+
- [coreview.js bundling](#coreviewjs-bundling)
|
|
29
|
+
- [Project structure](#project-structure)
|
|
30
|
+
- [Building from source](#building-from-source)
|
|
31
|
+
- [Troubleshooting](#troubleshooting)
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## What it does
|
|
36
|
+
|
|
37
|
+
`scorm-review` takes a SCORM package (zip file, unzipped folder, or a standalone HTML file) and injects the **coreview** annotation tool into it. The output is a new file your reviewers can open in any browser and leave comments directly on the slides — no install needed on their end.
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
Before: my-course.zip ← plain SCORM package
|
|
41
|
+
After: my-course_review.zip ← same package + annotation panel built in
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Reviewers open `index.html` from the output zip and the annotation sidebar appears automatically.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## How it works
|
|
49
|
+
|
|
50
|
+
1. Opens the input (zip, folder, or HTML file)
|
|
51
|
+
2. Finds the HTML entry point (`index.html`)
|
|
52
|
+
3. Injects a `<script>` tag referencing `coreview.js` into that HTML file
|
|
53
|
+
4. Adds `coreview.js` (the annotation tool) next to the entry HTML
|
|
54
|
+
5. Saves the modified package as a new zip (or HTML file for single-file input)
|
|
55
|
+
|
|
56
|
+
The original file is never modified. A new `_review` file is always created.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Requirements
|
|
61
|
+
|
|
62
|
+
- [Node.js](https://nodejs.org/) **v18 or higher**
|
|
63
|
+
|
|
64
|
+
That's all. No other tools, no browser extensions, no server.
|
|
65
|
+
|
|
66
|
+
To check your Node.js version:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
node --version
|
|
70
|
+
# Should print v18.x.x or higher
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If you don't have Node.js, download the LTS version from [nodejs.org](https://nodejs.org).
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Installation
|
|
78
|
+
|
|
79
|
+
### Option A — Use with npx (no install)
|
|
80
|
+
|
|
81
|
+
Run it directly without installing anything:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npx scorm-review ./my-course.zip
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`npx` is included with Node.js. On first run it fetches the package automatically.
|
|
88
|
+
|
|
89
|
+
### Option B — Install globally
|
|
90
|
+
|
|
91
|
+
Install once, use from anywhere without the `npx` prefix:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm install -g scorm-review
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Then:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
scorm-review ./my-course.zip
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Usage
|
|
106
|
+
|
|
107
|
+
### Convert a SCORM zip
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npx scorm-review ./my-course.zip
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Output in the same folder:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
Input: my-course.zip
|
|
117
|
+
Output: C:\path\to\my-course_review.zip
|
|
118
|
+
|
|
119
|
+
Processing SCORM zip... done.
|
|
120
|
+
|
|
121
|
+
✓ Created: my-course_review.zip (15.2 MB)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Convert a SCORM folder
|
|
125
|
+
|
|
126
|
+
If your SCORM package is already unzipped:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx scorm-review ./my-course/
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The tool walks the folder, finds `index.html`, injects the annotation tool, and packages everything back into a zip.
|
|
133
|
+
|
|
134
|
+
### Convert a plain HTML file
|
|
135
|
+
|
|
136
|
+
For a standalone HTML file (not a SCORM package):
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npx scorm-review ./page.html
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Output: `page_review.html` — the script is embedded inline so no separate `coreview.js` file is needed.
|
|
143
|
+
|
|
144
|
+
### Specify a custom output path
|
|
145
|
+
|
|
146
|
+
Use `-o` or `--output` to choose where the output file is saved:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npx scorm-review ./my-course.zip -o ./output/my-course_review.zip
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The output directory is created automatically if it doesn't exist.
|
|
153
|
+
|
|
154
|
+
### Show help
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npx scorm-review --help
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Output explained
|
|
163
|
+
|
|
164
|
+
| Input | Output file | Notes |
|
|
165
|
+
|---|---|---|
|
|
166
|
+
| `my-course.zip` | `my-course_review.zip` | New zip with `coreview.js` added and `index.html` injected |
|
|
167
|
+
| `my-course/` (folder) | `my-course_review.zip` | Folder re-zipped with `coreview.js` added and `index.html` injected |
|
|
168
|
+
| `page.html` | `page_review.html` | Single file — script embedded inline |
|
|
169
|
+
|
|
170
|
+
The output is always saved **next to the input file** unless you specify `-o`.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## What gets changed inside your package
|
|
175
|
+
|
|
176
|
+
Only two things change inside the output zip compared to the original:
|
|
177
|
+
|
|
178
|
+
1. **`coreview.js` is added** — placed in the same folder as `index.html`
|
|
179
|
+
2. **One `<script>` tag is added to `index.html`** — injected just before `</body>`
|
|
180
|
+
|
|
181
|
+
```html
|
|
182
|
+
<!-- Added by scorm-review -->
|
|
183
|
+
<script
|
|
184
|
+
src="./coreview.js"
|
|
185
|
+
data-project="scorm-review"
|
|
186
|
+
data-note="Please review all slides. Check layout, wording, and content."
|
|
187
|
+
data-start-open="false">
|
|
188
|
+
</script>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Everything else — folder structure, file names, SCORM manifest, assets — is **untouched**.
|
|
192
|
+
|
|
193
|
+
If a `coreview.js` script tag already exists in the HTML, it is replaced rather than duplicated.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## How to send to a reviewer
|
|
198
|
+
|
|
199
|
+
1. Run `scorm-review` on your SCORM package
|
|
200
|
+
2. Send the `_review.zip` to your reviewer (email, shared drive, etc.)
|
|
201
|
+
3. Reviewer unzips it and opens `index.html` in any modern browser (Chrome, Edge, Firefox, Safari)
|
|
202
|
+
4. The annotation panel appears automatically — they can leave comments on any slide
|
|
203
|
+
5. They share their annotated session back to you (via the coreview export feature)
|
|
204
|
+
|
|
205
|
+
No installs, no accounts, no browser extensions required on the reviewer's side.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## CLI reference
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
scorm-review <input> [options]
|
|
213
|
+
|
|
214
|
+
Arguments:
|
|
215
|
+
<input> Path to a .zip file, a folder, or a .html file
|
|
216
|
+
|
|
217
|
+
Options:
|
|
218
|
+
-o, --output <path> Custom output file path (default: <name>_review.zip next to input)
|
|
219
|
+
-h, --help Show help message
|
|
220
|
+
|
|
221
|
+
Supported input types:
|
|
222
|
+
.zip SCORM package zip file
|
|
223
|
+
folder/ Unzipped SCORM package directory
|
|
224
|
+
.html / .htm Plain HTML file
|
|
225
|
+
|
|
226
|
+
Exit codes:
|
|
227
|
+
0 Success
|
|
228
|
+
1 Error (path not found, unsupported file type, no HTML entry point found)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## How it works internally
|
|
234
|
+
|
|
235
|
+
### Entry point detection
|
|
236
|
+
|
|
237
|
+
The tool looks for the HTML entry point in this priority order:
|
|
238
|
+
|
|
239
|
+
1. `index.html` at the root of the zip/folder
|
|
240
|
+
2. `Index.html` at the root (case-insensitive fallback)
|
|
241
|
+
3. `<subfolder>/index.html` — one level deep (common in SCORM packages where content is inside `scorm_package/`)
|
|
242
|
+
4. Any `.html` file anywhere in the package
|
|
243
|
+
|
|
244
|
+
If no HTML file is found, the tool exits with an error.
|
|
245
|
+
|
|
246
|
+
### Script injection
|
|
247
|
+
|
|
248
|
+
The `<script>` tag is injected just before `</body>`. If the HTML has no `</body>` tag, the script is appended to the end of the file.
|
|
249
|
+
|
|
250
|
+
Any existing `coreview.js` script tags are removed before injecting the new one — so re-running the tool on an already-injected package is safe and idempotent.
|
|
251
|
+
|
|
252
|
+
### coreview.js bundling
|
|
253
|
+
|
|
254
|
+
`coreview.js` is **baked into the CLI binary at build time** using esbuild. This means:
|
|
255
|
+
|
|
256
|
+
- The CLI is a single file with no runtime file dependencies
|
|
257
|
+
- The same version of the annotation tool ships with every release
|
|
258
|
+
- No network access is needed at runtime — everything is self-contained
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Project structure
|
|
263
|
+
|
|
264
|
+
```
|
|
265
|
+
scorm-review-cli/
|
|
266
|
+
├── src/
|
|
267
|
+
│ ├── cli.ts # Entry point — argument parsing, file I/O, orchestration
|
|
268
|
+
│ ├── bundler.ts # Core logic — zip handling, HTML injection, folder packing
|
|
269
|
+
│ └── bundler-template.ts # Template used during the build to embed coreview.js
|
|
270
|
+
├── dist/ # Compiled output (generated by build)
|
|
271
|
+
│ └── cli.js # Single-file compiled CLI (published to npm)
|
|
272
|
+
├── build.mjs # esbuild build script — compiles + inlines coreview.js
|
|
273
|
+
├── tsconfig.json # TypeScript configuration
|
|
274
|
+
└── package.json
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Key files
|
|
278
|
+
|
|
279
|
+
**`src/cli.ts`** — Handles all CLI concerns: argument parsing, input validation, calling the right bundler function, and writing the output file. Contains no bundling logic itself.
|
|
280
|
+
|
|
281
|
+
**`src/bundler.ts`** — Contains three exported functions:
|
|
282
|
+
- `bundleScormZip(zipBuffer, coreviewScript)` — processes a zip Buffer
|
|
283
|
+
- `bundleScormFolder(folderPath, coreviewScript)` — processes a folder on disk
|
|
284
|
+
- `bundlePlainHtml(htmlBuffer, coreviewScript)` — processes a standalone HTML file
|
|
285
|
+
|
|
286
|
+
**`build.mjs`** — esbuild script that reads `coreview.js` from disk, base64-encodes it (or inlines it as a string), and substitutes the `__COREVIEW_SCRIPT__` constant at bundle time. The result is `dist/cli.js`, a single portable file with no external dependencies.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Building from source
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# Install dev dependencies
|
|
294
|
+
npm install
|
|
295
|
+
|
|
296
|
+
# Build dist/cli.js
|
|
297
|
+
npm run build
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
The build script (`build.mjs`) uses esbuild to:
|
|
301
|
+
1. Compile TypeScript to JavaScript
|
|
302
|
+
2. Bundle all imports into a single file
|
|
303
|
+
3. Inline `coreview.js` as a string constant at build time
|
|
304
|
+
4. Output `dist/cli.js` with the Node.js shebang line
|
|
305
|
+
|
|
306
|
+
To test the built binary locally:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
node dist/cli.js ./samplefolder/sample3.zip
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Troubleshooting
|
|
315
|
+
|
|
316
|
+
**`npx: command not found`**
|
|
317
|
+
|
|
318
|
+
Node.js is not installed or not on your PATH. Download from [nodejs.org](https://nodejs.org) and reinstall.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
**`Error: Path not found: ...`**
|
|
323
|
+
|
|
324
|
+
The file or folder you specified doesn't exist at that path. Check for typos, or use the full absolute path:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
npx scorm-review "C:\Users\yourname\Desktop\my-course.zip"
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
**`Error: No HTML entry point found`**
|
|
333
|
+
|
|
334
|
+
The zip doesn't contain an `index.html`. Possible causes:
|
|
335
|
+
- You pointed at a zip that isn't a SCORM package
|
|
336
|
+
- The SCORM package has a non-standard entry point (e.g. `story.html` instead of `index.html`)
|
|
337
|
+
- The `index.html` is nested more than one level deep
|
|
338
|
+
|
|
339
|
+
Try unzipping manually and pointing the tool at the folder that contains `index.html`:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
npx scorm-review ./unzipped-course/
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
**`Error: Unsupported file type ".pptx"`**
|
|
348
|
+
|
|
349
|
+
Only `.zip`, `.html`, `.htm`, and folders are accepted. Other file types are not supported.
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
**Output zip is much larger than the original**
|
|
354
|
+
|
|
355
|
+
This is expected when the original zip used maximum compression. The tool re-compresses with level 6 (balanced), which may produce a slightly larger file compared to an original that was compressed at level 9. The content is identical.
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
**Running the tool again on a `_review.zip` adds a second injection**
|
|
360
|
+
|
|
361
|
+
Re-running on an already-processed file is safe — the tool removes any existing `coreview.js` script tag before injecting a new one, so no duplication occurs.
|
package/dist/cli.js
CHANGED
|
@@ -9745,19 +9745,52 @@ var import_fs = __toESM(require("fs"));
|
|
|
9745
9745
|
var import_path = __toESM(require("path"));
|
|
9746
9746
|
function findEntryHtml(files) {
|
|
9747
9747
|
const norm = files.map((f) => f.replace(/\\/g, "/"));
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
|
|
9748
|
+
const rootCandidates = [
|
|
9749
|
+
"index.html",
|
|
9750
|
+
"Index.html",
|
|
9751
|
+
"story.html",
|
|
9752
|
+
"Story.html",
|
|
9753
|
+
"index_lms.html",
|
|
9754
|
+
"launch.html",
|
|
9755
|
+
"default.html"
|
|
9756
|
+
];
|
|
9757
|
+
for (const candidate of rootCandidates) {
|
|
9758
|
+
const match = norm.find((f) => f.toLowerCase() === candidate.toLowerCase());
|
|
9759
|
+
if (match) return match;
|
|
9760
|
+
}
|
|
9761
|
+
const nestedCandidates = ["index.html", "story.html", "index_lms.html", "launch.html", "default.html"];
|
|
9762
|
+
for (const candidate of nestedCandidates) {
|
|
9763
|
+
const match = norm.find((f) => new RegExp(`^[^/]+/${candidate}$`, "i").test(f));
|
|
9764
|
+
if (match) return match;
|
|
9765
|
+
}
|
|
9766
|
+
const rootHtml = norm.find((f) => /^[^/]+\.html?$/i.test(f));
|
|
9767
|
+
if (rootHtml) return rootHtml;
|
|
9752
9768
|
const anyHtml = norm.find((f) => /\.html?$/i.test(f));
|
|
9753
9769
|
return anyHtml ?? null;
|
|
9754
9770
|
}
|
|
9755
9771
|
function injectCoreviewTag(html) {
|
|
9756
9772
|
const scriptTag = `<script src="./coreview.js" data-project="scorm-review" data-note="Please review all slides. Check layout, wording, and content." data-start-open="false"></script>`;
|
|
9757
9773
|
html = html.replace(/<script[^>]*src="[^"]*coreview\.js"[^>]*><\/script>\s*/gi, "");
|
|
9758
|
-
|
|
9774
|
+
const hasBody = /<\/body>/i.test(html);
|
|
9775
|
+
const hasHtml = /<\/html>/i.test(html);
|
|
9776
|
+
if (hasBody && hasHtml) {
|
|
9777
|
+
const bodyIdx = html.search(/<\/body>/i);
|
|
9778
|
+
const htmlIdx = html.search(/<\/html>/i);
|
|
9779
|
+
const betweenBodyAndHtml = html.slice(bodyIdx + "</body>".length, htmlIdx).trim();
|
|
9780
|
+
if (betweenBodyAndHtml.length > 0) {
|
|
9781
|
+
return html.replace(/<\/html>/i, `${scriptTag}
|
|
9782
|
+
</html>`);
|
|
9783
|
+
}
|
|
9759
9784
|
return html.replace(/<\/body>/i, `${scriptTag}
|
|
9760
9785
|
</body>`);
|
|
9786
|
+
}
|
|
9787
|
+
if (hasBody) {
|
|
9788
|
+
return html.replace(/<\/body>/i, `${scriptTag}
|
|
9789
|
+
</body>`);
|
|
9790
|
+
}
|
|
9791
|
+
if (hasHtml) {
|
|
9792
|
+
return html.replace(/<\/html>/i, `${scriptTag}
|
|
9793
|
+
</html>`);
|
|
9761
9794
|
}
|
|
9762
9795
|
return html + "\n" + scriptTag;
|
|
9763
9796
|
}
|