spectrum-ts 1.18.0 → 2.0.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.
Files changed (36) hide show
  1. package/README.md +11 -1
  2. package/dist/{attachment-DfWSZS5L.d.ts → attachment-B4nSrKVd.d.ts} +1 -1
  3. package/dist/{authoring-C9uDdZ2F.d.ts → authoring-BjE5BvlO.d.ts} +2 -2
  4. package/dist/authoring.d.ts +3 -3
  5. package/dist/authoring.js +6 -3
  6. package/dist/chunk-34FQGGD7.js +34 -0
  7. package/dist/chunk-3B4QH4JG.js +35 -0
  8. package/dist/chunk-3GEJYGZK.js +84 -0
  9. package/dist/chunk-5LT5J3NR.js +695 -0
  10. package/dist/{chunk-MC6ZKFSG.js → chunk-5XEFJBN2.js} +25 -103
  11. package/dist/{chunk-JQN6CRSC.js → chunk-6BI4PFTP.js} +10 -39
  12. package/dist/{chunk-QGJFZMD5.js → chunk-6UZFVXQF.js} +17 -101
  13. package/dist/{chunk-YN6WOTBF.js → chunk-ATNAE7OR.js} +77 -7
  14. package/dist/{chunk-IPOFBAIM.js → chunk-NGC4DJIX.js} +23 -19
  15. package/dist/{chunk-5TIF3FIE.js → chunk-Q537JPTG.js} +8 -6
  16. package/dist/{chunk-5BKZJMZV.js → chunk-U3LXXT3W.js} +61 -32
  17. package/dist/chunk-U7AWXDH6.js +91 -0
  18. package/dist/{chunk-3OTECDNH.js → chunk-WXY5QP3M.js} +5 -3
  19. package/dist/index.d.ts +69 -124
  20. package/dist/index.js +350 -90
  21. package/dist/manifest.json +6 -0
  22. package/dist/providers/imessage/index.d.ts +2 -2
  23. package/dist/providers/imessage/index.js +8 -5
  24. package/dist/providers/index.d.ts +5 -2
  25. package/dist/providers/index.js +16 -8
  26. package/dist/providers/slack/index.d.ts +1 -1
  27. package/dist/providers/slack/index.js +4 -3
  28. package/dist/providers/telegram/index.d.ts +47 -0
  29. package/dist/providers/telegram/index.js +13 -0
  30. package/dist/providers/terminal/index.d.ts +17 -419
  31. package/dist/providers/terminal/index.js +5 -3
  32. package/dist/providers/whatsapp-business/index.d.ts +1 -1
  33. package/dist/providers/whatsapp-business/index.js +6 -4
  34. package/dist/types-BD0-kKyv.d.ts +82 -0
  35. package/dist/{types-DcQ5a7PK.d.ts → types-Bje8aq1k.d.ts} +34 -4
  36. package/package.json +2 -1
@@ -1,83 +1,5 @@
1
1
  import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
2
2
 
