coursecode 0.1.19 → 0.1.21
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.
|
@@ -123,7 +123,7 @@ The browser only downloads the one chunk matching the meta tag. Unused driver ch
|
|
|
123
123
|
| `coursecode build` | `dist/` | Universal build + format manifest + meta tag stamped |
|
|
124
124
|
| `coursecode build` (with `PACKAGE=true`) | `dist/` + ZIP | Same + format-specific ZIP for LMS upload |
|
|
125
125
|
| `coursecode preview --export` | `course-preview/` | Copy of `dist/` wrapped in stub player (for Netlify/GitHub Pages) |
|
|
126
|
-
| `coursecode deploy` | Uploads `dist/` | Cloud hosts universal build, assembles format ZIPs on demand. Flags: `--promote` (force live), `--stage` (force staged), `--preview` (preview-only: production untouched, preview always moved), `--repair-binding` (clear stale local cloud binding first if the remote course was deleted). `--promote`/`--stage` are mutually exclusive; `--preview` stacks with either. |
|
|
126
|
+
| `coursecode deploy` | Uploads `dist/` | Cloud hosts universal build, assembles format ZIPs on demand. Flags: `--promote` (force live), `--stage` (force staged), `--preview` (preview-only: production untouched, preview always moved), `--repair-binding` (clear stale local cloud binding first if the remote course was deleted). `--promote`/`--stage` are mutually exclusive; `--preview` stacks with either. **GitHub-linked courses**: production deploy blocked; only `--preview` allowed (see GitHub Source Guard below). |
|
|
127
127
|
|
|
128
128
|
The ZIP never includes preview/stub player assets. Preview is a separate concern (see below).
|
|
129
129
|
|
|
@@ -610,6 +610,20 @@ User: coursecode build → uploads dist/
|
|
|
610
610
|
|
|
611
611
|
**Security boundary:** The cloud never executes `course-config.js` or any user-authored JavaScript. The meta tag and manifest are the only format-specific artifacts, and both are generated from trusted framework source code.
|
|
612
612
|
|
|
613
|
+
#### GitHub Source Guard
|
|
614
|
+
|
|
615
|
+
Courses linked to GitHub for production deploys are protected from accidental CLI overwrites via two layers:
|
|
616
|
+
|
|
617
|
+
| Layer | Mechanism | Key |
|
|
618
|
+
|-------|-----------|-----|
|
|
619
|
+
| **CLI (local)** | `deploy()` reads `sourceType` from `.coursecoderc.json` | Fast fail before build — no wasted time |
|
|
620
|
+
| **Server (safety net)** | Deploy endpoint rejects non-preview uploads for `source_type = 'github'` | Can't bypass via old CLI or `curl` |
|
|
621
|
+
|
|
622
|
+
- **`--preview` always allowed** — useful for testing without touching production pointer
|
|
623
|
+
- **`.coursecoderc.json`** carries `sourceType` and `githubRepo` (committed to repo by cloud's GitHub integration), so anyone cloning gets the guard automatically
|
|
624
|
+
- **Self-healing on unlink:** If the cloud course is unlinked from GitHub, both `status()` and `deploy()` reconcile — they detect the server no longer reports `source_type: 'github'` and clear the local `sourceType`/`githubRepo` from `.coursecoderc.json`. No manual cleanup or repo commit needed.
|
|
625
|
+
- CLI error code: `github_source_blocked` (structured JSON for Desktop/CI consumers)
|
|
626
|
+
|
|
613
627
|
---
|
|
614
628
|
|
|
615
629
|
## Course Validation
|
|
@@ -740,6 +740,7 @@ Open the URL in any browser, log in with your CourseCode account, and enter the
|
|
|
740
740
|
- **Preview pointer** — the version served on the cloud preview link (for stakeholder review).
|
|
741
741
|
- **deploy_mode** — a per-course or org setting in the Cloud dashboard. Default is auto-promote (new uploads immediately go live). Can be set to staged (new uploads require a manual promote step).
|
|
742
742
|
- `--promote` and `--stage` are mutually exclusive.
|
|
743
|
+
- **GitHub-linked courses:** If your course is connected to a GitHub repo in the Cloud dashboard, production deploys happen via `git push` — the CLI blocks direct production uploads. Use `coursecode deploy --preview` to push a preview build for stakeholder review.
|
|
743
744
|
- If a cloud deployment was deleted outside the CLI and this project still has the old local binding, rerun with `coursecode deploy --repair-binding`. To clear the stale binding without deploying yet, run `coursecode status --repair-binding`.
|
|
744
745
|
|
|
745
746
|
**Typical Cloud workflow:**
|
package/lib/cloud.js
CHANGED
|
@@ -982,6 +982,45 @@ export async function deploy(options = {}) {
|
|
|
982
982
|
if (handled) return;
|
|
983
983
|
} else if (!statusRes.ok) {
|
|
984
984
|
await handleResponse(statusRes);
|
|
985
|
+
} else {
|
|
986
|
+
// Reconcile local sourceType with cloud truth (handles unlink-via-dashboard)
|
|
987
|
+
try {
|
|
988
|
+
const statusData = JSON.parse(await statusRes.text());
|
|
989
|
+
const serverSourceType = statusData.source?.type || statusData.source_type;
|
|
990
|
+
const localRc = readRcConfig();
|
|
991
|
+
if (localRc?.sourceType === 'github' && serverSourceType !== 'github') {
|
|
992
|
+
updateRcConfig((rc) => {
|
|
993
|
+
delete rc.sourceType;
|
|
994
|
+
delete rc.githubRepo;
|
|
995
|
+
return rc;
|
|
996
|
+
});
|
|
997
|
+
log(' ℹ️ GitHub link removed on Cloud — updated local config.\n');
|
|
998
|
+
}
|
|
999
|
+
} catch { /* non-critical — guard will use whatever rcConfig has */ }
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
// Block production deploys for GitHub-linked courses
|
|
1004
|
+
const rcConfig = readRcConfig();
|
|
1005
|
+
if (rcConfig?.sourceType === 'github') {
|
|
1006
|
+
if (options.preview) {
|
|
1007
|
+
log(' ℹ️ GitHub-linked course — deploying preview only.\n');
|
|
1008
|
+
} else {
|
|
1009
|
+
const repo = rcConfig.githubRepo || 'unknown';
|
|
1010
|
+
logErr(`\n❌ This course deploys to production via GitHub, not CLI.`);
|
|
1011
|
+
logErr(` Repo: ${repo}`);
|
|
1012
|
+
logErr(' Push to your repo to trigger a production deploy.');
|
|
1013
|
+
logErr(' Use --preview to deploy a preview build via CLI.\n');
|
|
1014
|
+
if (options.json) {
|
|
1015
|
+
process.stdout.write(JSON.stringify({
|
|
1016
|
+
success: false,
|
|
1017
|
+
error: 'Production deploy blocked — course is GitHub-linked',
|
|
1018
|
+
errorCode: 'github_source_blocked',
|
|
1019
|
+
githubRepo: repo,
|
|
1020
|
+
hint: 'Use --preview for preview deploys, or push to GitHub for production.',
|
|
1021
|
+
}) + '\n');
|
|
1022
|
+
}
|
|
1023
|
+
process.exit(1);
|
|
985
1024
|
}
|
|
986
1025
|
}
|
|
987
1026
|
|
|
@@ -1294,6 +1333,20 @@ export async function status(options = {}) {
|
|
|
1294
1333
|
|
|
1295
1334
|
const data = await handleResponse(firstRes, { retryFn: makeRequest, _isRetry: false });
|
|
1296
1335
|
|
|
1336
|
+
// Reconcile local sourceType with cloud truth (handles unlink-via-dashboard)
|
|
1337
|
+
const localRc = readRcConfig();
|
|
1338
|
+
const serverSourceType = data.source?.type || data.source_type;
|
|
1339
|
+
if (localRc?.sourceType === 'github' && serverSourceType !== 'github') {
|
|
1340
|
+
updateRcConfig((rc) => {
|
|
1341
|
+
delete rc.sourceType;
|
|
1342
|
+
delete rc.githubRepo;
|
|
1343
|
+
return rc;
|
|
1344
|
+
});
|
|
1345
|
+
if (!options.json) {
|
|
1346
|
+
console.log(' ℹ️ GitHub link removed on Cloud — updated local config.\n');
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1297
1350
|
if (options.json) {
|
|
1298
1351
|
process.stdout.write(JSON.stringify(data) + '\n');
|
|
1299
1352
|
return;
|
|
@@ -1301,14 +1354,13 @@ export async function status(options = {}) {
|
|
|
1301
1354
|
|
|
1302
1355
|
console.log(`\n${data.slug} — ${data.name} (${data.orgName})\n`);
|
|
1303
1356
|
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
console.log(
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
console.log(`Source: ${data.source_type}`);
|
|
1357
|
+
const sourceType = data.source?.type || data.source_type;
|
|
1358
|
+
const githubRepo = data.source?.githubRepo || data.github_repo;
|
|
1359
|
+
if (sourceType === 'github' && githubRepo) {
|
|
1360
|
+
console.log(`Source: GitHub — ${githubRepo}`);
|
|
1361
|
+
console.log(' production=github | preview=cli+github');
|
|
1362
|
+
} else if (sourceType) {
|
|
1363
|
+
console.log(`Source: ${sourceType}`);
|
|
1312
1364
|
}
|
|
1313
1365
|
|
|
1314
1366
|
if (data.courseId) console.log(`Course ID: ${data.courseId}`);
|