@messenger-box/platform-client 10.0.3-alpha.37 → 10.0.3-alpha.38

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/CHANGELOG.md CHANGED
@@ -3,6 +3,10 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [10.0.3-alpha.38](https://github.com/CDEBase/messenger-box/compare/v10.0.3-alpha.37...v10.0.3-alpha.38) (2025-04-25)
7
+
8
+ **Note:** Version bump only for package @messenger-box/platform-client
9
+
6
10
  ## [10.0.3-alpha.37](https://github.com/CDEBase/messenger-box/compare/v10.0.3-alpha.36...v10.0.3-alpha.37) (2025-04-25)
7
11
 
8
12
  **Note:** Version bump only for package @messenger-box/platform-client
@@ -1 +1 @@
1
- {"version":3,"file":"messages-policies.d.ts","sourceRoot":"","sources":["../../../src/graphql/policies/messages-policies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,eAAO,MAAM,gBAAgB,EAAE,YA2L9B,CAAC"}
1
+ {"version":3,"file":"messages-policies.d.ts","sourceRoot":"","sources":["../../../src/graphql/policies/messages-policies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,eAAO,MAAM,gBAAgB,EAAE,YA8T9B,CAAC"}
@@ -29,32 +29,42 @@ const messagesPolicies = {
29
29
  data: {
30
30
  keyArgs: ['channelId', 'parentId'],
31
31
  merge: (existing = [], incoming = [], {
32
- readField,
33
- mergeObjects
32
+ readField
34
33
  }) => {
35
- // Create a map of existing messages by ID for efficient lookups
34
+ // Use a Map for O(1) lookups instead of array iterations
36
35
  const existingMap = new Map();
37
- existing.forEach(item => {
38
- const id = readField('id', item);
39
- if (id) existingMap.set(id, item);
40
- });
41
- // Create a new array by merging incoming with existing
42
- const merged = incoming.map(incomingItem => {
43
- const id = readField('id', incomingItem);
44
- // If item already exists, merge them, otherwise use incoming
45
- if (id && existingMap.has(id)) {
46
- return mergeObjects(existingMap.get(id), incomingItem);
36
+ // Populate map with existing messages
37
+ if (existing && existing.length > 0) {
38
+ for (let i = 0; i < existing.length; i++) {
39
+ const id = readField('id', existing[i]);
40
+ if (id) {
41
+ existingMap.set(id, existing[i]);
42
+ }
43
+ }
44
+ }
45
+ // Create result array with same capacity as total items
46
+ const result = [];
47
+ // Add incoming items, overwriting existing ones
48
+ if (incoming && incoming.length > 0) {
49
+ for (let i = 0; i < incoming.length; i++) {
50
+ const item = incoming[i];
51
+ const id = readField('id', item);
52
+ if (id) {
53
+ existingMap.set(id, item);
54
+ }
55
+ result.push(item);
47
56
  }
48
- return incomingItem;
49
- });
50
- // Add any existing items that aren't in the incoming list
51
- existing.forEach(existingItem => {
52
- const id = readField('id', existingItem);
53
- if (id && !merged.some(item => readField('id', item) === id)) {
54
- merged.push(existingItem);
57
+ }
58
+ // Add remaining existing items not in incoming
59
+ if (existing && existing.length > 0) {
60
+ for (let i = 0; i < existing.length; i++) {
61
+ const id = readField('id', existing[i]);
62
+ if (id && !result.some(item => readField('id', item) === id)) {
63
+ result.push(existing[i]);
64
+ }
55
65
  }
56
- });
57
- return merged;
66
+ }
67
+ return result;
58
68
  }
59
69
  },
60
70
  totalCount: {
@@ -114,80 +124,194 @@ const messagesPolicies = {
114
124
  }) {
115
125
  if (!incoming) return existing;
116
126
  if (!existing) return incoming;
117
- // Create a deep copy of the existing data
118
- const result = {
119
- ...existing,
120
- totalCount: incoming.totalCount ?? existing.totalCount
121
- };
122
- // If there's no data in either, return the basic structure
123
- if (!existing.data || !incoming.data) {
124
- return result;
125
- }
126
- // Create a map of existing messages by ID
127
- const existingMessages = new Map();
128
- existing.data.forEach(message => {
129
- const id = readField('id', message);
130
- if (id) existingMessages.set(id, message);
131
- });
132
- // Create merged data array with deduplication
133
- let mergedData = [...existing.data];
134
- // Add new messages, replacing existing ones with same ID
135
- incoming.data.forEach(incomingMessage => {
136
- const id = readField('id', incomingMessage);
137
- if (!id) return;
138
- // If message already exists, update it at its current position
139
- const existingIndex = mergedData.findIndex(msg => readField('id', msg) === id);
140
- if (existingIndex >= 0) {
141
- // Replace the existing message with the incoming one
142
- mergedData[existingIndex] = incomingMessage;
127
+ // Fast return if incoming has no data
128
+ if (!incoming.data || incoming.data.length === 0) {
129
+ return {
130
+ ...existing,
131
+ totalCount: incoming.totalCount ?? existing.totalCount
132
+ };
133
+ }
134
+ // Fast return if existing has no data
135
+ if (!existing.data || existing.data.length === 0) {
136
+ return incoming;
137
+ }
138
+ // Determine if this is likely a new message or pagination
139
+ const isNewMessage = args && args.skip === 0;
140
+ // Create a map for existing messages for fast lookups
141
+ const idSet = new Set();
142
+ const mergedData = [...existing.data];
143
+ // Mark all existing IDs
144
+ for (let i = 0; i < mergedData.length; i++) {
145
+ const id = readField('id', mergedData[i]);
146
+ if (id) idSet.add(id);
147
+ }
148
+ // Process incoming messages
149
+ for (let i = 0; i < incoming.data.length; i++) {
150
+ const incomingMsg = incoming.data[i];
151
+ const id = readField('id', incomingMsg);
152
+ if (!id) continue;
153
+ if (idSet.has(id)) {
154
+ // Replace existing message with same ID
155
+ const existingIndex = mergedData.findIndex(msg => readField('id', msg) === id);
156
+ if (existingIndex >= 0) {
157
+ mergedData[existingIndex] = incomingMsg;
158
+ }
143
159
  } else {
144
- // Add the new message
145
- // For optimistic updates with sendMessage mutation, we want to add to the beginning
146
- // For pagination/fetchMore, we should add according to the sort order
147
- if (args && args.skip === 0) {
148
- // This is likely a new message or an optimistic update
149
- mergedData.unshift(incomingMessage);
160
+ // Add new message
161
+ if (isNewMessage) {
162
+ // Add to beginning for new messages
163
+ mergedData.unshift(incomingMsg);
150
164
  } else {
151
- // This is likely from pagination
152
- mergedData.push(incomingMessage);
165
+ // Add to end for pagination
166
+ mergedData.push(incomingMsg);
153
167
  }
168
+ idSet.add(id);
154
169
  }
155
- });
156
- // Ensure no duplicate messages
157
- const uniqueIds = new Set();
158
- mergedData = mergedData.filter(message => {
159
- const id = readField('id', message);
160
- if (!id || uniqueIds.has(id)) return false;
161
- uniqueIds.add(id);
162
- return true;
163
- });
170
+ }
164
171
  return {
165
- ...result,
172
+ ...existing,
173
+ totalCount: incoming.totalCount ?? existing.totalCount,
166
174
  data: mergedData
167
175
  };
168
176
  }
169
177
  }
170
178
  }
171
179
  },
180
+ FilesInfo: {
181
+ merge: true,
182
+ // Use default merging behavior for FilesInfo
183
+ fields: {
184
+ data: {
185
+ merge(existing = [], incoming = [], {
186
+ readField
187
+ }) {
188
+ // If no existing data, just return incoming
189
+ if (!existing || existing.length === 0) {
190
+ return incoming;
191
+ }
192
+ // If no incoming data, keep existing
193
+ if (!incoming || incoming.length === 0) {
194
+ return existing;
195
+ }
196
+ // Create a map for efficient lookup
197
+ const fileMap = new Map();
198
+ // Add existing files to map
199
+ for (let i = 0; i < existing.length; i++) {
200
+ const file = existing[i];
201
+ if (file) {
202
+ const id = readField('id', file);
203
+ if (id) {
204
+ fileMap.set(id, file);
205
+ }
206
+ }
207
+ }
208
+ // Merge in incoming files, overwriting existing ones
209
+ for (let i = 0; i < incoming.length; i++) {
210
+ const file = incoming[i];
211
+ if (file) {
212
+ const id = readField('id', file);
213
+ if (id) {
214
+ fileMap.set(id, file);
215
+ }
216
+ }
217
+ }
218
+ // Convert map values back to array
219
+ return Array.from(fileMap.values());
220
+ }
221
+ }
222
+ }
223
+ },
224
+ FileInfo: {
225
+ // Use ID as key field
226
+ keyFields: ['id'],
227
+ fields: {
228
+ url: {
229
+ // Ensure URL is always preserved and not normalized
230
+ merge(existing, incoming) {
231
+ return incoming ?? existing;
232
+ }
233
+ }
234
+ }
235
+ },
172
236
  Post: {
173
237
  fields: {
174
238
  replies: {
175
239
  merge(existing, incoming) {
176
240
  if (!incoming) return existing;
177
241
  if (!existing) return incoming;
242
+ // Use a Set for fast duplicate checking
243
+ const uniqueIds = new Set();
244
+ const mergedData = [];
245
+ // Add all existing items to the result and track IDs
246
+ if (existing.data && existing.data.length > 0) {
247
+ for (let i = 0; i < existing.data.length; i++) {
248
+ const item = existing.data[i];
249
+ if (item && item.id && !uniqueIds.has(item.id)) {
250
+ uniqueIds.add(item.id);
251
+ mergedData.push(item);
252
+ }
253
+ }
254
+ }
255
+ // Add incoming items that don't exist yet
256
+ if (incoming.data && incoming.data.length > 0) {
257
+ for (let i = 0; i < incoming.data.length; i++) {
258
+ const item = incoming.data[i];
259
+ if (item && item.id && !uniqueIds.has(item.id)) {
260
+ uniqueIds.add(item.id);
261
+ mergedData.push(item);
262
+ }
263
+ }
264
+ }
178
265
  return {
179
266
  ...incoming,
180
- data: [...(existing?.data || []), ...(incoming?.data || [])].filter((message, index, self) => index === self.findIndex(m => m.id === message.id))
267
+ data: mergedData
181
268
  };
182
269
  }
183
270
  },
184
271
  files: {
185
- merge(existing, incoming) {
272
+ merge(existing, incoming, {
273
+ readField
274
+ }) {
186
275
  if (!incoming) return existing;
187
276
  if (!existing) return incoming;
277
+ // If either has no data or totalCount is 0, prefer the one with data
278
+ if (!existing.data || existing.data.length === 0) {
279
+ return incoming;
280
+ }
281
+ if (!incoming.data || incoming.data.length === 0) {
282
+ return existing;
283
+ }
284
+ // Create a map for efficient lookup
285
+ const fileMap = new Map();
286
+ // Add existing files to map
287
+ if (existing.data) {
288
+ for (let i = 0; i < existing.data.length; i++) {
289
+ const file = existing.data[i];
290
+ if (file) {
291
+ const id = readField('id', file);
292
+ if (id) {
293
+ fileMap.set(id, file);
294
+ }
295
+ }
296
+ }
297
+ }
298
+ // Merge in incoming files, overwriting existing ones
299
+ if (incoming.data) {
300
+ for (let i = 0; i < incoming.data.length; i++) {
301
+ const file = incoming.data[i];
302
+ if (file) {
303
+ const id = readField('id', file);
304
+ if (id) {
305
+ fileMap.set(id, file);
306
+ }
307
+ }
308
+ }
309
+ }
310
+ // Create merged result
188
311
  return {
189
- ...incoming,
190
- data: [...(existing?.data || []), ...(incoming?.data || [])].filter((file, index, self) => index === self.findIndex(f => f.id === file.id))
312
+ __typename: 'FilesInfo',
313
+ totalCount: Math.max(existing.totalCount || 0, incoming.totalCount || 0, fileMap.size),
314
+ data: Array.from(fileMap.values())
191
315
  };
192
316
  }
193
317
  }
@@ -1 +1 @@
1
- {"version":3,"file":"messages-policies.js","sources":["../../../src/graphql/policies/messages-policies.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messages-policies.js","sources":["../../../src/graphql/policies/messages-policies.ts"],"sourcesContent":[null],"names":[],"mappings":"AAEa,MAAA,gBAAgB,GAAiB;AAC1C,EAAA,QAAA,EAAQ;;;;AAIJ,IAAA,MAAA,EAAA;AACI,MAAA,EAAA,EAAA;AACI,QAAA,IAAA,CAAA,QAAK,EAAA;AACD,UAAA;AACA,SAAA,EAAA;gBACJ;AACH,YAAA,SAAA;AACD,YAAA;AACI,WAAA,GAAA,SAAK;AACD,UAAA,OAAA,QAAA,GAAQ,CAAS,EAAA,qBAAoB,iBAAU,CAAA,CAAA;AAC/C;;AAEP,MAAA,aAAA,EAAA;AACD,QAAA,IAAA,CAAA,QAAM,EAAA;AACF,UAAA;AACA,SAAA,EAAA;;AAEI,YAAA,SAAA;;uBAGI;AACA,UAAA,OAAA,QAAA,GAAA,CAAK,EAAI,SAAO,CAAC,CAAA,EAAG,QAAQ,CAAC,CAAM,GAAA,CAAA,EAAA,SAAQ,CAAA,CAAA;;;;6BAItC,EAAA,UAAA,CAAA;wBACL,GAAC,EAAA,EAAA,QAAA,GAAA,EAAA,EAAA;;;;2BAM2C,GAAA,IAAA,GAAA,EAAA;;AAE5C,UAAA,IAAA,QAAA,IAAA,QAAU,CAAG,MAAI,GAAG,CAAQ,EAAA;AACxB,YAAA,KAAA,IAAA,CAAA,GAAA,CAAA,EAAA,CAAA,GAAA,QAAa,CAAA,MAAA,EAAQ,CAAC,EAAE,EAAC;kCACnB,CAAA,IAAK,EAAS,QAAC,IAAI;;AAErB,gBAAA,WAAA,CAAA,GAAA,CAAA,EAAA,EAAA,QAAY,CAAG,CAAA,CAAA,CAAC;;AAEpB;;;sBAIuC,GAAA,EAAA;;AAE3C,UAAA,IAAA,QAAA,IAAA,QAAU,CAAG,MAAI,GAAG,CAAQ,EAAA;4BACxB,CAAM,GAAA,QAAK,CAAA,MAAA,EAAU,CAAA,EAAA,EAAM;sCACjB;kCACA,CAAA,IAAC,MAAK,CAAA;;2BAEnB,CAAA,GAAA,CAAA,EAAA,EAAA,IAAA,CAAA;;AAGL,cAAA,MAAA,CAAA,IAAA,CAAA;;AAEP;AACD;AACI,UAAA,IAAA,QAAA,IAAU,QAAW,CAAA;iBAChB,IAAA,CAAC,GAAQ,CAAA,EAAA,CAAA,GAAE,QAAQ,CAAA,MAAA,EAAA,CAAA,EAAA,EAAA;oBACpB,EAAO,GAAA,SAAA,CAAQ,IAAK,EAAA,QAAS,CAAC,CAAC,CAAC,CAAA;kBACnC,EAAA,IAAA,CAAA,MAAA,CAAA,IAAA,CAAA,IAAA,IAAA,SAAA,CAAA,IAAA,EAAA,IAAA,CAAA,KAAA,EAAA,CAAA,EAAA;AACJ,gBAAA,MAAA,CAAA,IAAA,CAAA,QAAA,CAAA,CAAA,CAAA,CAAA;;;;iBAI2D,MAAA;;;gBAGT,EAAA;eACC,EAAA,CAAA,WAAA,EAAA,UAAA,CAAA;aACxC,CAAA,QAAA,EAAA,QAAA,EAAA;iBACa,QAAA,KAAA,SAAA,GAAA,QAAA,GAAA,QAAA;;;AAG5B;AACJ;AACD;;AAEI;AACI;AACI;AACI;AACA;;AAEP;AACD;AACI;AACI,GAAA;AACA,EAAA,kBAAA,EAAA;;AAEP,IAAA,MAAA,EAAA;AACJ,MAAA,mBAAA,EAAA;AACJ,QAAA,IAAA,CAAA,QAAA,EAAA;AACD,UAAO;AACH,SAAA,EAAA;AACI,UAAA,MAAA;AACI,YAAA,SAAA;;AAEI,WAAA,GAAA,SAAA;AAAe,UAAA,OAAA,QAAA,GAAA,CAAA,EAAO,SAAS,CAAA,CAAA,EAAA,QAAA,CAAA,CAAA,GAAA,CAAA,EAAA,SAAA,CAAA,CAAA;AAC/B;AAAe,OAAA;;AAGf,QAAA,IAAA,CAAA,QAAA,EAAA;;AAEQ,SAAA,EAAA;AACA,UAAA,MAAA;;;uBAI8B;AACtC,UAAA,OAAA,QAAK,GAAA,CAAA,EAAA,SAAiB,CAAA,CAAA,EAAA,QAAS,CAAA,CAAA,GAAK,CAAA,EAAA,UAAc,CAAC;AAC/C;;;;;AAOJ,IAAA,MAAA,EAAA;;6BAGwB,EAAA,UAAA,CAAA;AACxB,QAAA,KAAA,CAAA,QAAA,EAAA,QAAa,EAAC;;AAEV,UAAA;AAAQ,SAAA,EAAA;uBACX,EAAA,OAAA,QAAA;uBAE2B,EAAA,OAAA,QAAA;AAC5B;wBACI,IAAM,IAAA,QAAA,CAAW,IAAW,CAAA,MAAA,KAAK,CAAC,EAAE;;AAGpC,cAAA,GAAA,QAAA;kCAAkB,CAAA,UAAA,IAAA,QAAA,CAAA;AAElB,aAAA;;;AAGI,UAAA,IAAA,CAAA,QAAA,CAAA,IAAA,IAAI,QAAa,CAAA,IAAA,CAAA,MAAO,KAAC,CAAA,EAAA;AACrB,YAAA,OAAA,QAAA;;;+BAEA,IAAA,IAAA,IAAA,CAAA,IAAA,KAAA,CAAA;;4BAEJ,GAAI,EAAA;iCACoC,QAAA,CAAA,IAAA,CAAA;AACpC;8BACH,UAAA,CAAA,MAAA,EAAA,CAAA,EAAA,EAAA;iCAAM,IAAC,EAAA,UAAA,CAAA,CAAA,CAAA,CAAA;gCACJ,CAA4B;AAC5B;;AAEJ,UAAA,KAAA,IAAA,CAAA,GAAA,CAAA,EAAA,CAAA,GAAA,QAAU,CAAA,IAAI,CAAA,MAAA,EAAA,CAAA,EAAA,EAAA;6BACjB,GAAA,QAAA,CAAA,IAAA,CAAA,CAAA,CAAA;oBACL,GAAC,SAAA,CAAA,IAAA,EAAA,WAAA,CAAA;qBAEM;AACH,YAAA,IAAA,KAAA,CAAA,GAAA,CAAA,EAAW,CAAA,EAAA;AACX;AACA,cAAA,MAAA,aAAgB,GAAA,UAAA,CAAA,SAAA,CAAA,GAAA,IAAA,SAAA,CAAA,IAAA,EAAA,GAAA,CAAA,KAAA,EAAA,CAAA;+BAClB,IAAA,CAAA,EAAA;gBACN,UAAC,CAAA,aAAA,CAAA,GAAA,WAAA;AACJ;AACJ,aAAA,MAAA;AACJ;AACD,cAAW,IAAA,YAAA,EAAA;;AAEP,gBAAQ,UAAA,CAAA,OAAA,CAAA,WAAA,CAAA;AACJ,eAAA,MAAM;;0BAE8C,CAAA,IAAA,CAAA,WAAA,CAAA;;AAExC,cAAA,KAAA,CAAA,GAAA,CAAA,EAAA,CAAA;;;;AAKA,YAAA,GAAA,QAAA;sBACH,EAAA,QAAA,CAAA,UAAA,IAAA,QAAA,CAAA,UAAA;;AAGD,WAAA;;AAGA;AACI;;;;AAIQ;;;sBAGX,GAAA,EAAA,EAAA,QAAA,GAAA,EAAA,EAAA;;AAGD,SAAA,EAAA;AACI;2BACI,QAAO,CAAA,MAAA,KAAA,CAAA,EAAA;;;AAGH;mCACH,CAAA,MAAA,KAAA,CAAA,EAAA;2BACJ;;;uBAIE,GAAA,IAAA,GAAM,EAAI;;AAExB,UAAA,KAAA,IAAA,CAAA,GAAA,CAAA,EAAA,CAAA,GAAA,QAAA,CAAA,MAAA,EAAA,CAAA,EAAA,EAAA;AACJ,YAAA,MAAA,IAAA,GAAA,QAAA,CAAA,CAAA,CAAA;AACJ,YAAA,IAAA,IAAA,EAAA;AACD,cAAU,MAAA,EAAA,GAAA,SAAA,CAAA,IAAA,EAAA,IAAA,CAAA;cACgB,IAAA,EAAA,EAAA;gBACb,OAAG,CAAI,GAAC,CAAA,EAAA,EAAA,IAAA,CAAA;AACjB;AACI;;;oBAGQ,GAAO,CAAA,EAAA,CAAA,GAAA,QAAY,CAAA,MAAA,EAAQ,CAAC,EAAA,EAAA;kBAC/B,IAAA,GAAA,QAAA,CAAA,CAAA,CAAA;AACJ,YAAA,IAAA,IAAA,EAAA;AACJ,cAAA,MAAA,EAAA,GAAA,SAAA,CAAA,IAAA,EAAA,IAAA,CAAA;AACJ,cAAA,IAAA,EAAA,EAAA;AACD,gBAAM,OAAA,CAAA,GAAA,CAAA,EAAA,EAAA,IAAA,CAAA;AACF;AACI;;AAEQ;AAAe,UAAA,OAAA,KAAA,CAAA,IAAA,CAAA,cAAgB,EAAA,CAAA;AAC/B;AAAe;;AAGf,GAAA;;;AAIA,IAAA,SAAA,EAAA,CAAA,IAAA,CAAA;AACI,IAAA,MAAA,EAAA;;AAEI;AACI,QAAA,KAAA,CAAA,QAAA,EAAA,QAAA,EAAA;AACA,UAAA,OAAA,QAAA,IAAA,QAAA;;;;;AAMZ,EAAA,IAAA,EAAA;AACI,IAAA,MAAA,EAAA;;AAEI,QAAA,KAAA,CAAA,QAAA,EAAA,QAAI;AACA,UAAA,IAAA,CAAA,QAAA,EAAA,OAAA,QAAA;AACA,UAAA,IAAA,CAAA,QAAA,EAAA,OAAA,QAAA;;yBAEP,GAAA,IAAA,GAAA,EAAA;0BACJ,GAAA,EAAA;;AAGG,UAAA,IAAA,QAAA,CAAA,IAAG,IAAQ,QAAA,CAAA,IAAA,CAAA,MAAA,GAAA,CAAA,EAAA;AACX,YAAA,KAAA,IAAA,CAAA,GAAA,CAAA,EAAI,IAAY,QAAA,CAAA,IAAA,CAAA,MAAA,EAAA,CAAA,EAAA,EAAA;wBAClB,GAAA,QAAA,CAAA,IAAA,CAAA,CAAA,CAAA;kBACL,IAAA,IAAA,IAAA,CAAA,EAAA,IAAA,CAAA,SAAA,CAAA,GAAA,CAAA,IAAA,CAAA,EAAA,CAAA,EAAA;AACJ,gBAAA,SAAA,CAAA,GAAA,CAAA,IAAA,CAAA,EAAA,CAAA;AACD,gBAAA,UAAO,CAAA,IAAA,CAAA,IAAA,CAAA;AACH;AACI;AAAe;AACf;AAAe,UAAA,IAAA,QAAA,CAAA,IAAA,IAAO,QAAQ,CAAC,IAAA,CAAA,MAAA,GAAA,CAAA,EAAA;qBAEsC,CAAA,GAAA,CAAA,EAAA,CAAA,GAAA,QAAA,CAAA,IAAA,CAAA,MAAA,EAAA,CAAA,EAAA,EAAA;AACrE,cAAA,MAAA,IAAI,GAAC,QAAS,CAAA,IAAQ,CAAA,CAAA,CAAA;AAClB,cAAA,IAAA,IAAA,IAAA,IAAA,CAAO,gBAAS,CAAA,GAAA,CAAA,IAAA,CAAA,EAAA,CAAA,EAAA;yBACnB,CAAA,GAAA,CAAA,IAAA,CAAA,EAAA,CAAA;AAED,gBAAA,UAAK,CAAA,IAAA,CAAA,IAAS,CAAA;AACV;;;AAIJ,UAAA,OAAA;uBAE4B;AAC5B,YAAA,IAAA,EAAA;AACI,WAAA;;;;gCAIQ,EAAI;AACA,UAAA;;gCAEP,QAAA;yBACJ,OAAA,QAAA;;uBAGgD,CAAA,IAAA,IAAA,QAAA,CAAA,IAAA,CAAA,MAAA,KAAA,CAAA,EAAA;AACrD,YAAA,OAAA,QAAY;AACR;4BACI,IAAM,SAAO,IAAQ,CAAA,WAAQ,CAAC,EAAA;;;;AAItB,UAAA,MAAA,OAAA,GAAA,IAAA,GAAA,EAAA;;6BAEP;yBACJ,CAAA,EAAA,CAAA,GAAA,QAAA,CAAA,IAAA,CAAA,MAAA,EAAA,CAAA,EAAA,EAAA;oBACL,IAAC,GAAA,QAAA,CAAA,IAAA,CAAA,CAAA,CAAA;sBAEsB,EAAA;sBAChB,EAAA,GAAA,SAAA,CAAA,IAAA,EAAA,IAAA,CAAA;AACH,gBAAA,IAAA,EAAA,EAAA;yBACU,CAAA,GAAA,CAAA,EAAA,EAAA;;;;AAIrB;AACJ;AACJ,UAAA,IAAA,QAAA,CAAA,IAAA,EAAA;YACH,KAAA,IAAA,CAAA,GAAA,CAAA,EAAA,CAAA,GAAA,QAAA,CAAA,IAAA,CAAA,MAAA,EAAA,CAAA,EAAA,EAAA;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@messenger-box/platform-client",
3
- "version": "10.0.3-alpha.37",
3
+ "version": "10.0.3-alpha.38",
4
4
  "description": "Sample core for higher packages to depend on",
5
5
  "license": "ISC",
6
6
  "author": "CDMBase LLC",
@@ -35,5 +35,5 @@
35
35
  "typescript": {
36
36
  "definition": "lib/index.d.ts"
37
37
  },
38
- "gitHead": "4a360a1be756050ed8c3c1cd61a037c6109f8866"
38
+ "gitHead": "1b4c409ed6591e28e3b0d6d08c6ff55b6bca54ce"
39
39
  }
@@ -20,33 +20,46 @@ export const messagesPolicies: TypePolicies = {
20
20
  },
21
21
  data: {
22
22
  keyArgs: ['channelId', 'parentId'],
23
- merge: (existing = [], incoming = [], { readField, mergeObjects }) => {
24
- // Create a map of existing messages by ID for efficient lookups
23
+ merge: (existing = [], incoming = [], { readField }) => {
24
+ // Use a Map for O(1) lookups instead of array iterations
25
25
  const existingMap = new Map();
26
- existing.forEach((item) => {
27
- const id = readField<string>('id', item);
28
- if (id) existingMap.set(id, item);
29
- });
30
-
31
- // Create a new array by merging incoming with existing
32
- const merged = incoming.map((incomingItem) => {
33
- const id = readField<string>('id', incomingItem);
34
- // If item already exists, merge them, otherwise use incoming
35
- if (id && existingMap.has(id)) {
36
- return mergeObjects(existingMap.get(id), incomingItem);
26
+
27
+ // Populate map with existing messages
28
+ if (existing && existing.length > 0) {
29
+ for (let i = 0; i < existing.length; i++) {
30
+ const id = readField('id', existing[i]);
31
+ if (id) {
32
+ existingMap.set(id, existing[i]);
33
+ }
37
34
  }
38
- return incomingItem;
39
- });
40
-
41
- // Add any existing items that aren't in the incoming list
42
- existing.forEach((existingItem) => {
43
- const id = readField<string>('id', existingItem);
44
- if (id && !merged.some((item) => readField<string>('id', item) === id)) {
45
- merged.push(existingItem);
35
+ }
36
+
37
+ // Create result array with same capacity as total items
38
+ const result = [];
39
+
40
+ // Add incoming items, overwriting existing ones
41
+ if (incoming && incoming.length > 0) {
42
+ for (let i = 0; i < incoming.length; i++) {
43
+ const item = incoming[i];
44
+ const id = readField('id', item);
45
+ if (id) {
46
+ existingMap.set(id, item);
47
+ }
48
+ result.push(item);
46
49
  }
47
- });
50
+ }
48
51
 
49
- return merged;
52
+ // Add remaining existing items not in incoming
53
+ if (existing && existing.length > 0) {
54
+ for (let i = 0; i < existing.length; i++) {
55
+ const id = readField('id', existing[i]);
56
+ if (id && !result.some((item) => readField('id', item) === id)) {
57
+ result.push(existing[i]);
58
+ }
59
+ }
60
+ }
61
+
62
+ return result;
50
63
  },
51
64
  },
52
65
  totalCount: {
@@ -94,69 +107,125 @@ export const messagesPolicies: TypePolicies = {
94
107
  if (!incoming) return existing;
95
108
  if (!existing) return incoming;
96
109
 
97
- // Create a deep copy of the existing data
98
- const result = {
99
- ...existing,
100
- totalCount: incoming.totalCount ?? existing.totalCount,
101
- };
110
+ // Fast return if incoming has no data
111
+ if (!incoming.data || incoming.data.length === 0) {
112
+ return {
113
+ ...existing,
114
+ totalCount: incoming.totalCount ?? existing.totalCount,
115
+ };
116
+ }
102
117
 
103
- // If there's no data in either, return the basic structure
104
- if (!existing.data || !incoming.data) {
105
- return result;
118
+ // Fast return if existing has no data
119
+ if (!existing.data || existing.data.length === 0) {
120
+ return incoming;
106
121
  }
107
122
 
108
- // Create a map of existing messages by ID
109
- const existingMessages = new Map();
110
- existing.data.forEach((message) => {
111
- const id = readField<string>('id', message);
112
- if (id) existingMessages.set(id, message);
113
- });
123
+ // Determine if this is likely a new message or pagination
124
+ const isNewMessage = args && args.skip === 0;
114
125
 
115
- // Create merged data array with deduplication
116
- let mergedData = [...existing.data];
126
+ // Create a map for existing messages for fast lookups
127
+ const idSet = new Set();
128
+ const mergedData = [...existing.data];
117
129
 
118
- // Add new messages, replacing existing ones with same ID
119
- incoming.data.forEach((incomingMessage) => {
120
- const id = readField<string>('id', incomingMessage);
121
- if (!id) return;
130
+ // Mark all existing IDs
131
+ for (let i = 0; i < mergedData.length; i++) {
132
+ const id = readField('id', mergedData[i]);
133
+ if (id) idSet.add(id);
134
+ }
135
+
136
+ // Process incoming messages
137
+ for (let i = 0; i < incoming.data.length; i++) {
138
+ const incomingMsg = incoming.data[i];
139
+ const id = readField('id', incomingMsg);
122
140
 
123
- // If message already exists, update it at its current position
124
- const existingIndex = mergedData.findIndex((msg) => readField<string>('id', msg) === id);
141
+ if (!id) continue;
125
142
 
126
- if (existingIndex >= 0) {
127
- // Replace the existing message with the incoming one
128
- mergedData[existingIndex] = incomingMessage;
143
+ if (idSet.has(id)) {
144
+ // Replace existing message with same ID
145
+ const existingIndex = mergedData.findIndex((msg) => readField('id', msg) === id);
146
+ if (existingIndex >= 0) {
147
+ mergedData[existingIndex] = incomingMsg;
148
+ }
129
149
  } else {
130
- // Add the new message
131
- // For optimistic updates with sendMessage mutation, we want to add to the beginning
132
- // For pagination/fetchMore, we should add according to the sort order
133
- if (args && args.skip === 0) {
134
- // This is likely a new message or an optimistic update
135
- mergedData.unshift(incomingMessage);
150
+ // Add new message
151
+ if (isNewMessage) {
152
+ // Add to beginning for new messages
153
+ mergedData.unshift(incomingMsg);
136
154
  } else {
137
- // This is likely from pagination
138
- mergedData.push(incomingMessage);
155
+ // Add to end for pagination
156
+ mergedData.push(incomingMsg);
139
157
  }
158
+ idSet.add(id);
140
159
  }
141
- });
142
-
143
- // Ensure no duplicate messages
144
- const uniqueIds = new Set();
145
- mergedData = mergedData.filter((message) => {
146
- const id = readField<string>('id', message);
147
- if (!id || uniqueIds.has(id)) return false;
148
- uniqueIds.add(id);
149
- return true;
150
- });
160
+ }
151
161
 
152
162
  return {
153
- ...result,
163
+ ...existing,
164
+ totalCount: incoming.totalCount ?? existing.totalCount,
154
165
  data: mergedData,
155
166
  };
156
167
  },
157
168
  },
158
169
  },
159
170
  },
171
+ FilesInfo: {
172
+ merge: true, // Use default merging behavior for FilesInfo
173
+ fields: {
174
+ data: {
175
+ merge(existing = [], incoming = [], { readField }) {
176
+ // If no existing data, just return incoming
177
+ if (!existing || existing.length === 0) {
178
+ return incoming;
179
+ }
180
+
181
+ // If no incoming data, keep existing
182
+ if (!incoming || incoming.length === 0) {
183
+ return existing;
184
+ }
185
+
186
+ // Create a map for efficient lookup
187
+ const fileMap = new Map();
188
+
189
+ // Add existing files to map
190
+ for (let i = 0; i < existing.length; i++) {
191
+ const file = existing[i];
192
+ if (file) {
193
+ const id = readField('id', file);
194
+ if (id) {
195
+ fileMap.set(id, file);
196
+ }
197
+ }
198
+ }
199
+
200
+ // Merge in incoming files, overwriting existing ones
201
+ for (let i = 0; i < incoming.length; i++) {
202
+ const file = incoming[i];
203
+ if (file) {
204
+ const id = readField('id', file);
205
+ if (id) {
206
+ fileMap.set(id, file);
207
+ }
208
+ }
209
+ }
210
+
211
+ // Convert map values back to array
212
+ return Array.from(fileMap.values());
213
+ },
214
+ },
215
+ },
216
+ },
217
+ FileInfo: {
218
+ // Use ID as key field
219
+ keyFields: ['id'],
220
+ fields: {
221
+ url: {
222
+ // Ensure URL is always preserved and not normalized
223
+ merge(existing, incoming) {
224
+ return incoming ?? existing;
225
+ },
226
+ },
227
+ },
228
+ },
160
229
  Post: {
161
230
  fields: {
162
231
  replies: {
@@ -164,24 +233,86 @@ export const messagesPolicies: TypePolicies = {
164
233
  if (!incoming) return existing;
165
234
  if (!existing) return incoming;
166
235
 
236
+ // Use a Set for fast duplicate checking
237
+ const uniqueIds = new Set();
238
+ const mergedData = [];
239
+
240
+ // Add all existing items to the result and track IDs
241
+ if (existing.data && existing.data.length > 0) {
242
+ for (let i = 0; i < existing.data.length; i++) {
243
+ const item = existing.data[i];
244
+ if (item && item.id && !uniqueIds.has(item.id)) {
245
+ uniqueIds.add(item.id);
246
+ mergedData.push(item);
247
+ }
248
+ }
249
+ }
250
+
251
+ // Add incoming items that don't exist yet
252
+ if (incoming.data && incoming.data.length > 0) {
253
+ for (let i = 0; i < incoming.data.length; i++) {
254
+ const item = incoming.data[i];
255
+ if (item && item.id && !uniqueIds.has(item.id)) {
256
+ uniqueIds.add(item.id);
257
+ mergedData.push(item);
258
+ }
259
+ }
260
+ }
261
+
167
262
  return {
168
263
  ...incoming,
169
- data: [...(existing?.data || []), ...(incoming?.data || [])].filter(
170
- (message, index, self) => index === self.findIndex((m) => m.id === message.id),
171
- ),
264
+ data: mergedData,
172
265
  };
173
266
  },
174
267
  },
175
268
  files: {
176
- merge(existing, incoming) {
269
+ merge(existing, incoming, { readField }) {
177
270
  if (!incoming) return existing;
178
271
  if (!existing) return incoming;
179
272
 
273
+ // If either has no data or totalCount is 0, prefer the one with data
274
+ if (!existing.data || existing.data.length === 0) {
275
+ return incoming;
276
+ }
277
+
278
+ if (!incoming.data || incoming.data.length === 0) {
279
+ return existing;
280
+ }
281
+
282
+ // Create a map for efficient lookup
283
+ const fileMap = new Map();
284
+
285
+ // Add existing files to map
286
+ if (existing.data) {
287
+ for (let i = 0; i < existing.data.length; i++) {
288
+ const file = existing.data[i];
289
+ if (file) {
290
+ const id = readField('id', file);
291
+ if (id) {
292
+ fileMap.set(id, file);
293
+ }
294
+ }
295
+ }
296
+ }
297
+
298
+ // Merge in incoming files, overwriting existing ones
299
+ if (incoming.data) {
300
+ for (let i = 0; i < incoming.data.length; i++) {
301
+ const file = incoming.data[i];
302
+ if (file) {
303
+ const id = readField('id', file);
304
+ if (id) {
305
+ fileMap.set(id, file);
306
+ }
307
+ }
308
+ }
309
+ }
310
+
311
+ // Create merged result
180
312
  return {
181
- ...incoming,
182
- data: [...(existing?.data || []), ...(incoming?.data || [])].filter(
183
- (file, index, self) => index === self.findIndex((f) => f.id === file.id),
184
- ),
313
+ __typename: 'FilesInfo',
314
+ totalCount: Math.max(existing.totalCount || 0, incoming.totalCount || 0, fileMap.size),
315
+ data: Array.from(fileMap.values()),
185
316
  };
186
317
  },
187
318
  },