3
- // src/utils/cloud.ts
4
- var SPECTRUM_CLOUD_URL = process.env.SPECTRUM_CLOUD_URL ?? "https://spectrum.photon.codes";
5
- var SpectrumCloudError = class extends Error {
6
- status;
7
- code;
8
- constructor(status, code, message) {
9
- super(message);
10
- this.name = "SpectrumCloudError";
11
- this.status = status;
12
- this.code = code;
13
- }
14
- };
15
- var request = async (path, init) => {
16
- const response = await fetch(`${SPECTRUM_CLOUD_URL}${path}`, init);
17
- if (!response.ok) {
18
- const body = await response.text().catch(() => "");
19
- try {
20
- const parsed = JSON.parse(body);
21
- throw new SpectrumCloudError(
22
- response.status,
23
- parsed.code,
24
- parsed.message
25
- );
26
- } catch (error) {
27
- if (error instanceof SpectrumCloudError) {
28
- throw error;
29
- }
30
- throw new SpectrumCloudError(
31
- response.status,
32
- "UNKNOWN",
33
- body || response.statusText
34
- );
35
- }
36
- }
37
- const json = await response.json();
38
- if (!json.succeed) {
39
- throw new SpectrumCloudError(
40
- response.status,
41
- "UNKNOWN",
42
- "Server returned succeed=false"
43
- );
44
- }
45
- return json.data;
46
- };
47
- var basicAuth = (projectId, projectSecret) => `Basic ${btoa(`${projectId}:${projectSecret}`)}`;
48
- var cloud = {
49
- getProject: (projectId, projectSecret) => request(`/projects/${projectId}/`, {
50
- headers: { Authorization: basicAuth(projectId, projectSecret) }
51
- }),
52
- getSubscription: (projectId) => request(`/projects/${projectId}/billing/subscription`),
53
- issueImessageTokens: (projectId, projectSecret) => request(`/projects/${projectId}/imessage/tokens`, {
54
- method: "POST",
55
- headers: { Authorization: basicAuth(projectId, projectSecret) }
56
- }),
57
- getImessageInfo: (projectId) => request(`/projects/${projectId}/imessage/`),
58
- issueWhatsappBusinessTokens: (projectId, projectSecret) => request(`/projects/${projectId}/whatsapp-business/tokens`, {
59
- method: "POST",
60
- headers: { Authorization: basicAuth(projectId, projectSecret) }
61
- }),
62
- issueSlackTokens: (projectId, projectSecret) => request(`/projects/${projectId}/slack/tokens`, {
63
- method: "POST",
64
- headers: { Authorization: basicAuth(projectId, projectSecret) }
65
- }),
66
- issueFusorToken: (projectId, projectSecret) => request(`/projects/${projectId}/fusor/token`, {
67
- method: "POST",
68
- headers: { Authorization: basicAuth(projectId, projectSecret) }
69
- }),
70
- getPlatforms: (projectId) => request(`/projects/${projectId}/platforms/`),
71
- togglePlatform: (projectId, projectSecret, platform, enabled) => request(`/projects/${projectId}/platforms/`, {
72
- method: "PATCH",
73
- headers: {
74
- Authorization: basicAuth(projectId, projectSecret),
75
- "Content-Type": "application/json"
76
- },
77
- body: JSON.stringify({ platform, enabled })
78
- })
79
- };
80
-
81
3
  // src/utils/stream.ts
82
4
  import { Repeater } from "@repeaterjs/repeater";
