spectrum-ts 1.16.1 → 1.17.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.
@@ -1,5 +1,5 @@
1
1
  import z__default from 'zod';
2
- import { C as ContentBuilder } from './types-Dqv4Ffqg.js';
2
+ import { C as ContentBuilder } from './types-DcQ5a7PK.js';
3
3
 
4
4
  declare const attachmentSchema: z__default.ZodObject<{
5
5
  type: z__default.ZodLiteral<"attachment">;
@@ -1,7 +1,7 @@
1
- import './attachment-Bz66JIjW.js';
1
+ import './attachment-DfWSZS5L.js';
2
2
  import vCard from 'vcf';
3
3
  import z__default from 'zod';
4
- import { U as User, C as ContentBuilder, M as Message, b as Space, c as ContentInput } from './types-Dqv4Ffqg.js';
4
+ import { U as User, C as ContentBuilder, M as Message, b as Space, c as ContentInput } from './types-DcQ5a7PK.js';
5
5
 
6
6
  declare const nameSchema: z__default.ZodObject<{
7
7
  formatted: z__default.ZodOptional<z__default.ZodString>;
@@ -1,6 +1,6 @@
1
- export { c as asAttachment } from './attachment-Bz66JIjW.js';
2
- export { s as asContact, u as asCustom, w as asGroup, x as asPoll, y as asPollOption, z as asReaction, A as asRichlink, B as asText, D as asVoice } from './authoring-e7xyaumK.js';
3
- export { f as ProviderMessageRecord } from './types-Dqv4Ffqg.js';
1
+ export { c as asAttachment } from './attachment-DfWSZS5L.js';
2
+ export { s as asContact, u as asCustom, w as asGroup, x as asPoll, y as asPollOption, z as asReaction, A as asRichlink, B as asText, D as asVoice } from './authoring-C9uDdZ2F.js';
3
+ export { f as ProviderMessageRecord } from './types-DcQ5a7PK.js';
4
4
  import 'zod';
5
5
  import 'vcf';
6
6
  import 'hotscript';
@@ -11,7 +11,7 @@ import {
11
11
  cloud,
12
12
  mergeStreams,
13
13
  stream
14
- } from "./chunk-VNMOZFWV.js";
14
+ } from "./chunk-KYEHKHXT.js";
15
15
  import {
16
16
  asContact,
17
17
  fromVCard,
@@ -1650,6 +1650,53 @@ var resumableOrderedStream = (options) => stream((emit, end) => {
1650
1650
  };
1651
1651
  });
1652
1652
 
1653
+ // src/providers/imessage/remote/contact-share.ts
1654
+ import { sanitizeErrorMessage } from "@photon-ai/otel";
1655
+ import { LRUCache } from "lru-cache";
1656
+ var SHARE_TTL_MS = 24 * 60 * 60 * 1e3;
1657
+ var MAX_TRACKED_CHATS = 1e4;
1658
+ var ContactShareTracker = class {
1659
+ cache = new LRUCache({
1660
+ max: MAX_TRACKED_CHATS,
1661
+ ttl: SHARE_TTL_MS,
1662
+ ttlAutopurge: false
1663
+ });
1664
+ /**
1665
+ * Best-effort share. The cache is set eagerly so that a burst of inbound
1666
+ * messages for the same chat coalesces to a single API call. On failure the
1667
+ * entry is evicted so the next inbound retries — transient errors don't
1668
+ * permanently mute the feature for a chat. Never awaits and never throws:
1669
+ * the receive stream must not crash on share failures.
1670
+ */
1671
+ maybeShare(client, chatGuid) {
1672
+ if (this.cache.has(chatGuid)) {
1673
+ return;
1674
+ }
1675
+ this.cache.set(chatGuid, true);
1676
+ const safeChatGuid = sanitizeErrorMessage(chatGuid);
1677
+ client.chats.shareContactInfo(chatGuid).then(() => {
1678
+ console.info(
1679
+ `[spectrum-ts][imessage][contact-share] shared contact info to ${safeChatGuid}`
1680
+ );
1681
+ }).catch((error) => {
1682
+ this.cache.delete(chatGuid);
1683
+ console.warn(
1684
+ `[spectrum-ts][imessage][contact-share] failed to share contact info to ${safeChatGuid}`,
1685
+ error
1686
+ );
1687
+ });
1688
+ }
1689
+ };
1690
+ var trackers = /* @__PURE__ */ new WeakMap();
1691
+ var getContactShareTracker = (owner) => {
1692
+ let tracker = trackers.get(owner);
1693
+ if (!tracker) {
1694
+ tracker = new ContactShareTracker();
1695
+ trackers.set(owner, tracker);
1696
+ }
1697
+ return tracker;
1698
+ };
1699
+
1653
1700
  // src/providers/imessage/remote/polls.ts
1654
1701
  var isVotedPollEvent = (event) => event.delta.type === "voted";
1655
1702
  var isUnvotedPollEvent = (event) => event.delta.type === "unvoted";
@@ -1789,11 +1836,15 @@ var isRetryableIMessageStreamError = (error) => {
1789
1836
  return false;
1790
1837
  };
1791
1838
  var isEventFromCurrentAccount = (event, phone) => event.isFromMe || phone !== SHARED_PHONE && event.actor?.address !== void 0 && event.actor.address === phone;
1792
- var toMessageItem = async (client, event, phone, cursor) => {
1839
+ var toMessageItem = async (client, event, phone, cursor, onInbound) => {
1793
1840
  if (event.type === "message.received") {
1794
1841
  if (event.message.isFromMe) {
1795
1842
  return { cursor, id: event.message.guid, values: [] };
1796
1843
  }
1844
+ const inboundChatGuid = event.message.chatGuids?.[0];
1845
+ if (inboundChatGuid) {
1846
+ onInbound?.(inboundChatGuid);
1847
+ }
1797
1848
  const cache = getMessageCache(client);
1798
1849
  return {
1799
1850
  cursor,
@@ -1884,11 +1935,17 @@ var withClose = (source, cursor) => Object.assign(afterCursor(source, cursor), {
1884
1935
  await source.close?.();
1885
1936
  }
1886
1937
  });
1887
- var messageStream = (client, phone) => resumableOrderedStream({
1938
+ var messageStream = (client, phone, onInbound) => resumableOrderedStream({
1888
1939
  fetchMissed: (cursor) => catchUpEvents(client, cursor, isMessageEvent),
1889
1940
  isRetryableError: isRetryableIMessageStreamError,
1890
- processLive: (event) => toMessageItem(client, event, phone, String(event.sequence)),
1891
- processMissed: (event) => event.type === "catchup.complete" ? Promise.resolve(toCatchUpCompleteItem(event)) : toMessageItem(client, event, phone, String(event.sequence)),
1941
+ processLive: (event) => toMessageItem(client, event, phone, String(event.sequence), onInbound),
1942
+ processMissed: (event) => event.type === "catchup.complete" ? Promise.resolve(toCatchUpCompleteItem(event)) : toMessageItem(
1943
+ client,
1944
+ event,
1945
+ phone,
1946
+ String(event.sequence),
1947
+ onInbound
1948
+ ),
1892
1949
  subscribeLive: (cursor) => withClose(client.messages.subscribeEvents(), cursor)
1893
1950
  });
1894
1951
  var pollStream = (client, pollCache, phone) => resumableOrderedStream({
@@ -1898,14 +1955,23 @@ var pollStream = (client, pollCache, phone) => resumableOrderedStream({
1898
1955
  processMissed: (event) => event.type === "catchup.complete" ? Promise.resolve(toCatchUpCompleteItem(event)) : toPollItem(client, pollCache, event, phone, String(event.sequence)),
1899
1956
  subscribeLive: (cursor) => withClose(client.polls.subscribeEvents(), cursor)
1900
1957
  });
1901
- var clientStream = (client, pollCache, phone) => mergeStreams([
1902
- messageStream(client, phone),
1958
+ var clientStream = (client, pollCache, phone, onInbound) => mergeStreams([
1959
+ messageStream(client, phone, onInbound),
1903
1960
  pollStream(client, pollCache, phone)
1904
1961
  ]);
1905
- var messages3 = (clients) => {
1962
+ var messages3 = (clients, projectConfig) => {
1906
1963
  const pollCache = getPollCache(clients);
1964
+ const shareEnabled = projectConfig?.profile?.imessageSynced === true;
1965
+ const tracker = shareEnabled ? getContactShareTracker(clients) : void 0;
1907
1966
  return mergeStreams(
1908
- clients.map((entry) => clientStream(entry.client, pollCache, entry.phone))
1967
+ clients.map(
1968
+ (entry) => clientStream(
1969
+ entry.client,
1970
+ pollCache,
1971
+ entry.phone,
1972
+ tracker ? (chatGuid) => tracker.maybeShare(entry.client, chatGuid) : void 0
1973
+ )
1974
+ )
1909
1975
  );
1910
1976
  };
1911
1977
 
@@ -1918,7 +1984,7 @@ var stopTyping = async (remote, spaceId) => {
1918
1984
  };
1919
1985
 
1920
1986
  // src/providers/imessage/remote/api.ts
1921
- var messages4 = (clients) => messages3(clients);
1987
+ var messages4 = (clients, projectConfig) => messages3(clients, projectConfig);
1922
1988
  var setBackground2 = async (remote, spaceId, content) => setBackground(remote, spaceId, content);
1923
1989
  var setDisplayName2 = async (remote, spaceId, content) => setDisplayName(remote, spaceId, content);
1924
1990
  var setIcon2 = async (remote, spaceId, content) => setIcon(remote, spaceId, content);
@@ -2159,7 +2225,7 @@ var imessage = definePlatform("iMessage", {
2159
2225
  }
2160
2226
  }
2161
2227
  },
2162
- messages: ({ client }) => isLocal(client) ? messages2(client) : messages4(client),
2228
+ messages: ({ client, projectConfig }) => isLocal(client) ? messages2(client) : messages4(client, projectConfig),
2163
2229
  send: async ({ space, content, client }) => {
2164
2230
  if (content.type === "reply") {
2165
2231
  if (isLocal(client)) {
@@ -5,7 +5,7 @@ import {
5
5
  cloud,
6
6
  mergeStreams,
7
7
  stream
8
- } from "./chunk-VNMOZFWV.js";
8
+ } from "./chunk-KYEHKHXT.js";
9
9
  import {
10
10
  asContact
11
11
  } from "./chunk-RNGEA4UW.js";
@@ -44,6 +44,9 @@ var request = async (path, init) => {
44
44
  };
45
45
  var basicAuth = (projectId, projectSecret) => `Basic ${btoa(`${projectId}:${projectSecret}`)}`;
46
46
  var cloud = {
47
+ getProject: (projectId, projectSecret) => request(`/projects/${projectId}/`, {
48
+ headers: { Authorization: basicAuth(projectId, projectSecret) }
49
+ }),
47
50
  getSubscription: (projectId) => request(`/projects/${projectId}/billing/subscription`),
48
51
  issueImessageTokens: (projectId, projectSecret) => request(`/projects/${projectId}/imessage/tokens`, {
49
52
  method: "POST",
@@ -2,7 +2,7 @@ import {
2
2
  cloud,
3
3
  mergeStreams,
4
4
  stream
5
- } from "./chunk-VNMOZFWV.js";
5
+ } from "./chunk-KYEHKHXT.js";
6
6
  import {
7
7
  UnsupportedError,
8
8
  definePlatform
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- export { A as Attachment, a as AttachmentInput, b as attachment } from './attachment-Bz66JIjW.js';
1
+ export { A as Attachment, a as AttachmentInput, b as attachment } from './attachment-DfWSZS5L.js';
2
2
  import z__default from 'zod';
3
3
  import { P as PhotoInput } from './photo-content-BJKnqgN-.js';
4
- import { C as ContentBuilder, M as Message, U as User, b as Space, c as ContentInput, e as Content, f as ProviderMessageRecord, g as SpaceActionFn, h as MessageActionFn, i as CreateClientContext, d as Store, P as Platform, a as PlatformDef, j as ProviderMessage, E as EventProducer, I as InstanceActionFn, k as PlatformProviderConfig, l as SpectrumLike, m as CustomEventStreams, A as AgentSender } from './types-Dqv4Ffqg.js';
5
- export { n as AnyPlatformDef, B as Broadcaster, o as ManagedStream, p as PlatformInstance, q as PlatformMessage, r as PlatformRuntime, s as PlatformSpace, t as PlatformUser, S as SchemaMessage, u as broadcast, v as mergeStreams, w as stream } from './types-Dqv4Ffqg.js';
6
- import { C as ContactInput, a as Contact } from './authoring-e7xyaumK.js';
7
- export { b as ContactAddress, c as ContactDetails, d as ContactEmail, e as ContactName, f as ContactOrg, g as ContactPhone, G as Group, P as Poll, h as PollChoice, i as PollChoiceInput, j as PollOption, R as Reaction, k as Richlink, V as Voice, l as contact, m as custom, n as group, o as option, p as poll, r as reaction, q as richlink, t as text, v as voice } from './authoring-e7xyaumK.js';
4
+ import { C as ContentBuilder, M as Message, U as User, b as Space, c as ContentInput, e as Content, f as ProviderMessageRecord, g as SpaceActionFn, h as MessageActionFn, i as CreateClientContext, d as Store, P as Platform, a as PlatformDef, j as ProviderMessage, E as EventProducer, I as InstanceActionFn, k as PlatformProviderConfig, l as SpectrumLike, m as CustomEventStreams, A as AgentSender, n as ProjectData } from './types-DcQ5a7PK.js';
5
+ export { o as AnyPlatformDef, B as Broadcaster, p as CloudPlatform, D as DedicatedTokenData, F as FusorTokenData, q as ImessageInfoData, r as ManagedStream, s as PlatformInstance, t as PlatformMessage, u as PlatformRuntime, v as PlatformSpace, w as PlatformStatus, x as PlatformUser, y as PlatformsData, z as ProjectProfile, S as SchemaMessage, G as SharedTokenData, H as SlackTeamMeta, J as SlackTokenData, K as SpectrumCloudError, L as SubscriptionData, N as SubscriptionStatus, T as TokenData, O as broadcast, Q as cloud, R as mergeStreams, V as stream } from './types-DcQ5a7PK.js';
6
+ import { C as ContactInput, a as Contact } from './authoring-C9uDdZ2F.js';
7
+ export { b as ContactAddress, c as ContactDetails, d as ContactEmail, e as ContactName, f as ContactOrg, g as ContactPhone, G as Group, P as Poll, h as PollChoice, i as PollChoiceInput, j as PollOption, R as Reaction, k as Richlink, V as Voice, l as contact, m as custom, n as group, o as option, p as poll, r as reaction, q as richlink, t as text, v as voice } from './authoring-C9uDdZ2F.js';
8
8
  import 'hotscript';
9
9
  import 'vcf';
10
10
 
@@ -2803,7 +2803,10 @@ declare function Spectrum<const Providers extends PlatformProviderConfig[]>(opti
2803
2803
  options?: SpectrumOptions;
2804
2804
  telemetry?: boolean;
2805
2805
  webhookSecret?: string;
2806
- } | {
2806
+ }): Promise<SpectrumInstance<Providers> & {
2807
+ readonly config: ProjectData;
2808
+ }>;
2809
+ declare function Spectrum<const Providers extends PlatformProviderConfig[]>(options: {
2807
2810
  projectId?: never;
2808
2811
  projectSecret?: never;
2809
2812
  providers: [...Providers];
@@ -2812,67 +2815,6 @@ declare function Spectrum<const Providers extends PlatformProviderConfig[]>(opti
2812
2815
  webhookSecret?: string;
2813
2816
  }): Promise<SpectrumInstance<Providers>>;
2814
2817
 
2815
- type SubscriptionStatus = "active" | "canceled" | "past_due";
2816
- interface SubscriptionData {
2817
- status: SubscriptionStatus | null;
2818
- tier: string;
2819
- }
2820
- interface SharedTokenData {
2821
- expiresIn: number;
2822
- token: string;
2823
- type: "shared";
2824
- }
2825
- interface DedicatedTokenData {
2826
- auth: Record<string, string>;
2827
- expiresIn: number;
2828
- numbers: Record<string, string | null>;
2829
- type: "dedicated";
2830
- }
2831
- type TokenData = SharedTokenData | DedicatedTokenData;
2832
- type CloudPlatform = "imessage" | "whatsapp_business" | "slack";
2833
- interface PlatformStatus {
2834
- enabled: boolean;
2835
- }
2836
- type PlatformsData = Record<CloudPlatform, PlatformStatus>;
2837
- interface ImessageInfoData {
2838
- type: "shared" | "dedicated";
2839
- }
2840
- interface WhatsappBusinessTokenData {
2841
- auth: Record<string, string>;
2842
- expiresIn: number;
2843
- numbers: Record<string, string | null>;
2844
- }
2845
- interface SlackTeamMeta {
2846
- appId: string;
2847
- botUserId: string;
2848
- grantedScopes: string[];
2849
- teamName: string;
2850
- }
2851
- interface SlackTokenData {
2852
- auth: Record<string, string>;
2853
- expiresIn: number;
2854
- teams: Record<string, SlackTeamMeta>;
2855
- }
2856
- interface FusorTokenData {
2857
- expiresIn: number;
2858
- token: string;
2859
- }
2860
- declare class SpectrumCloudError extends Error {
2861
- readonly status: number;
2862
- readonly code: string;
2863
- constructor(status: number, code: string, message: string);
2864
- }
2865
- declare const cloud: {
2866
- getSubscription: (projectId: string) => Promise<SubscriptionData>;
2867
- issueImessageTokens: (projectId: string, projectSecret: string) => Promise<TokenData>;
2868
- getImessageInfo: (projectId: string) => Promise<ImessageInfoData>;
2869
- issueWhatsappBusinessTokens: (projectId: string, projectSecret: string) => Promise<WhatsappBusinessTokenData>;
2870
- issueSlackTokens: (projectId: string, projectSecret: string) => Promise<SlackTokenData>;
2871
- issueFusorToken: (projectId: string, projectSecret: string) => Promise<FusorTokenData>;
2872
- getPlatforms: (projectId: string) => Promise<PlatformsData>;
2873
- togglePlatform: (projectId: string, projectSecret: string, platform: CloudPlatform, enabled: boolean) => Promise<PlatformsData>;
2874
- };
2875
-
2876
2818
  type UnsupportedKind = "content" | "action";
2877
2819
  interface UnsupportedErrorOptions {
2878
2820
  action?: string;
@@ -2896,4 +2838,4 @@ declare class UnsupportedError extends Error {
2896
2838
  declare const fromVCard: (vcf: string) => ContactInput;
2897
2839
  declare const toVCard: (contact: Contact) => Promise<string>;
2898
2840
 
2899
- export { AgentSender, type Avatar, type AvatarInput, type CloudPlatform, Contact, ContactInput, Content, ContentBuilder, ContentInput, type DedicatedTokenData, type Edit, Emoji, type EmojiKey, EventProducer, type FusorClient, type FusorMessages, type FusorMessagesCtx, type FusorMessagesReturn, type FusorReply, type FusorRespond, type FusorTokenData, type FusorVerify, type FusorVerifyRequest, type ImessageInfoData, Message, Platform, PlatformDef, PlatformProviderConfig, type PlatformStatus, type PlatformsData, ProviderMessage, type Rename, type Reply, type SharedTokenData, type SlackTeamMeta, type SlackTokenData, Space, Spectrum, SpectrumCloudError, type SpectrumInstance, type SubscriptionData, type SubscriptionStatus, type TokenData, type Typing, UnsupportedError, type UnsupportedKind, User, type WebhookHandler, type WebhookRawRequest, type WebhookRawResult, avatar, cloud, defineFusorPlatform, definePlatform, edit, fromVCard, fusor, isFusorClient, rename, reply, resolveContents, toVCard, typing };
2841
+ export { AgentSender, type Avatar, type AvatarInput, Contact, ContactInput, Content, ContentBuilder, ContentInput, type Edit, Emoji, type EmojiKey, EventProducer, type FusorClient, type FusorMessages, type FusorMessagesCtx, type FusorMessagesReturn, type FusorReply, type FusorRespond, type FusorVerify, type FusorVerifyRequest, Message, Platform, PlatformDef, PlatformProviderConfig, ProjectData, ProviderMessage, type Rename, type Reply, Space, Spectrum, type SpectrumInstance, type Typing, UnsupportedError, type UnsupportedKind, User, type WebhookHandler, type WebhookRawRequest, type WebhookRawResult, avatar, defineFusorPlatform, definePlatform, edit, fromVCard, fusor, isFusorClient, rename, reply, resolveContents, toVCard, typing };
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  createAsyncQueue,
17
17
  mergeStreams,
18
18
  stream
19
- } from "./chunk-VNMOZFWV.js";
19
+ } from "./chunk-KYEHKHXT.js";
20
20
  import {
21
21
  contact,
22
22
  fromVCard,
@@ -27639,6 +27639,7 @@ async function Spectrum(options) {
27639
27639
  } = options;
27640
27640
  const flattenGroups = runtimeOptions?.flattenGroups ?? false;
27641
27641
  const otelHandle = telemetry ? bootstrapTelemetry({ projectId, projectSecret }) : void 0;
27642
+ const projectConfig = projectId !== void 0 && projectSecret !== void 0 ? await cloud.getProject(projectId, projectSecret) : void 0;
27642
27643
  const platformStates = /* @__PURE__ */ new Map();
27643
27644
  const fusorMessageSources = /* @__PURE__ */ new Map();
27644
27645
  const messageBroadcasters = /* @__PURE__ */ new Map();
@@ -27719,6 +27720,7 @@ async function Spectrum(options) {
27719
27720
  const raw = fusorSource ? fusorSource.iterable : definition.messages({
27720
27721
  client,
27721
27722
  config,
27723
+ projectConfig,
27722
27724
  store
27723
27725
  });
27724
27726
  const bindSend = async function* () {
@@ -27859,7 +27861,12 @@ async function Spectrum(options) {
27859
27861
  if (!producer) {
27860
27862
  continue;
27861
27863
  }
27862
- const providerEvents = producer({ client, config, store });
27864
+ const providerEvents = producer({
27865
+ client,
27866
+ config,
27867
+ projectConfig,
27868
+ store
27869
+ });
27863
27870
  const annotatePlatform = async function* () {
27864
27871
  for await (const value of providerEvents) {
27865
27872
  const annotated = await withSpan(
@@ -28116,6 +28123,7 @@ async function Spectrum(options) {
28116
28123
  const base = {
28117
28124
  __providers: providers,
28118
28125
  __internal: { platforms: platformStates },
28126
+ config: projectConfig,
28119
28127
  messages,
28120
28128
  stop: stopOnce,
28121
28129
  webhook: handleWebhook,
@@ -1,8 +1,8 @@
1
- import { C as ContentBuilder, c as ContentInput, M as Message, S as SchemaMessage, P as Platform, a as PlatformDef, b as Space, d as Store } from '../../types-Dqv4Ffqg.js';
1
+ import { C as ContentBuilder, c as ContentInput, M as Message, S as SchemaMessage, P as Platform, a as PlatformDef, b as Space, d as Store } from '../../types-DcQ5a7PK.js';
2
2
  import * as zod_v4_core from 'zod/v4/core';
3
3
  import * as z from 'zod';
4
4
  import z__default from 'zod';
5
- import { A as Attachment } from '../../attachment-Bz66JIjW.js';
5
+ import { A as Attachment } from '../../attachment-DfWSZS5L.js';
6
6
  import { P as PhotoInput } from '../../photo-content-BJKnqgN-.js';
7
7
  import { MessageEffect, AdvancedIMessage } from '@photon-ai/advanced-imessage';
8
8
  import { IMessageSDK } from '@photon-ai/imessage-kit';
@@ -3,10 +3,10 @@ import {
3
3
  effect,
4
4
  imessage,
5
5
  read
6
- } from "../../chunk-PIULC4CM.js";
6
+ } from "../../chunk-DK4P2SHC.js";
7
7
  import "../../chunk-LJM5D2T5.js";
8
8
  import "../../chunk-KO67KDBD.js";
9
- import "../../chunk-VNMOZFWV.js";
9
+ import "../../chunk-KYEHKHXT.js";
10
10
  import "../../chunk-RNGEA4UW.js";
11
11
  import "../../chunk-32H3VVUE.js";
12
12
  import "../../chunk-FTLJVVH7.js";
@@ -2,11 +2,11 @@ export { imessage } from './imessage/index.js';
2
2
  export { slack } from './slack/index.js';
3
3
  export { terminal } from './terminal/index.js';
4
4
  export { whatsappBusiness } from './whatsapp-business/index.js';
5
- import '../types-Dqv4Ffqg.js';
5
+ import '../types-DcQ5a7PK.js';
6
6
  import 'hotscript';
7
7
  import 'zod';
8
8
  import 'zod/v4/core';
9
- import '../attachment-Bz66JIjW.js';
9
+ import '../attachment-DfWSZS5L.js';
10
10
  import '../photo-content-BJKnqgN-.js';
11
11
  import '@photon-ai/advanced-imessage';
12
12
  import '@photon-ai/imessage-kit';
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  imessage
3
- } from "../chunk-PIULC4CM.js";
3
+ } from "../chunk-DK4P2SHC.js";
4
4
  import "../chunk-LJM5D2T5.js";
5
5
  import {
6
6
  slack
7
- } from "../chunk-UFAZMTKC.js";
7
+ } from "../chunk-Y4CZ5JFD.js";
8
8
  import {
9
9
  terminal
10
10
  } from "../chunk-6NGVREPQ.js";
11
11
  import "../chunk-5QSNQ6YN.js";
12
12
  import {
13
13
  whatsappBusiness
14
- } from "../chunk-753K5YPL.js";
14
+ } from "../chunk-GHERTIUM.js";
15
15
  import "../chunk-KO67KDBD.js";
16
- import "../chunk-VNMOZFWV.js";
16
+ import "../chunk-KYEHKHXT.js";
17
17
  import "../chunk-RNGEA4UW.js";
18
18
  import "../chunk-32H3VVUE.js";
19
19
  import "../chunk-FTLJVVH7.js";
@@ -1,4 +1,4 @@
1
- import { S as SchemaMessage, P as Platform, a as PlatformDef } from '../../types-Dqv4Ffqg.js';
1
+ import { S as SchemaMessage, P as Platform, a as PlatformDef } from '../../types-DcQ5a7PK.js';
2
2
  import * as z from 'zod';
3
3
  import z__default from 'zod';
4
4
  import * as _photon_ai_slack from '@photon-ai/slack';
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  slack
3
- } from "../../chunk-UFAZMTKC.js";
4
- import "../../chunk-VNMOZFWV.js";
3
+ } from "../../chunk-Y4CZ5JFD.js";
4
+ import "../../chunk-KYEHKHXT.js";
5
5
  import "../../chunk-32H3VVUE.js";
6
6
  import "../../chunk-FTLJVVH7.js";
7
7
  export {
@@ -1,4 +1,4 @@
1
- import { P as Platform, a as PlatformDef, M as Message, U as User, b as Space } from '../../types-Dqv4Ffqg.js';
1
+ import { P as Platform, a as PlatformDef, M as Message, U as User, b as Space } from '../../types-DcQ5a7PK.js';
2
2
  import { ChildProcess } from 'node:child_process';
3
3
  import z__default from 'zod';
4
4
  import { Socket } from 'node:net';
@@ -1,4 +1,4 @@
1
- import { S as SchemaMessage, P as Platform, a as PlatformDef } from '../../types-Dqv4Ffqg.js';
1
+ import { S as SchemaMessage, P as Platform, a as PlatformDef } from '../../types-DcQ5a7PK.js';
2
2
  import { WhatsAppClient } from '@photon-ai/whatsapp-business';
3
3
  import * as z from 'zod';
4
4
  import z__default from 'zod';
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  whatsappBusiness
3
- } from "../../chunk-753K5YPL.js";
3
+ } from "../../chunk-GHERTIUM.js";
4
4
  import "../../chunk-KO67KDBD.js";
5
- import "../../chunk-VNMOZFWV.js";
5
+ import "../../chunk-KYEHKHXT.js";
6
6
  import "../../chunk-RNGEA4UW.js";
7
7
  import "../../chunk-32H3VVUE.js";
8
8
  import "../../chunk-FTLJVVH7.js";
@@ -762,6 +762,85 @@ interface Message<TPlatform extends string = string, TSender extends User = User
762
762
  timestamp: Date;
763
763
  }
764
764
 
765
+ type SubscriptionStatus = "active" | "canceled" | "past_due";
766
+ interface SubscriptionData {
767
+ status: SubscriptionStatus | null;
768
+ tier: string;
769
+ }
770
+ interface SharedTokenData {
771
+ expiresIn: number;
772
+ token: string;
773
+ type: "shared";
774
+ }
775
+ interface DedicatedTokenData {
776
+ auth: Record<string, string>;
777
+ expiresIn: number;
778
+ numbers: Record<string, string | null>;
779
+ type: "dedicated";
780
+ }
781
+ type TokenData = SharedTokenData | DedicatedTokenData;
782
+ type CloudPlatform = "imessage" | "whatsapp_business" | "slack";
783
+ interface PlatformStatus {
784
+ enabled: boolean;
785
+ }
786
+ type PlatformsData = Record<CloudPlatform, PlatformStatus>;
787
+ interface ImessageInfoData {
788
+ type: "shared" | "dedicated";
789
+ }
790
+ interface WhatsappBusinessTokenData {
791
+ auth: Record<string, string>;
792
+ expiresIn: number;
793
+ numbers: Record<string, string | null>;
794
+ }
795
+ interface SlackTeamMeta {
796
+ appId: string;
797
+ botUserId: string;
798
+ grantedScopes: string[];
799
+ teamName: string;
800
+ }
801
+ interface SlackTokenData {
802
+ auth: Record<string, string>;
803
+ expiresIn: number;
804
+ teams: Record<string, SlackTeamMeta>;
805
+ }
806
+ interface FusorTokenData {
807
+ expiresIn: number;
808
+ token: string;
809
+ }
810
+ /**
811
+ * Per-project profile bag — a flexible record of project-level settings
812
+ * defined in Spectrum Cloud. Concrete fields depend on the project; consumers
813
+ * read them as `app.config.profile.<key>`.
814
+ */
815
+ interface ProjectProfile {
816
+ [key: string]: unknown;
817
+ }
818
+ /**
819
+ * The project record returned by `GET /projects/{projectId}/`. Populated on
820
+ * `app.config` when `Spectrum()` is called with `projectId` + `projectSecret`.
821
+ */
822
+ interface ProjectData {
823
+ id: string;
824
+ name: string;
825
+ profile: ProjectProfile;
826
+ }
827
+ declare class SpectrumCloudError extends Error {
828
+ readonly status: number;
829
+ readonly code: string;
830
+ constructor(status: number, code: string, message: string);
831
+ }
832
+ declare const cloud: {
833
+ getProject: (projectId: string, projectSecret: string) => Promise<ProjectData>;
834
+ getSubscription: (projectId: string) => Promise<SubscriptionData>;
835
+ issueImessageTokens: (projectId: string, projectSecret: string) => Promise<TokenData>;
836
+ getImessageInfo: (projectId: string) => Promise<ImessageInfoData>;
837
+ issueWhatsappBusinessTokens: (projectId: string, projectSecret: string) => Promise<WhatsappBusinessTokenData>;
838
+ issueSlackTokens: (projectId: string, projectSecret: string) => Promise<SlackTokenData>;
839
+ issueFusorToken: (projectId: string, projectSecret: string) => Promise<FusorTokenData>;
840
+ getPlatforms: (projectId: string) => Promise<PlatformsData>;
841
+ togglePlatform: (projectId: string, projectSecret: string, platform: CloudPlatform, enabled: boolean) => Promise<PlatformsData>;
842
+ };
843
+
765
844
  /**
766
845
  * A small per-platform key-value bag, modeled after Swift's `UserDefaults`.
767
846
  * Untyped writes; typed reads return `undefined` on missing key OR type
@@ -891,6 +970,13 @@ type InputSchema<TSchema> = TSchema extends z__default.ZodType<object> ? z__defa
891
970
  type EventProducer<TPayload = unknown, TClient = unknown, TConfig = unknown> = (ctx: {
892
971
  client: NoInferClient<TClient>;
893
972
  config: TConfig;
973
+ /**
974
+ * Spectrum Cloud project metadata, fetched once at `Spectrum()` init.
975
+ * `undefined` when the instance was created without `projectId`/`projectSecret`
976
+ * (local-only setups). Providers read project-level toggles from
977
+ * `projectConfig.profile.<key>` — e.g. iMessage's `imessageSynced` flag.
978
+ */
979
+ projectConfig: ProjectData | undefined;
894
980
  store: Store;
895
981
  }) => AsyncIterable<TPayload>;
896
982
  type ProviderMessage<TSender extends ResolvedUser = ResolvedUser, TSpace extends ResolvedSpace = ResolvedSpace, TExtra extends object = Record<never, never>> = {
@@ -925,7 +1011,7 @@ type ProviderMessageRecord = {
925
1011
  type MergeSchema<TSchema extends z__default.ZodType | undefined, TBase extends object> = TSchema extends z__default.ZodType ? string extends keyof z__default.infer<TSchema> ? TBase : Omit<z__default.infer<TSchema>, keyof TBase> & TBase : TBase;
926
1012
  type SchemaMessage<TUserSchema extends z__default.ZodType | undefined = undefined, TSpaceSchema extends z__default.ZodType | undefined = undefined> = ProviderMessage<MergeSchema<TUserSchema, ResolvedUser>, MergeSchema<TSpaceSchema, ResolvedSpace>>;
927
1013
  type InferEventPayload<T> = T extends (ctx: never) => AsyncIterable<infer P> ? P : never;
928
- type ReservedNames = "stop" | "send" | "__internal" | "__providers";
1014
+ type ReservedNames = "stop" | "send" | "config" | "__internal" | "__providers";
929
1015
  interface CreateClientContext<_ConfigSchema extends z__default.ZodType<object>> {
930
1016
  config: z__default.infer<_ConfigSchema>;
931
1017
  projectId: string | undefined;
@@ -1237,4 +1323,4 @@ interface Platform<Def extends AnyPlatformDef> {
1237
1323
  (message: Message): PlatformMessage<Def>;
1238
1324
  }
1239
1325
 
1240
- export { type AgentSender as A, type Broadcaster as B, type ContentBuilder as C, type EventProducer as E, type InstanceActionFn as I, type Message as M, type Platform as P, type SchemaMessage as S, type User as U, type PlatformDef as a, type Space as b, type ContentInput as c, type Store as d, type Content as e, type ProviderMessageRecord as f, type SpaceActionFn as g, type MessageActionFn as h, type CreateClientContext as i, type ProviderMessage as j, type PlatformProviderConfig as k, type SpectrumLike as l, type CustomEventStreams as m, type AnyPlatformDef as n, type ManagedStream as o, type PlatformInstance as p, type PlatformMessage as q, type PlatformRuntime as r, type PlatformSpace as s, type PlatformUser as t, broadcast as u, mergeStreams as v, stream as w };
1326
+ export { type AgentSender as A, type Broadcaster as B, type ContentBuilder as C, type DedicatedTokenData as D, type EventProducer as E, type FusorTokenData as F, type SharedTokenData as G, type SlackTeamMeta as H, type InstanceActionFn as I, type SlackTokenData as J, SpectrumCloudError as K, type SubscriptionData as L, type Message as M, type SubscriptionStatus as N, broadcast as O, type Platform as P, cloud as Q, mergeStreams as R, type SchemaMessage as S, type TokenData as T, type User as U, stream as V, type PlatformDef as a, type Space as b, type ContentInput as c, type Store as d, type Content as e, type ProviderMessageRecord as f, type SpaceActionFn as g, type MessageActionFn as h, type CreateClientContext as i, type ProviderMessage as j, type PlatformProviderConfig as k, type SpectrumLike as l, type CustomEventStreams as m, type ProjectData as n, type AnyPlatformDef as o, type CloudPlatform as p, type ImessageInfoData as q, type ManagedStream as r, type PlatformInstance as s, type PlatformMessage as t, type PlatformRuntime as u, type PlatformSpace as v, type PlatformStatus as w, type PlatformUser as x, type PlatformsData as y, type ProjectProfile as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spectrum-ts",
3
- "version": "1.16.1",
3
+ "version": "1.17.0",
4
4
  "description": "Bring agents to any interface — unified messaging SDK for TypeScript.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -45,6 +45,8 @@
45
45
  "@photon-ai/whatsapp-business": "^0.1.1",
46
46
  "@photon-ai/proto": "^0.2.4",
47
47
  "@repeaterjs/repeater": "^3.0.6",
48
+ "better-grpc": "^0.3.2",
49
+ "lru-cache": "^11.0.0",
48
50
  "mime-types": "^3.0.1",
49
51
  "nice-grpc": "^2.1.16",
50
52
  "nice-grpc-common": "^2.0.2",