pulse-js-framework 1.5.3 → 1.7.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/cli/release.js CHANGED
@@ -15,6 +15,7 @@ import { join, dirname } from 'path';
15
15
  import { fileURLToPath } from 'url';
16
16
  import { execSync } from 'child_process';
17
17
  import { createInterface } from 'readline';
18
+ import https from 'https';
18
19
  import { log } from './logger.js';
19
20
 
20
21
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -357,6 +358,104 @@ function escapeHtml(str) {
357
358
  .replace(/"/g, '"');
358
359
  }
359
360
 
361
+ /**
362
+ * Send release notification to Discord webhook
363
+ * @param {string} webhookUrl - Discord webhook URL
364
+ * @param {string} version - Release version
365
+ * @param {string} title - Release title
366
+ * @param {Object} changes - Changelog entries
367
+ * @returns {Promise<void>}
368
+ */
369
+ function sendDiscordNotification(webhookUrl, version, title, changes) {
370
+ return new Promise((resolve, reject) => {
371
+ // Build embed fields from changes
372
+ const fields = [];
373
+
374
+ if (changes.added?.length > 0) {
375
+ fields.push({
376
+ name: '✨ Added',
377
+ value: changes.added.map(c => `• ${c}`).join('\n').slice(0, 1024),
378
+ inline: false
379
+ });
380
+ }
381
+
382
+ if (changes.changed?.length > 0) {
383
+ fields.push({
384
+ name: '🔄 Changed',
385
+ value: changes.changed.map(c => `• ${c}`).join('\n').slice(0, 1024),
386
+ inline: false
387
+ });
388
+ }
389
+
390
+ if (changes.fixed?.length > 0) {
391
+ fields.push({
392
+ name: '🐛 Fixed',
393
+ value: changes.fixed.map(c => `• ${c}`).join('\n').slice(0, 1024),
394
+ inline: false
395
+ });
396
+ }
397
+
398
+ if (changes.removed?.length > 0) {
399
+ fields.push({
400
+ name: '🗑️ Removed',
401
+ value: changes.removed.map(c => `• ${c}`).join('\n').slice(0, 1024),
402
+ inline: false
403
+ });
404
+ }
405
+
406
+ // Discord webhook payload with rich embed
407
+ const payload = {
408
+ embeds: [{
409
+ title: `🚀 Pulse Framework v${version}`,
410
+ description: title || 'New release available!',
411
+ color: 0x5865F2, // Discord blurple
412
+ fields,
413
+ footer: {
414
+ text: 'Pulse JS Framework'
415
+ },
416
+ timestamp: new Date().toISOString(),
417
+ url: `https://github.com/vincenthirtz/pulse-js-framework/releases/tag/v${version}`
418
+ }]
419
+ };
420
+
421
+ const data = JSON.stringify(payload);
422
+ const url = new URL(webhookUrl);
423
+
424
+ const options = {
425
+ hostname: url.hostname,
426
+ port: 443,
427
+ path: url.pathname + url.search,
428
+ method: 'POST',
429
+ headers: {
430
+ 'Content-Type': 'application/json',
431
+ 'Content-Length': Buffer.byteLength(data)
432
+ }
433
+ };
434
+
435
+ const req = https.request(options, (res) => {
436
+ if (res.statusCode >= 200 && res.statusCode < 300) {
437
+ log.info(' Discord notification sent successfully');
438
+ resolve();
439
+ } else {
440
+ let body = '';
441
+ res.on('data', chunk => body += chunk);
442
+ res.on('end', () => {
443
+ log.error(` Discord notification failed: ${res.statusCode} - ${body}`);
444
+ reject(new Error(`Discord webhook failed: ${res.statusCode}`));
445
+ });
446
+ }
447
+ });
448
+
449
+ req.on('error', (error) => {
450
+ log.error(` Discord notification error: ${error.message}`);
451
+ reject(error);
452
+ });
453
+
454
+ req.write(data);
455
+ req.end();
456
+ });
457
+ }
458
+
360
459
  /**
361
460
  * Update CLAUDE.md if needed
362
461
  */
@@ -470,6 +569,7 @@ Options:
470
569
  --added <items> Comma-separated list of added features
471
570
  --changed <items> Comma-separated list of changes
472
571
  --fixed <items> Comma-separated list of fixes
572
+ --discord-webhook <url> Send release notification to Discord channel
473
573
 
474
574
  Examples:
475
575
  pulse release patch
@@ -478,6 +578,7 @@ Examples:
478
578
  pulse release patch --from-commits --title "Bug Fixes" -y
479
579
  pulse release patch --title "Security" --fixed "XSS vulnerability,SQL injection" -y
480
580
  pulse release patch --title "New API" --added "Feature A,Feature B" --fixed "Bug X" -y
581
+ pulse release patch --discord-webhook "https://discord.com/api/webhooks/..."
481
582
  `);
482
583
  }
483
584
 
@@ -505,6 +606,13 @@ export async function runRelease(args) {
505
606
  title = args[titleIndex + 1];
506
607
  }
507
608
 
609
+ // Parse --discord-webhook option
610
+ let discordWebhook = null;
611
+ const discordIndex = args.indexOf('--discord-webhook');
612
+ if (discordIndex !== -1 && args[discordIndex + 1]) {
613
+ discordWebhook = args[discordIndex + 1];
614
+ }
615
+
508
616
  // Parse --changes JSON option
509
617
  let changesFromArgs = null;
510
618
  const changesIndex = args.indexOf('--changes');
@@ -697,6 +805,19 @@ export async function runRelease(args) {
697
805
  log.info(`Release v${newVersion} complete!`);
698
806
  log.info('');
699
807
 
808
+ // Send Discord notification if webhook URL provided
809
+ if (discordWebhook && !dryRun) {
810
+ log.info('Sending Discord notification...');
811
+ try {
812
+ await sendDiscordNotification(discordWebhook, newVersion, title, changes);
813
+ } catch (error) {
814
+ log.warn(`Discord notification failed: ${error.message}`);
815
+ log.warn('Release was successful, but notification could not be sent.');
816
+ }
817
+ } else if (discordWebhook && dryRun) {
818
+ log.info(' [dry-run] Would send Discord notification to webhook');
819
+ }
820
+
700
821
  if (!dryRun && !noPush) {
701
822
  log.info('Next steps:');
702
823
  log.info(` 1. Create GitHub release: https://github.com/vincenthirtz/pulse-js-framework/releases/new?tag=v${newVersion}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulse-js-framework",
3
- "version": "1.5.3",
3
+ "version": "1.7.0",
4
4
  "description": "A declarative DOM framework with CSS selector-based structure and reactive pulsations",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -17,6 +17,10 @@
17
17
  "types": "./types/index.d.ts",
18
18
  "default": "./runtime/index.js"
19
19
  },