83
5
  function createAsyncQueue() {
@@ -190,6 +112,16 @@ function broadcast(source) {
190
112
  let terminalError;
191
113
  let pumpPromise;
192
114
  let closed = false;
115
+ const closeConsumers = (error) => {
116
+ if (consumers.size === 0) {
117
+ return;
118
+ }
119
+ const current = Array.from(consumers);
120
+ consumers.clear();
121
+ for (const consumer of current) {
122
+ consumer.end(error);
123
+ }
124
+ };
193
125
  const startPump = () => {
194
126
  if (pumping || terminated) {
195
127
  return;
@@ -198,35 +130,35 @@ function broadcast(source) {
198
130
  pumpPromise = (async () => {
199
131
  try {
200
132
  for await (const value of source) {
201
- for (const consumer of consumers) {
133
+ if (terminated) {
134
+ break;
135
+ }
136
+ for (const consumer of Array.from(consumers)) {
202
137
  consumer.deliveries = consumer.deliveries.then(
203
138
  () => consumer.emit(value).catch(() => {
204
139
  })
205
140
  );
206
141
  }
207
142
  }
143
+ if (terminated) {
144
+ return;
145
+ }
208
146
  terminated = true;
209
147
  await Promise.allSettled(
210
148
  Array.from(consumers, (consumer) => consumer.deliveries)
211
149
  );
212
- for (const consumer of consumers) {
213
- consumer.end();
214
- }
215
- consumers.clear();
150
+ closeConsumers();
216
151
  } catch (error) {
217
152
  terminated = true;
218
153
  terminalError = error;
219
- for (const consumer of consumers) {
220
- consumer.end(error);
221
- }
222
- consumers.clear();
154
+ closeConsumers(error);
223
155
  }
224
156
  })();
225
157
  };
226
158
  return {
227
159
  subscribe() {
228
160
  return stream((emit, end) => {
229
- if (terminated) {
161
+ if (terminated || closed) {
230
162
  end(terminalError);
231
163
  return;
232
164
  }
@@ -247,27 +179,17 @@ function broadcast(source) {
247
179
  return;
248
180
  }
249
181
  closed = true;
250
- try {
251
- await source.close();
252
- if (pumpPromise) {
253
- await pumpPromise.catch(ignoreCleanupError);
254
- }
255
- } finally {
256
- if (!terminated) {
257
- terminated = true;
258
- for (const consumer of consumers) {
259
- consumer.end();
260
- }
261
- consumers.clear();
262
- }
182
+ terminated = true;
183
+ closeConsumers();
184
+ await source.close().catch(ignoreCleanupError);
185
+ if (pumpPromise) {
186
+ await pumpPromise.catch(ignoreCleanupError);
263
187
  }
264
188
  }
265
189
  };
266
190
  }
267
191
 
268
192
  export {
269
- SpectrumCloudError,
270
- cloud,
271
193
  createAsyncQueue,
272
194
  stream,
273
195
  mergeStreams,
@@ -3,37 +3,11 @@ import {
3
3
  bufferToStream,
4
4
  fetchUrlBytes,
5
5
  readSchema,
6
- resolveContents,
7
6
  streamSchema
8
7
  } from "./chunk-2ILTJC35.js";
9
8
 
10
- // src/content/group.ts
11
- import z from "zod";
12
- var isMessage = (v) => typeof v === "object" && v !== null && "id" in v && "content" in v;
13
- var groupSchema = z.object({
14
- type: z.literal("group"),
15
- items: z.array(z.custom(isMessage)).min(2)
16
- });
17
- var asGroup = (input) => groupSchema.parse({ type: "group", items: input.items });
18
- var stubOutboundMessage = (content) => ({ id: "", content });
19
- function group(...items) {
20
- return {
21
- build: async () => {
22
- const resolved = await resolveContents(items);
23
- const members = [];
24
- for (const item of resolved) {
25
- if (item.type === "group" || item.type === "reaction") {
26
- throw new Error(`group() cannot contain "${item.type}" items`);
27
- }
28
- members.push(stubOutboundMessage(item));
29
- }
30
- return asGroup({ items: members });
31
- }
32
- };
33
- }
34
-
35
9
  // src/content/richlink.ts
36
- import z2 from "zod";
10
+ import z from "zod";
37
11
 
38
12
  // src/utils/link-metadata.ts
39
13
  import ogs from "open-graph-scraper";
@@ -90,22 +64,22 @@ var fetchImage = (url) => fetchUrlBytes(new URL(url), {
90
64
  });
91
65
 
92
66
  // src/content/richlink.ts
93
- var richlinkCoverSchema = z2.object({
94
- mimeType: z2.string().min(1).optional(),
67
+ var richlinkCoverSchema = z.object({
68
+ mimeType: z.string().min(1).optional(),
95
69
  read: readSchema,
96
70
  stream: streamSchema
97
71
  });
98
- var optionalStringAccessor = z2.function({
72
+ var optionalStringAccessor = z.function({
99
73
  input: [],
100
- output: z2.promise(z2.string().min(1).optional())
74
+ output: z.promise(z.string().min(1).optional())
101
75
  });
102
- var coverAccessor = z2.function({
76
+ var coverAccessor = z.function({
103
77
  input: [],
104
- output: z2.promise(richlinkCoverSchema.optional())
78
+ output: z.promise(richlinkCoverSchema.optional())
105
79
  });
106
- var richlinkSchema = z2.object({
107
- type: z2.literal("richlink"),
108
- url: z2.url(),
80
+ var richlinkSchema = z.object({
81
+ type: z.literal("richlink"),
82
+ url: z.url(),
109
83
  title: optionalStringAccessor,
110
84
  summary: optionalStringAccessor,
111
85
  cover: coverAccessor
@@ -150,9 +124,6 @@ function richlink(url) {
150
124
  }
151
125
 
152
126
  export {
153
- groupSchema,
154
- asGroup,
155
- group,
156
127
  asRichlink,
157
128
  richlink
158
129
  };
@@ -1,7 +1,4 @@
1
1
  import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
2
- import {
3
- readSchema
4
- } from "./chunk-2ILTJC35.js";
5
2
 
6
3
  // src/utils/vcard.ts
7
4
  import vCard from "vcf";
@@ -350,109 +347,28 @@ var writePhoto = async (card, photo) => {
350
347
  type: photoTypeParam(photo.mimeType)
351
348
  });
352
349
  };
353
- var toVCard = async (contact2) => {
354
- if (typeof contact2.raw === "string" && contact2.raw.startsWith("BEGIN:VCARD")) {
355
- return contact2.raw;
350
+ var toVCard = async (contact) => {
351
+ if (typeof contact.raw === "string" && contact.raw.startsWith("BEGIN:VCARD")) {
352
+ return contact.raw;
356
353
  }
357
354
  const card = new vCard();
358
- writeName(card, contact2.name);
359
- writePhones(card, contact2.phones);
360
- writeEmails(card, contact2.emails);
361
- writeAddresses(card, contact2.addresses);
362
- writeOrg(card, contact2.org);
363
- writeUrls(card, contact2.urls);
364
- if (contact2.birthday) {
365
- card.set("bday", contact2.birthday);
366
- }
367
- if (contact2.note) {
368
- card.set("note", contact2.note);
369
- }
370
- await writePhoto(card, contact2.photo);
355
+ writeName(card, contact.name);
356
+ writePhones(card, contact.phones);
357
+ writeEmails(card, contact.emails);
358
+ writeAddresses(card, contact.addresses);
359
+ writeOrg(card, contact.org);
360
+ writeUrls(card, contact.urls);
361
+ if (contact.birthday) {
362
+ card.set("bday", contact.birthday);
363
+ }
364
+ if (contact.note) {
365
+ card.set("note", contact.note);
366
+ }
367
+ await writePhoto(card, contact.photo);
371
368
  return card.toString();
372
369
  };
373
370
 
374
- // src/content/contact.ts
375
- import vCard2 from "vcf";
376
- import z from "zod";
377
- var userRefSchema = z.object({
378
- __platform: z.string(),
379
- id: z.string()
380
- });
381
- var nameSchema = z.object({
382
- formatted: z.string().optional(),
383
- first: z.string().optional(),
384
- last: z.string().optional(),
385
- middle: z.string().optional(),
386
- prefix: z.string().optional(),
387
- suffix: z.string().optional()
388
- });
389
- var phoneTypeSchema = z.enum(["mobile", "home", "work", "other"]);
390
- var emailTypeSchema = z.enum(["home", "work", "other"]);
391
- var addressTypeSchema = z.enum(["home", "work", "other"]);
392
- var phoneSchema = z.object({
393
- value: z.string(),
394
- type: phoneTypeSchema.optional()
395
- });
396
- var emailSchema = z.object({
397
- value: z.string(),
398
- type: emailTypeSchema.optional()
399
- });
400
- var addressSchema = z.object({
401
- street: z.string().optional(),
402
- city: z.string().optional(),
403
- region: z.string().optional(),
404
- postalCode: z.string().optional(),
405
- country: z.string().optional(),
406
- type: addressTypeSchema.optional()
407
- });
408
- var orgSchema = z.object({
409
- name: z.string().optional(),
410
- title: z.string().optional(),
411
- department: z.string().optional()
412
- });
413
- var photoSchema = z.object({
414
- mimeType: z.string(),
415
- read: readSchema
416
- });
417
- var contactSchema = z.object({
418
- type: z.literal("contact"),
419
- user: userRefSchema.optional(),
420
- name: nameSchema.optional(),
421
- phones: z.array(phoneSchema).optional(),
422
- emails: z.array(emailSchema).optional(),
423
- addresses: z.array(addressSchema).optional(),
424
- org: orgSchema.optional(),
425
- urls: z.array(z.string()).optional(),
426
- birthday: z.string().optional(),
427
- note: z.string().optional(),
428
- photo: photoSchema.optional(),
429
- raw: z.unknown().optional()
430
- });
431
- var asContact = (input) => contactSchema.parse({ type: "contact", ...input });
432
- var isUser = (value) => typeof value === "object" && value !== null && "__platform" in value && "id" in value && typeof value.__platform === "string" && typeof value.id === "string";
433
- function contact(input, details) {
434
- return {
435
- build: async () => {
436
- if (typeof input === "string") {
437
- return asContact(fromVCard(input));
438
- }
439
- if (input instanceof vCard2) {
440
- return asContact(fromVCard(input.toString()));
441
- }
442
- if (isUser(input)) {
443
- return asContact({
444
- user: { __platform: input.__platform, id: input.id },
445
- ...details
446
- });
447
- }
448
- return asContact(input);
449
- }
450
- };
451
- }
452
-
453
371
  export {
454
372
  fromVCard,
455
- toVCard,
456
- asContact,
457
- contact
373
+ toVCard
458
374
  };
@@ -1,29 +1,35 @@
1
1
  import { createRequire as __spectrumCreateRequire } from "node:module"; const require = __spectrumCreateRequire(import.meta.url);
2
+ import {
3
+ asRichlink
4
+ } from "./chunk-6BI4PFTP.js";
2
5
  import {
3
6
  asGroup,
4
- asRichlink,
5
7
  groupSchema
6
- } from "./chunk-JQN6CRSC.js";
8
+ } from "./chunk-3B4QH4JG.js";
7
9
  import {
8
10
  asPoll,
9
11
  asPollOption
10
12
  } from "./chunk-2D27WW5B.js";
11
13
  import {
12
- cloud,
14
+ cloud
15
+ } from "./chunk-3GEJYGZK.js";
16
+ import {
17
+ asContact
18
+ } from "./chunk-U7AWXDH6.js";
19
+ import {
13
20
  mergeStreams,
14
21
  stream
15
- } from "./chunk-MC6ZKFSG.js";
22
+ } from "./chunk-5XEFJBN2.js";
16
23
  import {
17
- asContact,
18
24
  fromVCard,
19
25
  toVCard
20
- } from "./chunk-QGJFZMD5.js";
26
+ } from "./chunk-6UZFVXQF.js";
21
27
  import {
22
28
  UnsupportedError,
23
29
  buildPhotoAction,
24
30
  definePlatform,
25
31
  photoActionSchema
26
- } from "./chunk-IPOFBAIM.js";
32
+ } from "./chunk-NGC4DJIX.js";
27
33
  import {
28
34
  asAttachment,
29
35
  asCustom,
@@ -2039,6 +2045,55 @@ var messages3 = (clients, projectConfig) => {
2039
2045
  );
2040
2046
  };
2041
2047
 
2048
+ // src/providers/imessage/remote/stream-text.ts
2049
+ var INITIAL_THROTTLE_MS = 1e3;
2050
+ var BACKOFF_FACTOR = 2;
2051
+ var MAX_EDITS = 5;
2052
+ var sendStreamText = async (remote, spaceId, content) => {
2053
+ const chat = toChatGuid(spaceId);
2054
+ let sent;
2055
+ let full = "";
2056
+ let lastSentText = "";
2057
+ let lastEditAt = 0;
2058
+ let editCount = 0;
2059
+ const flushEdit = async (text2) => {
2060
+ if (!sent || text2 === lastSentText) {
2061
+ return;
2062
+ }
2063
+ await remote.messages.edit(chat, toMessageGuid(sent.guid), text2);
2064
+ lastSentText = text2;
2065
+ lastEditAt = Date.now();
2066
+ editCount += 1;
2067
+ };
2068
+ for await (const delta of content.stream()) {
2069
+ full += delta;
2070
+ if (!sent) {
2071
+ sent = await remote.messages.sendText(chat, full);
2072
+ lastSentText = full;
2073
+ lastEditAt = Date.now();
2074
+ continue;
2075
+ }
2076
+ const hasBudgetForInterimEdit = editCount < MAX_EDITS - 1;
2077
+ const requiredGap = INITIAL_THROTTLE_MS * BACKOFF_FACTOR ** editCount;
2078
+ if (hasBudgetForInterimEdit && Date.now() - lastEditAt >= requiredGap) {
2079
+ await flushEdit(full);
2080
+ }
2081
+ }
2082
+ if (!sent) {
2083
+ throw unsupportedRemoteContent(
2084
+ "streamText",
2085
+ "stream produced no text \u2014 nothing to send"
2086
+ );
2087
+ }
2088
+ await flushEdit(full);
2089
+ return {
2090
+ id: sent.guid,
2091
+ content: asText(full),
2092
+ space: { id: spaceId },
2093
+ timestamp: sent.dateCreated
2094
+ };
2095
+ };
2096
+
2042
2097
  // src/providers/imessage/remote/typing.ts
2043
2098
  var startTyping = async (remote, spaceId) => {
2044
2099
  await remote.chats.setTyping(toChatGuid(spaceId), true);
@@ -2063,6 +2118,7 @@ var stopTyping2 = async (remote, spaceId) => {
2063
2118
  await stopTyping(remote, spaceId);
2064
2119
  };
2065
2120
  var send4 = async (remote, spaceId, content) => send3(remote, spaceId, content);
2121
+ var sendStreamText2 = async (remote, spaceId, content) => sendStreamText(remote, spaceId, content);
2066
2122
  var replyToMessage2 = async (remote, spaceId, msgId, content) => replyToMessage(remote, spaceId, msgId, content);
2067
2123
  var editMessage2 = async (remote, spaceId, msgId, content) => editMessage(remote, spaceId, msgId, content);
2068
2124
  var reactToMessage2 = async (remote, spaceId, target, reaction) => {
@@ -2120,6 +2176,17 @@ var handleEdit = async (client, space, content) => {
2120
2176
  const remote = clientForPhone(client, space.phone);
2121
2177
  await editMessage2(remote, space.id, content.target.id, content.content);
2122
2178
  };
2179
+ var handleStreamText = async (client, space, content) => {
2180
+ if (isLocal(client)) {
2181
+ throw UnsupportedError.action(
2182
+ "streamText",
2183
+ "iMessage (local mode)",
2184
+ "streaming text responses require remote iMessage"
2185
+ );
2186
+ }
2187
+ const remote = clientForPhone(client, space.phone);
2188
+ return await sendStreamText2(remote, space.id, content);
2189
+ };
2123
2190
  var handleBackground = async (client, space, content) => {
2124
2191
  if (isLocal(client)) {
2125
2192
  throw UnsupportedError.action(
@@ -2350,6 +2417,9 @@ var imessage = definePlatform("iMessage", {
2350
2417
  await handleEdit(client, space, content);
2351
2418
  return;
2352
2419
  }
2420
+ if (content.type === "streamText") {
2421
+ return await handleStreamText(client, space, content);
2422
+ }
2353
2423
  if (content.type === "rename") {
2354
2424
  await handleRename(client, space, content);
2355
2425
  return;
@@ -216,7 +216,7 @@ var UnsupportedError = class _UnsupportedError extends Error {
216
216
  };
217
217
 
218
218
  // src/platform/define.ts
219
- import { withSpan as withSpan2 } from "@photon-ai/otel";
219
+ import { createLogger as createLogger2, withSpan as withSpan2 } from "@photon-ai/otel";
220
220
 
221
221
  // src/utils/identifier.ts
222
222
  import { sanitizeEmail, sanitizePhone } from "@photon-ai/otel";
@@ -747,6 +747,7 @@ function buildMessage(params) {
747
747
  }
748
748
 
749
749
  // src/platform/define.ts
750
+ var platformLog2 = createLogger2("spectrum.platform");
750
751
  function classifySpaceIdentifier(args) {
751
752
  const stringArgs = args.filter((a) => typeof a === "string");
752
753
  if (stringArgs.length > 1) {
@@ -910,13 +911,20 @@ function createPlatformInstance(def, runtime) {
910
911
  const eventProperties = {};
911
912
  const customEvents = def.events ?? {};
912
913
  for (const eventName of Object.keys(customEvents)) {
913
- const producer = customEvents[eventName];
914
- if (producer) {
914
+ const declared = customEvents[eventName];
915
+ if (typeof declared === "function") {
916
+ const producer = declared;
915
917
  eventProperties[eventName] = producer({
916
918
  client: runtime.client,
917
919
  config: runtime.config,
920
+ projectConfig: runtime.projectConfig,
918
921
  store: runtime.store
919
922
  });
923
+ continue;
924
+ }
925
+ const fusorEvents = runtime.subscribeEvent?.(eventName);
926
+ if (fusorEvents) {
927
+ eventProperties[eventName] = fusorEvents;
920
928
  }
921
929
  }
922
930
  let messagesIterable;
@@ -948,8 +956,9 @@ function createPlatformInstance(def, runtime) {
948
956
  eventProperties
949
957
  );
950
958
  }
951
- function definePlatform(name, def) {
952
- const fullDef = { name, ...def };
959
+ function definePlatform(name, rawDef) {
960
+ const def = rawDef;
961
+ const fullDef = { ...def, name };
953
962
  const platformCache = /* @__PURE__ */ new WeakMap();
954
963
  const narrowSpectrum = (spectrum) => {
955
964
  const cached = platformCache.get(spectrum);
@@ -969,17 +978,19 @@ function definePlatform(name, def) {
969
978
  };
970
979
  const narrowSpace = (input) => {
971
980
  if (input.__platform !== name) {
972
- throw new Error(
973
- `Expected space from "${name}", got "${input.__platform}"`
974
- );
981
+ platformLog2.warn("space platform mismatch; narrowing skipped", {
982
+ expected: name,
983
+ actual: input.__platform
984
+ });
975
985
  }
976
986
  return input;
977
987
  };
978
988
  const narrowMessage = (input) => {
979
989
  if (input.platform !== name) {
980
- throw new Error(
981
- `Expected message from "${name}", got "${input.platform}"`
982
- );
990
+ platformLog2.warn("message platform mismatch; narrowing skipped", {
991
+ expected: name,
992
+ actual: input.platform
993
+ });
983
994
  }
984
995
  return input;
985
996
  };
@@ -1022,12 +1033,6 @@ function definePlatform(name, def) {
1022
1033
  }
1023
1034
  return narrower;
1024
1035
  }
1025
- function defineFusorPlatform(name, def) {
1026
- return definePlatform(
1027
- name,
1028
- def
1029
- );
1030
- }
1031
1036
 
1032
1037
  export {
1033
1038
  photoActionSchema,
@@ -1042,6 +1047,5 @@ export {
1042
1047
  senderAttrs,
1043
1048
  wrapProviderMessage,
1044
1049
  buildSpace,
1045
- definePlatform,
1046
- defineFusorPlatform
1050
+ definePlatform
1047
1051
  };
@@ -3,17 +3,19 @@ import {
3
3
  asPollOption
4
4
  } from "./chunk-2D27WW5B.js";
5
5
  import {
6
- cloud,
7
- mergeStreams,
8
- stream
9
- } from "./chunk-MC6ZKFSG.js";
6
+ cloud
7
+ } from "./chunk-3GEJYGZK.js";
10
8
  import {
11
9
  asContact
12
- } from "./chunk-QGJFZMD5.js";
10
+ } from "./chunk-U7AWXDH6.js";
11
+ import {
12
+ mergeStreams,
13
+ stream
14
+ } from "./chunk-5XEFJBN2.js";
13
15
  import {
14
16
  UnsupportedError,
15
17
  definePlatform
16
- } from "./chunk-IPOFBAIM.js";
18
+ } from "./chunk-NGC4DJIX.js";
17
19
  import {
18
20
  asAttachment,
19
21
  asCustom,