@spectrum-ts/core 6.0.0 → 6.1.1

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.
@@ -447,6 +447,10 @@ interface Message<TPlatform extends string = string, TSender extends User = User
447
447
  declare const editSchema: z.ZodObject<{
448
448
  type: z.ZodLiteral<"edit">;
449
449
  content: z.ZodCustom<{
450
+ type: "reaction";
451
+ emoji: string;
452
+ target: Message<string, User, Space<unknown>>;
453
+ } | {
450
454
  type: "text";
451
455
  text: string;
452
456
  } | {
@@ -541,10 +545,6 @@ declare const editSchema: z.ZodObject<{
541
545
  imageSubtitle: z.ZodOptional<z.ZodString>;
542
546
  summary: z.ZodOptional<z.ZodString>;
543
547
  }, z.core.$strip>>>;
544
- } | {
545
- type: "reaction";
546
- emoji: string;
547
- target: Message<string, User, Space<unknown>>;
548
548
  } | {
549
549
  type: "group";
550
550
  items: Message<string, User, Space<unknown>>[];
@@ -602,6 +602,10 @@ declare const editSchema: z.ZodObject<{
602
602
  kind: "clear";
603
603
  };
604
604
  }, {
605
+ type: "reaction";
606
+ emoji: string;
607
+ target: Message<string, User, Space<unknown>>;
608
+ } | {
605
609
  type: "text";
606
610
  text: string;
607
611
  } | {
@@ -696,10 +700,6 @@ declare const editSchema: z.ZodObject<{
696
700
  imageSubtitle: z.ZodOptional<z.ZodString>;
697
701
  summary: z.ZodOptional<z.ZodString>;
698
702
  }, z.core.$strip>>>;
699
- } | {
700
- type: "reaction";
701
- emoji: string;
702
- target: Message<string, User, Space<unknown>>;
703
703
  } | {
704
704
  type: "group";
705
705
  items: Message<string, User, Space<unknown>>[];
@@ -982,6 +982,10 @@ declare function rename(displayName: string): ContentBuilder;
982
982
  declare const replySchema: z.ZodObject<{
983
983
  type: z.ZodLiteral<"reply">;
984
984
  content: z.ZodCustom<{
985
+ type: "reaction";
986
+ emoji: string;
987
+ target: Message<string, User, Space<unknown>>;
988
+ } | {
985
989
  type: "text";
986
990
  text: string;
987
991
  } | {
@@ -1076,10 +1080,6 @@ declare const replySchema: z.ZodObject<{
1076
1080
  imageSubtitle: z.ZodOptional<z.ZodString>;
1077
1081
  summary: z.ZodOptional<z.ZodString>;
1078
1082
  }, z.core.$strip>>>;
1079
- } | {
1080
- type: "reaction";
1081
- emoji: string;
1082
- target: Message<string, User, Space<unknown>>;
1083
1083
  } | {
1084
1084
  type: "group";
1085
1085
  items: Message<string, User, Space<unknown>>[];
@@ -1137,6 +1137,10 @@ declare const replySchema: z.ZodObject<{
1137
1137
  kind: "clear";
1138
1138
  };
1139
1139
  }, {
1140
+ type: "reaction";
1141
+ emoji: string;
1142
+ target: Message<string, User, Space<unknown>>;
1143
+ } | {
1140
1144
  type: "text";
1141
1145
  text: string;
1142
1146
  } | {
@@ -1231,10 +1235,6 @@ declare const replySchema: z.ZodObject<{
1231
1235
  imageSubtitle: z.ZodOptional<z.ZodString>;
1232
1236
  summary: z.ZodOptional<z.ZodString>;
1233
1237
  }, z.core.$strip>>>;
1234
- } | {
1235
- type: "reaction";
1236
- emoji: string;
1237
- target: Message<string, User, Space<unknown>>;
1238
1238
  } | {
1239
1239
  type: "group";
1240
1240
  items: Message<string, User, Space<unknown>>[];
@@ -6893,6 +6893,10 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
6893
6893
  }, z.core.$strip>, z.ZodObject<{
6894
6894
  type: z.ZodLiteral<"reply">;
6895
6895
  content: z.ZodCustom<{
6896
+ type: "reaction";
6897
+ emoji: string;
6898
+ target: Message<string, User, Space<unknown>>;
6899
+ } | {
6896
6900
  type: "text";
6897
6901
  text: string;
6898
6902
  } | {
@@ -6987,10 +6991,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
6987
6991
  imageSubtitle: z.ZodOptional<z.ZodString>;
6988
6992
  summary: z.ZodOptional<z.ZodString>;
6989
6993
  }, z.core.$strip>>>;
6990
- } | {
6991
- type: "reaction";
6992
- emoji: string;
6993
- target: Message<string, User, Space<unknown>>;
6994
6994
  } | {
6995
6995
  type: "group";
6996
6996
  items: Message<string, User, Space<unknown>>[];
@@ -7048,6 +7048,10 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7048
7048
  kind: "clear";
7049
7049
  };
7050
7050
  }, {
7051
+ type: "reaction";
7052
+ emoji: string;
7053
+ target: Message<string, User, Space<unknown>>;
7054
+ } | {
7051
7055
  type: "text";
7052
7056
  text: string;
7053
7057
  } | {
@@ -7142,10 +7146,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7142
7146
  imageSubtitle: z.ZodOptional<z.ZodString>;
7143
7147
  summary: z.ZodOptional<z.ZodString>;
7144
7148
  }, z.core.$strip>>>;
7145
- } | {
7146
- type: "reaction";
7147
- emoji: string;
7148
- target: Message<string, User, Space<unknown>>;
7149
7149
  } | {
7150
7150
  type: "group";
7151
7151
  items: Message<string, User, Space<unknown>>[];
@@ -7207,6 +7207,10 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7207
7207
  }, z.core.$strip>, z.ZodObject<{
7208
7208
  type: z.ZodLiteral<"edit">;
7209
7209
  content: z.ZodCustom<{
7210
+ type: "reaction";
7211
+ emoji: string;
7212
+ target: Message<string, User, Space<unknown>>;
7213
+ } | {
7210
7214
  type: "text";
7211
7215
  text: string;
7212
7216
  } | {
@@ -7301,10 +7305,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7301
7305
  imageSubtitle: z.ZodOptional<z.ZodString>;
7302
7306
  summary: z.ZodOptional<z.ZodString>;
7303
7307
  }, z.core.$strip>>>;
7304
- } | {
7305
- type: "reaction";
7306
- emoji: string;
7307
- target: Message<string, User, Space<unknown>>;
7308
7308
  } | {
7309
7309
  type: "group";
7310
7310
  items: Message<string, User, Space<unknown>>[];
@@ -7362,6 +7362,10 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7362
7362
  kind: "clear";
7363
7363
  };
7364
7364
  }, {
7365
+ type: "reaction";
7366
+ emoji: string;
7367
+ target: Message<string, User, Space<unknown>>;
7368
+ } | {
7365
7369
  type: "text";
7366
7370
  text: string;
7367
7371
  } | {
@@ -7456,10 +7460,6 @@ declare const contentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7456
7460
  imageSubtitle: z.ZodOptional<z.ZodString>;
7457
7461
  summary: z.ZodOptional<z.ZodString>;
7458
7462
  }, z.core.$strip>>>;
