create-wirejs-app 2.0.94 → 2.0.95-async-api

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-wirejs-app",
3
- "version": "2.0.94",
3
+ "version": "2.0.95-async-api",
4
4
  "description": "Initializes a wirejs package.",
5
5
  "author": "Jon Wire",
6
6
  "license": "MIT",
@@ -1,16 +1,33 @@
1
- import { withContext, RealtimeService, AuthenticationApi } from "wirejs-resources";
1
+ import {
2
+ AuthenticationApi,
3
+ BackgroundJob,
4
+ RealtimeService,
5
+ withContext,
6
+ } from "wirejs-resources";
2
7
 
3
8
  const realtimeService = new RealtimeService<{
4
9
  username: string;
5
10
  body: string;
6
11
  }>('app', 'realtime');
7
12
 
8
- function sanitizedRoomName(room: string | null): string {
9
- if (room === null || room === '') {
10
- return 'default';
11
- }
12
- return room.replace(/[^-_a-zA-Z0-9]/g, '-').slice(0, 50);
13
- }
13
+ const counter = new BackgroundJob('app', 'countdowns', {
14
+ handler: async (room: string, seconds: number) => {
15
+ return new Promise<void>((resolve) => {
16
+ let remaining = seconds;
17
+ const interval = setInterval(() => {
18
+ if (remaining <= 0) {
19
+ clearInterval(interval);
20
+ resolve();
21
+ } else {
22
+ realtimeService.publish(sanitizedRoomName(room), [{
23
+ username: 'Countdown',
24
+ body: `Time remaining: ${remaining--} seconds`
25
+ }]);
26
+ }
27
+ }, 1000);
28
+ });
29
+ },
30
+ });
14
31
 
15
32
  export const Chat = (auth: AuthenticationApi) => withContext(context => ({
16
33
  async publish(room: string, message: string) {
@@ -23,5 +40,19 @@ export const Chat = (auth: AuthenticationApi) => withContext(context => ({
23
40
  async getRoom(room: string) {
24
41
  await auth.requireCurrentUser(context);
25
42
  return realtimeService.getStream(sanitizedRoomName(room));
43
+ },
44
+ async startCountdown(room: string, seconds: number) {
45
+ await auth.requireCurrentUser(context);
46
+ if (seconds < 5 || seconds > 600) {
47
+ throw new Error('Countdown must be between 5 and 60 seconds.');
48
+ }
49
+ await counter.start(sanitizedRoomName(room), seconds);
26
50
  }
27
- }));
51
+ }));
52
+
53
+ function sanitizedRoomName(room: string | null): string {
54
+ if (room === null || room === '') {
55
+ return 'default';
56
+ }
57
+ return room.replace(/[^-_a-zA-Z0-9]/g, '-').slice(0, 50);
58
+ }
@@ -11,11 +11,11 @@
11
11
  "dompurify": "^3.2.3",
12
12
  "marked": "^15.0.6",
13
13
  "wirejs-dom": "^1.0.41",
14
- "wirejs-resources": "^0.1.89",
15
- "wirejs-components": "^0.1.32"
14
+ "wirejs-resources": "^0.1.90-async-api",
15
+ "wirejs-components": "^0.1.33-async-api"
16
16
  },
17
17
  "devDependencies": {
18
- "wirejs-scripts": "^3.0.87",
18
+ "wirejs-scripts": "^3.0.88-async-api",
19
19
  "typescript": "^5.7.3"
20
20
  },
21
21
  "scripts": {
@@ -18,7 +18,7 @@ async function Chat() {
18
18
  marked.parse(`**${message.username}:** ${message.body}`
19
19
  ) as string))}`)}
20
20
 
21
- <!-- Input for new messages. -->
21
+ <!-- New message form -->
22
22
  <form onsubmit=${(event: Event) => {
23
23
  event.preventDefault();
24
24
  chat.publish(null, self.data.room, self.data.message);
@@ -31,7 +31,7 @@ async function Chat() {
31
31
  <!-- Connection status -->
32
32
  <span style='color: var(--color-muted)'>${text('status', 'Connecting ...')}</span>
33
33
 
34
- <!-- Room selection -->
34
+ <!-- Room selection form -->
35
35
  <form ${id('roomChangeForm')} onsubmit=${(event: Event) => {
36
36
  event.preventDefault();
37
37
  self.data.messages = [];
@@ -49,8 +49,31 @@ async function Chat() {
49
49
  }} />
50
50
  </form>
51
51
 
52
+ <!-- Countdown form -->
53
+ <form ${id('countdownForm')} onsubmit=${(event: Event) => {
54
+ event.preventDefault();
55
+ if (self.data.countdownDisabled) {
56
+ // discourage spamming the countdown
57
+ alert('Countdown is already running. One at a time please!');
58
+ return;
59
+ }
60
+ self.data.countdownDisabled = true;
61
+ chat.startCountdown(null, self.data.room, self.data.countdownSeconds);
62
+ self.data.countdownSeconds = 10;
63
+ setTimeout(() => {
64
+ self.data.countdownDisabled = false;
65
+ }, self.data.countdownSeconds * 1000);
66
+ }}>
67
+ <input type='hidden' value=${attribute('countdownDisabled', false as boolean)} />
68
+ <input type='number' style='width: 10rem;'
69
+ value=${attribute('countdownSeconds', 10 as number)}
70
+ min='5' max='60' />
71
+ <input type='submit' style='width: 10rem;' value='Start Counting' />
72
+ </form>
73
+
52
74
  <!-- Description -->
53
75
  <p>A simple example of realtime messaging. Messages are 100% ephemeral. If you reload the page, messages are lost. If you're not connected when a message it sent, you won't receive it.</p>
76
+ <p>The countdown feature is a simple background job that sends a message every second until the countdown reaches zero.</p>
54
77
  </div>`.extend(() => ({
55
78
  disconnect() {
56
79
  // no implementation until connected