@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.
- package/dist/chunks/http.d.ts +25 -6
- package/dist/chunks/http.js +13 -0
- package/dist/index.d.ts +111 -1
- package/dist/index.js +451 -4
- package/package.json +1 -1
package/dist/chunks/http.d.ts
CHANGED
|
@@ -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
|
|
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:
|
|
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?:
|
|
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
|
}>;
|
package/dist/chunks/http.js
CHANGED
|
@@ -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 };
|