wirejs-deploy-amplify-basic 0.0.115-realtime → 0.0.117-realtime

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.
@@ -3,6 +3,6 @@
3
3
  "dependencies": {
4
4
  "jsdom": "^25.0.1",
5
5
  "wirejs-dom": "^1.0.41",
6
- "wirejs-resources": "^0.1.83-realtime"
6
+ "wirejs-resources": "^0.1.85-realtime"
7
7
  }
8
8
  }
package/build.js CHANGED
@@ -5,7 +5,7 @@ import path from 'path';
5
5
  import fs from 'fs';
6
6
  import { rimraf } from 'rimraf';
7
7
  import copy from 'recursive-copy';
8
- import { exec, execSync } from 'child_process';
8
+ import { execSync } from 'child_process';
9
9
 
10
10
  const CWD = process.cwd();
11
11
  const __filename = import.meta.url.replace(/^file:/, '');
@@ -87,14 +87,13 @@ async function installDeps() {
87
87
  async function discoverResources() {
88
88
  console.log("discovering resources")
89
89
  // exploratory import. resources will emit to globalThis.wirejsResources
90
+ execSync(`cd api && npm run prebuild`);
90
91
  await import(path.join(CWD, 'api', 'dist', 'index.js'));
91
92
  console.log('discovered resources', globalThis.wirejsResources);
92
93
  await fs.promises.writeFile(
93
94
  path.join(BACKEND_DIR, 'generated-resources.ts'),
94
95
  `export default ${JSON.stringify(globalThis.wirejsResources, null, 2)}`
95
96
  );
96
-
97
- return outputPath;
98
97
  }
99
98
 
100
99
  async function deployFrontend() {
@@ -40,23 +40,41 @@ function getAuthProtocol(authorization) {
40
40
  const header = getBase64URLEncoded(authorization);
41
41
  return `header-${header}`;
42
42
  }
43
- export function subscribe(url, channel, token, authHost, subscriber) {
43
+ function urlString(url) {
44
+ if (!url.startsWith('ws://') && !url.startsWith('wss://')) {
45
+ throw new Error(`Invalid WebSocket URL: ${url}`);
46
+ }
47
+ return url;
48
+ }
49
+ function fullChannelNameString(url, channel) {
50
+ if (!channel || typeof channel !== 'string') {
51
+ throw new Error(`Invalid channel name: ${channel}`);
52
+ }
44
53
  const fullChannelName = `${url}#${channel}`;
54
+ return fullChannelName;
55
+ }
56
+ function subscriptionIdString(id) {
57
+ return id;
58
+ }
59
+ export function subscribe(url, channel, token, authHost, subscriber) {
60
+ const urlKey = urlString(url);
61
+ const fullChannelName = fullChannelNameString(urlKey, channel);
45
62
  const authorization = {
46
63
  Authorization: token,
47
64
  host: authHost,
48
65
  };
49
- if (!connections.has(url)) {
66
+ if (!connections.has(urlKey)) {
50
67
  const ws = new WebSocket(url, [
51
68
  'aws-appsync-event-ws',
52
69
  getAuthProtocol(authorization)
53
70
  ]);
54
- connections.set(url, ws);
71
+ connections.set(urlKey, ws);
55
72
  ws.onmessage = event => {
56
73
  const data = JSON.parse(event.data);
74
+ const sid = subscriptionIdString(data.id);
57
75
  if (data.type === 'data') {
58
76
  const eventData = JSON.parse(data.event);
59
- for (const subscriber of subscribers.get(data.id) || []) {
77
+ for (const subscriber of subscribers.get(sid) || []) {
60
78
  try {
61
79
  subscriber.onmessage(eventData);
62
80
  }
@@ -66,8 +84,8 @@ export function subscribe(url, channel, token, authHost, subscriber) {
66
84
  }
67
85
  }
68
86
  else if (data.type === 'subscribe_success') {
69
- subscriptionState.set(data.id, 'open');
70
- for (const subscriber of subscribers.get(data.id) || []) {
87
+ subscriptionState.set(sid, 'open');
88
+ for (const subscriber of subscribers.get(sid) || []) {
71
89
  try {
72
90
  subscriber.onopen?.();
73
91
  }
@@ -80,7 +98,7 @@ export function subscribe(url, channel, token, authHost, subscriber) {
80
98
  const notifyClosed = () => {
81
99
  const subscriptionIds = Array.from(channelSubs.entries())
82
100
  .filter(([urlChannel, _subId]) => urlChannel.startsWith(`${url}#`))
83
- .map(([_urlChannel, subId]) => subId);
101
+ .map(([_urlChannel, subId]) => subscriptionIdString(subId));
84
102
  for (const subscriptionId of subscriptionIds) {
85
103
  subscriptionState.set(subscriptionId, 'closed');
86
104
  const subs = subscribers.get(subscriptionId);
@@ -104,9 +122,9 @@ export function subscribe(url, channel, token, authHost, subscriber) {
104
122
  ws.onerror = () => notifyClosed();
105
123
  }
106
124
  if (!channelSubs.has(fullChannelName)) {
107
- const subscriptionId = crypto.randomUUID();
125
+ const subscriptionId = subscriptionIdString(crypto.randomUUID());
108
126
  subscriptionState.set(subscriptionId, 'connecting');
109
- const ws = connections.get(url);
127
+ const ws = connections.get(urlKey);
110
128
  const subscribe = () => {
111
129
  ws.send(JSON.stringify({
112
130
  id: subscriptionId,
@@ -136,25 +154,32 @@ export function subscribe(url, channel, token, authHost, subscriber) {
136
154
  }
137
155
  }
138
156
  export function unsubscribe(url, channel, subscriber) {
139
- const fullChannelName = `${url}#${channel}`;
140
- if (subscribers.has(fullChannelName)) {
141
- const subs = subscribers.get(fullChannelName);
142
- const index = subs.indexOf(subscriber);
143
- if (index !== -1) {
144
- subs.splice(index, 1);
145
- if (subs.length === 0) {
146
- channelSubs.delete(fullChannelName);
147
- const urlSubs = Array.from(channelSubs.keys())
148
- .filter(id => id.startsWith(`${url}#`));
149
- if (urlSubs.length === 0) {
150
- const ws = connections.get(url);
151
- if (ws) {
152
- ws.close();
153
- connections.delete(url);
154
- }
155
- }
156
- subscribers.delete(url);
157
- }
158
- }
157
+ const urlKey = urlString(url);
158
+ const ws = connections.get(urlKey);
159
+ const fullChannelName = fullChannelNameString(urlKey, channel);
160
+ const subId = channelSubs.get(fullChannelName);
161
+ const subs = subId && subscribers.get(subId);
162
+ const sub = subs ? subs.find(s => s === subscriber) : undefined;
163
+ if (sub && subs) {
164
+ subs.splice(subs.indexOf(sub), 1);
165
+ subscribers.set(subId, subs);
166
+ sub.onclose?.();
167
+ }
168
+ if (subs && subs.length === 0) {
169
+ // No subscribers left for this channel. We can unsubscribe from channel.
170
+ ws?.send(JSON.stringify({
171
+ id: subId,
172
+ type: 'unsubscribe',
173
+ }));
174
+ subscriptionState.delete(subId);
175
+ subscribers.delete(subId);
176
+ channelSubs.delete(fullChannelName);
177
+ }
178
+ const socketSubs = Array.from(channelSubs.keys())
179
+ .filter(k => k.startsWith(urlKey));
180
+ if (socketSubs.length === 0) {
181
+ // No channels left for this URL. We can close the WebSocket connection.
182
+ ws?.close();
183
+ connections.delete(urlKey);
159
184
  }
160
185
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wirejs-deploy-amplify-basic",
3
- "version": "0.0.115-realtime",
3
+ "version": "0.0.117-realtime",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -41,7 +41,7 @@
41
41
  "recursive-copy": "^2.0.14",
42
42
  "rimraf": "^6.0.1",
43
43
  "wirejs-dom": "^1.0.41",
44
- "wirejs-resources": "^0.1.83-realtime"
44
+ "wirejs-resources": "^0.1.85-realtime"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@aws-amplify/backend": "^1.14.0",