@joai/core 4.16.0 → 5.0.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/index.d.mts CHANGED
@@ -584,7 +584,7 @@ type Media = {
584
584
  };
585
585
  //#endregion
586
586
  //#region src/integration/types.d.ts
587
- type IntegrationType = 'none' | 'webhook' | 'api-token' | 'telegram' | 'slack' | 'whatsapp' | 'whatsapp-personal' | 'twilio' | 'sms' | 'n8n' | 'apple-health' | 'mcp' | 'x' | 'xchat' | 'instagram' | 'facebook' | 'linkedin' | 'grok' | 'cloudflare' | 'email' | 'calendar' | 'embed' | 'discord' | 'github' | 'push' | 'sentry' | 'readwise';
587
+ type IntegrationType = 'none' | 'webhook' | 'api-token' | 'telegram' | 'slack' | 'whatsapp' | 'whatsapp-personal' | 'twilio' | 'sms' | 'n8n' | 'apple-health' | 'mcp' | 'x' | 'xchat' | 'instagram' | 'facebook' | 'linkedin' | 'grok' | 'cloudflare' | 'google-search-console' | 'email' | 'calendar' | 'embed' | 'discord' | 'github' | 'push' | 'sentry' | 'readwise';
588
588
  type IntegrationDetails = {
589
589
  type: IntegrationType;
590
590
  name: string;
@@ -1128,6 +1128,7 @@ declare const NativeApps: {
1128
1128
  readonly Social: "social";
1129
1129
  readonly Studio: "studio";
1130
1130
  readonly Loyalty: "loyalty";
1131
+ readonly Documents: "documents";
1131
1132
  };
1132
1133
  type NativeApp = (typeof NativeApps)[keyof typeof NativeApps];
1133
1134
  declare const nativeAppSlugs: NativeApp[];
@@ -2440,7 +2441,7 @@ type AppointmentRequest = {
2440
2441
  };
2441
2442
  //#endregion
2442
2443
  //#region src/automation/types.d.ts
2443
- type AutomationTriggerType = 'prop' | 'segment' | 'manual' | 'webhook';
2444
+ type AutomationTriggerType = 'prop' | 'segment' | 'manual' | 'webhook' | 'site_monthly_report';
2444
2445
  type AutomationActionType = 'wait' | 'halt' | 'warp' | 'branch';
2445
2446
  type AutomationEnrollmentStatus = 'active' | 'completed' | 'skipped';
2446
2447
  type AutomationEnrollmentChange = 'created' | 'advanced' | 'sent' | 'completed' | 'skipped' | 'errored';
@@ -2654,6 +2655,45 @@ type PatchContentInput = {
2654
2655
  publish?: boolean;
2655
2656
  };
2656
2657
  //#endregion
2658
+ //#region src/content/image-processing.d.ts
2659
+ type ImageDimensions = {
2660
+ width: number;
2661
+ height: number;
2662
+ };
2663
+ type ImageCropState = {
2664
+ x: number;
2665
+ y: number;
2666
+ zoom: number;
2667
+ };
2668
+ type ImageCropRectangle = {
2669
+ x: number;
2670
+ y: number;
2671
+ width: number;
2672
+ height: number;
2673
+ };
2674
+ type ImageDimensionRules = {
2675
+ minWidth?: number;
2676
+ minHeight?: number;
2677
+ maxWidth?: number;
2678
+ maxHeight?: number;
2679
+ maxPixels?: number;
2680
+ };
2681
+ type ImageCompressionOptions = {
2682
+ maxWidth?: number;
2683
+ maxHeight?: number;
2684
+ mimeType?: 'image/jpeg' | 'image/png' | 'image/webp';
2685
+ quality?: number;
2686
+ };
2687
+ type ImageCropOptions = {
2688
+ aspectRatio: number;
2689
+ outputWidth?: number;
2690
+ outputHeight?: number;
2691
+ };
2692
+ declare const validateImageDimensions: (dimensions: ImageDimensions, rules: ImageDimensionRules) => "too-small" | "too-large" | null;
2693
+ declare const imageCropRectangle: (dimensions: ImageDimensions, aspectRatio: number, crop: ImageCropState) => ImageCropRectangle;
2694
+ declare const containedImageDimensions: (source: ImageDimensions, options: ImageCompressionOptions) => ImageDimensions;
2695
+ declare const cropOutputDimensions: (source: ImageDimensions, options: ImageCropOptions, compression: ImageCompressionOptions) => ImageDimensions;
2696
+ //#endregion
2657
2697
  //#region src/address/formatAddressSnapshot.d.ts
2658
2698
  /** Accepts camelCase API snapshots and legacy snake_case stored snapshots. */
2659
2699
  declare const formatAddressSnapshotLines: (address: AddressSnapshot | null | undefined) => string[];
@@ -3204,7 +3244,7 @@ declare const buildMcpServerName: (slug: string, teamName?: string) => string;
3204
3244
  declare const buildAgentMcpServerName: (agentName: string, teamName?: string) => string;
3205
3245
  //#endregion
3206
3246
  //#region src/metric/types.d.ts
3207
- type MetricSource = 'cloudflare';
3247
+ type MetricSource = 'cloudflare' | 'google_search_console';
3208
3248
  type Metric = {
3209
3249
  key: string;
3210
3250
  value: number;
@@ -4865,4 +4905,4 @@ type CliSessionStatus = {
4865
4905
  meta: CliSessionMeta | null;
4866
4906
  };
4867
4907
  //#endregion
4868
- export { AUTOMATION_SEND_CHANNELS, Achievement, Address, AddressCreatePayload, AddressInput, AddressSnapshot, type AddressType, AddressTypes, AddressUpdatePayload, Affiliate, AffiliateStatus, AffiliateTier, AffiliateTierName, Agent, AgentActionHistoryEntry, AgentCharacter, AgentDelegatable, AgentEngine, AgentExecuteHandler, AgentExecuteOptions, AgentGender, AgentMessageMeta, AgentMessageOptions, AgentPrivate, AgentSettings, AgentSetupTarget, AgentSimple, AgentToolingAccess, AgentTrustedActionRule, AgentWalletMode, AggregatedRoute, AiCostEntry, AiCostsResponse, AiCostsSummary, Alert, ApiToken, AppAccessRule, AppEnv, AppFile, AppFileType, AppIngestion, AppSetupTarget, AppendKvEntryResult, AppointmentAvailability, AppointmentAvailabilityService, AppointmentAvailabilitySlot, AppointmentBooking, AppointmentBookingContext, AppointmentPolicy, AppointmentPolicySync, AppointmentPolicyUpsert, AppointmentRequest, AppointmentSlot, Artifact, ArtifactBlock, ArtifactBlockType, ArtifactContactSummary, ArtifactCreatePayload, ArtifactDeliverIntegration, ArtifactDeliverPayload, ArtifactDelivery, ArtifactLink, ArtifactStatus, ArtifactType, ArtifactUpdatePayload, AuthUser, Automation, AutomationAction, AutomationActionConfig, AutomationActionInput, AutomationActionType, AutomationAudiencePreview, AutomationCreatePayload, AutomationEnrollment, AutomationEnrollmentChange, AutomationEnrollmentStatus, AutomationEnrollmentUpdatedPayload, AutomationSendChannel, AutomationSendChannelId, AutomationSkipReason, AutomationStats, AutomationTriggerConfig, AutomationTriggerType, AutomationUpdatePayload, BillingManageAccess, Blueprint, BlueprintOnboardingStep, BlueprintRedirect, BlueprintSettings, BlueprintShortcut, BlueprintTask, BlueprintTeam, BoardSummaryViewable, BookmarkEntry, BrandBackend, BrandIntegration, BrandIntegrationAction, BrandIntegrationProvider, BrandSearchHit, BrandSiteConfig, BrandSourceConfig, Budget, ByokProviderConfig, ByokProviderName, ByokProviders, CAMPAIGN_CHANNELS, CONTACT_MESSAGE_SEND_WARP, CalendarProvider, CalendarStatus, Campaign, CampaignApproval, CampaignAudiencePreview, CampaignAudiencePreviewPayload, CampaignCategory, CampaignChannel, CampaignChannelId, CampaignCreatePayload, CampaignRecipient, CampaignRecipientStatus, CampaignSkipReason, CampaignSkipReasons, CampaignStats, CampaignStatus, CampaignUpdatePayload, Card, Cart, CartItem, CartLine, Challenge, Challenges, ChangelogEntry, Character, ChatClientAction, ChatClientThought, ChatStreamData, ChatStreamEventType, CheckoutSnapshot, CheckoutSnapshotRequest, CliSessionMeta, CliSessionStatus, CommissionAgreement, Configuration, Contact, ContactActivity, ContactActivityAuthor, ContactActivityType, ContactConsent, ContactConsentStatus, ContactCreatePayload, ContactFormData, ContactHealth, ContactRelation, ContactRelationCategory, ContactRelationContact, ContactRelationDirection, ContactRelationPayload, ContactRelationType, ContactRelationUpdatePayload, ContactViewable, Content, ContentDefinition, ContentEntry, ContentField, ContentFieldType, ContentPatch, ContentStatus, ContentValue, ContentVersion, Contract, ContractCategoryDisplayNames, ContractCategoryName, ContractCodeMetadata, ContractEntity, ContractOnNetwork, ContractVersion, ContractsAddressConfig, CortexExecuteOptions, Coupon, CouponCondition, CouponRestrictedItem, CouponRestrictedItemType, CreateContentInput, CreateHookPayload, CreateInboundHookPayload, CreateInternalHookPayload, CreateKvFieldPayload, CreateWarpLinkedHookPayload, CreateWebHookPayload, DefaultAppLocale, DefaultCodeMetadata, DefaultInviteTeamRole, DemoFlow, DemoMessage, Desk, DeskItem, DeskItemRole, Document, EarnResponse, Earning, Element, ElementSpec, ElementType, ElementVariation, EmailProvider, EmbedStatus, EncryptionStatus, Entity, EntityDirectExecuteRequest, EntityProposable, EntitySignable, EntityTemplate, Experience, FeatureSetupTarget, FileInfo, FileMetadata, Flow, FlowCategory, FlowInputMapping, FlowStatus, FlowStep, Fulfillment, FulfillmentFlowAction, FulfillmentFlowStep, FulfillmentLocation, type FulfillmentMethod, FulfillmentMethods, type FulfillmentStatus, FulfillmentStatuses, GamificationData, GamificationEventType, Goal, GoalCreatePayload, GoalPriority, GoalProgressViewable, GoalStatus, GuestBuyer, HintOptions, HintPosition, Hook, HookSample, HookTrigger, HookTriggerCondition, HookTriggerInput, HttpService, IAppResponse, IHttpService, IRequestOptions, IngestionSourceType, IngestionStatus, Inquiry, InquiryStatus, InquiryType, Integration, IntegrationConnectionDetails, IntegrationDetails, IntegrationMeta, IntegrationType, Intent, InviteableTeamRoles, Item, ItemCreatePayload, ItemExecutionStatus, ItemPriority, ItemStatus, ItemUpdatePayload, ItemViewable, JoaiUrls, JsonValue, KvEntry, KvEntryPayload, KvField, KvFieldWithEntries, KvValue, Kyc, KycStatus, Link, LinkCreatePayload, LinkScanHistory, LinkStats, LinkUpdatePayload, LinkVariation, LinkVariationBatchCreatePayload, LinkVariationCreatePayload, LocalAgentWallet, LoyaltyAccount, LoyaltyMember, LoyaltyNextTier, LoyaltyProgram, LoyaltyPromotion, LoyaltyReward, LoyaltyStatus, LoyaltyTier, LoyaltyTierInfo, LoyaltyTransaction, McpToolCall, McpToolCallBroadcast, McpToolCallStatus, Media, MediaAspectRatio, MediaAttributes, MediaItems, MediaLibraryAttributes, MediaMime, Meeting, MeetingConferenceProvider, MeetingFeature, MeetingJoinInfo, MeetingJoinTeam, MeetingParticipant, MeetingSessionState, MeetingSpeakerAssignment, MeetingStatus, MeetingSummary, MeetingTranscriptEntry, MeetingUsage, Memory, Message, MessageId, MessageRole, Metric, MetricSource, MetricsResult, Milestone, MilestoneType, Mission, MissionBudget, MissionCreatePayload, MissionPlan, MissionPriority, MissionSchedule, MissionStatus, MissionViewable, MollieTerminalPaymentResult, MultimodalContent, MultimodalFile, NATIVE_AUTH_TOKEN_PARAM, NativeApp, NativeApps, Notification, NotificationAction, NotificationAgent, NotificationChannel, NotificationSetting, OG_IMAGE_CONFIG, OG_IMAGE_HEIGHT, OG_IMAGE_WIDTH, ORDER_FULFILLMENT_STATUSES, ORDER_POST_CHECKOUT_STATUSES, OUTBOUND_CHANNELS, OfficeAgent, OfficeEntity, OfficeEntityKind, OfficeLiveOverrides, OfficeMember, OfficeSnapshot, OfficeStatus, OfficeStatusFilter, OfficeTypeFilter, OgImageColors, Order, OrderConfigurationItem, OrderContext, OrderItem, OrderPriceMode, OrderSource, OrderStatus, OrderStatusDisplay, OrderType, OutboundChannel, OutboundChannelId, PLATFORM_CURRENCY, PaginatedResponse, Pass, PatchContentInput, PaymentAccount, PaymentAccountOnboarding, PaymentProvider, PayoutEntry, PeriodTypeLabels, PeriodTypeOptions, PermissionConfigType, PermissionPresetName, PermissionPresetNames, PersonaQuestionable, PickupNextAction, Plan, PlanBenefit, PlanExtra, PlanFeature, PlanInterval, PolicyMethod, PolicySetting, PricingModel, Product, ProductDetailKind, ProductDetailRow, ProductDetailSection, ProductDetailText, ProductDiscount, ProductMeta, ProductPieces, ProductRating, ProductRelation, ProductRelationType, ProductVariation, ProductVariationMeta, ProductVariationType, ProgramSettings, Project, ProjectAspectRatio, ProjectAssembly, ProjectCaptionStyle, ProjectClipCandidate, ProjectClips, ProjectExport, ProjectExportAsset, ProjectExportResponse, ProjectImages, ProjectInputAssistIntent, ProjectInputAssistResponse, ProjectMutation, ProjectOutputPreset, ProjectOutputType, ProjectPlan, ProjectRender, ProjectRenderMode, ProjectSelectedClip, ProjectShot, ProjectSoundtrack, ProjectSourceMedia, ProjectStatus, ProjectStudioHistoryEntry, ProjectStudioQuestion, ProjectStudioResponse, ProjectStudioStage, ProjectStudioState, ProjectStudioSummary, ProjectStyleDirection, ProjectTranscript, ProjectTranscriptSegment, Proposal, ProposalAction, ProposalActionPayment, ProposalActionPaymentSerializable, ProposalActionSerializable, ProposalPollOption, ProposalStatus, PublicFormResults, PurchaseOptions, PurchaseResult, RampProvider, RampProviderInfo, Reactions, RecentExperience, RedeemResponse, Reminder, Return, type ReturnStatus, ReturnStatuses, ReturnUpdateStatus, ReturnUpdateStatuses, Room, RoomId, RoomKind, ScInfo, SchedulePreset, SecretAuthorizable, SecretSettable, Segment, SegmentCondition, SegmentConditionType, SegmentCountPayload, SegmentCountResult, SegmentCreatePayload, SegmentGroup, SendableActivityUpdate, SendableAgentAction, SendableAgentMessage, SendableAgentThought, SendableMedia, SendableUserMessage, Service, SetKvEntryResult, SharedSocialPost, ShippingCarrierOption, ShippingRate, ShippingZone, Shortcut, Site, SiteAgent, SiteBrand, SiteRoute, SiteTeam, SiteType, Skill, SkillMediaBindingRole, SkillMediaBindingRoleValue, SkillScope, SkillScopeValue, SkillType, SkillTypeValue, SocialAuthProvider, SocialBot, SocialPlatform, SocialPost, SocialPostConnection, SocialPostCreatePayload, SocialPostGenerateCaptionPayload, SocialPostGeneratedCaption, SocialPostPlatform, SocialPostStatus, SocialPostUpdatePayload, StampResponse, StoreAgent, StoreCheckoutItem, StoreData, StoreEntityType, StoreInfo, StoreItem, StoreListing, StorePriceTier, StorePricing, StorePurchasable, StorePurchaseResult, Streak, Subscription, SubscriptionDelivery, SubscriptionInterval, SubscriptionPlan, SubscriptionStatus, SupportedAppLocale, SupportedAppLocales, Swarm, Tag, TagType, Task, TaxBreakdownRow, TaxClass, Team, TeamAccessCatalog, TeamAccessConfig, TeamBrand, TeamCategory, TeamCurrencySource, TeamEarning, TeamEarningsBalance, TeamFeature, TeamFeatureAccess, TeamFeatureArea, TeamFeatureUsage, TeamManageAccess, TeamMember, TeamMeta, TeamOrderStats, TeamPayout, TeamPayoutAddress, TeamPlace, TeamPrivate, TeamSettings, TeamUsage, TeamViewAccess, TerminalConnectionToken, TerminalPaymentIntent, Tier, TierFeature, TierName, ToggleKvFieldResult, TranscriptEntry, TranscriptionCorrection, TranscriptionResponse, TranslatableValue, UNIFIED_MCP_SERVER_NAME, Update, UpdateCreatePayload, UpdateRelation, UpdateStats, UpdateStatus, UpdateType, UpdateUpdatePayload, Upgrade, UpgradeSourceType, UpgradeStatus, User, UserInterest, UserMode, type UserPermission, UserPermissions, UserPrivate, type UserRole, UserRoles, UserSettings, UserSocialAccount, UserStats, VolumePrice, Wallet, WalletList, WarpApprovable, WarpBackend, WarpBackendStatus, WarpBatchItem, WarpBatchable, WarpCloudExecutable, WarpCreateable, WarpExecutable, WarpExecutionBackend, WarpExtras, WarpExtrasFaq, WarpInputable, WarpScreenshotVariant, WarpSearchHit, WarpSelectable, WarpSelectableDetails, WarpSuggestion, WarpTestable, WarpViewable, WebHookTriggerEvent, WorkspaceCloudFile, WorkspaceContext, WorkspaceInfo, WorkspaceSettings, XIntegrationStatus, abbreviateNumber, addressTypeValues, automationSendChannel, buildAgentMcpServerName, buildAgentSetupClipboardText, buildAppSetupClipboardText, buildFeatureSetupClipboardText, buildMcpServerName, canOpenFulfillmentFlow, canTransitionOrderStatus, cartLineTotal, cartPayableTotal, createCursorMcpInstallLink, defaultInviteTeamRole, documentShareUrl, firstValidationMessage, formatAddressSnapshotLines, fulfillmentMethodValues, fulfillmentStatusValues, getAgentSetupPromptUrl, getAgentsBaseUrl, getApiBaseUrl, getAppBaseUrl, getAssetAppLogoUrl, getAssetChainLogoUrl, getAssetPartnerLogoUrl, getAssetTokenLogoUrl, getAssetWalletLogoUrl, getCortexBaseUrl, getDigestBaseUrl, getDocumentsBaseUrl, getEditableOrderStatuses, getFormsBaseUrl, getFulfillmentFlowAction, getFulfillmentFlowStepperIndex, getGenBaseUrl, getInvoiceEditableStatuses, getLoginUrl, getMcpServerAgentUrl, getMcpServerUrl, getPickupEditableStatuses, getPickupNextAction, getShippingEditableStatuses, getSiteUrl, getSitesBaseUrl, getSitesRootDomain, getStoreBaseUrl, getWarpScreenshotUrl, hasAllPermissions, hasAllTeamPermissions, hasAnyPermissions, hasPermission, hasTeamPermission, integrationSlugForChannel, inviteableTeamRoles, isAutomationSendChannelId, isCampaignChannelId, isCompleteAddressInput, isContactMessageAction, isContactMessageWarpId, isFileFormatAudio, isFileFormatImage, isFileFormatVideo, isNativeApp, isNativeAppAccessible, isNativeAppGated, isNativeAppLocked, isOrderCanceled, isOrderInFulfillment, isOrderPending, isOrderPostCheckout, isPickupOrderReady, isPickupReady, isSupportedAppLocale, isTeamFeatureAccessible, isTeamFeatureGated, isTeamFeatureLocked, isUnifiedMcpUrl, isUserRole, localize, nativeAppSlugs, normalizeAutomationActionType, ogImageUrl, outboundChannel, permissionPresetRules, resolveAccessCatalog, resolveAgentMcpUrl, resolveConnectMcpUrl, resolveFulfillmentFlowStep, resolveOrderStatusDisplay, resolveTeamCurrency, resolveWarpText, returnStatusValues, returnUpdateStatusValues, sanitizeAlphanumeric, sanitizeNumeric, slugifyMcpSegment, teamCategories, toCurrencyDisplay, toHexEncodedNonce, toNameInitials, toNftId, toPreviewText, userPermissionValues, userRoleValues, validationMessageFor, withRetry };
4908
+ export { AUTOMATION_SEND_CHANNELS, Achievement, Address, AddressCreatePayload, AddressInput, AddressSnapshot, type AddressType, AddressTypes, AddressUpdatePayload, Affiliate, AffiliateStatus, AffiliateTier, AffiliateTierName, Agent, AgentActionHistoryEntry, AgentCharacter, AgentDelegatable, AgentEngine, AgentExecuteHandler, AgentExecuteOptions, AgentGender, AgentMessageMeta, AgentMessageOptions, AgentPrivate, AgentSettings, AgentSetupTarget, AgentSimple, AgentToolingAccess, AgentTrustedActionRule, AgentWalletMode, AggregatedRoute, AiCostEntry, AiCostsResponse, AiCostsSummary, Alert, ApiToken, AppAccessRule, AppEnv, AppFile, AppFileType, AppIngestion, AppSetupTarget, AppendKvEntryResult, AppointmentAvailability, AppointmentAvailabilityService, AppointmentAvailabilitySlot, AppointmentBooking, AppointmentBookingContext, AppointmentPolicy, AppointmentPolicySync, AppointmentPolicyUpsert, AppointmentRequest, AppointmentSlot, Artifact, ArtifactBlock, ArtifactBlockType, ArtifactContactSummary, ArtifactCreatePayload, ArtifactDeliverIntegration, ArtifactDeliverPayload, ArtifactDelivery, ArtifactLink, ArtifactStatus, ArtifactType, ArtifactUpdatePayload, AuthUser, Automation, AutomationAction, AutomationActionConfig, AutomationActionInput, AutomationActionType, AutomationAudiencePreview, AutomationCreatePayload, AutomationEnrollment, AutomationEnrollmentChange, AutomationEnrollmentStatus, AutomationEnrollmentUpdatedPayload, AutomationSendChannel, AutomationSendChannelId, AutomationSkipReason, AutomationStats, AutomationTriggerConfig, AutomationTriggerType, AutomationUpdatePayload, BillingManageAccess, Blueprint, BlueprintOnboardingStep, BlueprintRedirect, BlueprintSettings, BlueprintShortcut, BlueprintTask, BlueprintTeam, BoardSummaryViewable, BookmarkEntry, BrandBackend, BrandIntegration, BrandIntegrationAction, BrandIntegrationProvider, BrandSearchHit, BrandSiteConfig, BrandSourceConfig, Budget, ByokProviderConfig, ByokProviderName, ByokProviders, CAMPAIGN_CHANNELS, CONTACT_MESSAGE_SEND_WARP, CalendarProvider, CalendarStatus, Campaign, CampaignApproval, CampaignAudiencePreview, CampaignAudiencePreviewPayload, CampaignCategory, CampaignChannel, CampaignChannelId, CampaignCreatePayload, CampaignRecipient, CampaignRecipientStatus, CampaignSkipReason, CampaignSkipReasons, CampaignStats, CampaignStatus, CampaignUpdatePayload, Card, Cart, CartItem, CartLine, Challenge, Challenges, ChangelogEntry, Character, ChatClientAction, ChatClientThought, ChatStreamData, ChatStreamEventType, CheckoutSnapshot, CheckoutSnapshotRequest, CliSessionMeta, CliSessionStatus, CommissionAgreement, Configuration, Contact, ContactActivity, ContactActivityAuthor, ContactActivityType, ContactConsent, ContactConsentStatus, ContactCreatePayload, ContactFormData, ContactHealth, ContactRelation, ContactRelationCategory, ContactRelationContact, ContactRelationDirection, ContactRelationPayload, ContactRelationType, ContactRelationUpdatePayload, ContactViewable, Content, ContentDefinition, ContentEntry, ContentField, ContentFieldType, ContentPatch, ContentStatus, ContentValue, ContentVersion, Contract, ContractCategoryDisplayNames, ContractCategoryName, ContractCodeMetadata, ContractEntity, ContractOnNetwork, ContractVersion, ContractsAddressConfig, CortexExecuteOptions, Coupon, CouponCondition, CouponRestrictedItem, CouponRestrictedItemType, CreateContentInput, CreateHookPayload, CreateInboundHookPayload, CreateInternalHookPayload, CreateKvFieldPayload, CreateWarpLinkedHookPayload, CreateWebHookPayload, DefaultAppLocale, DefaultCodeMetadata, DefaultInviteTeamRole, DemoFlow, DemoMessage, Desk, DeskItem, DeskItemRole, Document, EarnResponse, Earning, Element, ElementSpec, ElementType, ElementVariation, EmailProvider, EmbedStatus, EncryptionStatus, Entity, EntityDirectExecuteRequest, EntityProposable, EntitySignable, EntityTemplate, Experience, FeatureSetupTarget, FileInfo, FileMetadata, Flow, FlowCategory, FlowInputMapping, FlowStatus, FlowStep, Fulfillment, FulfillmentFlowAction, FulfillmentFlowStep, FulfillmentLocation, type FulfillmentMethod, FulfillmentMethods, type FulfillmentStatus, FulfillmentStatuses, GamificationData, GamificationEventType, Goal, GoalCreatePayload, GoalPriority, GoalProgressViewable, GoalStatus, GuestBuyer, HintOptions, HintPosition, Hook, HookSample, HookTrigger, HookTriggerCondition, HookTriggerInput, HttpService, IAppResponse, IHttpService, IRequestOptions, ImageCompressionOptions, ImageCropOptions, ImageCropRectangle, ImageCropState, ImageDimensionRules, ImageDimensions, IngestionSourceType, IngestionStatus, Inquiry, InquiryStatus, InquiryType, Integration, IntegrationConnectionDetails, IntegrationDetails, IntegrationMeta, IntegrationType, Intent, InviteableTeamRoles, Item, ItemCreatePayload, ItemExecutionStatus, ItemPriority, ItemStatus, ItemUpdatePayload, ItemViewable, JoaiUrls, JsonValue, KvEntry, KvEntryPayload, KvField, KvFieldWithEntries, KvValue, Kyc, KycStatus, Link, LinkCreatePayload, LinkScanHistory, LinkStats, LinkUpdatePayload, LinkVariation, LinkVariationBatchCreatePayload, LinkVariationCreatePayload, LocalAgentWallet, LoyaltyAccount, LoyaltyMember, LoyaltyNextTier, LoyaltyProgram, LoyaltyPromotion, LoyaltyReward, LoyaltyStatus, LoyaltyTier, LoyaltyTierInfo, LoyaltyTransaction, McpToolCall, McpToolCallBroadcast, McpToolCallStatus, Media, MediaAspectRatio, MediaAttributes, MediaItems, MediaLibraryAttributes, MediaMime, Meeting, MeetingConferenceProvider, MeetingFeature, MeetingJoinInfo, MeetingJoinTeam, MeetingParticipant, MeetingSessionState, MeetingSpeakerAssignment, MeetingStatus, MeetingSummary, MeetingTranscriptEntry, MeetingUsage, Memory, Message, MessageId, MessageRole, Metric, MetricSource, MetricsResult, Milestone, MilestoneType, Mission, MissionBudget, MissionCreatePayload, MissionPlan, MissionPriority, MissionSchedule, MissionStatus, MissionViewable, MollieTerminalPaymentResult, MultimodalContent, MultimodalFile, NATIVE_AUTH_TOKEN_PARAM, NativeApp, NativeApps, Notification, NotificationAction, NotificationAgent, NotificationChannel, NotificationSetting, OG_IMAGE_CONFIG, OG_IMAGE_HEIGHT, OG_IMAGE_WIDTH, ORDER_FULFILLMENT_STATUSES, ORDER_POST_CHECKOUT_STATUSES, OUTBOUND_CHANNELS, OfficeAgent, OfficeEntity, OfficeEntityKind, OfficeLiveOverrides, OfficeMember, OfficeSnapshot, OfficeStatus, OfficeStatusFilter, OfficeTypeFilter, OgImageColors, Order, OrderConfigurationItem, OrderContext, OrderItem, OrderPriceMode, OrderSource, OrderStatus, OrderStatusDisplay, OrderType, OutboundChannel, OutboundChannelId, PLATFORM_CURRENCY, PaginatedResponse, Pass, PatchContentInput, PaymentAccount, PaymentAccountOnboarding, PaymentProvider, PayoutEntry, PeriodTypeLabels, PeriodTypeOptions, PermissionConfigType, PermissionPresetName, PermissionPresetNames, PersonaQuestionable, PickupNextAction, Plan, PlanBenefit, PlanExtra, PlanFeature, PlanInterval, PolicyMethod, PolicySetting, PricingModel, Product, ProductDetailKind, ProductDetailRow, ProductDetailSection, ProductDetailText, ProductDiscount, ProductMeta, ProductPieces, ProductRating, ProductRelation, ProductRelationType, ProductVariation, ProductVariationMeta, ProductVariationType, ProgramSettings, Project, ProjectAspectRatio, ProjectAssembly, ProjectCaptionStyle, ProjectClipCandidate, ProjectClips, ProjectExport, ProjectExportAsset, ProjectExportResponse, ProjectImages, ProjectInputAssistIntent, ProjectInputAssistResponse, ProjectMutation, ProjectOutputPreset, ProjectOutputType, ProjectPlan, ProjectRender, ProjectRenderMode, ProjectSelectedClip, ProjectShot, ProjectSoundtrack, ProjectSourceMedia, ProjectStatus, ProjectStudioHistoryEntry, ProjectStudioQuestion, ProjectStudioResponse, ProjectStudioStage, ProjectStudioState, ProjectStudioSummary, ProjectStyleDirection, ProjectTranscript, ProjectTranscriptSegment, Proposal, ProposalAction, ProposalActionPayment, ProposalActionPaymentSerializable, ProposalActionSerializable, ProposalPollOption, ProposalStatus, PublicFormResults, PurchaseOptions, PurchaseResult, RampProvider, RampProviderInfo, Reactions, RecentExperience, RedeemResponse, Reminder, Return, type ReturnStatus, ReturnStatuses, ReturnUpdateStatus, ReturnUpdateStatuses, Room, RoomId, RoomKind, ScInfo, SchedulePreset, SecretAuthorizable, SecretSettable, Segment, SegmentCondition, SegmentConditionType, SegmentCountPayload, SegmentCountResult, SegmentCreatePayload, SegmentGroup, SendableActivityUpdate, SendableAgentAction, SendableAgentMessage, SendableAgentThought, SendableMedia, SendableUserMessage, Service, SetKvEntryResult, SharedSocialPost, ShippingCarrierOption, ShippingRate, ShippingZone, Shortcut, Site, SiteAgent, SiteBrand, SiteRoute, SiteTeam, SiteType, Skill, SkillMediaBindingRole, SkillMediaBindingRoleValue, SkillScope, SkillScopeValue, SkillType, SkillTypeValue, SocialAuthProvider, SocialBot, SocialPlatform, SocialPost, SocialPostConnection, SocialPostCreatePayload, SocialPostGenerateCaptionPayload, SocialPostGeneratedCaption, SocialPostPlatform, SocialPostStatus, SocialPostUpdatePayload, StampResponse, StoreAgent, StoreCheckoutItem, StoreData, StoreEntityType, StoreInfo, StoreItem, StoreListing, StorePriceTier, StorePricing, StorePurchasable, StorePurchaseResult, Streak, Subscription, SubscriptionDelivery, SubscriptionInterval, SubscriptionPlan, SubscriptionStatus, SupportedAppLocale, SupportedAppLocales, Swarm, Tag, TagType, Task, TaxBreakdownRow, TaxClass, Team, TeamAccessCatalog, TeamAccessConfig, TeamBrand, TeamCategory, TeamCurrencySource, TeamEarning, TeamEarningsBalance, TeamFeature, TeamFeatureAccess, TeamFeatureArea, TeamFeatureUsage, TeamManageAccess, TeamMember, TeamMeta, TeamOrderStats, TeamPayout, TeamPayoutAddress, TeamPlace, TeamPrivate, TeamSettings, TeamUsage, TeamViewAccess, TerminalConnectionToken, TerminalPaymentIntent, Tier, TierFeature, TierName, ToggleKvFieldResult, TranscriptEntry, TranscriptionCorrection, TranscriptionResponse, TranslatableValue, UNIFIED_MCP_SERVER_NAME, Update, UpdateCreatePayload, UpdateRelation, UpdateStats, UpdateStatus, UpdateType, UpdateUpdatePayload, Upgrade, UpgradeSourceType, UpgradeStatus, User, UserInterest, UserMode, type UserPermission, UserPermissions, UserPrivate, type UserRole, UserRoles, UserSettings, UserSocialAccount, UserStats, VolumePrice, Wallet, WalletList, WarpApprovable, WarpBackend, WarpBackendStatus, WarpBatchItem, WarpBatchable, WarpCloudExecutable, WarpCreateable, WarpExecutable, WarpExecutionBackend, WarpExtras, WarpExtrasFaq, WarpInputable, WarpScreenshotVariant, WarpSearchHit, WarpSelectable, WarpSelectableDetails, WarpSuggestion, WarpTestable, WarpViewable, WebHookTriggerEvent, WorkspaceCloudFile, WorkspaceContext, WorkspaceInfo, WorkspaceSettings, XIntegrationStatus, abbreviateNumber, addressTypeValues, automationSendChannel, buildAgentMcpServerName, buildAgentSetupClipboardText, buildAppSetupClipboardText, buildFeatureSetupClipboardText, buildMcpServerName, canOpenFulfillmentFlow, canTransitionOrderStatus, cartLineTotal, cartPayableTotal, containedImageDimensions, createCursorMcpInstallLink, cropOutputDimensions, defaultInviteTeamRole, documentShareUrl, firstValidationMessage, formatAddressSnapshotLines, fulfillmentMethodValues, fulfillmentStatusValues, getAgentSetupPromptUrl, getAgentsBaseUrl, getApiBaseUrl, getAppBaseUrl, getAssetAppLogoUrl, getAssetChainLogoUrl, getAssetPartnerLogoUrl, getAssetTokenLogoUrl, getAssetWalletLogoUrl, getCortexBaseUrl, getDigestBaseUrl, getDocumentsBaseUrl, getEditableOrderStatuses, getFormsBaseUrl, getFulfillmentFlowAction, getFulfillmentFlowStepperIndex, getGenBaseUrl, getInvoiceEditableStatuses, getLoginUrl, getMcpServerAgentUrl, getMcpServerUrl, getPickupEditableStatuses, getPickupNextAction, getShippingEditableStatuses, getSiteUrl, getSitesBaseUrl, getSitesRootDomain, getStoreBaseUrl, getWarpScreenshotUrl, hasAllPermissions, hasAllTeamPermissions, hasAnyPermissions, hasPermission, hasTeamPermission, imageCropRectangle, integrationSlugForChannel, inviteableTeamRoles, isAutomationSendChannelId, isCampaignChannelId, isCompleteAddressInput, isContactMessageAction, isContactMessageWarpId, isFileFormatAudio, isFileFormatImage, isFileFormatVideo, isNativeApp, isNativeAppAccessible, isNativeAppGated, isNativeAppLocked, isOrderCanceled, isOrderInFulfillment, isOrderPending, isOrderPostCheckout, isPickupOrderReady, isPickupReady, isSupportedAppLocale, isTeamFeatureAccessible, isTeamFeatureGated, isTeamFeatureLocked, isUnifiedMcpUrl, isUserRole, localize, nativeAppSlugs, normalizeAutomationActionType, ogImageUrl, outboundChannel, permissionPresetRules, resolveAccessCatalog, resolveAgentMcpUrl, resolveConnectMcpUrl, resolveFulfillmentFlowStep, resolveOrderStatusDisplay, resolveTeamCurrency, resolveWarpText, returnStatusValues, returnUpdateStatusValues, sanitizeAlphanumeric, sanitizeNumeric, slugifyMcpSegment, teamCategories, toCurrencyDisplay, toHexEncodedNonce, toNameInitials, toNftId, toPreviewText, userPermissionValues, userRoleValues, validateImageDimensions, validationMessageFor, withRetry };
package/dist/index.mjs CHANGED
@@ -410,6 +410,63 @@ function integrationSlugForChannel(channel) {
410
410
  return channel === "sms" ? "twilio" : channel;
411
411
  }
412
412
  //#endregion
413
+ //#region src/content/image-processing.ts
414
+ const positiveFinite = (value) => typeof value === "number" && Number.isFinite(value) && value > 0;
415
+ const validateImageDimensions = (dimensions, rules) => {
416
+ if (!positiveFinite(dimensions.width) || !positiveFinite(dimensions.height)) return "too-small";
417
+ if (rules.minWidth && dimensions.width < rules.minWidth || rules.minHeight && dimensions.height < rules.minHeight) return "too-small";
418
+ if (rules.maxWidth && dimensions.width > rules.maxWidth || rules.maxHeight && dimensions.height > rules.maxHeight || rules.maxPixels && dimensions.width * dimensions.height > rules.maxPixels) return "too-large";
419
+ return null;
420
+ };
421
+ const imageCropRectangle = (dimensions, aspectRatio, crop) => {
422
+ if (!positiveFinite(aspectRatio)) throw new RangeError("Crop aspect ratio must be a positive finite number.");
423
+ if (!positiveFinite(dimensions.width) || !positiveFinite(dimensions.height)) throw new RangeError("Image dimensions must be positive finite numbers.");
424
+ const sourceAspect = dimensions.width / dimensions.height;
425
+ const baseWidth = sourceAspect > aspectRatio ? dimensions.height * aspectRatio : dimensions.width;
426
+ const baseHeight = sourceAspect > aspectRatio ? dimensions.height : dimensions.width / aspectRatio;
427
+ const zoom = Number.isFinite(crop.zoom) ? Math.max(1, crop.zoom) : 1;
428
+ const positionX = Number.isFinite(crop.x) ? Math.max(-1, Math.min(1, crop.x)) : 0;
429
+ const positionY = Number.isFinite(crop.y) ? Math.max(-1, Math.min(1, crop.y)) : 0;
430
+ const width = baseWidth / zoom;
431
+ const height = baseHeight / zoom;
432
+ const availableX = dimensions.width - width;
433
+ const availableY = dimensions.height - height;
434
+ return {
435
+ x: availableX * ((positionX + 1) / 2),
436
+ y: availableY * ((positionY + 1) / 2),
437
+ width,
438
+ height
439
+ };
440
+ };
441
+ const containedImageDimensions = (source, options) => {
442
+ if (!positiveFinite(source.width) || !positiveFinite(source.height)) throw new RangeError("Image dimensions must be positive finite numbers.");
443
+ const maxWidth = positiveFinite(options.maxWidth) ? options.maxWidth : source.width;
444
+ const maxHeight = positiveFinite(options.maxHeight) ? options.maxHeight : source.height;
445
+ const scale = Math.min(1, maxWidth / source.width, maxHeight / source.height);
446
+ return {
447
+ width: Math.max(1, Math.round(source.width * scale)),
448
+ height: Math.max(1, Math.round(source.height * scale))
449
+ };
450
+ };
451
+ const cropOutputDimensions = (source, options, compression) => {
452
+ if (!positiveFinite(options.aspectRatio)) throw new RangeError("Crop aspect ratio must be a positive finite number.");
453
+ const width = positiveFinite(options.outputWidth) ? options.outputWidth : void 0;
454
+ const height = positiveFinite(options.outputHeight) ? options.outputHeight : void 0;
455
+ if (width && height) return {
456
+ width: Math.max(1, Math.round(width)),
457
+ height: Math.max(1, Math.round(height))
458
+ };
459
+ if (width) return {
460
+ width: Math.max(1, Math.round(width)),
461
+ height: Math.max(1, Math.round(width / options.aspectRatio))
462
+ };
463
+ if (height) return {
464
+ width: Math.max(1, Math.round(height * options.aspectRatio)),
465
+ height: Math.max(1, Math.round(height))
466
+ };
467
+ return containedImageDimensions(source, compression);
468
+ };
469
+ //#endregion
413
470
  //#region src/address/enums.ts
414
471
  const AddressTypes = {
415
472
  Billing: "billing",
@@ -878,7 +935,8 @@ const NativeApps = {
878
935
  Artifacts: "artifacts",
879
936
  Social: "social",
880
937
  Studio: "studio",
881
- Loyalty: "loyalty"
938
+ Loyalty: "loyalty",
939
+ Documents: "documents"
882
940
  };
883
941
  const nativeAppSlugs = Object.values(NativeApps);
884
942
  const isNativeApp = (value) => typeof value === "string" && nativeAppSlugs.includes(value);
@@ -976,4 +1034,4 @@ const DefaultInviteTeamRole = UserRoles.Member;
976
1034
  const inviteableTeamRoles = () => [...InviteableTeamRoles];
977
1035
  const defaultInviteTeamRole = () => DefaultInviteTeamRole;
978
1036
  //#endregion
979
- export { AUTOMATION_SEND_CHANNELS, AddressTypes, AgentToolingAccess, BillingManageAccess, CAMPAIGN_CHANNELS, CONTACT_MESSAGE_SEND_WARP, ContractCategoryDisplayNames, DefaultAppLocale, DefaultCodeMetadata, DefaultInviteTeamRole, FulfillmentMethods, FulfillmentStatuses, HttpService, InviteableTeamRoles, JoaiUrls, NATIVE_AUTH_TOKEN_PARAM, NativeApps, OG_IMAGE_CONFIG, OG_IMAGE_HEIGHT, OG_IMAGE_WIDTH, ORDER_FULFILLMENT_STATUSES, ORDER_POST_CHECKOUT_STATUSES, OUTBOUND_CHANNELS, OgImageColors, PLATFORM_CURRENCY, PeriodTypeLabels, PeriodTypeOptions, PermissionPresetNames, ReturnStatuses, ReturnUpdateStatuses, SkillMediaBindingRole, SkillScope, SkillType, SupportedAppLocales, TeamManageAccess, TeamViewAccess, UNIFIED_MCP_SERVER_NAME, UserPermissions, UserRoles, abbreviateNumber, addressTypeValues, automationSendChannel, buildAgentMcpServerName, buildAgentSetupClipboardText, buildAppSetupClipboardText, buildFeatureSetupClipboardText, buildMcpServerName, canOpenFulfillmentFlow, canTransitionOrderStatus, cartLineTotal, cartPayableTotal, createCursorMcpInstallLink, defaultInviteTeamRole, documentShareUrl, firstValidationMessage, formatAddressSnapshotLines, fulfillmentMethodValues, fulfillmentStatusValues, getAgentSetupPromptUrl, getAgentsBaseUrl, getApiBaseUrl, getAppBaseUrl, getAssetAppLogoUrl, getAssetChainLogoUrl, getAssetPartnerLogoUrl, getAssetTokenLogoUrl, getAssetWalletLogoUrl, getCortexBaseUrl, getDigestBaseUrl, getDocumentsBaseUrl, getEditableOrderStatuses, getFormsBaseUrl, getFulfillmentFlowAction, getFulfillmentFlowStepperIndex, getGenBaseUrl, getInvoiceEditableStatuses, getLoginUrl, getMcpServerAgentUrl, getMcpServerUrl, getPickupEditableStatuses, getPickupNextAction, getShippingEditableStatuses, getSiteUrl, getSitesBaseUrl, getSitesRootDomain, getStoreBaseUrl, getWarpScreenshotUrl, hasAllPermissions, hasAllTeamPermissions, hasAnyPermissions, hasPermission, hasTeamPermission, integrationSlugForChannel, inviteableTeamRoles, isAutomationSendChannelId, isCampaignChannelId, isCompleteAddressInput, isContactMessageAction, isContactMessageWarpId, isFileFormatAudio, isFileFormatImage, isFileFormatVideo, isNativeApp, isNativeAppAccessible, isNativeAppGated, isNativeAppLocked, isOrderCanceled, isOrderInFulfillment, isOrderPending, isOrderPostCheckout, isPickupOrderReady, isPickupReady, isSupportedAppLocale, isTeamFeatureAccessible, isTeamFeatureGated, isTeamFeatureLocked, isUnifiedMcpUrl, isUserRole, localize, nativeAppSlugs, normalizeAutomationActionType, ogImageUrl, outboundChannel, permissionPresetRules, resolveAccessCatalog, resolveAgentMcpUrl, resolveConnectMcpUrl, resolveFulfillmentFlowStep, resolveOrderStatusDisplay, resolveTeamCurrency, resolveWarpText, returnStatusValues, returnUpdateStatusValues, sanitizeAlphanumeric, sanitizeNumeric, slugifyMcpSegment, teamCategories, toCurrencyDisplay, toHexEncodedNonce, toNameInitials, toNftId, toPreviewText, userPermissionValues, userRoleValues, validationMessageFor, withRetry };
1037
+ export { AUTOMATION_SEND_CHANNELS, AddressTypes, AgentToolingAccess, BillingManageAccess, CAMPAIGN_CHANNELS, CONTACT_MESSAGE_SEND_WARP, ContractCategoryDisplayNames, DefaultAppLocale, DefaultCodeMetadata, DefaultInviteTeamRole, FulfillmentMethods, FulfillmentStatuses, HttpService, InviteableTeamRoles, JoaiUrls, NATIVE_AUTH_TOKEN_PARAM, NativeApps, OG_IMAGE_CONFIG, OG_IMAGE_HEIGHT, OG_IMAGE_WIDTH, ORDER_FULFILLMENT_STATUSES, ORDER_POST_CHECKOUT_STATUSES, OUTBOUND_CHANNELS, OgImageColors, PLATFORM_CURRENCY, PeriodTypeLabels, PeriodTypeOptions, PermissionPresetNames, ReturnStatuses, ReturnUpdateStatuses, SkillMediaBindingRole, SkillScope, SkillType, SupportedAppLocales, TeamManageAccess, TeamViewAccess, UNIFIED_MCP_SERVER_NAME, UserPermissions, UserRoles, abbreviateNumber, addressTypeValues, automationSendChannel, buildAgentMcpServerName, buildAgentSetupClipboardText, buildAppSetupClipboardText, buildFeatureSetupClipboardText, buildMcpServerName, canOpenFulfillmentFlow, canTransitionOrderStatus, cartLineTotal, cartPayableTotal, containedImageDimensions, createCursorMcpInstallLink, cropOutputDimensions, defaultInviteTeamRole, documentShareUrl, firstValidationMessage, formatAddressSnapshotLines, fulfillmentMethodValues, fulfillmentStatusValues, getAgentSetupPromptUrl, getAgentsBaseUrl, getApiBaseUrl, getAppBaseUrl, getAssetAppLogoUrl, getAssetChainLogoUrl, getAssetPartnerLogoUrl, getAssetTokenLogoUrl, getAssetWalletLogoUrl, getCortexBaseUrl, getDigestBaseUrl, getDocumentsBaseUrl, getEditableOrderStatuses, getFormsBaseUrl, getFulfillmentFlowAction, getFulfillmentFlowStepperIndex, getGenBaseUrl, getInvoiceEditableStatuses, getLoginUrl, getMcpServerAgentUrl, getMcpServerUrl, getPickupEditableStatuses, getPickupNextAction, getShippingEditableStatuses, getSiteUrl, getSitesBaseUrl, getSitesRootDomain, getStoreBaseUrl, getWarpScreenshotUrl, hasAllPermissions, hasAllTeamPermissions, hasAnyPermissions, hasPermission, hasTeamPermission, imageCropRectangle, integrationSlugForChannel, inviteableTeamRoles, isAutomationSendChannelId, isCampaignChannelId, isCompleteAddressInput, isContactMessageAction, isContactMessageWarpId, isFileFormatAudio, isFileFormatImage, isFileFormatVideo, isNativeApp, isNativeAppAccessible, isNativeAppGated, isNativeAppLocked, isOrderCanceled, isOrderInFulfillment, isOrderPending, isOrderPostCheckout, isPickupOrderReady, isPickupReady, isSupportedAppLocale, isTeamFeatureAccessible, isTeamFeatureGated, isTeamFeatureLocked, isUnifiedMcpUrl, isUserRole, localize, nativeAppSlugs, normalizeAutomationActionType, ogImageUrl, outboundChannel, permissionPresetRules, resolveAccessCatalog, resolveAgentMcpUrl, resolveConnectMcpUrl, resolveFulfillmentFlowStep, resolveOrderStatusDisplay, resolveTeamCurrency, resolveWarpText, returnStatusValues, returnUpdateStatusValues, sanitizeAlphanumeric, sanitizeNumeric, slugifyMcpSegment, teamCategories, toCurrencyDisplay, toHexEncodedNonce, toNameInitials, toNftId, toPreviewText, userPermissionValues, userRoleValues, validateImageDimensions, validationMessageFor, withRetry };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joai/core",
3
- "version": "4.16.0",
3
+ "version": "5.0.0",
4
4
  "description": "JoAi shared types, HTTP service, and config",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,10 +10,6 @@
10
10
  ".": {
11
11
  "import": "./dist/index.mjs",
12
12
  "types": "./dist/index.d.mts"
13
- },
14
- "./react": {
15
- "import": "./dist/react/index.mjs",
16
- "types": "./dist/react/index.d.mts"
17
13
  }
18
14
  },
19
15
  "files": [
@@ -26,17 +22,10 @@
26
22
  "test:watch": "jest --watch"
27
23
  },
28
24
  "peerDependencies": {
29
- "@joai/warps": ">=4.0.0",
30
- "react": ">=18.0.0"
31
- },
32
- "peerDependenciesMeta": {
33
- "react": {
34
- "optional": true
35
- }
25
+ "@joai/warps": ">=4.0.0"
36
26
  },
37
27
  "devDependencies": {
38
28
  "@types/jest": "^30.0.0",
39
- "@types/react": "^19.2.14",
40
29
  "jest": "^30.3.0",
41
30
  "ts-jest": "^29.4.6",
42
31
  "tsdown": "^0.21.0",
@@ -1,362 +0,0 @@
1
- 'use client';
2
- import * as _$react from "react";
3
- import { ReactNode } from "react";
4
-
5
- //#region src/react/types.d.ts
6
- type EmbedChatItem = {
7
- content: string;
8
- byUser: boolean;
9
- streaming?: boolean;
10
- error?: boolean;
11
- };
12
- //#endregion
13
- //#region src/react/guest.d.ts
14
- declare function getOrCreateGuestId(storageKey?: string): string;
15
- declare function loadRoom(storageKey: string): string | null;
16
- declare function saveRoom(storageKey: string, roomId: string): void;
17
- declare function clearRoom(storageKey: string): void;
18
- //#endregion
19
- //#region src/react/stream-connection.d.ts
20
- type StreamDataHandler = (data: unknown) => void;
21
- declare function openEventSourceStream(url: string, onData: StreamDataHandler, options?: {
22
- withCredentials?: boolean;
23
- onError?: (e: unknown) => void;
24
- onConnectionError?: (e: Event | null) => void;
25
- }): () => void;
26
- //#endregion
27
- //#region src/react/components.d.ts
28
- type ListClassNames = {
29
- container?: string;
30
- userBubble?: string;
31
- agentBubble?: string;
32
- errorBubble?: string;
33
- thinkingWrapper?: string;
34
- dot?: string;
35
- };
36
- type EmbedChatListProps = {
37
- items: EmbedChatItem[];
38
- agentName: string;
39
- awaitingResponse: boolean;
40
- classNames?: ListClassNames;
41
- renderEmptyState?: () => ReactNode;
42
- renderAgentContent?: (item: EmbedChatItem) => ReactNode;
43
- };
44
- declare function EmbedChatList({
45
- items,
46
- agentName,
47
- awaitingResponse,
48
- classNames,
49
- renderEmptyState,
50
- renderAgentContent
51
- }: EmbedChatListProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | _$react.ReactPortal | _$react.ReactElement<unknown, string | _$react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | _$react.JSX.Element | null | undefined;
52
- type EmbedChatInputProps = {
53
- onSend: (message: string) => void;
54
- disabled: boolean;
55
- placeholder?: string;
56
- maxLength?: number;
57
- classNames?: {
58
- container?: string;
59
- textarea?: string;
60
- };
61
- renderSendButton: (props: {
62
- onClick: () => void;
63
- disabled: boolean;
64
- }) => ReactNode;
65
- };
66
- declare function EmbedChatInput({
67
- onSend,
68
- disabled,
69
- placeholder,
70
- maxLength,
71
- classNames,
72
- renderSendButton
73
- }: EmbedChatInputProps): _$react.JSX.Element;
74
- //#endregion
75
- //#region src/http/types.d.ts
76
- interface IHttpService {
77
- readonly baseUrl: string;
78
- readonly authToken: string | null;
79
- onNetworkError: (error: Error) => void;
80
- onUnauthorized: (response: IAppResponse<any>) => void;
81
- onSuccessfulResponse: (response: IAppResponse<any>) => void;
82
- onMaintenanceMode: (response: IAppResponse<any>) => void;
83
- onTooManyRequests: (response: IAppResponse<any>) => void;
84
- get: <T>(url: string, options?: IRequestOptions) => Promise<IAppResponse<T>>;
85
- post: <T>(url: string, data?: any, options?: IRequestOptions) => Promise<IAppResponse<T>>;
86
- put: <T>(url: string, data?: any, options?: IRequestOptions) => Promise<IAppResponse<T>>;
87
- patch: <T>(url: string, data?: any, options?: IRequestOptions) => Promise<IAppResponse<T>>;
88
- delete: <T>(url: string, options?: IRequestOptions) => Promise<IAppResponse<T>>;
89
- }
90
- interface IAppResponse<T> {
91
- data: T;
92
- meta?: any;
93
- body: any;
94
- errors: any;
95
- ok: boolean;
96
- paymentRequired: boolean;
97
- noContent: boolean;
98
- original: Response;
99
- }
100
- interface IRequestOptions {
101
- isJson?: boolean;
102
- headers?: {
103
- [name: string]: string;
104
- };
105
- }
106
- //#endregion
107
- //#region src/react/use-embed-chat.d.ts
108
- type Options = {
109
- agentUuid: string | null;
110
- http: IHttpService;
111
- cortexBaseUrl: string;
112
- guestId: string;
113
- roomStorageKey: string;
114
- enabled?: boolean;
115
- extraPayload?: Record<string, unknown>;
116
- };
117
- declare function useEmbedChat({
118
- agentUuid,
119
- http,
120
- cortexBaseUrl,
121
- guestId,
122
- roomStorageKey,
123
- enabled,
124
- extraPayload
125
- }: Options): {
126
- items: EmbedChatItem[];
127
- setItems: _$react.Dispatch<_$react.SetStateAction<EmbedChatItem[]>>;
128
- sending: boolean;
129
- awaitingResponse: boolean;
130
- roomId: string | null;
131
- setRoomId: _$react.Dispatch<_$react.SetStateAction<string | null>>;
132
- send: (message: string) => Promise<void>;
133
- connectionError: boolean;
134
- };
135
- //#endregion
136
- //#region src/content/types.d.ts
137
- type ContentStatus = 'draft' | 'published' | 'archived';
138
- type ContentFieldType = 'text' | 'richText' | 'number' | 'boolean' | 'url' | 'image' | 'media' | 'list' | 'object' | 'reference';
139
- type ContentField = {
140
- key: string;
141
- type: ContentFieldType;
142
- label?: string;
143
- required?: boolean;
144
- };
145
- type ContentDefinition = {
146
- fields: ContentField[];
147
- };
148
- type ContentValue = string | number | boolean | null | ContentValue[] | {
149
- [key: string]: ContentValue;
150
- };
151
- type ContentEntry = {
152
- key: string;
153
- value: ContentValue;
154
- updatedAt: string;
155
- };
156
- type ContentVersion = {
157
- id: string;
158
- number: number;
159
- status: ContentStatus;
160
- entries: ContentEntry[];
161
- snapshotHash: string;
162
- origin: string;
163
- createdAt: string;
164
- updatedAt: string;
165
- publishedAt: string | null;
166
- };
167
- type Content = {
168
- id: string;
169
- name: string;
170
- slug: string;
171
- schema: string | null;
172
- definition: ContentDefinition;
173
- metadata: Record<string, ContentValue>;
174
- version: ContentVersion | null;
175
- createdAt: string;
176
- updatedAt: string;
177
- };
178
- type ContentPatch = {
179
- key: string;
180
- value: ContentValue;
181
- };
182
- type PatchContentInput = {
183
- expectedVersion: number;
184
- patches: ContentPatch[];
185
- origin?: 'api' | 'inlineEditor' | 'joai' | 'mcp';
186
- publish?: boolean;
187
- };
188
- //#endregion
189
- //#region src/json/types.d.ts
190
- type JsonValue = string | number | boolean | null | JsonValue[] | {
191
- [key: string]: JsonValue;
192
- };
193
- //#endregion
194
- //#region src/media/types.d.ts
195
- type MediaLibraryAttributes = {
196
- uuid: string;
197
- order: number;
198
- name: string;
199
- custom_properties: {
200
- [key: string]: JsonValue;
201
- };
202
- preview_url: null | string;
203
- original_url: null | string;
204
- extension?: string;
205
- size?: number;
206
- };
207
- type MediaMime = 'image/png' | 'image/jpeg' | 'image/gif' | 'image/webp' | 'video/mp4' | 'video/webm' | 'video/quicktime' | 'video/x-msvideo' | 'audio/mpeg' | 'audio/mp3' | 'audio/ogg' | 'audio/wav' | 'audio/webm' | 'audio/aac' | 'audio/m4a' | 'audio/m4b' | 'audio/m4p' | 'audio/m4v' | 'application/pdf' | 'application/json';
208
- type Media = {
209
- id: string;
210
- name: string;
211
- mime: MediaMime;
212
- url: string;
213
- library: MediaLibraryAttributes;
214
- tags?: string[];
215
- copyright?: string | null;
216
- aiGenerated?: boolean;
217
- };
218
- //#endregion
219
- //#region src/react/content/types.d.ts
220
- type ContentResource = {
221
- get: (contentId: string) => Promise<{
222
- ok: boolean;
223
- data?: Content;
224
- }>;
225
- getPublic: (slug: string) => Promise<{
226
- ok: boolean;
227
- data?: Content;
228
- }>;
229
- patch: (contentId: string, input: PatchContentInput) => Promise<{
230
- ok: boolean;
231
- data?: ContentVersion;
232
- }>;
233
- publish: (contentId: string, expectedVersion: number) => Promise<{
234
- ok: boolean;
235
- data?: ContentVersion;
236
- }>;
237
- };
238
- type ContentClient = {
239
- content: ContentResource;
240
- media?: {
241
- list: (team: string, params?: {
242
- page?: number;
243
- mime?: string;
244
- }) => Promise<{
245
- ok: boolean;
246
- data?: Media[];
247
- }>;
248
- upload: (data: {
249
- team: string;
250
- file: File;
251
- type: 'output';
252
- label?: string;
253
- }) => Promise<{
254
- ok: boolean;
255
- data?: Media;
256
- }>;
257
- };
258
- };
259
- type ContentContextValue = {
260
- content: Content | null;
261
- values: Record<string, ContentValue>;
262
- isLoading: boolean;
263
- isSaving: boolean;
264
- isEditing: boolean;
265
- isDirty: boolean;
266
- canEdit: boolean;
267
- canPublish: boolean;
268
- teamSlug?: string;
269
- media?: ContentClient['media'];
270
- error: string | null;
271
- setEditing: (editing: boolean) => void;
272
- setValue: (key: string, value: ContentValue) => void;
273
- save: () => Promise<boolean>;
274
- publish: () => Promise<boolean>;
275
- };
276
- type ContentProviderProp = {
277
- children: ReactNode;
278
- client: ContentClient;
279
- contentId?: string;
280
- publicSlug?: string;
281
- initialContent?: Content;
282
- canEdit?: boolean;
283
- canPublish?: boolean;
284
- teamSlug?: string;
285
- };
286
- type EditableContentProp = {
287
- field: string;
288
- as?: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3';
289
- className?: string;
290
- placeholder?: string;
291
- multiline?: boolean;
292
- };
293
- type EditableImageProp = {
294
- field: string;
295
- alt?: string;
296
- className?: string;
297
- onSelect?: () => void;
298
- inputClassName?: string;
299
- placeholder?: string;
300
- };
301
- type ContentToolbarProp = {
302
- className?: string;
303
- confirmPublish?: () => boolean | Promise<boolean>;
304
- labels?: {
305
- edit?: string;
306
- save?: string;
307
- publish?: string;
308
- cancel?: string;
309
- };
310
- };
311
- //#endregion
312
- //#region src/react/content/provider.d.ts
313
- declare function ContentProvider({
314
- children,
315
- client,
316
- contentId,
317
- publicSlug,
318
- initialContent,
319
- canEdit,
320
- canPublish,
321
- teamSlug
322
- }: ContentProviderProp): _$react.JSX.Element;
323
- //#endregion
324
- //#region src/react/content/editable-content.d.ts
325
- declare function EditableContent({
326
- field,
327
- as: Tag,
328
- className,
329
- placeholder,
330
- multiline
331
- }: EditableContentProp): _$react.JSX.Element;
332
- declare function useContentValue<T extends ContentValue = ContentValue>(key: string): T | undefined;
333
- //#endregion
334
- //#region src/react/content/editable-image.d.ts
335
- declare function EditableImage({
336
- field,
337
- alt,
338
- className,
339
- inputClassName,
340
- placeholder,
341
- onSelect
342
- }: EditableImageProp): _$react.JSX.Element | null;
343
- //#endregion
344
- //#region src/react/content/toolbar.d.ts
345
- declare function ContentToolbar({
346
- className,
347
- labels,
348
- confirmPublish
349
- }: ContentToolbarProp): _$react.JSX.Element | null;
350
- //#endregion
351
- //#region src/react/content/content-editor.d.ts
352
- type Prop = ContentProviderProp & {
353
- children: ReactNode;
354
- title?: string;
355
- };
356
- declare function ContentEditor({
357
- children,
358
- title,
359
- ...provider
360
- }: Prop): _$react.JSX.Element;
361
- //#endregion
362
- export { ContentClient, ContentContextValue, ContentEditor, ContentProvider, ContentProviderProp, ContentResource, ContentToolbar, ContentToolbarProp, EditableContent, EditableContentProp, EditableImage, EditableImageProp, EmbedChatInput, EmbedChatItem, EmbedChatList, StreamDataHandler, clearRoom, getOrCreateGuestId, loadRoom, openEventSourceStream, saveRoom, useContentValue, useEmbedChat };
@@ -1,729 +0,0 @@
1
- 'use client';
2
- import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
3
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
- //#region src/react/guest.ts
5
- function safeGet(key) {
6
- try {
7
- return localStorage.getItem(key);
8
- } catch {
9
- return null;
10
- }
11
- }
12
- function safeSet(key, value) {
13
- try {
14
- localStorage.setItem(key, value);
15
- } catch {}
16
- }
17
- function safeRemove(key) {
18
- try {
19
- localStorage.removeItem(key);
20
- } catch {}
21
- }
22
- function getOrCreateGuestId(storageKey = "joai_embed_guest") {
23
- if (typeof window === "undefined") return "";
24
- const existing = safeGet(storageKey);
25
- if (existing) return existing;
26
- const id = crypto.randomUUID();
27
- safeSet(storageKey, id);
28
- return id;
29
- }
30
- function loadRoom(storageKey) {
31
- return safeGet(storageKey);
32
- }
33
- function saveRoom(storageKey, roomId) {
34
- safeSet(storageKey, roomId);
35
- }
36
- function clearRoom(storageKey) {
37
- safeRemove(storageKey);
38
- }
39
- //#endregion
40
- //#region src/react/stream-connection.ts
41
- function openEventSourceStream(url, onData, options) {
42
- const es = new EventSource(url, { withCredentials: options?.withCredentials ?? false });
43
- es.onmessage = (event) => {
44
- try {
45
- onData(JSON.parse(event.data));
46
- } catch (e) {
47
- options?.onError?.(e);
48
- }
49
- };
50
- es.onerror = (event) => {
51
- options?.onConnectionError?.(event);
52
- };
53
- return () => es.close();
54
- }
55
- //#endregion
56
- //#region src/react/components.tsx
57
- function EmbedChatList({ items, agentName, awaitingResponse, classNames = {}, renderEmptyState, renderAgentContent }) {
58
- const containerRef = useRef(null);
59
- useEffect(() => {
60
- const el = containerRef.current;
61
- if (!el) return;
62
- if (el.scrollHeight - el.scrollTop - el.clientHeight < 120) el.scrollTop = el.scrollHeight;
63
- }, [items, awaitingResponse]);
64
- if (items.length === 0 && !awaitingResponse) return renderEmptyState ? renderEmptyState() : /* @__PURE__ */ jsx("div", {
65
- className: classNames.container,
66
- children: /* @__PURE__ */ jsxs("p", { children: [
67
- "Send ",
68
- agentName,
69
- " a message to start chatting"
70
- ] })
71
- });
72
- return /* @__PURE__ */ jsxs("div", {
73
- ref: containerRef,
74
- className: classNames.container,
75
- role: "log",
76
- "aria-live": "polite",
77
- children: [items.map((item, i) => /* @__PURE__ */ jsx(EmbedChatBubble, {
78
- item,
79
- classNames,
80
- renderAgentContent
81
- }, i)), awaitingResponse && /* @__PURE__ */ jsx(EmbedThinkingIndicator, {
82
- wrapperClassName: classNames.thinkingWrapper,
83
- dotClassName: classNames.dot
84
- })]
85
- });
86
- }
87
- function EmbedChatBubble({ item, classNames, renderAgentContent }) {
88
- if (item.byUser) return /* @__PURE__ */ jsx("div", {
89
- className: classNames.userBubble,
90
- children: item.content
91
- });
92
- return /* @__PURE__ */ jsx("div", {
93
- className: item.error ? classNames.errorBubble : classNames.agentBubble,
94
- children: renderAgentContent ? renderAgentContent(item) : /* @__PURE__ */ jsxs(Fragment, { children: [item.content, item.streaming && /* @__PURE__ */ jsx("span", { className: "inline-block w-1 h-3 ml-1 bg-current animate-pulse rounded-full" })] })
95
- });
96
- }
97
- function EmbedThinkingIndicator({ wrapperClassName, dotClassName }) {
98
- return /* @__PURE__ */ jsx("div", {
99
- className: wrapperClassName,
100
- children: /* @__PURE__ */ jsxs("span", {
101
- className: "inline-flex gap-1",
102
- children: [
103
- /* @__PURE__ */ jsx("span", {
104
- className: dotClassName,
105
- style: { animationDelay: "0ms" }
106
- }),
107
- /* @__PURE__ */ jsx("span", {
108
- className: dotClassName,
109
- style: { animationDelay: "150ms" }
110
- }),
111
- /* @__PURE__ */ jsx("span", {
112
- className: dotClassName,
113
- style: { animationDelay: "300ms" }
114
- })
115
- ]
116
- })
117
- });
118
- }
119
- function EmbedChatInput({ onSend, disabled, placeholder = "Type a message...", maxLength = 4e3, classNames = {}, renderSendButton }) {
120
- const [text, setText] = useState("");
121
- const textareaRef = useRef(null);
122
- function handleSend() {
123
- const trimmed = text.trim();
124
- if (!trimmed || disabled) return;
125
- onSend(trimmed);
126
- setText("");
127
- if (textareaRef.current) textareaRef.current.style.height = "auto";
128
- }
129
- function handleKeyDown(e) {
130
- if (e.key === "Enter" && !e.shiftKey) {
131
- e.preventDefault();
132
- handleSend();
133
- }
134
- }
135
- function handleInput() {
136
- if (textareaRef.current) {
137
- textareaRef.current.style.height = "auto";
138
- textareaRef.current.style.height = Math.min(textareaRef.current.scrollHeight, 120) + "px";
139
- }
140
- }
141
- return /* @__PURE__ */ jsxs("div", {
142
- className: classNames.container,
143
- children: [/* @__PURE__ */ jsx("textarea", {
144
- ref: textareaRef,
145
- value: text,
146
- onChange: (e) => setText(e.target.value),
147
- onKeyDown: handleKeyDown,
148
- onInput: handleInput,
149
- placeholder,
150
- "aria-label": "Message input",
151
- maxLength,
152
- rows: 1,
153
- disabled,
154
- className: classNames.textarea
155
- }), renderSendButton({
156
- onClick: handleSend,
157
- disabled: disabled || !text.trim()
158
- })]
159
- });
160
- }
161
- //#endregion
162
- //#region src/react/use-embed-chat.ts
163
- const RESPONSE_TIMEOUT_MS = 3e4;
164
- function useEmbedChat({ agentUuid, http, cortexBaseUrl, guestId, roomStorageKey, enabled = true, extraPayload }) {
165
- const [items, setItems] = useState([]);
166
- const [sending, setSending] = useState(false);
167
- const [awaitingResponse, setAwaitingResponse] = useState(false);
168
- const [roomId, setRoomId] = useState(null);
169
- const [connectionError, setConnectionError] = useState(false);
170
- const roomIdRef = useRef(null);
171
- roomIdRef.current = roomId;
172
- const extraPayloadRef = useRef(extraPayload);
173
- extraPayloadRef.current = extraPayload;
174
- useEffect(() => {
175
- if (!roomId) return;
176
- setConnectionError(false);
177
- return openEventSourceStream(`${cortexBaseUrl}/agents/stream/${roomId}`, (raw) => {
178
- setConnectionError(false);
179
- const data = raw;
180
- if (data.type === "response:chunk") {
181
- setAwaitingResponse(false);
182
- setItems((prev) => {
183
- const last = prev[prev.length - 1];
184
- if (last && last.streaming && !last.byUser) {
185
- const updated = [...prev];
186
- updated[updated.length - 1] = {
187
- ...last,
188
- content: last.content + (data.content ?? "")
189
- };
190
- return updated;
191
- }
192
- return [...prev, {
193
- content: data.content ?? "",
194
- byUser: false,
195
- streaming: true
196
- }];
197
- });
198
- } else if (data.type === "response") {
199
- setAwaitingResponse(false);
200
- setItems((prev) => {
201
- const updated = [...prev];
202
- const lastIdx = updated.length - 1;
203
- if (lastIdx >= 0 && updated[lastIdx].streaming) updated[lastIdx] = {
204
- ...updated[lastIdx],
205
- content: data.content ?? updated[lastIdx].content,
206
- streaming: false
207
- };
208
- else updated.push({
209
- content: data.content ?? "",
210
- byUser: false
211
- });
212
- return updated;
213
- });
214
- } else if (data.type === "complete") {
215
- setAwaitingResponse(false);
216
- setItems((prev) => prev.map((item) => item.streaming ? {
217
- ...item,
218
- streaming: false
219
- } : item));
220
- }
221
- }, { onConnectionError: () => setConnectionError(true) });
222
- }, [roomId, cortexBaseUrl]);
223
- useEffect(() => {
224
- if (!awaitingResponse) return;
225
- const timer = setTimeout(() => {
226
- setAwaitingResponse(false);
227
- setItems((prev) => [...prev, {
228
- content: "Response timed out. Please try again.",
229
- byUser: false,
230
- error: true
231
- }]);
232
- }, RESPONSE_TIMEOUT_MS);
233
- return () => clearTimeout(timer);
234
- }, [awaitingResponse]);
235
- return {
236
- items,
237
- setItems,
238
- sending,
239
- awaitingResponse,
240
- roomId,
241
- setRoomId,
242
- send: useCallback(async (message) => {
243
- if (!enabled || sending || !agentUuid) return;
244
- setItems((prev) => [...prev, {
245
- content: message,
246
- byUser: true
247
- }]);
248
- setSending(true);
249
- setConnectionError(false);
250
- try {
251
- const res = await http.post(`integrations/embed/${agentUuid}/execute`, {
252
- message,
253
- guestId,
254
- ...extraPayloadRef.current
255
- });
256
- if (!res.ok) {
257
- const msg = res.data && typeof res.data === "object" && "message" in res.data ? res.data.message : "Something went wrong. Please try again.";
258
- setItems((prev) => [...prev, {
259
- content: msg,
260
- byUser: false,
261
- error: true
262
- }]);
263
- return;
264
- }
265
- setAwaitingResponse(true);
266
- const newRoomId = res.data?.roomId;
267
- if (newRoomId && !roomIdRef.current) {
268
- setRoomId(newRoomId);
269
- saveRoom(roomStorageKey, newRoomId);
270
- }
271
- } catch {
272
- setItems((prev) => [...prev, {
273
- content: "Something went wrong. Please try again.",
274
- byUser: false,
275
- error: true
276
- }]);
277
- } finally {
278
- setSending(false);
279
- }
280
- }, [
281
- enabled,
282
- sending,
283
- agentUuid,
284
- http,
285
- guestId,
286
- roomStorageKey
287
- ]),
288
- connectionError
289
- };
290
- }
291
- //#endregion
292
- //#region src/react/content/context.ts
293
- const ContentContext = createContext(null);
294
- function useContent() {
295
- const context = useContext(ContentContext);
296
- if (!context) throw new Error("useContent must be used within a ContentProvider.");
297
- return context;
298
- }
299
- //#endregion
300
- //#region src/react/content/content-cache.ts
301
- const contentCache = /* @__PURE__ */ new Map();
302
- const pendingLoads = /* @__PURE__ */ new Map();
303
- function cacheContent(content) {
304
- contentCache.set(`id:${content.id}`, content);
305
- contentCache.set(`slug:${content.slug}`, content);
306
- }
307
- async function loadContent(client, contentId, publicSlug) {
308
- const target = contentId ?? publicSlug;
309
- if (!target) return null;
310
- const key = contentId ? `id:${contentId}` : `slug:${publicSlug}`;
311
- const cached = contentCache.get(key);
312
- if (cached) return cached;
313
- const pending = pendingLoads.get(key);
314
- if (pending) return pending;
315
- const request = (contentId ? client.content.get(target) : client.content.getPublic(target)).then((result) => result.ok && result.data ? result.data : null).then((content) => {
316
- if (content) cacheContent(content);
317
- return content;
318
- }).finally(() => pendingLoads.delete(key));
319
- pendingLoads.set(key, request);
320
- return request;
321
- }
322
- //#endregion
323
- //#region src/react/content/state.ts
324
- function contentValues(content) {
325
- return Object.fromEntries(content?.version?.entries.map((entry) => [entry.key, entry.value]) ?? []);
326
- }
327
- function contentPatches(content, values) {
328
- const original = contentValues(content);
329
- return Object.entries(values).filter(([key, value]) => JSON.stringify(value) !== JSON.stringify(original[key])).map(([key, value]) => ({
330
- key,
331
- value
332
- }));
333
- }
334
- //#endregion
335
- //#region src/react/content/provider.tsx
336
- function ContentProvider({ children, client, contentId, publicSlug, initialContent, canEdit = false, canPublish = false, teamSlug }) {
337
- const [content, setContent] = useState(initialContent ?? null);
338
- const [values, setValues] = useState(() => contentValues(initialContent ?? null));
339
- const [isLoading, setIsLoading] = useState(!initialContent && Boolean(contentId || publicSlug));
340
- const [isSaving, setIsSaving] = useState(false);
341
- const [isEditing, setEditing] = useState(false);
342
- const [error, setError] = useState(null);
343
- useEffect(() => {
344
- if (initialContent && !contentId) {
345
- cacheContent(initialContent);
346
- setContent(initialContent);
347
- setValues(contentValues(initialContent));
348
- setIsLoading(false);
349
- return;
350
- }
351
- const load = async () => {
352
- if (!contentId && !publicSlug) return;
353
- setIsLoading(true);
354
- setError(null);
355
- const nextContent = await loadContent(client, contentId, publicSlug);
356
- if (!nextContent) setError("Content could not be loaded.");
357
- else {
358
- setContent(nextContent);
359
- setValues(contentValues(nextContent));
360
- }
361
- setIsLoading(false);
362
- };
363
- load();
364
- }, [
365
- contentId,
366
- initialContent,
367
- publicSlug
368
- ]);
369
- const setValue = useCallback((key, value) => {
370
- setValues((current) => ({
371
- ...current,
372
- [key]: value
373
- }));
374
- }, []);
375
- const isDirty = contentPatches(content, values).length > 0;
376
- const save = useCallback(async () => {
377
- if (!content?.version || !contentId || !canEdit) return false;
378
- const patches = contentPatches(content, values);
379
- if (patches.length === 0) return true;
380
- setIsSaving(true);
381
- setError(null);
382
- const result = await client.content.patch(contentId, {
383
- expectedVersion: content.version.number,
384
- patches,
385
- origin: "inlineEditor"
386
- });
387
- setIsSaving(false);
388
- if (!result.ok || !result.data) {
389
- setError("Changes could not be saved. Refresh and try again.");
390
- return false;
391
- }
392
- const nextContent = {
393
- ...content,
394
- version: result.data,
395
- updatedAt: result.data.updatedAt
396
- };
397
- cacheContent(nextContent);
398
- setContent(nextContent);
399
- setValues(contentValues(nextContent));
400
- return true;
401
- }, [
402
- canEdit,
403
- content,
404
- contentId,
405
- values
406
- ]);
407
- const publish = useCallback(async () => {
408
- if (!content?.version || !contentId || !canPublish) return false;
409
- const patches = contentPatches(content, values);
410
- setIsSaving(true);
411
- setError(null);
412
- const result = patches.length > 0 ? await client.content.patch(contentId, {
413
- expectedVersion: content.version.number,
414
- patches,
415
- origin: "inlineEditor",
416
- publish: true
417
- }) : await client.content.publish(contentId, content.version.number);
418
- setIsSaving(false);
419
- if (!result.ok || !result.data) {
420
- setError("Changes could not be published. Refresh and try again.");
421
- return false;
422
- }
423
- const nextContent = {
424
- ...content,
425
- version: result.data,
426
- updatedAt: result.data.updatedAt
427
- };
428
- cacheContent(nextContent);
429
- setContent(nextContent);
430
- setValues(contentValues(nextContent));
431
- setEditing(false);
432
- return true;
433
- }, [
434
- canPublish,
435
- content,
436
- contentId,
437
- values
438
- ]);
439
- const context = useMemo(() => ({
440
- content,
441
- values,
442
- isLoading,
443
- isSaving,
444
- isEditing,
445
- isDirty,
446
- canEdit,
447
- canPublish,
448
- teamSlug,
449
- media: client.media,
450
- error,
451
- setEditing,
452
- setValue,
453
- save,
454
- publish
455
- }), [
456
- canEdit,
457
- canPublish,
458
- content,
459
- error,
460
- isDirty,
461
- isEditing,
462
- isLoading,
463
- isSaving,
464
- publish,
465
- save,
466
- setValue,
467
- teamSlug,
468
- values
469
- ]);
470
- return /* @__PURE__ */ jsx(ContentContext.Provider, {
471
- value: context,
472
- children
473
- });
474
- }
475
- //#endregion
476
- //#region src/react/content/editable-content.tsx
477
- function EditableContent({ field, as: Tag = "span", className, placeholder = "Add text", multiline = false }) {
478
- const { values, isEditing, canEdit, setValue } = useContent();
479
- const value = values[field];
480
- const text = typeof value === "string" || typeof value === "number" ? String(value) : "";
481
- if (!canEdit || !isEditing) return /* @__PURE__ */ jsx(Tag, {
482
- className,
483
- children: text
484
- });
485
- if (multiline) return /* @__PURE__ */ jsx("textarea", {
486
- "aria-label": field,
487
- className,
488
- placeholder,
489
- value: text,
490
- onChange: (event) => setValue(field, event.target.value)
491
- });
492
- return /* @__PURE__ */ jsx("input", {
493
- "aria-label": field,
494
- className,
495
- placeholder,
496
- value: text,
497
- onChange: (event) => setValue(field, event.target.value)
498
- });
499
- }
500
- function useContentValue(key) {
501
- return useContent().values[key];
502
- }
503
- //#endregion
504
- //#region src/react/content/editable-image.tsx
505
- function EditableImage({ field, alt = "", className, inputClassName, placeholder = "Image URL", onSelect }) {
506
- const { values, isEditing, canEdit, media, setValue, teamSlug } = useContent();
507
- const source = typeof values[field] === "string" ? values[field] : "";
508
- const [isPickerOpen, setPickerOpen] = useState(false);
509
- const [images, setImages] = useState([]);
510
- const [isUploading, setUploading] = useState(false);
511
- useEffect(() => {
512
- if (!isPickerOpen || !media || !teamSlug) return;
513
- media.list(teamSlug, { mime: "image/" }).then((result) => setImages(result.ok ? result.data ?? [] : []));
514
- }, [
515
- isPickerOpen,
516
- media,
517
- teamSlug
518
- ]);
519
- const upload = async (file) => {
520
- if (!media || !teamSlug || !file.type.startsWith("image/")) return;
521
- setUploading(true);
522
- const result = await media.upload({
523
- team: teamSlug,
524
- file,
525
- type: "output",
526
- label: file.name
527
- });
528
- setUploading(false);
529
- if (!result.ok || !result.data) return;
530
- setImages((current) => [result.data, ...current]);
531
- setValue(field, result.data.url);
532
- setPickerOpen(false);
533
- };
534
- if (!canEdit || !isEditing) return source ? /* @__PURE__ */ jsx("img", {
535
- src: source,
536
- alt,
537
- className
538
- }) : null;
539
- return /* @__PURE__ */ jsxs("div", {
540
- className,
541
- children: [
542
- source && /* @__PURE__ */ jsx("img", {
543
- src: source,
544
- alt
545
- }),
546
- onSelect && /* @__PURE__ */ jsx("button", {
547
- className: "rounded-lg bg-blue-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-blue-500",
548
- type: "button",
549
- onClick: onSelect,
550
- children: "Choose image"
551
- }),
552
- !onSelect && media && teamSlug && /* @__PURE__ */ jsx("button", {
553
- className: "rounded-lg bg-blue-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-blue-500",
554
- type: "button",
555
- onClick: () => setPickerOpen(true),
556
- children: "Choose image"
557
- }),
558
- /* @__PURE__ */ jsx(ImagePicker, {
559
- open: isPickerOpen,
560
- onClose: () => setPickerOpen(false),
561
- images,
562
- isUploading,
563
- onUpload: upload,
564
- onSelect: (url) => {
565
- setValue(field, url);
566
- setPickerOpen(false);
567
- }
568
- }),
569
- /* @__PURE__ */ jsx("input", {
570
- "aria-label": field,
571
- className: inputClassName,
572
- type: "url",
573
- placeholder,
574
- value: source,
575
- onChange: (event) => setValue(field, event.target.value)
576
- })
577
- ]
578
- });
579
- }
580
- function ImagePicker({ open, onClose, images, isUploading, onUpload, onSelect }) {
581
- if (!open) return null;
582
- return /* @__PURE__ */ jsx("div", {
583
- className: "fixed inset-0 z-[1100] grid place-items-center bg-slate-950/45 p-4",
584
- role: "dialog",
585
- "aria-modal": "true",
586
- "aria-label": "Image library",
587
- children: /* @__PURE__ */ jsxs("div", {
588
- className: "max-h-[min(44rem,calc(100vh-2rem))] w-full max-w-2xl overflow-y-auto rounded-xl bg-white p-5 shadow-2xl",
589
- children: [
590
- /* @__PURE__ */ jsxs("div", {
591
- className: "flex items-start justify-between gap-4",
592
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", {
593
- className: "text-lg font-semibold text-slate-950",
594
- children: "Image library"
595
- }), /* @__PURE__ */ jsx("p", {
596
- className: "mt-1 text-sm text-slate-500",
597
- children: "Choose an existing image or upload a new one."
598
- })] }), /* @__PURE__ */ jsx("button", {
599
- className: "rounded-lg px-3 py-2 text-sm font-medium text-slate-700 transition hover:bg-slate-100",
600
- type: "button",
601
- onClick: onClose,
602
- children: "Close"
603
- })]
604
- }),
605
- /* @__PURE__ */ jsxs("label", {
606
- className: "mt-5 flex cursor-pointer items-center justify-center rounded-lg border border-dashed border-slate-300 px-4 py-6 text-sm font-medium text-slate-600 transition hover:border-blue-400 hover:text-blue-600",
607
- children: [/* @__PURE__ */ jsx("input", {
608
- className: "sr-only",
609
- type: "file",
610
- accept: "image/*",
611
- onChange: (event) => {
612
- const file = event.target.files?.[0];
613
- if (file) onUpload(file);
614
- }
615
- }), "Upload image"]
616
- }),
617
- isUploading && /* @__PURE__ */ jsx("span", {
618
- className: "mt-3 block text-sm text-slate-500",
619
- children: "Uploading…"
620
- }),
621
- /* @__PURE__ */ jsx("div", {
622
- className: "mt-5 grid grid-cols-2 gap-3 sm:grid-cols-3",
623
- role: "list",
624
- children: images.map((image) => /* @__PURE__ */ jsxs("button", {
625
- className: "overflow-hidden rounded-lg border border-slate-200 text-left transition-opacity hover:opacity-75",
626
- type: "button",
627
- onClick: () => onSelect(image.url),
628
- children: [/* @__PURE__ */ jsx("img", {
629
- className: "aspect-square w-full object-cover",
630
- src: image.url,
631
- alt: image.name
632
- }), /* @__PURE__ */ jsx("span", {
633
- className: "block truncate p-2 text-xs text-slate-700",
634
- children: image.name
635
- })]
636
- }, image.id))
637
- })
638
- ]
639
- })
640
- });
641
- }
642
- //#endregion
643
- //#region src/react/content/toolbar.tsx
644
- function ContentToolbar({ className, labels = {}, confirmPublish }) {
645
- const { canEdit, canPublish, isDirty, isEditing, isSaving, error, setEditing, save, publish } = useContent();
646
- if (!canEdit) return null;
647
- const edit = labels.edit ?? "Edit";
648
- const saveLabel = labels.save ?? "Save draft";
649
- const publishLabel = labels.publish ?? "Publish";
650
- const cancel = labels.cancel ?? "Cancel";
651
- const handlePublish = async () => {
652
- if (confirmPublish && !await confirmPublish()) return;
653
- await publish();
654
- };
655
- return /* @__PURE__ */ jsxs("div", {
656
- className: `flex flex-wrap items-center gap-2 ${className ?? ""}`,
657
- role: "toolbar",
658
- "aria-label": "Content editor",
659
- children: [
660
- !isEditing ? /* @__PURE__ */ jsx("button", {
661
- className: "rounded-lg bg-blue-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-blue-500",
662
- type: "button",
663
- onClick: () => setEditing(true),
664
- children: edit
665
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [
666
- /* @__PURE__ */ jsx("button", {
667
- className: "rounded-lg bg-blue-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-blue-500 disabled:opacity-60",
668
- type: "button",
669
- disabled: isSaving,
670
- onClick: () => void save(),
671
- children: isSaving ? "Saving…" : saveLabel
672
- }),
673
- canPublish && /* @__PURE__ */ jsx("button", {
674
- className: "rounded-lg bg-emerald-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-emerald-500 disabled:opacity-60",
675
- type: "button",
676
- disabled: isSaving,
677
- onClick: () => void handlePublish(),
678
- children: publishLabel
679
- }),
680
- /* @__PURE__ */ jsx("button", {
681
- className: "rounded-lg px-3 py-2 text-sm font-medium text-slate-700 transition hover:bg-slate-100 disabled:opacity-60",
682
- type: "button",
683
- disabled: isSaving,
684
- onClick: () => setEditing(false),
685
- children: cancel
686
- })
687
- ] }),
688
- error && /* @__PURE__ */ jsx("span", {
689
- className: "w-full text-sm text-red-600 dark:text-red-400",
690
- role: "alert",
691
- children: error
692
- }),
693
- isEditing && isDirty && /* @__PURE__ */ jsx("span", {
694
- className: "w-full text-xs text-slate-500",
695
- "aria-live": "polite",
696
- children: "Unsaved changes"
697
- })
698
- ]
699
- });
700
- }
701
- //#endregion
702
- //#region src/react/content/content-editor.tsx
703
- function EditorPanel({ title }) {
704
- const { canEdit } = useContent();
705
- if (!canEdit) return null;
706
- return /* @__PURE__ */ jsxs("div", {
707
- className: "fixed right-4 bottom-4 z-[1000] w-[min(24rem,calc(100vw-2rem))] rounded-xl border border-slate-200 bg-white p-3 text-slate-950 shadow-xl",
708
- children: [/* @__PURE__ */ jsx("strong", {
709
- className: "mb-2 block text-sm font-semibold",
710
- children: title
711
- }), /* @__PURE__ */ jsx(ContentToolbar, { labels: {
712
- edit: "Edit",
713
- save: "Save draft",
714
- publish: "Publish",
715
- cancel: "Cancel"
716
- } })]
717
- });
718
- }
719
- function ContentEditor({ children, title = "JoAi Content", ...provider }) {
720
- return /* @__PURE__ */ jsx(ContentProvider, {
721
- ...provider,
722
- children: /* @__PURE__ */ jsxs("div", {
723
- "data-joai-content-editor": "true",
724
- children: [/* @__PURE__ */ jsx(EditorPanel, { title }), children]
725
- })
726
- });
727
- }
728
- //#endregion
729
- export { ContentEditor, ContentProvider, ContentToolbar, EditableContent, EditableImage, EmbedChatInput, EmbedChatList, clearRoom, getOrCreateGuestId, loadRoom, openEventSourceStream, saveRoom, useContentValue, useEmbedChat };