@patch-adams/core 1.0.5 → 1.0.7
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.cjs +1121 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/index.cjs +1014 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +459 -0
- package/package.json +4 -3
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1014 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zod = require('zod');
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var path = require('path');
|
|
6
|
+
var url = require('url');
|
|
7
|
+
var AdmZip = require('adm-zip');
|
|
8
|
+
var fastXmlParser = require('fast-xml-parser');
|
|
9
|
+
var chalk = require('chalk');
|
|
10
|
+
|
|
11
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
|
|
13
|
+
var AdmZip__default = /*#__PURE__*/_interopDefault(AdmZip);
|
|
14
|
+
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
15
|
+
|
|
16
|
+
// src/config/schema.ts
|
|
17
|
+
var BlockingAssetConfigSchema = zod.z.object({
|
|
18
|
+
/** Filename for the asset */
|
|
19
|
+
filename: zod.z.string().min(1),
|
|
20
|
+
/** Whether this asset is enabled */
|
|
21
|
+
enabled: zod.z.boolean().default(true)
|
|
22
|
+
});
|
|
23
|
+
var AsyncAssetConfigSchema = zod.z.object({
|
|
24
|
+
/** Filename for the asset */
|
|
25
|
+
filename: zod.z.string().min(1),
|
|
26
|
+
/** Whether this asset is enabled */
|
|
27
|
+
enabled: zod.z.boolean().default(true),
|
|
28
|
+
/** Timeout in milliseconds for remote loading before falling back to local */
|
|
29
|
+
timeout: zod.z.number().min(1e3).max(3e4).default(5e3)
|
|
30
|
+
});
|
|
31
|
+
var LocalFoldersConfigSchema = zod.z.object({
|
|
32
|
+
/** Folder name for CSS files within scormcontent */
|
|
33
|
+
css: zod.z.string().default("css"),
|
|
34
|
+
/** Folder name for JS files within scormcontent */
|
|
35
|
+
js: zod.z.string().default("js")
|
|
36
|
+
});
|
|
37
|
+
var PatchAdamsConfigSchema = zod.z.object({
|
|
38
|
+
/** Remote domain for assets (e.g., "https://cdn.example.com/rise-overrides") */
|
|
39
|
+
remoteDomain: zod.z.string().url(),
|
|
40
|
+
/** CSS class added to <html> tag for specificity (default: "pa-patched") */
|
|
41
|
+
htmlClass: zod.z.string().default("pa-patched"),
|
|
42
|
+
/** CSS class added during loading, removed when ready (default: "pa-loading") */
|
|
43
|
+
loadingClass: zod.z.string().default("pa-loading"),
|
|
44
|
+
/** CSS loaded at start of <head> - blocking, prevents FOUC */
|
|
45
|
+
cssBefore: BlockingAssetConfigSchema.default({
|
|
46
|
+
filename: "before.css",
|
|
47
|
+
enabled: true
|
|
48
|
+
}),
|
|
49
|
+
/** CSS loaded at end of <head> - async with fallback, for overrides */
|
|
50
|
+
cssAfter: AsyncAssetConfigSchema.default({
|
|
51
|
+
filename: "after.css",
|
|
52
|
+
enabled: true,
|
|
53
|
+
timeout: 5e3
|
|
54
|
+
}),
|
|
55
|
+
/** JS loaded at start of <head> - blocking, for setup/interception */
|
|
56
|
+
jsBefore: BlockingAssetConfigSchema.default({
|
|
57
|
+
filename: "before.js",
|
|
58
|
+
enabled: true
|
|
59
|
+
}),
|
|
60
|
+
/** JS loaded at end of <body> - async with fallback, removes loading class */
|
|
61
|
+
jsAfter: AsyncAssetConfigSchema.default({
|
|
62
|
+
filename: "after.js",
|
|
63
|
+
enabled: true,
|
|
64
|
+
timeout: 5e3
|
|
65
|
+
}),
|
|
66
|
+
/** Local folder names for fallback files */
|
|
67
|
+
localFolders: LocalFoldersConfigSchema.default({}),
|
|
68
|
+
/** Whether to update manifest files (imsmanifest.xml, etc.) for SCORM compliance */
|
|
69
|
+
updateManifests: zod.z.boolean().default(true)
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// src/config/defaults.ts
|
|
73
|
+
var defaultConfig = {
|
|
74
|
+
remoteDomain: "https://cdn.example.com/rise-overrides",
|
|
75
|
+
htmlClass: "pa-patched",
|
|
76
|
+
loadingClass: "pa-loading",
|
|
77
|
+
cssBefore: {
|
|
78
|
+
filename: "before.css",
|
|
79
|
+
enabled: true
|
|
80
|
+
},
|
|
81
|
+
cssAfter: {
|
|
82
|
+
filename: "after.css",
|
|
83
|
+
enabled: true,
|
|
84
|
+
timeout: 5e3
|
|
85
|
+
},
|
|
86
|
+
jsBefore: {
|
|
87
|
+
filename: "before.js",
|
|
88
|
+
enabled: true
|
|
89
|
+
},
|
|
90
|
+
jsAfter: {
|
|
91
|
+
filename: "after.js",
|
|
92
|
+
enabled: true,
|
|
93
|
+
timeout: 5e3
|
|
94
|
+
},
|
|
95
|
+
localFolders: {
|
|
96
|
+
css: "css",
|
|
97
|
+
js: "js"
|
|
98
|
+
},
|
|
99
|
+
updateManifests: true
|
|
100
|
+
};
|
|
101
|
+
async function loadConfig(configPath) {
|
|
102
|
+
const absolutePath = path.resolve(configPath);
|
|
103
|
+
if (!fs.existsSync(absolutePath)) {
|
|
104
|
+
throw new Error(`Configuration file not found: ${absolutePath}`);
|
|
105
|
+
}
|
|
106
|
+
const ext = path.extname(absolutePath).toLowerCase();
|
|
107
|
+
let rawConfig;
|
|
108
|
+
if (ext === ".json") {
|
|
109
|
+
const content = fs.readFileSync(absolutePath, "utf-8");
|
|
110
|
+
rawConfig = JSON.parse(content);
|
|
111
|
+
} else if (ext === ".ts" || ext === ".js" || ext === ".mjs") {
|
|
112
|
+
const fileUrl = url.pathToFileURL(absolutePath).href;
|
|
113
|
+
const module = await import(fileUrl);
|
|
114
|
+
rawConfig = module.default ?? module;
|
|
115
|
+
} else {
|
|
116
|
+
throw new Error(`Unsupported config file extension: ${ext}. Use .ts, .js, .mjs, or .json`);
|
|
117
|
+
}
|
|
118
|
+
const validated = PatchAdamsConfigSchema.parse(rawConfig);
|
|
119
|
+
return validated;
|
|
120
|
+
}
|
|
121
|
+
function mergeWithDefaults(partial) {
|
|
122
|
+
return PatchAdamsConfigSchema.parse({
|
|
123
|
+
...defaultConfig,
|
|
124
|
+
...partial
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function generateConfigTemplate() {
|
|
128
|
+
return `import type { PatchAdamsConfig } from '@patch-adams/core';
|
|
129
|
+
|
|
130
|
+
const config: PatchAdamsConfig = {
|
|
131
|
+
// Remote domain where your CSS/JS files are hosted
|
|
132
|
+
remoteDomain: 'https://cdn.example.com/rise-overrides',
|
|
133
|
+
|
|
134
|
+
// HTML classes for specificity and loading state
|
|
135
|
+
htmlClass: 'pa-patched', // Always present on <html>
|
|
136
|
+
loadingClass: 'pa-loading', // Removed when assets are loaded
|
|
137
|
+
|
|
138
|
+
// CSS loaded at start of <head> - BLOCKING
|
|
139
|
+
// Use this to hide content and prevent flash of unstyled content
|
|
140
|
+
cssBefore: {
|
|
141
|
+
filename: 'before.css',
|
|
142
|
+
enabled: true,
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
// CSS loaded at end of <head> - ASYNC with fallback
|
|
146
|
+
// Use this for style overrides
|
|
147
|
+
cssAfter: {
|
|
148
|
+
filename: 'after.css',
|
|
149
|
+
enabled: true,
|
|
150
|
+
timeout: 5000, // ms before falling back to local
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
// JS loaded at start of <head> - BLOCKING
|
|
154
|
+
// Use this for setup, API interception, globals
|
|
155
|
+
jsBefore: {
|
|
156
|
+
filename: 'before.js',
|
|
157
|
+
enabled: true,
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// JS loaded at end of <body> - ASYNC with fallback
|
|
161
|
+
// Use this for DOM manipulation after Rise loads
|
|
162
|
+
// This should remove the loadingClass when done
|
|
163
|
+
jsAfter: {
|
|
164
|
+
filename: 'after.js',
|
|
165
|
+
enabled: true,
|
|
166
|
+
timeout: 5000, // ms before falling back to local
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
// Folder names for local fallback files within scormcontent/
|
|
170
|
+
localFolders: {
|
|
171
|
+
css: 'css',
|
|
172
|
+
js: 'js',
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
// Update manifest files for SCORM compliance
|
|
176
|
+
updateManifests: true,
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export default config;
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// src/templates/css-before.ts
|
|
184
|
+
function generateCssBeforeLoader(options) {
|
|
185
|
+
const { remoteUrl, localPath, htmlClass, loadingClass } = options;
|
|
186
|
+
return `<!-- === PATCH-ADAMS: CSS BEFORE (blocking) === -->
|
|
187
|
+
<style data-pa="css-before-critical">
|
|
188
|
+
/* Critical: Hide content until ready */
|
|
189
|
+
html.${htmlClass}.${loadingClass} body {
|
|
190
|
+
visibility: hidden !important;
|
|
191
|
+
}
|
|
192
|
+
</style>
|
|
193
|
+
<script data-pa="css-before-loader">
|
|
194
|
+
(function() {
|
|
195
|
+
'use strict';
|
|
196
|
+
var REMOTE_URL = "${remoteUrl}";
|
|
197
|
+
var LOCAL_PATH = "${localPath}";
|
|
198
|
+
|
|
199
|
+
function loadCSSSync(url) {
|
|
200
|
+
var link = document.createElement('link');
|
|
201
|
+
link.rel = 'stylesheet';
|
|
202
|
+
link.href = url;
|
|
203
|
+
link.setAttribute('data-pa', 'css-before');
|
|
204
|
+
document.head.appendChild(link);
|
|
205
|
+
return link;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Try remote first
|
|
209
|
+
var link = loadCSSSync(REMOTE_URL);
|
|
210
|
+
|
|
211
|
+
link.onerror = function() {
|
|
212
|
+
console.warn('[Patch-Adams] CSS before failed to load from remote, using local fallback');
|
|
213
|
+
document.head.removeChild(link);
|
|
214
|
+
loadCSSSync(LOCAL_PATH);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
link.onload = function() {
|
|
218
|
+
console.log('[Patch-Adams] CSS before loaded from remote:', REMOTE_URL);
|
|
219
|
+
};
|
|
220
|
+
})();
|
|
221
|
+
</script>`;
|
|
222
|
+
}
|
|
223
|
+
function buildCssBeforeOptions(config) {
|
|
224
|
+
return {
|
|
225
|
+
remoteUrl: `${config.remoteDomain}/${config.cssBefore.filename}`,
|
|
226
|
+
localPath: `${config.localFolders.css}/${config.cssBefore.filename}`,
|
|
227
|
+
htmlClass: config.htmlClass,
|
|
228
|
+
loadingClass: config.loadingClass
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/templates/css-after.ts
|
|
233
|
+
function generateCssAfterLoader(options) {
|
|
234
|
+
const { remoteUrl, localPath, timeout } = options;
|
|
235
|
+
return `<!-- === PATCH-ADAMS: CSS AFTER (async with fallback) === -->
|
|
236
|
+
<script data-pa="css-after-loader">
|
|
237
|
+
(function() {
|
|
238
|
+
'use strict';
|
|
239
|
+
var REMOTE_URL = "${remoteUrl}";
|
|
240
|
+
var LOCAL_PATH = "${localPath}";
|
|
241
|
+
var TIMEOUT = ${timeout};
|
|
242
|
+
|
|
243
|
+
function loadCSS(url, onSuccess, onError) {
|
|
244
|
+
var link = document.createElement('link');
|
|
245
|
+
link.rel = 'stylesheet';
|
|
246
|
+
link.href = url;
|
|
247
|
+
link.setAttribute('data-pa', 'css-after');
|
|
248
|
+
|
|
249
|
+
link.onload = function() {
|
|
250
|
+
if (onSuccess) onSuccess();
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
link.onerror = function() {
|
|
254
|
+
if (onError) onError();
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
document.head.appendChild(link);
|
|
258
|
+
return link;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function loadCSSWithFallback() {
|
|
262
|
+
var loaded = false;
|
|
263
|
+
var timeoutId;
|
|
264
|
+
|
|
265
|
+
// Try remote first
|
|
266
|
+
var remoteLink = loadCSS(
|
|
267
|
+
REMOTE_URL,
|
|
268
|
+
function() {
|
|
269
|
+
if (loaded) return;
|
|
270
|
+
loaded = true;
|
|
271
|
+
clearTimeout(timeoutId);
|
|
272
|
+
console.log('[Patch-Adams] CSS after loaded from remote:', REMOTE_URL);
|
|
273
|
+
},
|
|
274
|
+
function() {
|
|
275
|
+
if (loaded) return;
|
|
276
|
+
loaded = true;
|
|
277
|
+
clearTimeout(timeoutId);
|
|
278
|
+
loadLocalFallback();
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
// Timeout fallback
|
|
283
|
+
timeoutId = setTimeout(function() {
|
|
284
|
+
if (loaded) return;
|
|
285
|
+
loaded = true;
|
|
286
|
+
console.warn('[Patch-Adams] CSS after timed out, using local fallback');
|
|
287
|
+
if (remoteLink.parentNode) {
|
|
288
|
+
document.head.removeChild(remoteLink);
|
|
289
|
+
}
|
|
290
|
+
loadLocalFallback();
|
|
291
|
+
}, TIMEOUT);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function loadLocalFallback() {
|
|
295
|
+
loadCSS(
|
|
296
|
+
LOCAL_PATH,
|
|
297
|
+
function() {
|
|
298
|
+
console.log('[Patch-Adams] CSS after loaded from local fallback:', LOCAL_PATH);
|
|
299
|
+
},
|
|
300
|
+
function() {
|
|
301
|
+
console.error('[Patch-Adams] CSS after failed to load from both remote and local');
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Execute immediately
|
|
307
|
+
loadCSSWithFallback();
|
|
308
|
+
})();
|
|
309
|
+
</script>`;
|
|
310
|
+
}
|
|
311
|
+
function buildCssAfterOptions(config) {
|
|
312
|
+
return {
|
|
313
|
+
remoteUrl: `${config.remoteDomain}/${config.cssAfter.filename}`,
|
|
314
|
+
localPath: `${config.localFolders.css}/${config.cssAfter.filename}`,
|
|
315
|
+
timeout: config.cssAfter.timeout
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/templates/js-before.ts
|
|
320
|
+
function generateJsBeforeLoader(options) {
|
|
321
|
+
const { remoteUrl, localPath, htmlClass, loadingClass } = options;
|
|
322
|
+
return `<!-- === PATCH-ADAMS: JS BEFORE (blocking) === -->
|
|
323
|
+
<script data-pa="js-before-loader">
|
|
324
|
+
(function() {
|
|
325
|
+
'use strict';
|
|
326
|
+
var REMOTE_URL = "${remoteUrl}";
|
|
327
|
+
var LOCAL_PATH = "${localPath}";
|
|
328
|
+
|
|
329
|
+
// Initialize Patch-Adams global namespace
|
|
330
|
+
window.PatchAdams = window.PatchAdams || {
|
|
331
|
+
version: '1.0.0',
|
|
332
|
+
htmlClass: '${htmlClass}',
|
|
333
|
+
loadingClass: '${loadingClass}',
|
|
334
|
+
loaded: {
|
|
335
|
+
cssBefore: false,
|
|
336
|
+
cssAfter: false,
|
|
337
|
+
jsBefore: false,
|
|
338
|
+
jsAfter: false
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
function loadJSSync(url) {
|
|
343
|
+
var script = document.createElement('script');
|
|
344
|
+
script.src = url;
|
|
345
|
+
script.setAttribute('data-pa', 'js-before');
|
|
346
|
+
// Note: For truly blocking behavior, we use document.write
|
|
347
|
+
// but that's fragile. Instead we'll handle errors gracefully.
|
|
348
|
+
document.head.appendChild(script);
|
|
349
|
+
return script;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Try remote first
|
|
353
|
+
var script = loadJSSync(REMOTE_URL);
|
|
354
|
+
|
|
355
|
+
script.onerror = function() {
|
|
356
|
+
console.warn('[Patch-Adams] JS before failed to load from remote, using local fallback');
|
|
357
|
+
document.head.removeChild(script);
|
|
358
|
+
var fallback = loadJSSync(LOCAL_PATH);
|
|
359
|
+
fallback.onload = function() {
|
|
360
|
+
window.PatchAdams.loaded.jsBefore = true;
|
|
361
|
+
console.log('[Patch-Adams] JS before loaded from local fallback:', LOCAL_PATH);
|
|
362
|
+
};
|
|
363
|
+
fallback.onerror = function() {
|
|
364
|
+
console.error('[Patch-Adams] JS before failed to load from both remote and local');
|
|
365
|
+
};
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
script.onload = function() {
|
|
369
|
+
window.PatchAdams.loaded.jsBefore = true;
|
|
370
|
+
console.log('[Patch-Adams] JS before loaded from remote:', REMOTE_URL);
|
|
371
|
+
};
|
|
372
|
+
})();
|
|
373
|
+
</script>`;
|
|
374
|
+
}
|
|
375
|
+
function buildJsBeforeOptions(config) {
|
|
376
|
+
return {
|
|
377
|
+
remoteUrl: `${config.remoteDomain}/${config.jsBefore.filename}`,
|
|
378
|
+
localPath: `${config.localFolders.js}/${config.jsBefore.filename}`,
|
|
379
|
+
htmlClass: config.htmlClass,
|
|
380
|
+
loadingClass: config.loadingClass
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/templates/js-after.ts
|
|
385
|
+
function generateJsAfterLoader(options) {
|
|
386
|
+
const { remoteUrl, localPath, timeout, loadingClass } = options;
|
|
387
|
+
return `<!-- === PATCH-ADAMS: JS AFTER (async with fallback) === -->
|
|
388
|
+
<script data-pa="js-after-loader">
|
|
389
|
+
(function() {
|
|
390
|
+
'use strict';
|
|
391
|
+
var REMOTE_URL = "${remoteUrl}";
|
|
392
|
+
var LOCAL_PATH = "${localPath}";
|
|
393
|
+
var TIMEOUT = ${timeout};
|
|
394
|
+
var LOADING_CLASS = "${loadingClass}";
|
|
395
|
+
|
|
396
|
+
function loadJS(url, onSuccess, onError) {
|
|
397
|
+
var script = document.createElement('script');
|
|
398
|
+
script.src = url;
|
|
399
|
+
script.async = true;
|
|
400
|
+
script.setAttribute('data-pa', 'js-after');
|
|
401
|
+
|
|
402
|
+
script.onload = function() {
|
|
403
|
+
if (onSuccess) onSuccess();
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
script.onerror = function() {
|
|
407
|
+
if (onError) onError();
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
document.body.appendChild(script);
|
|
411
|
+
return script;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function removeLoadingClass() {
|
|
415
|
+
document.documentElement.classList.remove(LOADING_CLASS);
|
|
416
|
+
if (window.PatchAdams) {
|
|
417
|
+
window.PatchAdams.loaded.jsAfter = true;
|
|
418
|
+
}
|
|
419
|
+
console.log('[Patch-Adams] Loading complete, content revealed');
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function loadJSWithFallback() {
|
|
423
|
+
var loaded = false;
|
|
424
|
+
var timeoutId;
|
|
425
|
+
|
|
426
|
+
// Try remote first
|
|
427
|
+
var remoteScript = loadJS(
|
|
428
|
+
REMOTE_URL,
|
|
429
|
+
function() {
|
|
430
|
+
if (loaded) return;
|
|
431
|
+
loaded = true;
|
|
432
|
+
clearTimeout(timeoutId);
|
|
433
|
+
console.log('[Patch-Adams] JS after loaded from remote:', REMOTE_URL);
|
|
434
|
+
// Give the script a moment to execute, then remove loading class
|
|
435
|
+
setTimeout(removeLoadingClass, 50);
|
|
436
|
+
},
|
|
437
|
+
function() {
|
|
438
|
+
if (loaded) return;
|
|
439
|
+
loaded = true;
|
|
440
|
+
clearTimeout(timeoutId);
|
|
441
|
+
loadLocalFallback();
|
|
442
|
+
}
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
// Timeout fallback
|
|
446
|
+
timeoutId = setTimeout(function() {
|
|
447
|
+
if (loaded) return;
|
|
448
|
+
loaded = true;
|
|
449
|
+
console.warn('[Patch-Adams] JS after timed out, using local fallback');
|
|
450
|
+
if (remoteScript.parentNode) {
|
|
451
|
+
document.body.removeChild(remoteScript);
|
|
452
|
+
}
|
|
453
|
+
loadLocalFallback();
|
|
454
|
+
}, TIMEOUT);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function loadLocalFallback() {
|
|
458
|
+
loadJS(
|
|
459
|
+
LOCAL_PATH,
|
|
460
|
+
function() {
|
|
461
|
+
console.log('[Patch-Adams] JS after loaded from local fallback:', LOCAL_PATH);
|
|
462
|
+
setTimeout(removeLoadingClass, 50);
|
|
463
|
+
},
|
|
464
|
+
function() {
|
|
465
|
+
console.error('[Patch-Adams] JS after failed to load from both remote and local');
|
|
466
|
+
// Still remove loading class so content is visible even if JS fails
|
|
467
|
+
removeLoadingClass();
|
|
468
|
+
}
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Execute after DOM is ready to ensure Rise has loaded
|
|
473
|
+
if (document.readyState === 'loading') {
|
|
474
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
475
|
+
// Small delay to ensure Rise has initialized
|
|
476
|
+
setTimeout(loadJSWithFallback, 100);
|
|
477
|
+
});
|
|
478
|
+
} else {
|
|
479
|
+
// DOM is already ready
|
|
480
|
+
setTimeout(loadJSWithFallback, 100);
|
|
481
|
+
}
|
|
482
|
+
})();
|
|
483
|
+
</script>`;
|
|
484
|
+
}
|
|
485
|
+
function buildJsAfterOptions(config) {
|
|
486
|
+
return {
|
|
487
|
+
remoteUrl: `${config.remoteDomain}/${config.jsAfter.filename}`,
|
|
488
|
+
localPath: `${config.localFolders.js}/${config.jsAfter.filename}`,
|
|
489
|
+
timeout: config.jsAfter.timeout,
|
|
490
|
+
loadingClass: config.loadingClass
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// src/patcher/html-injector.ts
|
|
495
|
+
var HtmlInjector = class {
|
|
496
|
+
config;
|
|
497
|
+
constructor(config) {
|
|
498
|
+
this.config = config;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Inject all loaders into HTML
|
|
502
|
+
*/
|
|
503
|
+
inject(html) {
|
|
504
|
+
let result = html;
|
|
505
|
+
result = this.addHtmlClasses(result);
|
|
506
|
+
if (this.config.cssBefore.enabled) {
|
|
507
|
+
result = this.injectCssBefore(result);
|
|
508
|
+
}
|
|
509
|
+
if (this.config.jsBefore.enabled) {
|
|
510
|
+
result = this.injectJsBefore(result);
|
|
511
|
+
}
|
|
512
|
+
if (this.config.cssAfter.enabled) {
|
|
513
|
+
result = this.injectCssAfter(result);
|
|
514
|
+
}
|
|
515
|
+
if (this.config.jsAfter.enabled) {
|
|
516
|
+
result = this.injectJsAfter(result);
|
|
517
|
+
}
|
|
518
|
+
return result;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Add pa-patched and pa-loading classes to <html> tag
|
|
522
|
+
*/
|
|
523
|
+
addHtmlClasses(html) {
|
|
524
|
+
const { htmlClass, loadingClass } = this.config;
|
|
525
|
+
const classes = `${htmlClass} ${loadingClass}`;
|
|
526
|
+
const htmlTagPattern = /<html([^>]*)>/i;
|
|
527
|
+
const match = html.match(htmlTagPattern);
|
|
528
|
+
if (!match) {
|
|
529
|
+
return html;
|
|
530
|
+
}
|
|
531
|
+
const attributes = match[1];
|
|
532
|
+
if (/class\s*=\s*["'][^"']*["']/i.test(attributes)) {
|
|
533
|
+
return html.replace(
|
|
534
|
+
htmlTagPattern,
|
|
535
|
+
(_match, attrs) => {
|
|
536
|
+
const newAttrs = attrs.replace(
|
|
537
|
+
/class\s*=\s*["']([^"']*)["']/i,
|
|
538
|
+
(_fullMatch, existingClasses) => `class="${existingClasses} ${classes}"`
|
|
539
|
+
);
|
|
540
|
+
return `<html${newAttrs}>`;
|
|
541
|
+
}
|
|
542
|
+
);
|
|
543
|
+
} else {
|
|
544
|
+
return html.replace(htmlTagPattern, `<html${attributes} class="${classes}">`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Inject CSS Before loader at start of <head>
|
|
549
|
+
*/
|
|
550
|
+
injectCssBefore(html) {
|
|
551
|
+
const options = buildCssBeforeOptions(this.config);
|
|
552
|
+
const loader = generateCssBeforeLoader(options);
|
|
553
|
+
return html.replace(/<head([^>]*)>/i, `<head$1>
|
|
554
|
+
${loader}`);
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Inject JS Before loader at start of <head> (after CSS Before if present)
|
|
558
|
+
*/
|
|
559
|
+
injectJsBefore(html) {
|
|
560
|
+
const options = buildJsBeforeOptions(this.config);
|
|
561
|
+
const loader = generateJsBeforeLoader(options);
|
|
562
|
+
const cssBeforeMarker = "<!-- === PATCH-ADAMS: CSS BEFORE";
|
|
563
|
+
if (html.includes(cssBeforeMarker)) {
|
|
564
|
+
const cssBeforeEndPattern = /<\/script>\s*(?=\n|<)/;
|
|
565
|
+
const cssBeforeStart = html.indexOf(cssBeforeMarker);
|
|
566
|
+
const afterCssBefore = html.substring(cssBeforeStart);
|
|
567
|
+
const endMatch = afterCssBefore.match(cssBeforeEndPattern);
|
|
568
|
+
if (endMatch && endMatch.index !== void 0) {
|
|
569
|
+
const insertPos = cssBeforeStart + endMatch.index + endMatch[0].length;
|
|
570
|
+
return html.slice(0, insertPos) + "\n" + loader + html.slice(insertPos);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return html.replace(/<head([^>]*)>/i, `<head$1>
|
|
574
|
+
${loader}`);
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Inject CSS After loader at end of <head>
|
|
578
|
+
*/
|
|
579
|
+
injectCssAfter(html) {
|
|
580
|
+
const options = buildCssAfterOptions(this.config);
|
|
581
|
+
const loader = generateCssAfterLoader(options);
|
|
582
|
+
return html.replace(/<\/head>/i, `${loader}
|
|
583
|
+
</head>`);
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Inject JS After loader at end of <body> (after __loadEntry)
|
|
587
|
+
*/
|
|
588
|
+
injectJsAfter(html) {
|
|
589
|
+
const options = buildJsAfterOptions(this.config);
|
|
590
|
+
const loader = generateJsAfterLoader(options);
|
|
591
|
+
const loadEntryPattern = /(<script>__loadEntry\(\)<\/script>)/i;
|
|
592
|
+
if (loadEntryPattern.test(html)) {
|
|
593
|
+
return html.replace(loadEntryPattern, `$1
|
|
594
|
+
${loader}`);
|
|
595
|
+
}
|
|
596
|
+
return html.replace(/<\/body>/i, `${loader}
|
|
597
|
+
</body>`);
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
var ManifestUpdater = class {
|
|
601
|
+
config;
|
|
602
|
+
parser;
|
|
603
|
+
builder;
|
|
604
|
+
constructor(config) {
|
|
605
|
+
this.config = config;
|
|
606
|
+
this.parser = new fastXmlParser.XMLParser({
|
|
607
|
+
ignoreAttributes: false,
|
|
608
|
+
attributeNamePrefix: "@_",
|
|
609
|
+
preserveOrder: false,
|
|
610
|
+
parseAttributeValue: false,
|
|
611
|
+
trimValues: true
|
|
612
|
+
});
|
|
613
|
+
this.builder = new fastXmlParser.XMLBuilder({
|
|
614
|
+
ignoreAttributes: false,
|
|
615
|
+
attributeNamePrefix: "@_",
|
|
616
|
+
format: true,
|
|
617
|
+
indentBy: " ",
|
|
618
|
+
suppressEmptyNode: true
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Update manifest files based on package format
|
|
623
|
+
*/
|
|
624
|
+
update(zip, format, paths) {
|
|
625
|
+
const modified = [];
|
|
626
|
+
switch (format) {
|
|
627
|
+
case "scorm12":
|
|
628
|
+
case "scorm2004-3":
|
|
629
|
+
case "scorm2004-4":
|
|
630
|
+
modified.push(...this.updateImsManifest(zip, paths));
|
|
631
|
+
break;
|
|
632
|
+
case "cmi5":
|
|
633
|
+
modified.push(...this.updateImsManifest(zip, paths));
|
|
634
|
+
break;
|
|
635
|
+
case "xapi":
|
|
636
|
+
break;
|
|
637
|
+
case "aicc":
|
|
638
|
+
const aiccManifest = zip.getEntry("imsmanifest.xml");
|
|
639
|
+
if (aiccManifest) {
|
|
640
|
+
modified.push(...this.updateImsManifest(zip, paths));
|
|
641
|
+
}
|
|
642
|
+
break;
|
|
643
|
+
}
|
|
644
|
+
return modified;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Update imsmanifest.xml to include new file references
|
|
648
|
+
*/
|
|
649
|
+
updateImsManifest(zip, paths) {
|
|
650
|
+
const entry = zip.getEntry("imsmanifest.xml");
|
|
651
|
+
if (!entry) {
|
|
652
|
+
return [];
|
|
653
|
+
}
|
|
654
|
+
try {
|
|
655
|
+
const xmlContent = entry.getData().toString("utf-8");
|
|
656
|
+
const parsed = this.parser.parse(xmlContent);
|
|
657
|
+
this.addFilesToManifest(parsed, paths);
|
|
658
|
+
const xmlDeclaration = this.extractXmlDeclaration(xmlContent);
|
|
659
|
+
const updatedXml = xmlDeclaration + this.builder.build(parsed);
|
|
660
|
+
zip.updateFile("imsmanifest.xml", Buffer.from(updatedXml, "utf-8"));
|
|
661
|
+
return ["imsmanifest.xml"];
|
|
662
|
+
} catch (error) {
|
|
663
|
+
console.error("[Patch-Adams] Failed to update imsmanifest.xml:", error);
|
|
664
|
+
return [];
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Extract XML declaration from original content
|
|
669
|
+
*/
|
|
670
|
+
extractXmlDeclaration(xml) {
|
|
671
|
+
const match = xml.match(/<\?xml[^?]*\?>/);
|
|
672
|
+
return match ? match[0] + "\n" : '<?xml version="1.0" encoding="UTF-8"?>\n';
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Add file entries to the manifest
|
|
676
|
+
*/
|
|
677
|
+
addFilesToManifest(parsed, paths) {
|
|
678
|
+
const manifest = parsed.manifest;
|
|
679
|
+
if (!manifest) return;
|
|
680
|
+
const resources = manifest.resources;
|
|
681
|
+
if (!resources) return;
|
|
682
|
+
let resource = resources.resource;
|
|
683
|
+
if (!resource) return;
|
|
684
|
+
if (Array.isArray(resource)) {
|
|
685
|
+
resource = resource[0];
|
|
686
|
+
}
|
|
687
|
+
if (!resource.file) {
|
|
688
|
+
resource.file = [];
|
|
689
|
+
}
|
|
690
|
+
let files = resource.file;
|
|
691
|
+
if (!Array.isArray(files)) {
|
|
692
|
+
files = [files];
|
|
693
|
+
resource.file = files;
|
|
694
|
+
}
|
|
695
|
+
const filesToAdd = [
|
|
696
|
+
paths.cssBefore,
|
|
697
|
+
paths.cssAfter,
|
|
698
|
+
paths.jsBefore,
|
|
699
|
+
paths.jsAfter
|
|
700
|
+
].filter(Boolean);
|
|
701
|
+
for (const filePath of filesToAdd) {
|
|
702
|
+
const exists = files.some((f) => f["@_href"] === filePath);
|
|
703
|
+
if (!exists) {
|
|
704
|
+
files.push({ "@_href": filePath });
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Get the file paths that will be added to the package
|
|
710
|
+
*/
|
|
711
|
+
getFilePaths() {
|
|
712
|
+
const paths = {};
|
|
713
|
+
if (this.config.cssBefore.enabled) {
|
|
714
|
+
paths.cssBefore = `scormcontent/${this.config.localFolders.css}/${this.config.cssBefore.filename}`;
|
|
715
|
+
}
|
|
716
|
+
if (this.config.cssAfter.enabled) {
|
|
717
|
+
paths.cssAfter = `scormcontent/${this.config.localFolders.css}/${this.config.cssAfter.filename}`;
|
|
718
|
+
}
|
|
719
|
+
if (this.config.jsBefore.enabled) {
|
|
720
|
+
paths.jsBefore = `scormcontent/${this.config.localFolders.js}/${this.config.jsBefore.filename}`;
|
|
721
|
+
}
|
|
722
|
+
if (this.config.jsAfter.enabled) {
|
|
723
|
+
paths.jsAfter = `scormcontent/${this.config.localFolders.js}/${this.config.jsAfter.filename}`;
|
|
724
|
+
}
|
|
725
|
+
return paths;
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
// src/detectors/format-detector.ts
|
|
730
|
+
var FormatDetector = class {
|
|
731
|
+
/**
|
|
732
|
+
* Detect the package format from a ZIP file
|
|
733
|
+
*/
|
|
734
|
+
detect(zip) {
|
|
735
|
+
if (zip.getEntry("cmi5.xml")) {
|
|
736
|
+
return "cmi5";
|
|
737
|
+
}
|
|
738
|
+
if (zip.getEntry("tincan.xml")) {
|
|
739
|
+
return "xapi";
|
|
740
|
+
}
|
|
741
|
+
const manifest = zip.getEntry("imsmanifest.xml");
|
|
742
|
+
if (manifest) {
|
|
743
|
+
const content = manifest.getData().toString("utf-8");
|
|
744
|
+
return this.detectScormVersion(content);
|
|
745
|
+
}
|
|
746
|
+
if (this.hasAiccFiles(zip)) {
|
|
747
|
+
return "aicc";
|
|
748
|
+
}
|
|
749
|
+
return "unknown";
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Detect SCORM version from manifest content
|
|
753
|
+
*/
|
|
754
|
+
detectScormVersion(content) {
|
|
755
|
+
if (content.includes("4th Edition") || content.includes("CAM 1.4")) {
|
|
756
|
+
return "scorm2004-4";
|
|
757
|
+
}
|
|
758
|
+
if (content.includes("3rd Edition") || content.includes("2004 3rd") || content.includes("adlcp_v1p3")) {
|
|
759
|
+
return "scorm2004-3";
|
|
760
|
+
}
|
|
761
|
+
if (content.includes("2004") && content.includes("adlseq")) {
|
|
762
|
+
return "scorm2004-3";
|
|
763
|
+
}
|
|
764
|
+
if (content.includes("1.2") || content.includes("adlcp_rootv1p2") || content.includes("imscp_rootv1p1p2")) {
|
|
765
|
+
return "scorm12";
|
|
766
|
+
}
|
|
767
|
+
if (content.toLowerCase().includes("aicc")) {
|
|
768
|
+
return "aicc";
|
|
769
|
+
}
|
|
770
|
+
return "scorm12";
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Check for AICC-specific files
|
|
774
|
+
*/
|
|
775
|
+
hasAiccFiles(zip) {
|
|
776
|
+
const aiccExtensions = [".crs", ".au", ".des", ".cst"];
|
|
777
|
+
const entries = zip.getEntries();
|
|
778
|
+
for (const entry of entries) {
|
|
779
|
+
const name = entry.entryName.toLowerCase();
|
|
780
|
+
if (aiccExtensions.some((ext) => name.endsWith(ext))) {
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return false;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Get a human-readable format name
|
|
788
|
+
*/
|
|
789
|
+
getFormatDisplayName(format) {
|
|
790
|
+
const names = {
|
|
791
|
+
scorm12: "SCORM 1.2",
|
|
792
|
+
"scorm2004-3": "SCORM 2004 3rd Edition",
|
|
793
|
+
"scorm2004-4": "SCORM 2004 4th Edition",
|
|
794
|
+
cmi5: "cmi5",
|
|
795
|
+
xapi: "xAPI (Tin Can)",
|
|
796
|
+
aicc: "AICC",
|
|
797
|
+
unknown: "Unknown"
|
|
798
|
+
};
|
|
799
|
+
return names[format];
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
// src/patcher/index.ts
|
|
804
|
+
var DEFAULT_CSS_BEFORE = `/* Patch-Adams: CSS Before (blocking)
|
|
805
|
+
* This file loads at the start of <head> and blocks rendering.
|
|
806
|
+
* Use it to hide content and prevent flash of unstyled content.
|
|
807
|
+
*
|
|
808
|
+
* Example:
|
|
809
|
+
* html.pa-patched.pa-loading body {
|
|
810
|
+
* visibility: hidden !important;
|
|
811
|
+
* }
|
|
812
|
+
*/
|
|
813
|
+
`;
|
|
814
|
+
var DEFAULT_CSS_AFTER = `/* Patch-Adams: CSS After (async)
|
|
815
|
+
* This file loads at the end of <head> with remote fallback.
|
|
816
|
+
* Use it for style overrides that take precedence over Rise styles.
|
|
817
|
+
*
|
|
818
|
+
* Example:
|
|
819
|
+
* html.pa-patched .blocks-text {
|
|
820
|
+
* font-family: 'Your Font', sans-serif !important;
|
|
821
|
+
* }
|
|
822
|
+
*/
|
|
823
|
+
`;
|
|
824
|
+
var DEFAULT_JS_BEFORE = `// Patch-Adams: JS Before (blocking)
|
|
825
|
+
// This file loads at the start of <head> and blocks rendering.
|
|
826
|
+
// Use it for setup, API interception, and preparing globals.
|
|
827
|
+
//
|
|
828
|
+
// Example:
|
|
829
|
+
// window.PatchAdams.customConfig = {
|
|
830
|
+
// theme: 'dark',
|
|
831
|
+
// analytics: true
|
|
832
|
+
// };
|
|
833
|
+
|
|
834
|
+
console.log('[Patch-Adams] JS Before loaded');
|
|
835
|
+
`;
|
|
836
|
+
var DEFAULT_JS_AFTER = `// Patch-Adams: JS After (async)
|
|
837
|
+
// This file loads at the end of <body> with remote fallback.
|
|
838
|
+
// Use it for DOM manipulation after Rise has initialized.
|
|
839
|
+
//
|
|
840
|
+
// IMPORTANT: This script should NOT remove the loading class.
|
|
841
|
+
// The loader script handles that automatically after this script loads.
|
|
842
|
+
//
|
|
843
|
+
// Example:
|
|
844
|
+
// document.querySelectorAll('.blocks-text').forEach(function(el) {
|
|
845
|
+
// // Your modifications here
|
|
846
|
+
// });
|
|
847
|
+
|
|
848
|
+
console.log('[Patch-Adams] JS After loaded');
|
|
849
|
+
`;
|
|
850
|
+
var Patcher = class {
|
|
851
|
+
config;
|
|
852
|
+
htmlInjector;
|
|
853
|
+
manifestUpdater;
|
|
854
|
+
formatDetector;
|
|
855
|
+
constructor(config) {
|
|
856
|
+
this.config = config;
|
|
857
|
+
this.htmlInjector = new HtmlInjector(config);
|
|
858
|
+
this.manifestUpdater = new ManifestUpdater(config);
|
|
859
|
+
this.formatDetector = new FormatDetector();
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Patch a Rise course ZIP file
|
|
863
|
+
* @param inputBuffer - Input ZIP file as Buffer
|
|
864
|
+
* @param options - Additional patching options
|
|
865
|
+
* @returns Patched ZIP file as Buffer and result details
|
|
866
|
+
*/
|
|
867
|
+
async patch(inputBuffer, options = {}) {
|
|
868
|
+
const result = {
|
|
869
|
+
success: false,
|
|
870
|
+
format: "unknown",
|
|
871
|
+
formatDisplayName: "Unknown",
|
|
872
|
+
filesModified: [],
|
|
873
|
+
filesAdded: [],
|
|
874
|
+
errors: [],
|
|
875
|
+
warnings: []
|
|
876
|
+
};
|
|
877
|
+
try {
|
|
878
|
+
const zip = new AdmZip__default.default(inputBuffer);
|
|
879
|
+
result.format = this.formatDetector.detect(zip);
|
|
880
|
+
result.formatDisplayName = this.formatDetector.getFormatDisplayName(result.format);
|
|
881
|
+
if (result.format === "unknown") {
|
|
882
|
+
result.warnings.push("Could not determine package format, proceeding anyway");
|
|
883
|
+
}
|
|
884
|
+
const indexHtmlEntry = zip.getEntry("scormcontent/index.html");
|
|
885
|
+
if (!indexHtmlEntry) {
|
|
886
|
+
throw new Error("Could not find scormcontent/index.html in package. Is this a valid Rise export?");
|
|
887
|
+
}
|
|
888
|
+
const originalHtml = indexHtmlEntry.getData().toString("utf-8");
|
|
889
|
+
const patchedHtml = this.htmlInjector.inject(originalHtml);
|
|
890
|
+
zip.updateFile("scormcontent/index.html", Buffer.from(patchedHtml, "utf-8"));
|
|
891
|
+
result.filesModified.push("scormcontent/index.html");
|
|
892
|
+
const addedFiles = this.addFallbackFiles(zip, options);
|
|
893
|
+
result.filesAdded.push(...addedFiles);
|
|
894
|
+
if (this.config.updateManifests) {
|
|
895
|
+
const manifestPaths = this.manifestUpdater.getFilePaths();
|
|
896
|
+
const modifiedManifests = this.manifestUpdater.update(zip, result.format, manifestPaths);
|
|
897
|
+
result.filesModified.push(...modifiedManifests);
|
|
898
|
+
}
|
|
899
|
+
result.success = true;
|
|
900
|
+
return { buffer: zip.toBuffer(), result };
|
|
901
|
+
} catch (error) {
|
|
902
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
903
|
+
result.errors.push(message);
|
|
904
|
+
throw error;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Add local fallback files to the ZIP
|
|
909
|
+
*/
|
|
910
|
+
addFallbackFiles(zip, options) {
|
|
911
|
+
const added = [];
|
|
912
|
+
const cssFolder = `scormcontent/${this.config.localFolders.css}`;
|
|
913
|
+
const jsFolder = `scormcontent/${this.config.localFolders.js}`;
|
|
914
|
+
if (this.config.cssBefore.enabled) {
|
|
915
|
+
const path = `${cssFolder}/${this.config.cssBefore.filename}`;
|
|
916
|
+
const content = options.cssBeforeContent ?? DEFAULT_CSS_BEFORE;
|
|
917
|
+
zip.addFile(path, Buffer.from(content, "utf-8"));
|
|
918
|
+
added.push(path);
|
|
919
|
+
}
|
|
920
|
+
if (this.config.cssAfter.enabled) {
|
|
921
|
+
const path = `${cssFolder}/${this.config.cssAfter.filename}`;
|
|
922
|
+
const content = options.cssAfterContent ?? DEFAULT_CSS_AFTER;
|
|
923
|
+
zip.addFile(path, Buffer.from(content, "utf-8"));
|
|
924
|
+
added.push(path);
|
|
925
|
+
}
|
|
926
|
+
if (this.config.jsBefore.enabled) {
|
|
927
|
+
const path = `${jsFolder}/${this.config.jsBefore.filename}`;
|
|
928
|
+
const content = options.jsBeforeContent ?? DEFAULT_JS_BEFORE;
|
|
929
|
+
zip.addFile(path, Buffer.from(content, "utf-8"));
|
|
930
|
+
added.push(path);
|
|
931
|
+
}
|
|
932
|
+
if (this.config.jsAfter.enabled) {
|
|
933
|
+
const path = `${jsFolder}/${this.config.jsAfter.filename}`;
|
|
934
|
+
const content = options.jsAfterContent ?? DEFAULT_JS_AFTER;
|
|
935
|
+
zip.addFile(path, Buffer.from(content, "utf-8"));
|
|
936
|
+
added.push(path);
|
|
937
|
+
}
|
|
938
|
+
return added;
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Get the current configuration
|
|
942
|
+
*/
|
|
943
|
+
getConfig() {
|
|
944
|
+
return this.config;
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* Convenience method to patch a buffer and return only the patched buffer.
|
|
948
|
+
* Used by package-uploader integration.
|
|
949
|
+
* @param buffer - Input ZIP file as Buffer
|
|
950
|
+
* @returns Patched ZIP file as Buffer
|
|
951
|
+
*/
|
|
952
|
+
async patchBuffer(buffer) {
|
|
953
|
+
const { buffer: patchedBuffer } = await this.patch(buffer);
|
|
954
|
+
return patchedBuffer;
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
var Logger = class {
|
|
958
|
+
level;
|
|
959
|
+
constructor(level = "info") {
|
|
960
|
+
this.level = level;
|
|
961
|
+
}
|
|
962
|
+
shouldLog(level) {
|
|
963
|
+
const levels = ["debug", "info", "warn", "error", "silent"];
|
|
964
|
+
return levels.indexOf(level) >= levels.indexOf(this.level);
|
|
965
|
+
}
|
|
966
|
+
debug(...args) {
|
|
967
|
+
if (this.shouldLog("debug")) {
|
|
968
|
+
console.log(chalk__default.default.gray("[DEBUG]"), ...args);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
info(...args) {
|
|
972
|
+
if (this.shouldLog("info")) {
|
|
973
|
+
console.log(chalk__default.default.blue("[INFO]"), ...args);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
success(...args) {
|
|
977
|
+
if (this.shouldLog("info")) {
|
|
978
|
+
console.log(chalk__default.default.green("[SUCCESS]"), ...args);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
warn(...args) {
|
|
982
|
+
if (this.shouldLog("warn")) {
|
|
983
|
+
console.log(chalk__default.default.yellow("[WARN]"), ...args);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
error(...args) {
|
|
987
|
+
if (this.shouldLog("error")) {
|
|
988
|
+
console.error(chalk__default.default.red("[ERROR]"), ...args);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
setLevel(level) {
|
|
992
|
+
this.level = level;
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
|
|
996
|
+
exports.AsyncAssetConfigSchema = AsyncAssetConfigSchema;
|
|
997
|
+
exports.BlockingAssetConfigSchema = BlockingAssetConfigSchema;
|
|
998
|
+
exports.FormatDetector = FormatDetector;
|
|
999
|
+
exports.HtmlInjector = HtmlInjector;
|
|
1000
|
+
exports.LocalFoldersConfigSchema = LocalFoldersConfigSchema;
|
|
1001
|
+
exports.Logger = Logger;
|
|
1002
|
+
exports.ManifestUpdater = ManifestUpdater;
|
|
1003
|
+
exports.PatchAdamsConfigSchema = PatchAdamsConfigSchema;
|
|
1004
|
+
exports.Patcher = Patcher;
|
|
1005
|
+
exports.defaultConfig = defaultConfig;
|
|
1006
|
+
exports.generateConfigTemplate = generateConfigTemplate;
|
|
1007
|
+
exports.generateCssAfterLoader = generateCssAfterLoader;
|
|
1008
|
+
exports.generateCssBeforeLoader = generateCssBeforeLoader;
|
|
1009
|
+
exports.generateJsAfterLoader = generateJsAfterLoader;
|
|
1010
|
+
exports.generateJsBeforeLoader = generateJsBeforeLoader;
|
|
1011
|
+
exports.loadConfig = loadConfig;
|
|
1012
|
+
exports.mergeWithDefaults = mergeWithDefaults;
|
|
1013
|
+
//# sourceMappingURL=index.cjs.map
|
|
1014
|
+
//# sourceMappingURL=index.cjs.map
|