7459
- } | {
7460
- type: "reaction";
7461
- emoji: string;
7462
- target: Message<string, User, Space<unknown>>;
7463
7463
  } | {
7464
7464
  type: "group";
7465
7465
  items: Message<string, User, Space<unknown>>[];
@@ -1,4 +1,4 @@
1
- import { $t as groupSchema, Bt as asPollOption, Dn as buildPhotoAction, En as PhotoInput, H as ProviderMessageRecord, K as ManagedStream, Nt as asRead, On as photoActionSchema, St as asText, Tt as asRichlink, Wt as asMarkdown, Zt as asGroup, cn as reactionSchema, gt as asVoice, ln as asCustom, on as asReaction, r as asAttachment, yn as asContact, zt as asPoll } from "./attachment-CfEp6LAu.js";
1
+ import { $t as groupSchema, Bt as asPollOption, Dn as buildPhotoAction, En as PhotoInput, H as ProviderMessageRecord, K as ManagedStream, Nt as asRead, On as photoActionSchema, St as asText, Tt as asRichlink, Wt as asMarkdown, Zt as asGroup, cn as reactionSchema, gt as asVoice, ln as asCustom, on as asReaction, r as asAttachment, yn as asContact, zt as asPoll } from "./attachment-CQh4PQGl.js";
2
2
  import z from "zod";
3
3
  import { LogAttrs, LogAttrs as LogAttrs$1, LogLevel, PhotonLogger, createLogger, sanitizeEmail, sanitizeErrorMessage, sanitizePhone, setLogLevel } from "@photon-ai/otel";
4
4
  import { Token } from "marked";
@@ -69,6 +69,18 @@ interface ResumableOrderedStreamOptions<TLive, TMissed, TOutput> {
69
69
  maxRetryDelayMs?: number;
70
70
  processLive: (event: TLive) => Promise<ResumableStreamItem<TOutput>>;
71
71
  processMissed: (event: TMissed) => Promise<ResumableStreamItem<TOutput>>;
72
+ /**
73
+ * Invoked when reconnects have failed persistently (the consecutive-failure
74
+ * count has reached a multiple of `PERSISTENT_FAILURE_ERROR_THRESHOLD`) to
75
+ * rebuild state a plain reconnect cannot refresh — e.g. re-mint an auth token
76
+ * the server rejects after a restart. Runs between the failure and the next
77
+ * retry, throttled to once per threshold window, and resets once the stream
78
+ * recovers. Errors thrown are logged and swallowed; the reconnect loop
79
+ * continues either way, so a recover that itself fails is harmless.
80
+ */
81
+ recover?: (error: unknown, failureCount: number) => Promise<void> | void;
82
+ /** Cap on how long a `recover` hook may run before it is abandoned; injectable for tests. */
83
+ recoverTimeoutMs?: number;
72
84
  subscribeLive: (cursor?: string) => CloseableAsyncIterable<TLive>;
73
85
  }
74
86
  /**
package/dist/authoring.js CHANGED
@@ -147,6 +147,18 @@ const closeIterable = async (iterable) => {
147
147
  await iterable.close?.();
148
148
  };
149
149
  const ignoreCleanupError = () => void 0;
150
+ const RECOVER_TIMEOUT_MS = 3e4;
151
+ const runWithTimeout = async (work, timeoutMs, onTimeout) => {
152
+ work.catch(ignoreCleanupError);
153
+ let timer;
154
+ try {
155
+ await Promise.race([work, new Promise((_resolve, reject) => {
156
+ timer = setTimeout(() => reject(onTimeout()), timeoutMs);
157
+ })]);
158
+ } finally {
159
+ if (timer) clearTimeout(timer);
160
+ }
161
+ };
150
162
  const jitterDelay = (delayMs) => delayMs * (.5 + Math.random() * .5);
151
163
  async function* throwOnCursorRejection(source, isCursorRejected) {
152
164
  try {
@@ -178,10 +190,12 @@ const resumableOrderedStream = (options) => stream((emit, end) => {
178
190
  const initialRetryDelayMs = options.initialRetryDelayMs ?? 500;
179
191
  const maxRetryDelayMs = options.maxRetryDelayMs ?? 3e4;
180
192
  const jitter = options.jitter ?? jitterDelay;
193
+ const recoverTimeoutMs = options.recoverTimeoutMs ?? RECOVER_TIMEOUT_MS;
181
194
  const label = options.label;
182
195
  let activeLive;
183
196
  let closed = false;
184
197
  let failedAttempts = 0;
198
+ let lastRecoverAttempt = 0;
185
199
  let lastCursor;
186
200
  let retryDelayMs = initialRetryDelayMs;
187
201
  let sleepTimer;
@@ -197,6 +211,7 @@ const resumableOrderedStream = (options) => stream((emit, end) => {
197
211
  });
198
212
  const noteRecovery = () => {
199
213
  retryDelayMs = initialRetryDelayMs;
214
+ lastRecoverAttempt = 0;
200
215
  if (failedAttempts === 0) return;
201
216
  log.info("stream recovered", {
202
217
  "spectrum.stream.id": streamId,
@@ -267,6 +282,25 @@ const resumableOrderedStream = (options) => stream((emit, end) => {
267
282
  log.warn("stream interrupted; reconnecting", attrs, error);
268
283
  return delayMs;
269
284
  };
285
+ const maybeRecover = async (error) => {
286
+ if (!options.recover || failedAttempts < 5 || failedAttempts - lastRecoverAttempt < 5) return;
287
+ lastRecoverAttempt = failedAttempts;
288
+ try {
289
+ await runWithTimeout(Promise.resolve(options.recover(error, failedAttempts)), recoverTimeoutMs, () => /* @__PURE__ */ new Error(`recover hook did not settle within ${recoverTimeoutMs}ms`));
290
+ log.info("stream recover hook ran", {
291
+ "spectrum.stream.id": streamId,
292
+ "spectrum.stream.label": label,
293
+ "spectrum.stream.attempt": failedAttempts
294
+ });
295
+ } catch (recoverError) {
296
+ log.warn("stream recover hook failed", {
297
+ "spectrum.stream.id": streamId,
298
+ "spectrum.stream.label": label,
299
+ "spectrum.stream.attempt": failedAttempts,
300
+ ...errorAttrs(recoverError)
301
+ }, recoverError);
302
+ }
303
+ };
270
304
  const consumeLive = async () => {
271
305
  const live = options.subscribeLive(lastCursor);
272
306
  activeLive = live;
@@ -366,7 +400,9 @@ const resumableOrderedStream = (options) => stream((emit, end) => {
366
400
  await closeIterable(activeLive).catch(ignoreCleanupError);
367
401
  activeLive = void 0;
368
402
  if (closed) break;
369
- await sleep(handleFailure(error, phase));
403
+ const delayMs = handleFailure(error, phase);
404
+ await maybeRecover(error);
405
+ await sleep(delayMs);
370
406
  }
371
407
  }
372
408
  end();
package/dist/elysia.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { T as WebhookHandler, nn as Message, rn as Space } from "./attachment-CfEp6LAu.js";
1
+ import { T as WebhookHandler, nn as Message, rn as Space } from "./attachment-CQh4PQGl.js";
2
2
  import { Elysia } from "elysia";
3
3
 
4
4
  //#region src/elysia.d.ts
package/dist/express.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { T as WebhookHandler, nn as Message, rn as Space } from "./attachment-CfEp6LAu.js";
1
+ import { T as WebhookHandler, nn as Message, rn as Space } from "./attachment-CQh4PQGl.js";
2
2
  import { Router } from "express";
3
3
 
4
4
  //#region src/express.d.ts
package/dist/hono.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { T as WebhookHandler, nn as Message, rn as Space } from "./attachment-CfEp6LAu.js";
1
+ import { T as WebhookHandler, nn as Message, rn as Space } from "./attachment-CQh4PQGl.js";
2
2
 
3
3
  //#region src/hono.d.ts
4
4
  /**
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as FusorTokenData, A as isFusorEvent, An as AppLayout, At as Rename, B as PlatformUser, C as FusorVerify, Cn as Avatar, Ct as text, D as WebhookRawResult, Dt as resolveContents, E as WebhookRawRequest, Et as richlink, F as PlatformInstance, Ft as Poll, G as Broadcaster, Gt as markdown, Ht as poll, I as PlatformMessage, It as PollChoice, J as mergeStreams, Jt as StreamTextSource, K as ManagedStream, Kt as DeltaExtractor, L as PlatformProviderConfig, Lt as PollChoiceInput, M as EventProducer, Mn as app, Mt as Read, N as Platform, Nn as appLayoutSchema, O as FusorEvent, Ot as Reply, P as PlatformDef, Pt as read, Q as DedicatedTokenData, Qt as group, R as PlatformRuntime, Rt as PollOption, S as FusorRespond, Sn as User, T as WebhookHandler, Tn as avatar, U as SchemaMessage, Ut as Markdown, V as ProviderMessage, Vt as option, W as SpaceNamespace, X as Store, Xt as Group, Y as stream, Yt as TextStreamOptions, Z as CloudPlatform, _ as FusorClient, _n as ContactOrg, _t as voice, a as Content, an as ReactionBuilder, at as SharedTokenData, b as FusorMessagesReturn, bn as contact, bt as Typing, c as fromVCard, ct as SpectrumCloudError, d as UnsupportedKind, dn as Contact, dt as TokenData, en as Edit, et as ImessageInfoData, f as Spectrum, fn as ContactAddress, ft as cloud, g as isFusorClient, gn as ContactName, h as fusor, hn as ContactInput, ht as Voice, i as attachment, in as Reaction, it as ProjectProfile, j as AnyPlatformDef, jn as AppUrl, jt as rename, k as fusorEvent, kn as App, kt as reply, l as toVCard, lt as SubscriptionData, m as definePlatform, mn as ContactEmail, mt as EmojiKey, n as AttachmentInput, nn as Message, nt as PlatformsData, o as ContentBuilder, ot as SlackTeamMeta, p as SpectrumInstance, pn as ContactDetails, pt as Emoji, q as broadcast, qt as StreamText, rn as Space, rt as ProjectData, s as ContentInput, sn as reaction, st as SlackTokenData, t as Attachment, tn as edit, tt as PlatformStatus, u as UnsupportedError, un as custom, ut as SubscriptionStatus, v as FusorMessages, vn as ContactPhone, vt as Unsend, w as FusorVerifyRequest, wn as AvatarInput, wt as Richlink, x as FusorReply, xn as AgentSender, xt as typing, y as FusorMessagesCtx, yt as unsend, z as PlatformSpace } from "./attachment-CfEp6LAu.js";
1
+ import { $ as FusorTokenData, A as isFusorEvent, An as AppLayout, At as Rename, B as PlatformUser, C as FusorVerify, Cn as Avatar, Ct as text, D as WebhookRawResult, Dt as resolveContents, E as WebhookRawRequest, Et as richlink, F as PlatformInstance, Ft as Poll, G as Broadcaster, Gt as markdown, Ht as poll, I as PlatformMessage, It as PollChoice, J as mergeStreams, Jt as StreamTextSource, K as ManagedStream, Kt as DeltaExtractor, L as PlatformProviderConfig, Lt as PollChoiceInput, M as EventProducer, Mn as app, Mt as Read, N as Platform, Nn as appLayoutSchema, O as FusorEvent, Ot as Reply, P as PlatformDef, Pt as read, Q as DedicatedTokenData, Qt as group, R as PlatformRuntime, Rt as PollOption, S as FusorRespond, Sn as User, T as WebhookHandler, Tn as avatar, U as SchemaMessage, Ut as Markdown, V as ProviderMessage, Vt as option, W as SpaceNamespace, X as Store, Xt as Group, Y as stream, Yt as TextStreamOptions, Z as CloudPlatform, _ as FusorClient, _n as ContactOrg, _t as voice, a as Content, an as ReactionBuilder, at as SharedTokenData, b as FusorMessagesReturn, bn as contact, bt as Typing, c as fromVCard, ct as SpectrumCloudError, d as UnsupportedKind, dn as Contact, dt as TokenData, en as Edit, et as ImessageInfoData, f as Spectrum, fn as ContactAddress, ft as cloud, g as isFusorClient, gn as ContactName, h as fusor, hn as ContactInput, ht as Voice, i as attachment, in as Reaction, it as ProjectProfile, j as AnyPlatformDef, jn as AppUrl, jt as rename, k as fusorEvent, kn as App, kt as reply, l as toVCard, lt as SubscriptionData, m as definePlatform, mn as ContactEmail, mt as EmojiKey, n as AttachmentInput, nn as Message, nt as PlatformsData, o as ContentBuilder, ot as SlackTeamMeta, p as SpectrumInstance, pn as ContactDetails, pt as Emoji, q as broadcast, qt as StreamText, rn as Space, rt as ProjectData, s as ContentInput, sn as reaction, st as SlackTokenData, t as Attachment, tn as edit, tt as PlatformStatus, u as UnsupportedError, un as custom, ut as SubscriptionStatus, v as FusorMessages, vn as ContactPhone, vt as Unsend, w as FusorVerifyRequest, wn as AvatarInput, wt as Richlink, x as FusorReply, xn as AgentSender, xt as typing, y as FusorMessagesCtx, yt as unsend, z as PlatformSpace } from "./attachment-CQh4PQGl.js";
2
2
  export { type AgentSender, type AnyPlatformDef, type App, type AppLayout, type AppUrl, type Attachment, type AttachmentInput, type Avatar, type AvatarInput, type Broadcaster, type CloudPlatform, type Contact, type ContactAddress, type ContactDetails, type ContactEmail, type ContactInput, type ContactName, type ContactOrg, type ContactPhone, type Content, type ContentBuilder, type ContentInput, type DedicatedTokenData, type DeltaExtractor, type Edit, Emoji, type EmojiKey, type EventProducer, type FusorClient, type FusorEvent, type FusorMessages, type FusorMessagesCtx, type FusorMessagesReturn, type FusorReply, type FusorRespond, type FusorTokenData, type FusorVerify, type FusorVerifyRequest, type Group, type ImessageInfoData, type ManagedStream, type Markdown, type Message, type Platform, type PlatformDef, type PlatformInstance, type PlatformMessage, type PlatformProviderConfig, type PlatformRuntime, type PlatformSpace, type PlatformStatus, type PlatformUser, type PlatformsData, type Poll, type PollChoice, type PollChoiceInput, type PollOption, type ProjectData, type ProjectProfile, type ProviderMessage, type Reaction, type ReactionBuilder, type Read, type Rename, type Reply, type Richlink, type SchemaMessage, type SharedTokenData, type SlackTeamMeta, type SlackTokenData, type Space, type SpaceNamespace, Spectrum, SpectrumCloudError, type SpectrumInstance, type Store, type StreamText, type StreamTextSource, type SubscriptionData, type SubscriptionStatus, type TextStreamOptions, type TokenData, type Typing, type Unsend, UnsupportedError, type UnsupportedKind, type User, type Voice, type WebhookHandler, type WebhookRawRequest, type WebhookRawResult, app, appLayoutSchema, attachment, avatar, broadcast, cloud, contact, custom, definePlatform, edit, fromVCard, fusor, fusorEvent, group, isFusorClient, isFusorEvent, markdown, mergeStreams, option, poll, reaction, read, rename, reply, resolveContents, richlink, stream, text, toVCard, typing, unsend, voice };
package/dist/index.js CHANGED
@@ -2994,7 +2994,7 @@ function definePlatform(name, rawDef) {
2994
2994
  }
2995
2995
  //#endregion
2996
2996
  //#region src/build-env.ts
2997
- const SPECTRUM_SDK_VERSION = "6.0.0";
2997
+ const SPECTRUM_SDK_VERSION = "6.1.1";
2998
2998
  //#endregion
2999
2999
  //#region src/utils/provider-packages.ts
3000
3000
  const OFFICIAL_PROVIDER_PACKAGES = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectrum-ts/core",
3
- "version": "6.0.0",
3
+ "version": "6.1.1",
4
4
  "description": "The spectrum-ts runtime — Spectrum, content builders, fusor, and the provider authoring API.",
5
5
  "repository": {
6
6
  "type": "git",