@neta-art/cohub 2.4.0 → 2.6.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.
@@ -3,7 +3,14 @@ import { C as ContentBlock, S as Usage, _ as SessionForkRecord, a as WebsocketCl
3
3
  import { a as VoiceInputCreateOptions } from "./voice-input.js";
4
4
 
5
5
  //#region ../protocol/src/gateway/types.d.ts
6
- type DiscordChannelConfig = {
6
+ type ChannelModelConfig = {
7
+ provider: string;
8
+ id: string;
9
+ };
10
+ type BaseChannelConfig = {
11
+ model?: ChannelModelConfig | null;
12
+ };
13
+ type DiscordChannelConfig = BaseChannelConfig & {
7
14
  inbound?: {
8
15
  requireMentionInGuild?: boolean;
9
16
  };
@@ -12,7 +19,7 @@ type DiscordChannelConfig = {
12
19
  showToolCalls?: boolean;
13
20
  };
14
21
  };
15
- type FeishuChannelConfig = {
22
+ type FeishuChannelConfig = BaseChannelConfig & {
16
23
  brand?: "feishu" | "lark";
17
24
  inbound?: {
18
25
  requireMentionInGroup?: boolean;
@@ -23,12 +30,12 @@ type FeishuChannelConfig = {
23
30
  showToolCalls?: boolean;
24
31
  };
25
32
  };
26
- type WeChatChannelConfig = {
33
+ type WeChatChannelConfig = BaseChannelConfig & {
27
34
  outbound?: {
28
35
  showIntermediateStatus?: boolean;
29
36
  };
30
37
  };
31
- type ChannelConfig = DiscordChannelConfig | FeishuChannelConfig | WeChatChannelConfig | Record<string, unknown>;
38
+ type ChannelConfig = DiscordChannelConfig | FeishuChannelConfig | WeChatChannelConfig | (BaseChannelConfig & Record<string, unknown>);
32
39
  //#endregion
33
40
  //#region ../../node_modules/.pnpm/@neta-art+generation@0.1.10/node_modules/@neta-art/generation/dist/builtins-CWEB_GK4.d.ts
34
41
  //#region src/types.d.ts
@@ -1467,9 +1474,16 @@ declare class WorkRuntimeApi {
1467
1474
  private token;
1468
1475
  private readonly transport;
1469
1476
  private readonly tokenStorageKey;
1477
+ private readonly scopesStorageKey;
1478
+ /** Scopes previously granted via requestAuthorization, retained so token
1479
+ * refreshes can re-authorize (preserving viewerScopes) instead of falling
1480
+ * back to a base session token that only carries workScopes. */
1481
+ private authorizedScopes;
1470
1482
  constructor(transport?: WorkRuntimeTransport, workId?: string);
1471
1483
  private readStoredToken;
1472
1484
  private writeStoredToken;
1485
+ private readStoredScopes;
1486
+ private writeStoredScopes;
1473
1487
  context(): Promise<WorkRuntimeContext | null>;
1474
1488
  getAccessToken(options?: {
1475
1489
  forceRefresh?: boolean;
@@ -2010,6 +2024,10 @@ declare class SpaceFilesApi {
2010
2024
  * SDK can attach authorization headers.
2011
2025
  */
2012
2026
  getDownloadUrl(path: string): string;
2027
+ createPreviewSession(customFetch?: Fetch): Promise<{
2028
+ token: string;
2029
+ expiresIn: number;
2030
+ }>;
2013
2031
  download(path: string, customFetch?: Fetch): Promise<{
2014
2032
  blob: Blob;
2015
2033
  filename: string;
@@ -2190,7 +2208,7 @@ type SpaceChannelBindingRecord = {
2190
2208
  id: string;
2191
2209
  spaceId: string;
2192
2210
  channelId: string;
2193
- config: Record<string, unknown> | null;
2211
+ config: ChannelConfig | null;
2194
2212
  createdAt: string;
2195
2213
  channel: {
2196
2214
  id: string;
@@ -2207,7 +2225,8 @@ declare class SpaceChannelsApi {
2207
2225
  private readonly spaceId;
2208
2226
  constructor(transport: HttpTransport, spaceId: string);
2209
2227
  list(): Promise<SpaceChannelBindingRecord[]>;
2210
- bind(channelId: string, config?: Record<string, unknown> | null): Promise<SpaceChannelBindingRecord>;
2228
+ bind(channelId: string, config?: ChannelConfig | null): Promise<SpaceChannelBindingRecord>;
2229
+ updateConfig(channelId: string, config?: ChannelConfig | null): Promise<SpaceChannelBindingRecord>;
2211
2230
  unbind(channelId: string): Promise<{
2212
2231
  ok: true;
2213
2232
  }>;
@@ -1471,6 +1471,12 @@ var SpaceFilesApi = class {
1471
1471
  const params = new URLSearchParams({ path });
1472
1472
  return `/api/spaces/${this.spaceId}/fs/download?${params.toString()}`;
1473
1473
  }
1474
+ createPreviewSession(customFetch) {
1475
+ return this.transport.request(`/api/spaces/${this.spaceId}/preview-session`, {
1476
+ method: "POST",
1477
+ fetch: customFetch
1478
+ });
1479
+ }
1474
1480
  async download(path, customFetch) {
1475
1481
  const params = new URLSearchParams({ path });
1476
1482
  const raw = await this.transport.raw(`/api/spaces/${this.spaceId}/fs/download?${params.toString()}`, { fetch: customFetch });
@@ -1923,6 +1929,13 @@ var SpaceChannelsApi = class {
1923
1929
  body: JSON.stringify({ config: config ?? null })
1924
1930
  });
1925
1931
  }
1932
+ updateConfig(channelId, config) {
1933
+ return this.transport.request(`/api/spaces/${this.spaceId}/channels/${channelId}`, {
1934
+ method: "PATCH",
1935
+ headers: { "Content-Type": "application/json" },
1936
+ body: JSON.stringify({ config: config ?? null })
1937
+ });
1938
+ }
1926
1939
  unbind(channelId) {
1927
1940
  return this.transport.request(`/api/spaces/${this.spaceId}/channels/${channelId}`, { method: "DELETE" });
1928
1941
  }
package/dist/index.d.ts CHANGED
@@ -136,9 +136,119 @@ declare class CohubClient {
136
136
  }
137
137
  declare const createCohubClient: (options?: CohubClientOptions) => CohubClient;
138
138
  //#endregion
139
+ //#region src/work-bridge-core.d.ts
140
+ /**
141
+ * The subset of a work record the bridge host needs to answer bridge messages.
142
+ * Matches what the iframe host (WorkSurface) and the broker page both have on
143
+ * hand after loading the work.
144
+ */
145
+ type WorkBridgeCoreWork = Pick<WorkRecord, "id" | "spaceId" | "slug" | "userUuid" | "workScopes" | "allowedViewerScopes">;
146
+ /**
147
+ * A pending authorize request surfaced to the UI as a consent dialog.
148
+ */
149
+ type WorkAuthorizeRequest = {
150
+ requestId: string;
151
+ scopes: Permission[];
152
+ reason?: string;
153
+ };
154
+ /**
155
+ * A pending purchase request surfaced to the UI as a checkout confirmation.
156
+ */
157
+ type WorkPurchaseRequest = {
158
+ requestId: string;
159
+ productKey: string;
160
+ };
161
+ /**
162
+ * Reactive dialog state managed by the core. The host (Svelte or React)
163
+ * subscribes via {@link WorkBridgeCoreConfig.onStateChange} and mirrors these
164
+ * fields into its own reactive primitives.
165
+ */
166
+ type WorkBridgeDialogState = {
167
+ authOpen: boolean;
168
+ pendingAuth: WorkAuthorizeRequest | null;
169
+ authError: string | null;
170
+ authSaving: boolean;
171
+ purchaseOpen: boolean;
172
+ pendingPurchase: WorkPurchaseRequest | null;
173
+ purchaseError: string | null;
174
+ purchaseSaving: boolean;
175
+ };
176
+ /**
177
+ * Resolves the current user's Cohub API access token. The core uses this to
178
+ * mint work session / authorization tokens via the Cohub API.
179
+ */
180
+ type WorkBridgeGetAccessToken = (options?: {
181
+ forceRefresh?: boolean;
182
+ }) => Promise<string | null>;
183
+ /**
184
+ * Resolves the current viewer's user UUID (or null when unauthenticated).
185
+ * Used for ownership checks and silent re-authorization cache lookups.
186
+ */
187
+ type WorkBridgeGetViewerUuid = () => Promise<string | null>;
188
+ /**
189
+ * Requests the host to start a sign-in flow, redirecting back to the given
190
+ * path afterward. The core calls this when an API request fails due to missing
191
+ * authentication.
192
+ */
193
+ type WorkBridgeRequestSignIn = (redirectPath: string) => Promise<void>;
194
+ /**
195
+ * Configuration injected by the caller. The core is transport-agnostic: how a
196
+ * reply is delivered back to the work (iframe postMessage vs opener
197
+ * postMessage) and how the current checkout state is read (page URL) are the
198
+ * caller's responsibility, so the same core serves both bridge and broker
199
+ * hosts. Auth dependencies (token resolution, viewer identity, sign-in) are
200
+ * also injected so the core stays free of any framework's store/auth plumbing.
201
+ */
202
+ type WorkBridgeCoreConfig = {
203
+ work: WorkBridgeCoreWork; /** True when running as a background chat surface (owner auto-authorizes). */
204
+ isBackground?: boolean; /** Base origin for Cohub API requests (e.g. "https://cohub.run"). */
205
+ apiOrigin: string; /** Sends a reply payload back to the work runtime. */
206
+ reply: (requestId: string, payload: Record<string, unknown>) => void; /** Reads the current checkout state (typically derived from the page URL). */
207
+ getCheckoutState: () => WorkRuntimeCheckoutState; /** Resolves the current user's Cohub access token. */
208
+ getAccessToken: WorkBridgeGetAccessToken; /** Resolves the current viewer's user UUID. */
209
+ getViewerUuid: WorkBridgeGetViewerUuid; /** Starts a sign-in flow with a post-login redirect path. */
210
+ requestSignIn: WorkBridgeRequestSignIn; /** Called whenever the dialog state changes, for reactive UI binding. */
211
+ onStateChange?: (state: WorkBridgeDialogState) => void;
212
+ };
213
+ type WorkBridgeCore = {
214
+ /** Returns a snapshot of the current dialog state. */getState: () => WorkBridgeDialogState; /** Processes an inbound bridge message (already source/origin-validated). */
215
+ handleMessage: (event: MessageEvent) => Promise<void>; /** Confirm/cancel handlers for the authorize dialog. */
216
+ confirmAuth: () => Promise<void>;
217
+ cancelAuth: () => void; /** Confirm/cancel handlers for the purchase dialog. */
218
+ confirmPurchase: () => Promise<void>;
219
+ cancelPurchase: () => void;
220
+ };
221
+ /**
222
+ * Framework-agnostic work bridge host core — message handling, work session
223
+ * token minting, authorization (with silent re-grant cache), and
224
+ * purchase/checkout flow — without any rendering or reactive primitives.
225
+ *
226
+ * Both the Cohub iframe host (WorkSurface, Svelte) and the standalone broker
227
+ * page compose this with their own transport-specific reply and auth
228
+ * dependencies. External hosts (e.g. Neta-Studio in React) can do the same.
229
+ */
230
+ declare function createWorkBridgeCore(config: WorkBridgeCoreConfig): WorkBridgeCore;
231
+ //#endregion
232
+ //#region src/work-grant-cache.d.ts
233
+ /**
234
+ * Returns true when the viewer has previously granted every requested scope
235
+ * for this work, allowing a silent re-authorization.
236
+ */
237
+ declare function hasGrantedWorkScopes(userUuid: string | null | undefined, workId: string, scopes: readonly Permission[]): boolean;
238
+ /**
239
+ * Records the granted scopes for a work, merged with any previously granted
240
+ * scopes so a growing permission set stays covered.
241
+ */
242
+ declare function setGrantedWorkScopes(userUuid: string | null | undefined, workId: string, scopes: readonly Permission[]): void;
243
+ /**
244
+ * Clears cached grants. Pass a workId to clear a single work, or omit it to
245
+ * clear every cached grant for the user (used on sign-out).
246
+ */
247
+ declare function clearGrantedWorkScopes(userUuid: string | null | undefined, workId?: string): void;
248
+ //#endregion
139
249
  //#region src/http-error.d.ts
140
250
  declare function isHttpErrorCode(error: unknown, code: string): error is HttpError & {
141
251
  code: string;
142
252
  };
143
253
  //#endregion
144
- export { AcceptInvitationResponse, ApiError, type AssistantMessageCommit, BatchUserProfilesResponse, BillingAccessWarning, BillingApi, BillingBalanceActivity, BillingBalanceActivityKind, BillingBalanceActivityList, BillingBalanceActivityStatus, BillingCatalog, BillingCatalogProduct, BillingCheckoutActionState, BillingCheckoutResult, BillingConversionIntent, BillingCreditExpiryGroup, BillingCreditGrantStatus, BillingCreditStatus, BillingCreditUnit, BillingHistoryPagination, BillingPaymentStatus, BillingPluginStatus, BillingProductBillingInterval, BillingProductCreditBenefit, BillingProductDisplay, BillingProductKind, BillingProductPricing, BillingRedemptionResult, BillingSubscriptionHistoryList, BillingSubscriptionHistoryStatus, BillingSubscriptionSummary, COHUB_ENVIRONMENTS, CanvasBootstrapResponse, CanvasCreateInput, CanvasDocumentRecord, CanvasNodeInput, CanvasNodeRecord, CanvasSemanticOp, CanvasTransactionInput, Channel, type ChannelConfig, type ChannelEnvelope, CheckpointRecord, CohubClient, type CohubClientOptions, type CohubEnvironment, CohubHttpClient, type ContentBlock, type CreateGenerationTaskRequest, type CreateGenerationTaskResponse, CreateInvitationInput, CreateInvitationResponse, type CreatePublicAssetUploadInput, type CreatePublicAssetUploadResponse, CreateSpaceInput, CreateSpaceModInput, CreateSpacePromptInput, CreateSpacePromptResponse, CreateSpaceSessionInput, CronJobPayload, CronJobRecord, CronJobUpdatePatch, CursorPageInfo, type DiscordChannelConfig, ExploreSection, ExploreSpaceItem, ExploreSpacesResponse, type Fetch, type GenerationContentBlock, type GenerationModelPolicy, type GenerationParameterConstraint, type GenerationPolicy, GenerationPolicyError, type GenerationStreamCommitEvent, type GenerationStreamErrorEvent, type GenerationStreamEvent, type GenerationStreamFinalizedEvent, type GenerationStreamIntermediateMessage, type GenerationStreamLifecycleEvent, type GenerationStreamOutOfSyncEvent, type GenerationStreamStateEvent, type GenerationStreamSubscribeOptions, type GenerationStreamSubscriptionHandlers, type GenerationStreamTurnUpdatedEvent, type GenerationTaskResult, GlobalSearchResponse, GlobalSearchResult, GlobalSearchType, HttpError, InvitationDetail, JsonObject, JsonPrimitive, JsonValue, LabelAssignmentListItem, LabelAssignmentPageInfo, LabelAssignmentRecord, type LabelAssignmentsUpdatedEvent, LabelListItem, LabelRecord, LabelResourceType, LabelScopeType, LabelSource, type ListGenerationModelsResponse, MeResponse, type MessageRecord, ModelCatalogEntry, ParentBridgeTransport, PatchResourceLabelsInput, PatchResourceLabelsResponse, Permission, PopupBrokerTransport, PromptAccessMode, PromptTemplateCatalogEntry, PromptTemplateCatalogResponse, type PublicAssetMimeType, type PublicAssetPurpose, type PublicGenerationDeclaration, PublicUserProfile, type RawHttpResponse, type RealtimeServerEvent, ReferenceAggregateGroup, ReferenceAggregateGroupBy, ReferenceAggregateResponse, ReferenceDirection, ReferenceKind, ReferenceQueryResponse, ReferenceQueryableType, ReferenceRecord, type ReferenceResourceSelector, ReferenceResourceType, ReferencesApi, ResourceLabelsResponse, SendMessageCronJobPayload, SessionBindingRecord, type SessionEventName, type SessionForkRecord, SessionGenerationStreamClient, SessionMessageResponse, SessionMessagesPaginatedResponse, SessionMessagesResponse, type SessionPatchApplyInput, type SessionPatchApplyResult, SessionPatchReducer, type SessionPatchState, type SessionPatchStatus, SessionRecord, type SessionSubscriptionHandlers, type SessionTurnIndexItem, SessionTurnIndexResponse, type SessionTurnRecord, SessionTurnResponse, type SessionTurnSegmentRecord, SessionTurnSignedUrlsResponse, SessionTurnStreamSnapshotResponse, SessionTurnWindowResponse, SessionTurnsPaginatedResponse, SpaceAccess, SpaceAccessPolicy, SpaceBootstrapSource, SpaceChannelBindingInput, type SpaceChannelBindingRecord, SpaceCheckpointDetailResponse, SpaceCommerceBenefit, SpaceCommerceBuyerProfile, SpaceCommerceCreditsBenefit, SpaceCommerceFeatureBenefit, SpaceCommerceOrder, SpaceCommerceProduct, SpaceCommerceProductBenefitBinding, SpaceCommerceProductCreditBenefit, SpaceConfig, SpaceConfigInput, SpaceConfigResponse, SpaceCreateResponse, SpaceDefaultResponse, SpaceEnvInput, type SpaceEventName, SpaceFsCompleteUploadInput, SpaceFsCompleteUploadResponse, SpaceFsCreateUploadInput, SpaceFsCreateUploadResponse, SpaceFsEncoding, SpaceFsEntry, SpaceFsFileKind, SpaceFsFileResponse, SpaceFsMoveInput, SpaceFsPreparingFile, SpaceFsReadFilesError, SpaceFsReadFilesInput, SpaceFsReadFilesResponse, SpaceFsTreeResponse, SpaceFsUploadDestination, SpaceFsUploadEntry, SpaceFsUploadError, SpaceFsUploadPlanEntry, SpaceFsUploadPlanEntryInput, SpaceFsUploadProgress, SpaceFsUploadResponse, SpaceFsWriteFileInput, SpaceInvitation, SpaceListItem, SpaceMember, SpaceMeta, SpaceModListItem, SpacePresenceSnapshot, SpacePresenceUser, SpacePublicProfile, SpaceRecord, SpaceRole, SpaceSandboxAutoDestroyPolicy, SpaceSandboxConfig, SpaceSandboxProvider, SpaceSessionsResponse, SpaceUsageHourlyStat, SpaceUsageResponse, SpaceUsageSummary, TaskRunDetailResponse, TaskRunRecord, type UploadChatImageAttachmentInput, type UploadPublicAssetInput, UserProfile, UserRulesResponse, UsersApi, VoiceApi, type VoiceInputCallbacks, VoiceInputClient, type VoiceInputClientOptions, type VoiceInputCreateOptions, type VoiceInputEvent, type WebSocketConnectionState, WebsocketClient, type WorkAuthorizeResponse, WorkCommerceApi, type WorkCommerceCheckoutStatus, type WorkCommerceCreditConsumeResponse, type WorkCommerceCreditConsumeStatus, type WorkCommerceEntitlement, type WorkCommerceEntitlementsResponse, type WorkCommerceOrder, type WorkCommerceProductResolveResponse, type WorkCommercePurchaseResponse, type WorkCreateInput, type WorkDetailResponse, type WorkGetResponse, type WorkMeta, type WorkPresentationMeta, type WorkPublicOwnerRecord, type WorkPublicSpaceRecord, type WorkRecord, type WorkResolveResponse, WorkRuntimeApi, type WorkRuntimeCheckoutState, type WorkRuntimeCheckoutStatus, type WorkRuntimeContext, type WorkRuntimeModeConfig, type WorkRuntimeRequestOptions, type WorkRuntimeTransport, type WorkSessionResponse, type WorkStatus, type WorkTargetType, type WorkUpdateInput, type WorkVersionRecord, type WorkVisibility, WorksApi, assertGenerationRequestAllowedByPolicy, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createVoiceInputClient, createWebsocketClient, createWorkRuntime, decodeGenerationPolicy, encodeGenerationPolicy, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, getAllowedGenerationModelIds, isHttpErrorCode, normalizeBaseUrl, normalizeGenerationPolicy, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAssistantMessageCommit, parseGenerationPolicyFromEnv, resolveApiBaseUrl, resolveCohubEnvironment, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, resolveWorkTransport };
254
+ export { AcceptInvitationResponse, ApiError, type AssistantMessageCommit, BatchUserProfilesResponse, BillingAccessWarning, BillingApi, BillingBalanceActivity, BillingBalanceActivityKind, BillingBalanceActivityList, BillingBalanceActivityStatus, BillingCatalog, BillingCatalogProduct, BillingCheckoutActionState, BillingCheckoutResult, BillingConversionIntent, BillingCreditExpiryGroup, BillingCreditGrantStatus, BillingCreditStatus, BillingCreditUnit, BillingHistoryPagination, BillingPaymentStatus, BillingPluginStatus, BillingProductBillingInterval, BillingProductCreditBenefit, BillingProductDisplay, BillingProductKind, BillingProductPricing, BillingRedemptionResult, BillingSubscriptionHistoryList, BillingSubscriptionHistoryStatus, BillingSubscriptionSummary, COHUB_ENVIRONMENTS, CanvasBootstrapResponse, CanvasCreateInput, CanvasDocumentRecord, CanvasNodeInput, CanvasNodeRecord, CanvasSemanticOp, CanvasTransactionInput, Channel, type ChannelConfig, type ChannelEnvelope, CheckpointRecord, CohubClient, type CohubClientOptions, type CohubEnvironment, CohubHttpClient, type ContentBlock, type CreateGenerationTaskRequest, type CreateGenerationTaskResponse, CreateInvitationInput, CreateInvitationResponse, type CreatePublicAssetUploadInput, type CreatePublicAssetUploadResponse, CreateSpaceInput, CreateSpaceModInput, CreateSpacePromptInput, CreateSpacePromptResponse, CreateSpaceSessionInput, CronJobPayload, CronJobRecord, CronJobUpdatePatch, CursorPageInfo, type DiscordChannelConfig, ExploreSection, ExploreSpaceItem, ExploreSpacesResponse, type Fetch, type GenerationContentBlock, type GenerationModelPolicy, type GenerationParameterConstraint, type GenerationPolicy, GenerationPolicyError, type GenerationStreamCommitEvent, type GenerationStreamErrorEvent, type GenerationStreamEvent, type GenerationStreamFinalizedEvent, type GenerationStreamIntermediateMessage, type GenerationStreamLifecycleEvent, type GenerationStreamOutOfSyncEvent, type GenerationStreamStateEvent, type GenerationStreamSubscribeOptions, type GenerationStreamSubscriptionHandlers, type GenerationStreamTurnUpdatedEvent, type GenerationTaskResult, GlobalSearchResponse, GlobalSearchResult, GlobalSearchType, HttpError, InvitationDetail, JsonObject, JsonPrimitive, JsonValue, LabelAssignmentListItem, LabelAssignmentPageInfo, LabelAssignmentRecord, type LabelAssignmentsUpdatedEvent, LabelListItem, LabelRecord, LabelResourceType, LabelScopeType, LabelSource, type ListGenerationModelsResponse, MeResponse, type MessageRecord, ModelCatalogEntry, ParentBridgeTransport, PatchResourceLabelsInput, PatchResourceLabelsResponse, Permission, PopupBrokerTransport, PromptAccessMode, PromptTemplateCatalogEntry, PromptTemplateCatalogResponse, type PublicAssetMimeType, type PublicAssetPurpose, type PublicGenerationDeclaration, PublicUserProfile, type RawHttpResponse, type RealtimeServerEvent, ReferenceAggregateGroup, ReferenceAggregateGroupBy, ReferenceAggregateResponse, ReferenceDirection, ReferenceKind, ReferenceQueryResponse, ReferenceQueryableType, ReferenceRecord, type ReferenceResourceSelector, ReferenceResourceType, ReferencesApi, ResourceLabelsResponse, SendMessageCronJobPayload, SessionBindingRecord, type SessionEventName, type SessionForkRecord, SessionGenerationStreamClient, SessionMessageResponse, SessionMessagesPaginatedResponse, SessionMessagesResponse, type SessionPatchApplyInput, type SessionPatchApplyResult, SessionPatchReducer, type SessionPatchState, type SessionPatchStatus, SessionRecord, type SessionSubscriptionHandlers, type SessionTurnIndexItem, SessionTurnIndexResponse, type SessionTurnRecord, SessionTurnResponse, type SessionTurnSegmentRecord, SessionTurnSignedUrlsResponse, SessionTurnStreamSnapshotResponse, SessionTurnWindowResponse, SessionTurnsPaginatedResponse, SpaceAccess, SpaceAccessPolicy, SpaceBootstrapSource, SpaceChannelBindingInput, type SpaceChannelBindingRecord, SpaceCheckpointDetailResponse, SpaceCommerceBenefit, SpaceCommerceBuyerProfile, SpaceCommerceCreditsBenefit, SpaceCommerceFeatureBenefit, SpaceCommerceOrder, SpaceCommerceProduct, SpaceCommerceProductBenefitBinding, SpaceCommerceProductCreditBenefit, SpaceConfig, SpaceConfigInput, SpaceConfigResponse, SpaceCreateResponse, SpaceDefaultResponse, SpaceEnvInput, type SpaceEventName, SpaceFsCompleteUploadInput, SpaceFsCompleteUploadResponse, SpaceFsCreateUploadInput, SpaceFsCreateUploadResponse, SpaceFsEncoding, SpaceFsEntry, SpaceFsFileKind, SpaceFsFileResponse, SpaceFsMoveInput, SpaceFsPreparingFile, SpaceFsReadFilesError, SpaceFsReadFilesInput, SpaceFsReadFilesResponse, SpaceFsTreeResponse, SpaceFsUploadDestination, SpaceFsUploadEntry, SpaceFsUploadError, SpaceFsUploadPlanEntry, SpaceFsUploadPlanEntryInput, SpaceFsUploadProgress, SpaceFsUploadResponse, SpaceFsWriteFileInput, SpaceInvitation, SpaceListItem, SpaceMember, SpaceMeta, SpaceModListItem, SpacePresenceSnapshot, SpacePresenceUser, SpacePublicProfile, SpaceRecord, SpaceRole, SpaceSandboxAutoDestroyPolicy, SpaceSandboxConfig, SpaceSandboxProvider, SpaceSessionsResponse, SpaceUsageHourlyStat, SpaceUsageResponse, SpaceUsageSummary, TaskRunDetailResponse, TaskRunRecord, type UploadChatImageAttachmentInput, type UploadPublicAssetInput, UserProfile, UserRulesResponse, UsersApi, VoiceApi, type VoiceInputCallbacks, VoiceInputClient, type VoiceInputClientOptions, type VoiceInputCreateOptions, type VoiceInputEvent, type WebSocketConnectionState, WebsocketClient, type WorkAuthorizeRequest, type WorkAuthorizeResponse, type WorkBridgeCore, type WorkBridgeCoreConfig, type WorkBridgeCoreWork, type WorkBridgeDialogState, type WorkBridgeGetAccessToken, type WorkBridgeGetViewerUuid, type WorkBridgeRequestSignIn, WorkCommerceApi, type WorkCommerceCheckoutStatus, type WorkCommerceCreditConsumeResponse, type WorkCommerceCreditConsumeStatus, type WorkCommerceEntitlement, type WorkCommerceEntitlementsResponse, type WorkCommerceOrder, type WorkCommerceProductResolveResponse, type WorkCommercePurchaseResponse, type WorkCreateInput, type WorkDetailResponse, type WorkGetResponse, type WorkMeta, type WorkPresentationMeta, type WorkPublicOwnerRecord, type WorkPublicSpaceRecord, type WorkPurchaseRequest, type WorkRecord, type WorkResolveResponse, WorkRuntimeApi, type WorkRuntimeCheckoutState, type WorkRuntimeCheckoutStatus, type WorkRuntimeContext, type WorkRuntimeModeConfig, type WorkRuntimeRequestOptions, type WorkRuntimeTransport, type WorkSessionResponse, type WorkStatus, type WorkTargetType, type WorkUpdateInput, type WorkVersionRecord, type WorkVisibility, WorksApi, assertGenerationRequestAllowedByPolicy, clearGrantedWorkScopes, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createVoiceInputClient, createWebsocketClient, createWorkBridgeCore, createWorkRuntime, decodeGenerationPolicy, encodeGenerationPolicy, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, getAllowedGenerationModelIds, hasGrantedWorkScopes, isHttpErrorCode, normalizeBaseUrl, normalizeGenerationPolicy, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAssistantMessageCommit, parseGenerationPolicyFromEnv, resolveApiBaseUrl, resolveCohubEnvironment, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, resolveWorkTransport, setGrantedWorkScopes };
package/dist/index.js CHANGED
@@ -97,10 +97,10 @@ var UsersApi = class {
97
97
  };
98
98
  //#endregion
99
99
  //#region src/work-runtime.ts
100
- const isBrowser = () => typeof window !== "undefined" && typeof window.parent !== "undefined";
101
- const hasParent = () => isBrowser() && window.parent !== window;
100
+ const isBrowser$1 = () => typeof window !== "undefined" && typeof window.parent !== "undefined";
101
+ const hasParent = () => isBrowser$1() && window.parent !== window;
102
102
  const getParentOrigin = () => {
103
- if (!isBrowser()) return null;
103
+ if (!isBrowser$1()) return null;
104
104
  const ancestorOrigin = window.location.ancestorOrigins?.[0];
105
105
  if (typeof ancestorOrigin === "string" && ancestorOrigin) return ancestorOrigin;
106
106
  try {
@@ -274,14 +274,22 @@ var PopupBrokerTransport = class {
274
274
  }
275
275
  };
276
276
  const TOKEN_STORAGE_PREFIX = "cohub:work-token";
277
+ const AUTHORIZED_SCOPES_STORAGE_PREFIX = "cohub:work-auth-scopes";
277
278
  var WorkRuntimeApi = class {
278
279
  token = null;
279
280
  transport;
280
281
  tokenStorageKey;
282
+ scopesStorageKey;
283
+ /** Scopes previously granted via requestAuthorization, retained so token
284
+ * refreshes can re-authorize (preserving viewerScopes) instead of falling
285
+ * back to a base session token that only carries workScopes. */
286
+ authorizedScopes = null;
281
287
  constructor(transport = new ParentBridgeTransport(), workId) {
282
288
  this.transport = transport;
283
289
  this.tokenStorageKey = workId ? `${TOKEN_STORAGE_PREFIX}:${workId}` : null;
290
+ this.scopesStorageKey = workId ? `${AUTHORIZED_SCOPES_STORAGE_PREFIX}:${workId}` : null;
284
291
  this.token = this.readStoredToken();
292
+ this.authorizedScopes = this.readStoredScopes();
285
293
  }
286
294
  readStoredToken() {
287
295
  if (!this.tokenStorageKey || typeof localStorage === "undefined") return null;
@@ -298,6 +306,24 @@ var WorkRuntimeApi = class {
298
306
  else localStorage.removeItem(this.tokenStorageKey);
299
307
  } catch {}
300
308
  }
309
+ readStoredScopes() {
310
+ if (!this.scopesStorageKey || typeof localStorage === "undefined") return null;
311
+ try {
312
+ const raw = localStorage.getItem(this.scopesStorageKey);
313
+ if (!raw) return null;
314
+ const parsed = JSON.parse(raw);
315
+ return Array.isArray(parsed) && parsed.every((s) => typeof s === "string") ? parsed : null;
316
+ } catch {
317
+ return null;
318
+ }
319
+ }
320
+ writeStoredScopes(scopes) {
321
+ if (!this.scopesStorageKey || typeof localStorage === "undefined") return;
322
+ try {
323
+ if (scopes && scopes.length > 0) localStorage.setItem(this.scopesStorageKey, JSON.stringify(scopes));
324
+ else localStorage.removeItem(this.scopesStorageKey);
325
+ } catch {}
326
+ }
301
327
  async context() {
302
328
  return (await this.transport.request({ type: "cohub.work.context" }, {
303
329
  timeoutMs: 8e3,
@@ -310,6 +336,15 @@ var WorkRuntimeApi = class {
310
336
  this.token = null;
311
337
  this.writeStoredToken(null);
312
338
  }
339
+ if (options?.forceRefresh && this.authorizedScopes && this.authorizedScopes.length > 0) {
340
+ const response = await this.transport.request({
341
+ type: "cohub.work.authorize",
342
+ scopes: this.authorizedScopes
343
+ }, { timeoutMs: 12e4 });
344
+ this.token = response?.token ?? null;
345
+ this.writeStoredToken(this.token);
346
+ return this.token;
347
+ }
313
348
  const response = await this.transport.request({
314
349
  type: "cohub.work.token",
315
350
  forceRefresh: Boolean(options?.forceRefresh)
@@ -326,6 +361,10 @@ var WorkRuntimeApi = class {
326
361
  }, { timeoutMs: 12e4 });
327
362
  this.token = response?.token ?? null;
328
363
  this.writeStoredToken(this.token);
364
+ if (this.token) {
365
+ this.authorizedScopes = input.scopes;
366
+ this.writeStoredScopes(input.scopes);
367
+ }
329
368
  return Boolean(this.token);
330
369
  }
331
370
  async purchase(input) {
@@ -515,6 +554,414 @@ var CohubClient = class {
515
554
  };
516
555
  const createCohubClient = (options) => new CohubClient(options);
517
556
  //#endregion
557
+ //#region src/work-grant-cache.ts
558
+ const STORAGE_PREFIX = "cohub:work-grants";
559
+ const CACHE_VERSION = 1;
560
+ const MAX_AGE_MS = 336 * 60 * 60 * 1e3;
561
+ function isBrowser() {
562
+ return typeof localStorage !== "undefined";
563
+ }
564
+ function storageKey(userUuid, workId) {
565
+ return `${STORAGE_PREFIX}:${encodeURIComponent(userUuid)}:${encodeURIComponent(workId)}:v${CACHE_VERSION}`;
566
+ }
567
+ function userPrefix(userUuid) {
568
+ return `${STORAGE_PREFIX}:${encodeURIComponent(userUuid)}:`;
569
+ }
570
+ function isPermissionArray(value) {
571
+ return Array.isArray(value) && value.every((v) => typeof v === "string");
572
+ }
573
+ function isCachedWorkGrant(value) {
574
+ if (!value || typeof value !== "object") return false;
575
+ const record = value;
576
+ return record.version === CACHE_VERSION && typeof record.userUuid === "string" && typeof record.workId === "string" && isPermissionArray(record.scopes) && typeof record.updatedAt === "number";
577
+ }
578
+ function readEntry(userUuid, workId) {
579
+ if (!isBrowser()) return null;
580
+ const key = storageKey(userUuid, workId);
581
+ try {
582
+ const raw = localStorage.getItem(key);
583
+ if (!raw) return null;
584
+ const parsed = JSON.parse(raw);
585
+ if (!isCachedWorkGrant(parsed) || parsed.userUuid !== userUuid || parsed.workId !== workId) {
586
+ localStorage.removeItem(key);
587
+ return null;
588
+ }
589
+ if (Date.now() - parsed.updatedAt > MAX_AGE_MS) {
590
+ localStorage.removeItem(key);
591
+ return null;
592
+ }
593
+ return parsed;
594
+ } catch {
595
+ try {
596
+ localStorage.removeItem(key);
597
+ } catch {}
598
+ return null;
599
+ }
600
+ }
601
+ /**
602
+ * Returns true when the viewer has previously granted every requested scope
603
+ * for this work, allowing a silent re-authorization.
604
+ */
605
+ function hasGrantedWorkScopes(userUuid, workId, scopes) {
606
+ if (!userUuid || !workId || scopes.length === 0) return false;
607
+ const entry = readEntry(userUuid, workId);
608
+ if (!entry) return false;
609
+ const granted = new Set(entry.scopes);
610
+ return scopes.every((scope) => granted.has(scope));
611
+ }
612
+ /**
613
+ * Records the granted scopes for a work, merged with any previously granted
614
+ * scopes so a growing permission set stays covered.
615
+ */
616
+ function setGrantedWorkScopes(userUuid, workId, scopes) {
617
+ if (!userUuid || !workId || scopes.length === 0) return;
618
+ const existing = readEntry(userUuid, workId);
619
+ const entry = {
620
+ version: CACHE_VERSION,
621
+ userUuid,
622
+ workId,
623
+ scopes: Array.from(new Set([...existing?.scopes ?? [], ...scopes])),
624
+ updatedAt: Date.now()
625
+ };
626
+ if (!isBrowser()) return;
627
+ try {
628
+ localStorage.setItem(storageKey(userUuid, workId), JSON.stringify(entry));
629
+ } catch {}
630
+ }
631
+ /**
632
+ * Clears cached grants. Pass a workId to clear a single work, or omit it to
633
+ * clear every cached grant for the user (used on sign-out).
634
+ */
635
+ function clearGrantedWorkScopes(userUuid, workId) {
636
+ if (!isBrowser() || !userUuid) return;
637
+ try {
638
+ if (workId) {
639
+ localStorage.removeItem(storageKey(userUuid, workId));
640
+ return;
641
+ }
642
+ const prefix = userPrefix(userUuid);
643
+ for (let i = localStorage.length - 1; i >= 0; i -= 1) {
644
+ const key = localStorage.key(i);
645
+ if (key?.startsWith(prefix)) localStorage.removeItem(key);
646
+ }
647
+ } catch {}
648
+ }
649
+ //#endregion
650
+ //#region src/work-bridge-core.ts
651
+ function readTokenResponse(value) {
652
+ if (!value || typeof value !== "object") return null;
653
+ const token = value.token;
654
+ return typeof token === "string" && token ? token : null;
655
+ }
656
+ function clonePermissionScopes(scopes) {
657
+ return Array.from(scopes ?? []).filter((scope) => typeof scope === "string");
658
+ }
659
+ /**
660
+ * Framework-agnostic work bridge host core — message handling, work session
661
+ * token minting, authorization (with silent re-grant cache), and
662
+ * purchase/checkout flow — without any rendering or reactive primitives.
663
+ *
664
+ * Both the Cohub iframe host (WorkSurface, Svelte) and the standalone broker
665
+ * page compose this with their own transport-specific reply and auth
666
+ * dependencies. External hosts (e.g. Neta-Studio in React) can do the same.
667
+ */
668
+ function createWorkBridgeCore(config) {
669
+ const { work, reply, getCheckoutState, getAccessToken, getViewerUuid } = config;
670
+ const apiOrigin = config.apiOrigin;
671
+ const isBackground = config.isBackground ?? false;
672
+ const onStateChange = config.onStateChange;
673
+ let workToken = null;
674
+ const state = {
675
+ authOpen: false,
676
+ pendingAuth: null,
677
+ authError: null,
678
+ authSaving: false,
679
+ purchaseOpen: false,
680
+ pendingPurchase: null,
681
+ purchaseError: null,
682
+ purchaseSaving: false
683
+ };
684
+ function notify() {
685
+ onStateChange?.({ ...state });
686
+ }
687
+ const pendingPurchaseStorageKey = `cohub-work-purchase:${work.id}`;
688
+ async function isCurrentViewerWorkOwner() {
689
+ const viewerUuid = await getViewerUuid();
690
+ return Boolean(viewerUuid && viewerUuid === work.userUuid);
691
+ }
692
+ async function ensureBaseToken(forceRefresh = false) {
693
+ if (workToken && !forceRefresh) return workToken;
694
+ const userToken = await getAccessToken({ forceRefresh });
695
+ if (!userToken) {
696
+ await config.requestSignIn(typeof location !== "undefined" ? location.pathname : "/");
697
+ return null;
698
+ }
699
+ const response = await fetch(`${apiOrigin}/api/works/${work.id}/session`, {
700
+ method: "POST",
701
+ headers: { Authorization: `Bearer ${userToken}` }
702
+ });
703
+ if (!response.ok) throw new Error("Failed to create work session.");
704
+ const token = readTokenResponse(await response.json());
705
+ if (!token) throw new Error("Invalid work session response.");
706
+ workToken = token;
707
+ return workToken;
708
+ }
709
+ async function authorize(scopes) {
710
+ const userToken = await getAccessToken();
711
+ if (!userToken) {
712
+ await config.requestSignIn(typeof location !== "undefined" ? location.pathname : "/");
713
+ return null;
714
+ }
715
+ const response = await fetch(`${apiOrigin}/api/works/${work.id}/authorize`, {
716
+ method: "POST",
717
+ headers: {
718
+ Authorization: `Bearer ${userToken}`,
719
+ "Content-Type": "application/json"
720
+ },
721
+ body: JSON.stringify({ scopes })
722
+ });
723
+ if (!response.ok) throw new Error((await response.json().catch(() => null))?.message ?? "Authorization failed.");
724
+ const token = readTokenResponse(await response.json());
725
+ if (!token) throw new Error("Invalid work authorization response.");
726
+ workToken = token;
727
+ return workToken;
728
+ }
729
+ function writePendingPurchase(input) {
730
+ if (typeof sessionStorage === "undefined") return;
731
+ try {
732
+ sessionStorage.setItem(pendingPurchaseStorageKey, JSON.stringify({
733
+ ...input,
734
+ at: Date.now()
735
+ }));
736
+ } catch {}
737
+ }
738
+ function readPendingPurchase() {
739
+ if (typeof sessionStorage === "undefined") return null;
740
+ try {
741
+ const raw = sessionStorage.getItem(pendingPurchaseStorageKey);
742
+ if (!raw) return null;
743
+ const parsed = JSON.parse(raw);
744
+ return typeof parsed.orderId === "string" && typeof parsed.productKey === "string" && typeof parsed.at === "number" ? {
745
+ orderId: parsed.orderId,
746
+ productKey: parsed.productKey,
747
+ at: parsed.at
748
+ } : null;
749
+ } catch {
750
+ return null;
751
+ }
752
+ }
753
+ function clearPendingPurchase() {
754
+ if (typeof sessionStorage === "undefined") return;
755
+ try {
756
+ sessionStorage.removeItem(pendingPurchaseStorageKey);
757
+ } catch {}
758
+ }
759
+ async function createPurchase(productKey) {
760
+ const userToken = await getAccessToken();
761
+ if (!userToken) {
762
+ await config.requestSignIn(typeof location !== "undefined" ? location.pathname + location.search + location.hash : "/");
763
+ return null;
764
+ }
765
+ const response = await fetch(`${apiOrigin}/api/works/${work.id}/commerce/purchase`, {
766
+ method: "POST",
767
+ headers: {
768
+ Authorization: `Bearer ${userToken}`,
769
+ "Content-Type": "application/json"
770
+ },
771
+ body: JSON.stringify({ productKey })
772
+ });
773
+ if (!response.ok) throw new Error((await response.json().catch(() => null))?.message ?? "Purchase failed.");
774
+ return (await response.json()).checkout ?? null;
775
+ }
776
+ async function handleMessage(event) {
777
+ const data = event.data;
778
+ if (!data?.requestId) return;
779
+ try {
780
+ if (data.type === "cohub.work.context") {
781
+ const workScopes = clonePermissionScopes(work.workScopes);
782
+ reply(data.requestId, {
783
+ type: "cohub.work.context.result",
784
+ context: {
785
+ work: {
786
+ id: work.id,
787
+ slug: work.slug,
788
+ url: typeof location !== "undefined" ? location.href : ""
789
+ },
790
+ space: { id: work.spaceId },
791
+ permissions: {
792
+ scopes: workScopes,
793
+ workScopes,
794
+ viewerScopes: []
795
+ }
796
+ }
797
+ });
798
+ }
799
+ if (data.type === "cohub.work.token") {
800
+ const token = await ensureBaseToken(Boolean(data.forceRefresh));
801
+ reply(data.requestId, {
802
+ type: "cohub.work.token.result",
803
+ token
804
+ });
805
+ }
806
+ if (data.type === "cohub.work.checkout-state") {
807
+ const pending = readPendingPurchase();
808
+ const checkoutState = getCheckoutState();
809
+ const orderId = checkoutState.orderId ?? pending?.orderId ?? null;
810
+ if (checkoutState.status && checkoutState.orderId) clearPendingPurchase();
811
+ reply(data.requestId, {
812
+ type: "cohub.work.checkout-state.result",
813
+ status: checkoutState.status,
814
+ orderId
815
+ });
816
+ }
817
+ if (data.type === "cohub.work.purchase") {
818
+ const productKey = typeof data.productKey === "string" ? data.productKey.trim() : "";
819
+ if (!productKey) {
820
+ reply(data.requestId, {
821
+ type: "cohub.work.error",
822
+ message: "Product key is required."
823
+ });
824
+ return;
825
+ }
826
+ state.pendingPurchase = {
827
+ requestId: data.requestId,
828
+ productKey
829
+ };
830
+ state.purchaseError = null;
831
+ state.purchaseOpen = true;
832
+ notify();
833
+ }
834
+ if (data.type === "cohub.work.authorize") {
835
+ const allowedViewerScopes = clonePermissionScopes(work.allowedViewerScopes);
836
+ const scopes = clonePermissionScopes(data.scopes).filter((scope) => allowedViewerScopes.includes(scope));
837
+ if (scopes.length === 0) {
838
+ reply(data.requestId, {
839
+ type: "cohub.work.error",
840
+ message: "No allowed scopes requested."
841
+ });
842
+ return;
843
+ }
844
+ if (isBackground && await isCurrentViewerWorkOwner()) {
845
+ const token = await authorize(scopes);
846
+ reply(data.requestId, {
847
+ type: "cohub.work.authorize.result",
848
+ token
849
+ });
850
+ return;
851
+ }
852
+ const viewerUuid = await getViewerUuid();
853
+ if (viewerUuid && hasGrantedWorkScopes(viewerUuid, work.id, scopes)) try {
854
+ const token = await authorize(scopes);
855
+ reply(data.requestId, {
856
+ type: "cohub.work.authorize.result",
857
+ token
858
+ });
859
+ return;
860
+ } catch {
861
+ clearGrantedWorkScopes(viewerUuid, work.id);
862
+ }
863
+ state.pendingAuth = {
864
+ requestId: data.requestId,
865
+ scopes,
866
+ reason: data.reason
867
+ };
868
+ state.authError = null;
869
+ state.authOpen = true;
870
+ notify();
871
+ }
872
+ } catch (error) {
873
+ reply(data.requestId, {
874
+ type: "cohub.work.error",
875
+ message: error instanceof Error ? error.message : "Request failed."
876
+ });
877
+ }
878
+ }
879
+ function cancelAuth() {
880
+ if (state.authSaving) return;
881
+ if (!state.pendingAuth) return;
882
+ reply(state.pendingAuth.requestId, {
883
+ type: "cohub.work.authorize.result",
884
+ token: null
885
+ });
886
+ state.authOpen = false;
887
+ state.pendingAuth = null;
888
+ state.authError = null;
889
+ state.authSaving = false;
890
+ notify();
891
+ }
892
+ function cancelPurchase() {
893
+ if (state.purchaseSaving) return;
894
+ if (!state.pendingPurchase) return;
895
+ reply(state.pendingPurchase.requestId, {
896
+ type: "cohub.work.purchase.result",
897
+ checkout: null
898
+ });
899
+ state.purchaseOpen = false;
900
+ state.purchaseError = null;
901
+ state.pendingPurchase = null;
902
+ state.purchaseSaving = false;
903
+ notify();
904
+ }
905
+ async function confirmPurchase() {
906
+ if (!state.pendingPurchase || state.purchaseSaving) return;
907
+ state.purchaseSaving = true;
908
+ state.purchaseError = null;
909
+ notify();
910
+ try {
911
+ const checkout = await createPurchase(state.pendingPurchase.productKey);
912
+ reply(state.pendingPurchase.requestId, {
913
+ type: "cohub.work.purchase.result",
914
+ checkout
915
+ });
916
+ if (checkout && typeof checkout === "object") {
917
+ const next = checkout;
918
+ if (typeof next.orderId === "string" && typeof next.productKey === "string") writePendingPurchase({
919
+ orderId: next.orderId,
920
+ productKey: next.productKey
921
+ });
922
+ const url = next.checkoutUrl;
923
+ if (next.checkoutUsable === true && typeof url === "string" && url) window.location.href = url;
924
+ }
925
+ state.purchaseOpen = false;
926
+ state.pendingPurchase = null;
927
+ } catch (error) {
928
+ state.purchaseError = error instanceof Error ? error.message : "Purchase failed.";
929
+ } finally {
930
+ state.purchaseSaving = false;
931
+ notify();
932
+ }
933
+ }
934
+ async function confirmAuth() {
935
+ if (!state.pendingAuth || state.authSaving) return;
936
+ state.authError = null;
937
+ state.authSaving = true;
938
+ notify();
939
+ try {
940
+ const token = await authorize(state.pendingAuth.scopes);
941
+ setGrantedWorkScopes(await getViewerUuid(), work.id, state.pendingAuth.scopes);
942
+ reply(state.pendingAuth.requestId, {
943
+ type: "cohub.work.authorize.result",
944
+ token
945
+ });
946
+ state.authOpen = false;
947
+ state.pendingAuth = null;
948
+ } catch (error) {
949
+ state.authError = error instanceof Error ? error.message : "Authorization failed.";
950
+ } finally {
951
+ state.authSaving = false;
952
+ notify();
953
+ }
954
+ }
955
+ return {
956
+ getState: () => ({ ...state }),
957
+ handleMessage,
958
+ confirmAuth,
959
+ cancelAuth,
960
+ confirmPurchase,
961
+ cancelPurchase
962
+ };
963
+ }
964
+ //#endregion
518
965
  //#region src/http-error.ts
519
966
  function isHttpErrorCode(error, code) {
520
967
  return error instanceof HttpError && error.code === code;
@@ -751,4 +1198,4 @@ function filterGenerationDeclarationsByPolicy(declarations, policy) {
751
1198
  });
752
1199
  }
753
1200
  //#endregion
754
- export { BillingApi, COHUB_ENVIRONMENTS, CohubClient, CohubHttpClient, GenerationPolicyError, HttpError, ParentBridgeTransport, PopupBrokerTransport, ReferencesApi, SessionGenerationStreamClient, SessionPatchReducer, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRuntimeApi, WorksApi, assertGenerationRequestAllowedByPolicy, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createVoiceInputClient, createWebsocketClient, createWorkRuntime, decodeGenerationPolicy, encodeGenerationPolicy, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, getAllowedGenerationModelIds, isHttpErrorCode, normalizeBaseUrl, normalizeGenerationPolicy, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAssistantMessageCommit, parseGenerationPolicyFromEnv, resolveApiBaseUrl, resolveCohubEnvironment, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, resolveWorkTransport };
1201
+ export { BillingApi, COHUB_ENVIRONMENTS, CohubClient, CohubHttpClient, GenerationPolicyError, HttpError, ParentBridgeTransport, PopupBrokerTransport, ReferencesApi, SessionGenerationStreamClient, SessionPatchReducer, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRuntimeApi, WorksApi, assertGenerationRequestAllowedByPolicy, clearGrantedWorkScopes, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createVoiceInputClient, createWebsocketClient, createWorkBridgeCore, createWorkRuntime, decodeGenerationPolicy, encodeGenerationPolicy, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, getAllowedGenerationModelIds, hasGrantedWorkScopes, isHttpErrorCode, normalizeBaseUrl, normalizeGenerationPolicy, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAssistantMessageCommit, parseGenerationPolicyFromEnv, resolveApiBaseUrl, resolveCohubEnvironment, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, resolveWorkTransport, setGrantedWorkScopes };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neta-art/cohub",
3
- "version": "2.4.0",
3
+ "version": "2.6.0",
4
4
  "description": "Cohub SDK for spaces, sessions, checkpoints, and realtime agent collaboration.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,