@joai/core 4.5.0 → 4.7.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.mjs CHANGED
@@ -42,6 +42,7 @@ const getAgentsBaseUrl = (env) => {
42
42
  if (env === "testnet") return "https://testnet-agents.joai.ai";
43
43
  return "https://agents.joai.ai";
44
44
  };
45
+ const getMcpServerUrl = (env) => `${getCortexBaseUrl(env)}/mcp`;
45
46
  const getMcpServerAgentUrl = (env, agent) => `${getCortexBaseUrl(env)}/mcp/agents/${agent}`;
46
47
  const getSitesBaseUrl = (env) => {
47
48
  if (env === "local") return "http://sites.joai--api.test:3007";
@@ -370,10 +371,29 @@ const ContractCategoryDisplayNames = {
370
371
  };
371
372
  //#endregion
372
373
  //#region src/mcp/agent-setup.ts
374
+ const UNIFIED_MCP_SERVER_NAME = "joai";
375
+ const AGENT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
376
+ const isUnifiedMcpUrl = (mcpUrl) => {
377
+ try {
378
+ return (new URL(mcpUrl).pathname.replace(/\/+$/, "") || "/") === "/mcp";
379
+ } catch {
380
+ return false;
381
+ }
382
+ };
373
383
  const getAgentSetupPromptUrl = (env) => `${getAppBaseUrl(env)}/prompts/setup-agent.md`;
374
384
  const buildAgentSetupClipboardText = (env, target) => {
385
+ const promptUrl = getAgentSetupPromptUrl(env);
386
+ if (isUnifiedMcpUrl(target.mcpUrl)) return [
387
+ `Fetch and execute the appropriate instructions to set me up for JoAi from ${promptUrl}`,
388
+ "",
389
+ "Connect me to JoAi MCP:",
390
+ `- MCP: ${target.mcpUrl}`,
391
+ `- Agent: ${target.agentName}`,
392
+ "",
393
+ "Authenticate with OAuth. The agent in the MCP URL is preselected and can be changed."
394
+ ].join("\n");
375
395
  return [
376
- `Fetch and execute the appropriate instructions to set me up for JoAi from ${getAgentSetupPromptUrl(env)}`,
396
+ `Fetch and execute the appropriate instructions to set me up for JoAi from ${promptUrl}`,
377
397
  "",
378
398
  "Connect me to this JoAi agent:",
379
399
  `- Agent: ${target.agentName}`,
@@ -396,6 +416,16 @@ const createCursorMcpInstallLink = (mcpServerUrl, serverName) => {
396
416
  const encodedConfig = encodeURIComponent(btoa(configJson));
397
417
  return `https://cursor.com/en-US/install-mcp?name=${encodeURIComponent(serverName)}&config=${encodedConfig}`;
398
418
  };
419
+ /** Default owner/connect MCP URL. Optional agent UUID soft-prefills OAuth via `?agent=`. */
420
+ const resolveConnectMcpUrl = (env, mcpEndpoint, preferredAgentUuid) => {
421
+ const trimmed = mcpEndpoint?.trim();
422
+ const base = trimmed && isUnifiedMcpUrl(trimmed) ? `${new URL(trimmed).origin}${new URL(trimmed).pathname.replace(/\/+$/, "") || "/mcp"}` : `${getCortexBaseUrl(env)}/mcp`;
423
+ const fromUrl = trimmed && isUnifiedMcpUrl(trimmed) ? new URL(trimmed).searchParams.get("agent") || new URL(trimmed).searchParams.get("agent_uuid") : null;
424
+ const preferred = preferredAgentUuid?.trim() || fromUrl;
425
+ if (preferred && AGENT_UUID_RE.test(preferred)) return `${base}?agent=${encodeURIComponent(preferred)}`;
426
+ return base;
427
+ };
428
+ /** Agent-scoped MCP URL for public/direct addressing (Agent0, x402, marketplace). */
399
429
  const resolveAgentMcpUrl = (env, agentUuid, mcpEndpoint) => mcpEndpoint?.trim() || `${getCortexBaseUrl(env)}/mcp/agents/${agentUuid}`;
400
430
  const slugifyMcpSegment = (value) => value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
401
431
  const buildMcpServerName = (slug, teamName) => {
@@ -500,6 +530,8 @@ const UserPermissions = {
500
530
  BillingManage: "billing-manage",
501
531
  TeamManage: "team-manage",
502
532
  TeamView: "team-view",
533
+ ContentEdit: "content-edit",
534
+ ContentPublish: "content-publish",
503
535
  TeamMemberInvite: "team-member-invite",
504
536
  TeamMemberRemove: "team-member-remove",
505
537
  TeamSecretView: "team-secret-view",
@@ -585,4 +617,4 @@ const DefaultInviteTeamRole = UserRoles.Member;
585
617
  const inviteableTeamRoles = () => [...InviteableTeamRoles];
586
618
  const defaultInviteTeamRole = () => DefaultInviteTeamRole;
587
619
  //#endregion
588
- export { AddressTypes, AgentToolingAccess, BillingManageAccess, ContractCategoryDisplayNames, DefaultCodeMetadata, DefaultInviteTeamRole, FulfillmentMethods, FulfillmentStatuses, HttpService, InviteableTeamRoles, JoaiUrls, NATIVE_AUTH_TOKEN_PARAM, NativeApps, OG_IMAGE_CONFIG, OG_IMAGE_HEIGHT, OG_IMAGE_WIDTH, OgImageColors, PeriodTypeLabels, PeriodTypeOptions, PermissionPresetNames, ReturnStatuses, ReturnUpdateStatuses, SkillMediaBindingRole, SkillScope, SkillType, TeamManageAccess, TeamViewAccess, UserPermissions, UserRoles, abbreviateNumber, addressTypeValues, buildAgentMcpServerName, buildAgentSetupClipboardText, buildAppSetupClipboardText, buildMcpServerName, cartLineTotal, createCursorMcpInstallLink, defaultInviteTeamRole, fulfillmentMethodValues, fulfillmentStatusValues, getAgentSetupPromptUrl, getAgentsBaseUrl, getApiBaseUrl, getAppBaseUrl, getAssetAppLogoUrl, getAssetChainLogoUrl, getAssetPartnerLogoUrl, getAssetTokenLogoUrl, getAssetWalletLogoUrl, getCortexBaseUrl, getDigestBaseUrl, getFormsBaseUrl, getLoginUrl, getMcpServerAgentUrl, getSiteUrl, getSitesBaseUrl, getSitesRootDomain, getStoreBaseUrl, getWarpScreenshotUrl, hasAllPermissions, hasAllTeamPermissions, hasAnyPermissions, hasPermission, hasTeamPermission, inviteableTeamRoles, isCompleteAddressInput, isFileFormatAudio, isFileFormatImage, isFileFormatVideo, isNativeApp, isNativeAppAccessible, isNativeAppGated, isNativeAppLocked, isTeamFeatureAccessible, isTeamFeatureGated, isTeamFeatureLocked, isUserRole, localize, nativeAppSlugs, ogImageUrl, permissionPresetRules, resolveAccessCatalog, resolveAgentMcpUrl, resolveWarpText, returnStatusValues, returnUpdateStatusValues, sanitizeAlphanumeric, sanitizeNumeric, slugifyMcpSegment, teamCategories, toCurrencyDisplay, toHexEncodedNonce, toNameInitials, toNftId, toPreviewText, userPermissionValues, userRoleValues, withRetry };
620
+ export { AddressTypes, AgentToolingAccess, BillingManageAccess, ContractCategoryDisplayNames, DefaultCodeMetadata, DefaultInviteTeamRole, FulfillmentMethods, FulfillmentStatuses, HttpService, InviteableTeamRoles, JoaiUrls, NATIVE_AUTH_TOKEN_PARAM, NativeApps, OG_IMAGE_CONFIG, OG_IMAGE_HEIGHT, OG_IMAGE_WIDTH, OgImageColors, PeriodTypeLabels, PeriodTypeOptions, PermissionPresetNames, ReturnStatuses, ReturnUpdateStatuses, SkillMediaBindingRole, SkillScope, SkillType, TeamManageAccess, TeamViewAccess, UNIFIED_MCP_SERVER_NAME, UserPermissions, UserRoles, abbreviateNumber, addressTypeValues, buildAgentMcpServerName, buildAgentSetupClipboardText, buildAppSetupClipboardText, buildMcpServerName, cartLineTotal, createCursorMcpInstallLink, defaultInviteTeamRole, fulfillmentMethodValues, fulfillmentStatusValues, getAgentSetupPromptUrl, getAgentsBaseUrl, getApiBaseUrl, getAppBaseUrl, getAssetAppLogoUrl, getAssetChainLogoUrl, getAssetPartnerLogoUrl, getAssetTokenLogoUrl, getAssetWalletLogoUrl, getCortexBaseUrl, getDigestBaseUrl, getFormsBaseUrl, getLoginUrl, getMcpServerAgentUrl, getMcpServerUrl, getSiteUrl, getSitesBaseUrl, getSitesRootDomain, getStoreBaseUrl, getWarpScreenshotUrl, hasAllPermissions, hasAllTeamPermissions, hasAnyPermissions, hasPermission, hasTeamPermission, inviteableTeamRoles, isCompleteAddressInput, isFileFormatAudio, isFileFormatImage, isFileFormatVideo, isNativeApp, isNativeAppAccessible, isNativeAppGated, isNativeAppLocked, isTeamFeatureAccessible, isTeamFeatureGated, isTeamFeatureLocked, isUnifiedMcpUrl, isUserRole, localize, nativeAppSlugs, ogImageUrl, permissionPresetRules, resolveAccessCatalog, resolveAgentMcpUrl, resolveConnectMcpUrl, resolveWarpText, returnStatusValues, returnUpdateStatusValues, sanitizeAlphanumeric, sanitizeNumeric, slugifyMcpSegment, teamCategories, toCurrencyDisplay, toHexEncodedNonce, toNameInitials, toNftId, toPreviewText, userPermissionValues, userRoleValues, withRetry };
@@ -1,4 +1,4 @@
1
- import { n as IHttpService } from "../types-CWSaEVa7.mjs";
1
+ 'use client';
2
2
  import * as _$react from "react";
3
3
  import { ReactNode } from "react";
4
4
 
@@ -72,6 +72,37 @@ declare function EmbedChatInput({
72
72
  renderSendButton
73
73
  }: EmbedChatInputProps): _$react.JSX.Element;
74
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
+ get: <T>(url: string, options?: IRequestOptions) => Promise<IAppResponse<T>>;
84
+ post: <T>(url: string, data?: any, options?: IRequestOptions) => Promise<IAppResponse<T>>;
85
+ put: <T>(url: string, data?: any, options?: IRequestOptions) => Promise<IAppResponse<T>>;
86
+ patch: <T>(url: string, data?: any, options?: IRequestOptions) => Promise<IAppResponse<T>>;
87
+ delete: <T>(url: string, options?: IRequestOptions) => Promise<IAppResponse<T>>;
88
+ }
89
+ interface IAppResponse<T> {
90
+ data: T;
91
+ meta?: any;
92
+ body: any;
93
+ errors: any;
94
+ ok: boolean;
95
+ paymentRequired: boolean;
96
+ noContent: boolean;
97
+ original: Response;
98
+ }
99
+ interface IRequestOptions {
100
+ isJson?: boolean;
101
+ headers?: {
102
+ [name: string]: string;
103
+ };
104
+ }
105
+ //#endregion
75
106
  //#region src/react/use-embed-chat.d.ts
76
107
  type Options = {
77
108
  agentUuid: string | null;
@@ -101,4 +132,229 @@ declare function useEmbedChat({
101
132
  connectionError: boolean;
102
133
  };
103
134
  //#endregion
104
- export { EmbedChatInput, EmbedChatItem, EmbedChatList, StreamDataHandler, clearRoom, getOrCreateGuestId, loadRoom, openEventSourceStream, saveRoom, useEmbedChat };
135
+ //#region src/content/types.d.ts
136
+ type ContentStatus = 'draft' | 'published' | 'archived';
137
+ type ContentFieldType = 'text' | 'richText' | 'number' | 'boolean' | 'url' | 'image' | 'media' | 'list' | 'object' | 'reference';
138
+ type ContentField = {
139
+ key: string;
140
+ type: ContentFieldType;
141
+ label?: string;
142
+ required?: boolean;
143
+ };
144
+ type ContentDefinition = {
145
+ fields: ContentField[];
146
+ };
147
+ type ContentValue = string | number | boolean | null | ContentValue[] | {
148
+ [key: string]: ContentValue;
149
+ };
150
+ type ContentEntry = {
151
+ key: string;
152
+ value: ContentValue;
153
+ updatedAt: string;
154
+ };
155
+ type ContentVersion = {
156
+ id: string;
157
+ number: number;
158
+ status: ContentStatus;
159
+ entries: ContentEntry[];
160
+ snapshotHash: string;
161
+ origin: string;
162
+ createdAt: string;
163
+ updatedAt: string;
164
+ publishedAt: string | null;
165
+ };
166
+ type Content = {
167
+ id: string;
168
+ name: string;
169
+ slug: string;
170
+ schema: string | null;
171
+ definition: ContentDefinition;
172
+ metadata: Record<string, ContentValue>;
173
+ version: ContentVersion | null;
174
+ createdAt: string;
175
+ updatedAt: string;
176
+ };
177
+ type ContentPatch = {
178
+ key: string;
179
+ value: ContentValue;
180
+ };
181
+ type PatchContentInput = {
182
+ expectedVersion: number;
183
+ patches: ContentPatch[];
184
+ origin?: 'api' | 'inlineEditor' | 'joai' | 'mcp';
185
+ };
186
+ //#endregion
187
+ //#region src/json/types.d.ts
188
+ type JsonValue = string | number | boolean | null | JsonValue[] | {
189
+ [key: string]: JsonValue;
190
+ };
191
+ //#endregion
192
+ //#region src/media/types.d.ts
193
+ type MediaLibraryAttributes = {
194
+ uuid: string;
195
+ order: number;
196
+ name: string;
197
+ custom_properties: {
198
+ [key: string]: JsonValue;
199
+ };
200
+ preview_url: null | string;
201
+ original_url: null | string;
202
+ extension?: string;
203
+ size?: number;
204
+ };
205
+ 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';
206
+ type Media = {
207
+ id: string;
208
+ name: string;
209
+ mime: MediaMime;
210
+ url: string;
211
+ library: MediaLibraryAttributes;
212
+ tags?: string[];
213
+ copyright?: string | null;
214
+ aiGenerated?: boolean;
215
+ };
216
+ //#endregion
217
+ //#region src/react/content/types.d.ts
218
+ type ContentResource = {
219
+ get: (contentId: string) => Promise<{
220
+ ok: boolean;
221
+ data?: Content;
222
+ }>;
223
+ getPublic: (slug: string) => Promise<{
224
+ ok: boolean;
225
+ data?: Content;
226
+ }>;
227
+ patch: (contentId: string, input: PatchContentInput) => Promise<{
228
+ ok: boolean;
229
+ data?: ContentVersion;
230
+ }>;
231
+ publish: (contentId: string, expectedVersion: number) => Promise<{
232
+ ok: boolean;
233
+ data?: ContentVersion;
234
+ }>;
235
+ };
236
+ type ContentClient = {
237
+ content: ContentResource;
238
+ media?: {
239
+ list: (team: string, params?: {
240
+ page?: number;
241
+ mime?: string;
242
+ }) => Promise<{
243
+ ok: boolean;
244
+ data?: Media[];
245
+ }>;
246
+ upload: (data: {
247
+ team: string;
248
+ file: File;
249
+ type: 'output';
250
+ label?: string;
251
+ }) => Promise<{
252
+ ok: boolean;
253
+ data?: Media;
254
+ }>;
255
+ };
256
+ };
257
+ type ContentContextValue = {
258
+ content: Content | null;
259
+ values: Record<string, ContentValue>;
260
+ isLoading: boolean;
261
+ isSaving: boolean;
262
+ isEditing: boolean;
263
+ isDirty: boolean;
264
+ canEdit: boolean;
265
+ canPublish: boolean;
266
+ teamSlug?: string;
267
+ media?: ContentClient['media'];
268
+ error: string | null;
269
+ setEditing: (editing: boolean) => void;
270
+ setValue: (key: string, value: ContentValue) => void;
271
+ save: () => Promise<boolean>;
272
+ publish: () => Promise<boolean>;
273
+ };
274
+ type ContentProviderProp = {
275
+ children: ReactNode;
276
+ client: ContentClient;
277
+ contentId?: string;
278
+ publicSlug?: string;
279
+ initialContent?: Content;
280
+ canEdit?: boolean;
281
+ canPublish?: boolean;
282
+ teamSlug?: string;
283
+ };
284
+ type EditableContentProp = {
285
+ field: string;
286
+ as?: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3';
287
+ className?: string;
288
+ placeholder?: string;
289
+ multiline?: boolean;
290
+ };
291
+ type EditableImageProp = {
292
+ field: string;
293
+ alt?: string;
294
+ className?: string;
295
+ onSelect?: () => void;
296
+ inputClassName?: string;
297
+ placeholder?: string;
298
+ };
299
+ type ContentToolbarProp = {
300
+ className?: string;
301
+ confirmPublish?: () => boolean | Promise<boolean>;
302
+ labels?: {
303
+ edit?: string;
304
+ save?: string;
305
+ publish?: string;
306
+ cancel?: string;
307
+ };
308
+ };
309
+ //#endregion
310
+ //#region src/react/content/provider.d.ts
311
+ declare function ContentProvider({
312
+ children,
313
+ client,
314
+ contentId,
315
+ publicSlug,
316
+ initialContent,
317
+ canEdit,
318
+ canPublish,
319
+ teamSlug
320
+ }: ContentProviderProp): _$react.JSX.Element;
321
+ //#endregion
322
+ //#region src/react/content/editable-content.d.ts
323
+ declare function EditableContent({
324
+ field,
325
+ as: Tag,
326
+ className,
327
+ placeholder,
328
+ multiline
329
+ }: EditableContentProp): _$react.JSX.Element;
330
+ declare function useContentValue<T extends ContentValue = ContentValue>(key: string): T | undefined;
331
+ //#endregion
332
+ //#region src/react/content/editable-image.d.ts
333
+ declare function EditableImage({
334
+ field,
335
+ alt,
336
+ className,
337
+ inputClassName,
338
+ placeholder,
339
+ onSelect
340
+ }: EditableImageProp): _$react.JSX.Element | null;
341
+ //#endregion
342
+ //#region src/react/content/toolbar.d.ts
343
+ declare function ContentToolbar({
344
+ className,
345
+ labels,
346
+ confirmPublish
347
+ }: ContentToolbarProp): _$react.JSX.Element | null;
348
+ //#endregion
349
+ //#region src/react/content/content-editor.d.ts
350
+ type Prop = ContentProviderProp & {
351
+ children: ReactNode;
352
+ title?: string;
353
+ };
354
+ declare function ContentEditor({
355
+ children,
356
+ title,
357
+ ...provider
358
+ }: Prop): _$react.JSX.Element;
359
+ //#endregion
360
+ export { ContentClient, ContentContextValue, ContentEditor, ContentProvider, ContentProviderProp, ContentResource, ContentToolbar, ContentToolbarProp, EditableContent, EditableContentProp, EditableImage, EditableImageProp, EmbedChatInput, EmbedChatItem, EmbedChatList, StreamDataHandler, clearRoom, getOrCreateGuestId, loadRoom, openEventSourceStream, saveRoom, useContentValue, useEmbedChat };