20
+ "./runtime/lite": {
21
+ "types": "./types/lite.d.ts",
22
+ "default": "./runtime/lite.js"
23
+ },
20
24
  "./runtime/pulse": {
21
25
  "types": "./types/pulse.d.ts",
22
26
  "default": "./runtime/pulse.js"
@@ -41,6 +45,7 @@
41
45
  "types": "./types/logger.d.ts",
42
46
  "default": "./runtime/logger.js"
43
47
  },
48
+ "./runtime/logger/prod": "./runtime/logger.prod.js",
44
49
  "./runtime/hmr": {
45
50
  "types": "./types/hmr.d.ts",
46
51
  "default": "./runtime/hmr.js"
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Pulse Framework - Lite Build
3
+ * @module pulse-js-framework/runtime/lite
4
+ *
5
+ * Minimal bundle (~5KB gzipped) with core reactivity and DOM helpers.
6
+ * Use this for simple apps that don't need router or store.
7
+ *
8
+ * @example
9
+ * import { pulse, effect, el, mount } from 'pulse-js-framework/runtime/lite';
10
+ *
11
+ * const count = pulse(0);
12
+ * const app = el('div', [
13
+ * el('h1', () => `Count: ${count.get()}`),
14
+ * el('button', { onclick: () => count.update(n => n + 1) }, 'Increment')
15
+ * ]);
16
+ * mount('#app', app);
17
+ */
18
+
19
+ // Core reactivity - essential
20
+ export {
21
+ pulse,
22
+ effect,
23
+ computed,
24
+ batch,
25
+ onCleanup,
26
+ untrack
27
+ } from './pulse.js';
28
+
29
+ // DOM helpers - essential
30
+ export {
31
+ el,
32
+ text,
33
+ mount,
34
+ on,
35
+ bind,
36
+ list,
37
+ when,
38
+ model
39
+ } from './dom.js';
40
+
41
+ // Minimal re-exports for common patterns
42
+ export { show, cls, style, prop } from './dom.js';
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Pulse Logger - Production Build (minimal/noop)
3
+ * Replace logger.js with this in production builds for smaller bundle.
4
+ * @module pulse-js-framework/runtime/logger.prod
5
+ */
6
+
7
+ export const LogLevel = { SILENT: 0, ERROR: 1, WARN: 2, INFO: 3, DEBUG: 4 };
8
+
9
+ const noop = () => {};
10
+ const noopLogger = {
11
+ error: noop, warn: noop, info: noop, debug: noop,
12
+ group: noop, groupEnd: noop, log: noop,
13
+ child: () => noopLogger
14
+ };
15
+
16
+ export const setLogLevel = noop;
17
+ export const getLogLevel = () => LogLevel.SILENT;
18
+ export const setFormatter = noop;
19
+ export const createLogger = () => noopLogger;
20
+ export const logger = noopLogger;
21
+ export const loggers = {
22
+ pulse: noopLogger, dom: noopLogger, router: noopLogger,
23
+ store: noopLogger, native: noopLogger, hmr: noopLogger, cli: noopLogger
24
+ };
25
+ export default logger;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Pulse Framework - Lite Build Type Definitions
3
+ * Minimal bundle with core reactivity and DOM helpers.
4
+ */
5
+
6
+ // Re-export core reactivity types
7
+ export {
8
+ pulse,
9
+ effect,
10
+ computed,
11
+ batch,
12
+ onCleanup,
13
+ untrack,
14
+ Pulse
15
+ } from './pulse';
16
+
17
+ // Re-export DOM types
18
+ export {
19
+ el,
20
+ text,
21
+ mount,
22
+ on,
23
+ bind,
24
+ list,
25
+ when,
26
+ model,
27
+ show,
28
+ cls,
29
+ style,
30
+ prop
31
+ } from './dom';