@neta-art/cohub 2.4.0 → 2.5.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
@@ -2190,7 +2197,7 @@ type SpaceChannelBindingRecord = {
2190
2197
  id: string;
2191
2198
  spaceId: string;
2192
2199
  channelId: string;
2193
- config: Record<string, unknown> | null;
2200
+ config: ChannelConfig | null;
2194
2201
  createdAt: string;
2195
2202
  channel: {
2196
2203
  id: string;
@@ -2207,7 +2214,8 @@ declare class SpaceChannelsApi {
2207
2214
  private readonly spaceId;
2208
2215
  constructor(transport: HttpTransport, spaceId: string);
2209
2216
  list(): Promise<SpaceChannelBindingRecord[]>;
2210
- bind(channelId: string, config?: Record<string, unknown> | null): Promise<SpaceChannelBindingRecord>;
2217
+ bind(channelId: string, config?: ChannelConfig | null): Promise<SpaceChannelBindingRecord>;
2218
+ updateConfig(channelId: string, config?: ChannelConfig | null): Promise<SpaceChannelBindingRecord>;
2211
2219
  unbind(channelId: string): Promise<{
2212
2220
  ok: true;
2213
2221
  }>;
@@ -1923,6 +1923,13 @@ var SpaceChannelsApi = class {
1923
1923
  body: JSON.stringify({ config: config ?? null })
1924
1924
  });
1925
1925
  }
1926
+ updateConfig(channelId, config) {
1927
+ return this.transport.request(`/api/spaces/${this.spaceId}/channels/${channelId}`, {
1928
+ method: "PATCH",
1929
+ headers: { "Content-Type": "application/json" },
1930
+ body: JSON.stringify({ config: config ?? null })
1931
+ });
1932
+ }
1926
1933
  unbind(channelId) {
1927
1934
  return this.transport.request(`/api/spaces/${this.spaceId}/channels/${channelId}`, { method: "DELETE" });
1928
1935
  }
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 {
@@ -515,6 +515,414 @@ var CohubClient = class {
515
515
  };
516
516
  const createCohubClient = (options) => new CohubClient(options);
517
517
  //#endregion
518
+ //#region src/work-grant-cache.ts
519
+ const STORAGE_PREFIX = "cohub:work-grants";
520
+ const CACHE_VERSION = 1;
521
+ const MAX_AGE_MS = 336 * 60 * 60 * 1e3;
522
+ function isBrowser() {
523
+ return typeof localStorage !== "undefined";
524
+ }
525
+ function storageKey(userUuid, workId) {
526
+ return `${STORAGE_PREFIX}:${encodeURIComponent(userUuid)}:${encodeURIComponent(workId)}:v${CACHE_VERSION}`;
527
+ }
528
+ function userPrefix(userUuid) {
529
+ return `${STORAGE_PREFIX}:${encodeURIComponent(userUuid)}:`;
530
+ }
531
+ function isPermissionArray(value) {
532
+ return Array.isArray(value) && value.every((v) => typeof v === "string");
533
+ }
534
+ function isCachedWorkGrant(value) {
535
+ if (!value || typeof value !== "object") return false;
536
+ const record = value;
537
+ return record.version === CACHE_VERSION && typeof record.userUuid === "string" && typeof record.workId === "string" && isPermissionArray(record.scopes) && typeof record.updatedAt === "number";
538
+ }
539
+ function readEntry(userUuid, workId) {
540
+ if (!isBrowser()) return null;
541
+ const key = storageKey(userUuid, workId);
542
+ try {
543
+ const raw = localStorage.getItem(key);
544
+ if (!raw) return null;
545
+ const parsed = JSON.parse(raw);
546
+ if (!isCachedWorkGrant(parsed) || parsed.userUuid !== userUuid || parsed.workId !== workId) {
547
+ localStorage.removeItem(key);
548
+ return null;
549
+ }
550
+ if (Date.now() - parsed.updatedAt > MAX_AGE_MS) {
551
+ localStorage.removeItem(key);
552
+ return null;
553
+ }
554
+ return parsed;
555
+ } catch {
556
+ try {
557
+ localStorage.removeItem(key);
558
+ } catch {}
559
+ return null;
560
+ }
561
+ }
562
+ /**
563
+ * Returns true when the viewer has previously granted every requested scope
564
+ * for this work, allowing a silent re-authorization.
565
+ */
566
+ function hasGrantedWorkScopes(userUuid, workId, scopes) {
567
+ if (!userUuid || !workId || scopes.length === 0) return false;
568
+ const entry = readEntry(userUuid, workId);
569
+ if (!entry) return false;
570
+ const granted = new Set(entry.scopes);
571
+ return scopes.every((scope) => granted.has(scope));
572
+ }
573
+ /**
574
+ * Records the granted scopes for a work, merged with any previously granted
575
+ * scopes so a growing permission set stays covered.
576
+ */
577
+ function setGrantedWorkScopes(userUuid, workId, scopes) {
578
+ if (!userUuid || !workId || scopes.length === 0) return;
579
+ const existing = readEntry(userUuid, workId);
580
+ const entry = {
581
+ version: CACHE_VERSION,
582
+ userUuid,
583
+ workId,
584
+ scopes: Array.from(new Set([...existing?.scopes ?? [], ...scopes])),
585
+ updatedAt: Date.now()
586
+ };
587
+ if (!isBrowser()) return;
588
+ try {
589
+ localStorage.setItem(storageKey(userUuid, workId), JSON.stringify(entry));
590
+ } catch {}
591
+ }
592
+ /**
593
+ * Clears cached grants. Pass a workId to clear a single work, or omit it to
594
+ * clear every cached grant for the user (used on sign-out).
595
+ */
596
+ function clearGrantedWorkScopes(userUuid, workId) {
597
+ if (!isBrowser() || !userUuid) return;
598
+ try {
599
+ if (workId) {
600
+ localStorage.removeItem(storageKey(userUuid, workId));
601
+ return;
602
+ }
603
+ const prefix = userPrefix(userUuid);
604
+ for (let i = localStorage.length - 1; i >= 0; i -= 1) {
605
+ const key = localStorage.key(i);
606
+ if (key?.startsWith(prefix)) localStorage.removeItem(key);
607
+ }
608
+ } catch {}
609
+ }
610
+ //#endregion
611
+ //#region src/work-bridge-core.ts
612
+ function readTokenResponse(value) {
613
+ if (!value || typeof value !== "object") return null;
614
+ const token = value.token;
615
+ return typeof token === "string" && token ? token : null;
616
+ }
617
+ function clonePermissionScopes(scopes) {
618
+ return Array.from(scopes ?? []).filter((scope) => typeof scope === "string");
619
+ }
620
+ /**
621
+ * Framework-agnostic work bridge host core — message handling, work session
622
+ * token minting, authorization (with silent re-grant cache), and
623
+ * purchase/checkout flow — without any rendering or reactive primitives.
624
+ *
625
+ * Both the Cohub iframe host (WorkSurface, Svelte) and the standalone broker
626
+ * page compose this with their own transport-specific reply and auth
627
+ * dependencies. External hosts (e.g. Neta-Studio in React) can do the same.
628
+ */
629
+ function createWorkBridgeCore(config) {
630
+ const { work, reply, getCheckoutState, getAccessToken, getViewerUuid } = config;
631
+ const apiOrigin = config.apiOrigin;
632
+ const isBackground = config.isBackground ?? false;
633
+ const onStateChange = config.onStateChange;
634
+ let workToken = null;
635
+ const state = {
636
+ authOpen: false,
637
+ pendingAuth: null,
638
+ authError: null,
639
+ authSaving: false,
640
+ purchaseOpen: false,
641
+ pendingPurchase: null,
642
+ purchaseError: null,
643
+ purchaseSaving: false
644
+ };
645
+ function notify() {
646
+ onStateChange?.({ ...state });
647
+ }
648
+ const pendingPurchaseStorageKey = `cohub-work-purchase:${work.id}`;
649
+ async function isCurrentViewerWorkOwner() {
650
+ const viewerUuid = await getViewerUuid();
651
+ return Boolean(viewerUuid && viewerUuid === work.userUuid);
652
+ }
653
+ async function ensureBaseToken(forceRefresh = false) {
654
+ if (workToken && !forceRefresh) return workToken;
655
+ const userToken = await getAccessToken({ forceRefresh });
656
+ if (!userToken) {
657
+ await config.requestSignIn(typeof location !== "undefined" ? location.pathname : "/");
658
+ return null;
659
+ }
660
+ const response = await fetch(`${apiOrigin}/api/works/${work.id}/session`, {
661
+ method: "POST",
662
+ headers: { Authorization: `Bearer ${userToken}` }
663
+ });
664
+ if (!response.ok) throw new Error("Failed to create work session.");
665
+ const token = readTokenResponse(await response.json());
666
+ if (!token) throw new Error("Invalid work session response.");
667
+ workToken = token;
668
+ return workToken;
669
+ }
670
+ async function authorize(scopes) {
671
+ const userToken = await getAccessToken();
672
+ if (!userToken) {
673
+ await config.requestSignIn(typeof location !== "undefined" ? location.pathname : "/");
674
+ return null;
675
+ }
676
+ const response = await fetch(`${apiOrigin}/api/works/${work.id}/authorize`, {
677
+ method: "POST",
678
+ headers: {
679
+ Authorization: `Bearer ${userToken}`,
680
+ "Content-Type": "application/json"
681
+ },
682
+ body: JSON.stringify({ scopes })
683
+ });
684
+ if (!response.ok) throw new Error((await response.json().catch(() => null))?.message ?? "Authorization failed.");
685
+ const token = readTokenResponse(await response.json());
686
+ if (!token) throw new Error("Invalid work authorization response.");
687
+ workToken = token;
688
+ return workToken;
689
+ }
690
+ function writePendingPurchase(input) {
691
+ if (typeof sessionStorage === "undefined") return;
692
+ try {
693
+ sessionStorage.setItem(pendingPurchaseStorageKey, JSON.stringify({
694
+ ...input,
695
+ at: Date.now()
696
+ }));
697
+ } catch {}
698
+ }
699
+ function readPendingPurchase() {
700
+ if (typeof sessionStorage === "undefined") return null;
701
+ try {
702
+ const raw = sessionStorage.getItem(pendingPurchaseStorageKey);
703
+ if (!raw) return null;
704
+ const parsed = JSON.parse(raw);
705
+ return typeof parsed.orderId === "string" && typeof parsed.productKey === "string" && typeof parsed.at === "number" ? {
706
+ orderId: parsed.orderId,
707
+ productKey: parsed.productKey,
708
+ at: parsed.at
709
+ } : null;
710
+ } catch {
711
+ return null;
712
+ }
713
+ }
714
+ function clearPendingPurchase() {
715
+ if (typeof sessionStorage === "undefined") return;
716
+ try {
717
+ sessionStorage.removeItem(pendingPurchaseStorageKey);
718
+ } catch {}
719
+ }
720
+ async function createPurchase(productKey) {
721
+ const userToken = await getAccessToken();
722
+ if (!userToken) {
723
+ await config.requestSignIn(typeof location !== "undefined" ? location.pathname + location.search + location.hash : "/");
724
+ return null;
725
+ }
726
+ const response = await fetch(`${apiOrigin}/api/works/${work.id}/commerce/purchase`, {
727
+ method: "POST",
728
+ headers: {
729
+ Authorization: `Bearer ${userToken}`,
730
+ "Content-Type": "application/json"
731
+ },
732
+ body: JSON.stringify({ productKey })
733
+ });
734
+ if (!response.ok) throw new Error((await response.json().catch(() => null))?.message ?? "Purchase failed.");
735
+ return (await response.json()).checkout ?? null;
736
+ }
737
+ async function handleMessage(event) {
738
+ const data = event.data;
739
+ if (!data?.requestId) return;
740
+ try {
741
+ if (data.type === "cohub.work.context") {
742
+ const workScopes = clonePermissionScopes(work.workScopes);
743
+ reply(data.requestId, {
744
+ type: "cohub.work.context.result",
745
+ context: {
746
+ work: {
747
+ id: work.id,
748
+ slug: work.slug,
749
+ url: typeof location !== "undefined" ? location.href : ""
750
+ },
751
+ space: { id: work.spaceId },
752
+ permissions: {
753
+ scopes: workScopes,
754
+ workScopes,
755
+ viewerScopes: []
756
+ }
757
+ }
758
+ });
759
+ }
760
+ if (data.type === "cohub.work.token") {
761
+ const token = await ensureBaseToken(Boolean(data.forceRefresh));
762
+ reply(data.requestId, {
763
+ type: "cohub.work.token.result",
764
+ token
765
+ });
766
+ }
767
+ if (data.type === "cohub.work.checkout-state") {
768
+ const pending = readPendingPurchase();
769
+ const checkoutState = getCheckoutState();
770
+ const orderId = checkoutState.orderId ?? pending?.orderId ?? null;
771
+ if (checkoutState.status && checkoutState.orderId) clearPendingPurchase();
772
+ reply(data.requestId, {
773
+ type: "cohub.work.checkout-state.result",
774
+ status: checkoutState.status,
775
+ orderId
776
+ });
777
+ }
778
+ if (data.type === "cohub.work.purchase") {
779
+ const productKey = typeof data.productKey === "string" ? data.productKey.trim() : "";
780
+ if (!productKey) {
781
+ reply(data.requestId, {
782
+ type: "cohub.work.error",
783
+ message: "Product key is required."
784
+ });
785
+ return;
786
+ }
787
+ state.pendingPurchase = {
788
+ requestId: data.requestId,
789
+ productKey
790
+ };
791
+ state.purchaseError = null;
792
+ state.purchaseOpen = true;
793
+ notify();
794
+ }
795
+ if (data.type === "cohub.work.authorize") {
796
+ const allowedViewerScopes = clonePermissionScopes(work.allowedViewerScopes);
797
+ const scopes = clonePermissionScopes(data.scopes).filter((scope) => allowedViewerScopes.includes(scope));
798
+ if (scopes.length === 0) {
799
+ reply(data.requestId, {
800
+ type: "cohub.work.error",
801
+ message: "No allowed scopes requested."
802
+ });
803
+ return;
804
+ }
805
+ if (isBackground && await isCurrentViewerWorkOwner()) {
806
+ const token = await authorize(scopes);
807
+ reply(data.requestId, {
808
+ type: "cohub.work.authorize.result",
809
+ token
810
+ });
811
+ return;
812
+ }
813
+ const viewerUuid = await getViewerUuid();
814
+ if (viewerUuid && hasGrantedWorkScopes(viewerUuid, work.id, scopes)) try {
815
+ const token = await authorize(scopes);
816
+ reply(data.requestId, {
817
+ type: "cohub.work.authorize.result",
818
+ token
819
+ });
820
+ return;
821
+ } catch {
822
+ clearGrantedWorkScopes(viewerUuid, work.id);
823
+ }
824
+ state.pendingAuth = {
825
+ requestId: data.requestId,
826
+ scopes,
827
+ reason: data.reason
828
+ };
829
+ state.authError = null;
830
+ state.authOpen = true;
831
+ notify();
832
+ }
833
+ } catch (error) {
834
+ reply(data.requestId, {
835
+ type: "cohub.work.error",
836
+ message: error instanceof Error ? error.message : "Request failed."
837
+ });
838
+ }
839
+ }
840
+ function cancelAuth() {
841
+ if (state.authSaving) return;
842
+ if (!state.pendingAuth) return;
843
+ reply(state.pendingAuth.requestId, {
844
+ type: "cohub.work.authorize.result",
845
+ token: null
846
+ });
847
+ state.authOpen = false;
848
+ state.pendingAuth = null;
849
+ state.authError = null;
850
+ state.authSaving = false;
851
+ notify();
852
+ }
853
+ function cancelPurchase() {
854
+ if (state.purchaseSaving) return;
855
+ if (!state.pendingPurchase) return;
856
+ reply(state.pendingPurchase.requestId, {
857
+ type: "cohub.work.purchase.result",
858
+ checkout: null
859
+ });
860
+ state.purchaseOpen = false;
861
+ state.purchaseError = null;
862
+ state.pendingPurchase = null;
863
+ state.purchaseSaving = false;
864
+ notify();
865
+ }
866
+ async function confirmPurchase() {
867
+ if (!state.pendingPurchase || state.purchaseSaving) return;
868
+ state.purchaseSaving = true;
869
+ state.purchaseError = null;
870
+ notify();
871
+ try {
872
+ const checkout = await createPurchase(state.pendingPurchase.productKey);
873
+ reply(state.pendingPurchase.requestId, {
874
+ type: "cohub.work.purchase.result",
875
+ checkout
876
+ });
877
+ if (checkout && typeof checkout === "object") {
878
+ const next = checkout;
879
+ if (typeof next.orderId === "string" && typeof next.productKey === "string") writePendingPurchase({
880
+ orderId: next.orderId,
881
+ productKey: next.productKey
882
+ });
883
+ const url = next.checkoutUrl;
884
+ if (next.checkoutUsable === true && typeof url === "string" && url) window.location.href = url;
885
+ }
886
+ state.purchaseOpen = false;
887
+ state.pendingPurchase = null;
888
+ } catch (error) {
889
+ state.purchaseError = error instanceof Error ? error.message : "Purchase failed.";
890
+ } finally {
891
+ state.purchaseSaving = false;
892
+ notify();
893
+ }
894
+ }
895
+ async function confirmAuth() {
896
+ if (!state.pendingAuth || state.authSaving) return;
897
+ state.authError = null;
898
+ state.authSaving = true;
899
+ notify();
900
+ try {
901
+ const token = await authorize(state.pendingAuth.scopes);
902
+ setGrantedWorkScopes(await getViewerUuid(), work.id, state.pendingAuth.scopes);
903
+ reply(state.pendingAuth.requestId, {
904
+ type: "cohub.work.authorize.result",
905
+ token
906
+ });
907
+ state.authOpen = false;
908
+ state.pendingAuth = null;
909
+ } catch (error) {
910
+ state.authError = error instanceof Error ? error.message : "Authorization failed.";
911
+ } finally {
912
+ state.authSaving = false;
913
+ notify();
914
+ }
915
+ }
916
+ return {
917
+ getState: () => ({ ...state }),
918
+ handleMessage,
919
+ confirmAuth,
920
+ cancelAuth,
921
+ confirmPurchase,
922
+ cancelPurchase
923
+ };
924
+ }
925
+ //#endregion
518
926
  //#region src/http-error.ts
519
927
  function isHttpErrorCode(error, code) {
520
928
  return error instanceof HttpError && error.code === code;
@@ -751,4 +1159,4 @@ function filterGenerationDeclarationsByPolicy(declarations, policy) {
751
1159
  });
752
1160
  }
753
1161
  //#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 };
1162
+ 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.5.0",
4
4
  "description": "Cohub SDK for spaces, sessions, checkpoints, and realtime agent collaboration.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,