From 5f5beca4f5a8993ce06e036a6deef8e874eb85cc Mon Sep 17 00:00:00 2001 From: Marcos Candeia Date: Wed, 11 Sep 2024 14:55:25 -0300 Subject: [PATCH] Migrating to use @deco/deco from jsr (#845) * Migrating to use @deco/deco from jsr Signed-off-by: Marcos Candeia * Add necessary imports Signed-off-by: Marcos Candeia * Use setcookie from std Signed-off-by: Marcos Candeia * Upgrade deco version Signed-off-by: Marcos Candeia --------- Signed-off-by: Marcos Candeia --- admin/types.ts | 15 +- ai-assistants/actions/awsUploadImage.ts | 12 +- ai-assistants/actions/chat.ts | 50 ++---- ai-assistants/actions/describeImage.ts | 9 +- ai-assistants/actions/transcribeAudio.ts | 9 +- ai-assistants/chat/messages.ts | 149 +++++++---------- ai-assistants/mod.ts | 49 ++---- ai-assistants/runtime.ts | 3 +- ai-assistants/schema.ts | 13 +- ai-assistants/utils/blobConversion.ts | 9 +- algolia/mod.ts | 19 +-- algolia/sections/Analytics/Algolia.tsx | 50 ++---- algolia/workflows/index/product.ts | 42 +++-- analytics/components/DecoAnalytics.tsx | 38 ++--- analytics/loaders/DecoAnalyticsScript.ts | 33 +--- analytics/mod.ts | 10 +- anthropic/actions/code.ts | 13 +- anthropic/actions/stream.ts | 38 ++--- anthropic/mod.ts | 5 +- blog/mod.ts | 10 +- blog/utils/records.ts | 5 +- brand-assistant/loaders/assistant.ts | 7 +- brand-assistant/mod.ts | 10 +- commerce/mod.ts | 32 ++-- commerce/types.ts | 132 ++------------- compat/$live/handlers/devPage.ts | 17 +- compat/$live/handlers/router.ts | 16 +- compat/$live/loaders/state.ts | 31 ++-- compat/$live/mod.ts | 20 +-- compat/$live/sections/PageInclude.tsx | 10 +- compat/$live/sections/Slot.tsx | 13 +- .../functions/vtexLegacyProductDetailsPage.ts | 25 +-- compat/std/functions/vtexLegacyProductList.ts | 13 +- .../functions/vtexLegacyProductListingPage.ts | 28 +--- .../vtexLegacyRelatedProductsLoader.ts | 24 +-- compat/std/functions/vtexNavbar.ts | 15 +- .../std/functions/vtexProductDetailsPage.ts | 25 +-- compat/std/functions/vtexProductList.ts | 14 +- .../std/functions/vtexProductListingPage.ts | 30 +--- compat/std/functions/vtexSuggestions.ts | 19 +-- compat/std/functions/vtexWishlist.ts | 36 ++-- compat/std/mod.ts | 79 +++------ compat/std/runtime.ts | 3 +- compat/std/sections/Analytics.tsx | 18 +- crux/mod.ts | 6 +- crux/preview/Preview.tsx | 6 +- decohub/apps/vtex.ts | 4 +- decohub/mod.ts | 67 ++++---- deno.json | 24 +-- emailjs/mod.ts | 17 +- files/loaders/app.ts | 70 ++------ files/mod.ts | 9 +- htmx/mod.ts | 10 +- htmx/sections/Deferred.tsx | 20 +-- htmx/sections/htmx.tsx | 9 +- implementation/mod.ts | 12 +- konfidency/loaders/productDetailsPage.ts | 6 +- konfidency/mod.ts | 12 +- linx-impulse/mod.ts | 26 +-- linx-impulse/runtime.ts | 3 +- .../Analytics/LinxImpulsePageView.tsx | 85 +++------- .../sections/Script/LinxImpulseScript.tsx | 4 +- linx/loaders/page.ts | 10 +- linx/loaders/pages.ts | 10 +- linx/loaders/path.ts | 13 +- linx/mod.ts | 20 +-- linx/runtime.ts | 3 +- mailchimp/actions/subscribe.ts | 2 +- mailchimp/loaders/options/lists.ts | 5 +- mailchimp/mod.ts | 15 +- nuvemshop/mod.ts | 39 ++--- nuvemshop/runtime.ts | 3 +- nuvemshop/utils/types.ts | 39 +---- openai/mod.ts | 10 +- power-reviews/mod.ts | 19 +-- ra-trustvox/mod.ts | 12 +- ra-trustvox/sections/TrustvoxCertificate.tsx | 13 +- .../sections/TrustvoxProductReviews.tsx | 22 +-- ra-trustvox/sections/TrustvoxRateConfig.tsx | 32 +--- .../sections/TrustvoxStoreReviewsCarousel.tsx | 20 +-- records/deps.ts | 3 +- records/mod.ts | 16 +- records/utils.ts | 9 +- resend/README.md | 2 +- resend/mod.ts | 32 ++-- scripts/new.ts | 2 +- shopify/mod.ts | 19 +-- shopify/runtime.ts | 3 +- smarthint/loaders/productListingPage.ts | 27 +-- smarthint/mod.ts | 16 +- smarthint/runtime.ts | 3 +- .../sections/Analytics/SmarthintTracking.tsx | 78 +++------ sourei/mod.ts | 5 +- sourei/sections/Analytics/Sourei.tsx | 31 +--- typesense/mod.ts | 21 +-- typesense/workflows/index/product.ts | 33 ++-- utils/cookie.ts | 12 +- utils/fetch.ts | 35 ++-- utils/framework.tsx | 3 +- utils/http.ts | 82 ++++----- utils/weakcache.ts | 1 + verified-reviews/mod.ts | 5 +- verified-reviews/utils/client.ts | 65 +++----- vnda/actions/cart/simulation.ts | 6 +- vnda/mod.ts | 20 +-- vnda/runtime.ts | 3 +- .../VTEXPortalDataLayerCompatibility.tsx | 65 +++----- vtex/loaders/collections/list.ts | 31 ++-- .../intelligentSearch/productListingPage.ts | 129 ++++---------- vtex/loaders/options/productIdByTerm.ts | 14 +- vtex/mod.ts | 46 ++--- vtex/preview/Preview.tsx | 21 +-- vtex/runtime.ts | 3 +- vtex/sections/Analytics/Vtex.tsx | 27 +-- vtex/workflows/events.ts | 14 +- vtex/workflows/product/index.ts | 18 +- wake/mod.ts | 21 +-- wake/runtime.ts | 3 +- wap/mod.ts | 15 +- wap/runtime.ts | 3 +- weather/mod.ts | 10 +- website/actions/secrets/encrypt.ts | 6 +- website/components/Analytics.tsx | 28 +--- website/components/Clickhouse.tsx | 157 +++++++++--------- website/components/Events.tsx | 46 ++--- website/components/_Controls.tsx | 33 +--- website/flags/audience.ts | 26 ++- website/flags/everyone.ts | 19 +-- website/flags/flag.ts | 13 +- website/flags/multivariate/image.ts | 3 +- website/flags/multivariate/message.ts | 4 +- website/flags/multivariate/page.ts | 4 +- website/flags/multivariate/section.ts | 4 +- website/functions/requestToParam.ts | 17 +- website/handlers/fresh.ts | 87 ++++------ website/handlers/proxy.ts | 55 +----- website/handlers/redirect.ts | 4 +- website/handlers/router.ts | 117 ++++--------- website/handlers/sitemap.ts | 11 +- website/loaders/asset.ts | 9 +- website/loaders/extension.ts | 6 +- website/loaders/options/routes.ts | 15 +- website/loaders/options/urlParams.ts | 8 +- website/loaders/pages.ts | 5 +- website/loaders/redirects.ts | 5 +- website/loaders/secret.ts | 9 +- website/matchers/cookie.ts | 10 +- website/matchers/device.ts | 8 +- website/matchers/host.ts | 11 +- website/matchers/location.ts | 28 +--- website/matchers/multi.ts | 5 +- website/matchers/negate.ts | 5 +- website/matchers/pathname.ts | 24 +-- website/matchers/queryString.ts | 30 +--- website/matchers/site.ts | 5 +- website/matchers/userAgent.ts | 6 +- website/mod.ts | 60 ++----- website/pages/Page.tsx | 88 ++++------ website/sections/Rendering/Deferred.tsx | 42 +---- website/sections/Rendering/Lazy.tsx | 41 +---- website/utils/multivariate.ts | 13 +- workflows/actions/start.ts | 43 ++--- workflows/handlers/workflowRunner.ts | 12 +- workflows/initializer.ts | 4 +- workflows/loaders/events.ts | 9 +- workflows/loaders/get.ts | 3 +- workflows/mod.ts | 10 +- workflows/utils/awaiters.ts | 17 +- 168 files changed, 1147 insertions(+), 2845 deletions(-) create mode 100644 utils/weakcache.ts diff --git a/admin/types.ts b/admin/types.ts index 75ad8e5df..ad617df3b 100644 --- a/admin/types.ts +++ b/admin/types.ts @@ -1,23 +1,19 @@ -import { type Resolvable } from "deco/engine/core/resolver.ts"; import { type fjp } from "./deps.ts"; - +import { type Resolvable } from "@deco/deco"; export interface Pagination { data: T[]; page: number; pageSize: number; total: number; } - export interface PatchState { type: "patch-state"; payload: fjp.Operation[]; revision: string; } - export interface FetchState { type: "fetch-state"; } - export interface StatePatched { type: "state-patched"; payload: fjp.Operation[]; @@ -25,24 +21,21 @@ export interface StatePatched { // Maybe add data and user info in here metadata?: unknown; } - export interface StateFetched { type: "state-fetched"; payload: State; } - export interface OperationFailed { type: "operation-failed"; code: "UNAUTHORIZED" | "INTERNAL_SERVER_ERROR"; reason: string; } - -export type Acked = T & { ack: string }; - +export type Acked = T & { + ack: string; +}; export interface State { decofile: Record; revision: string; } - export type Commands = PatchState | FetchState; export type Events = StatePatched | StateFetched | OperationFailed; diff --git a/ai-assistants/actions/awsUploadImage.ts b/ai-assistants/actions/awsUploadImage.ts index a5904a065..34eb20426 100644 --- a/ai-assistants/actions/awsUploadImage.ts +++ b/ai-assistants/actions/awsUploadImage.ts @@ -1,22 +1,17 @@ -import { logger } from "deco/observability/otel/config.ts"; -import { meter } from "deco/observability/otel/metrics.ts"; import base64ToBlob from "../utils/blobConversion.ts"; import { AssistantIds } from "../types.ts"; -import { ValueType } from "deco/deps.ts"; import { AppContext } from "../mod.ts"; - +import { logger, meter, ValueType } from "@deco/deco/o11y"; const stats = { awsUploadImageError: meter.createCounter("assistant_aws_upload_error", { unit: "1", valueType: ValueType.INT, }), }; - export interface AWSUploadImageProps { file: string | ArrayBuffer | null; assistantIds?: AssistantIds; } - // TODO(ItamarRocha): Check if possible to upload straight to bucket instead of using presigned url async function getSignedUrl( mimetype: string, @@ -24,7 +19,6 @@ async function getSignedUrl( ): Promise { const randomID = crypto.randomUUID(); const name = `${randomID}.${mimetype.split("/")[1]}`; - // Get signed URL from S3 const s3Params = { Bucket: ctx.assistantAwsProps?.assistantBucketName.get?.() ?? "", @@ -32,16 +26,13 @@ async function getSignedUrl( ContentType: mimetype, ACL: "public-read", }; - const uploadURL = await ctx.s3?.getSignedUrlPromise("putObject", s3Params); return uploadURL as string; } - async function uploadFileToS3(presignedUrl: string, data: Blob) { const response = await fetch(presignedUrl, { method: "PUT", body: data }); return response; } - // TODO(ItamarRocha): Rate limit export default async function awsUploadImage( awsUploadImageProps: AWSUploadImageProps, @@ -57,7 +48,6 @@ export default async function awsUploadImage( ); const uploadURL = await getSignedUrl(blobData.type, ctx); const uploadResponse = await uploadFileToS3(uploadURL, blobData); - if (!uploadResponse.ok) { stats.awsUploadImageError.add(1, { assistantId, diff --git a/ai-assistants/actions/chat.ts b/ai-assistants/actions/chat.ts index 00aac7ec5..10f777d37 100644 --- a/ai-assistants/actions/chat.ts +++ b/ai-assistants/actions/chat.ts @@ -1,15 +1,12 @@ import { AppContext } from "../mod.ts"; - -import { badRequest, notFound } from "deco/mod.ts"; import { messageProcessorFor } from "../chat/messages.ts"; import { Notify, Queue } from "../deps.ts"; - +import { badRequest, notFound } from "@deco/deco"; export interface Props { thread?: string; assistant: string; message?: string; } - /** * Processes messages from the message queue. * @param {Queue} q - The message queue. @@ -35,18 +32,15 @@ const process = async ( ]); } }; - export interface MessageContentText { type: "text"; value: string; options?: string[]; } - export interface MessageContentFile { type: "file"; fileId: string; } - export interface ReplyMessage { threadId: string; messageId: string; @@ -54,16 +48,13 @@ export interface ReplyMessage { content: Array; role: "user" | "assistant"; } - export interface FunctionCall { name: string; props: unknown; } - export interface FunctionCallReply extends FunctionCall { response: T; } - export interface ReplyStartFunctionCall { threadId: string; messageId: string; @@ -76,17 +67,14 @@ export interface ReplyFunctionCalls { type: "function_calls"; content: FunctionCallReply[]; } - export type Reply = | ReplyMessage | ReplyFunctionCalls | ReplyStartFunctionCall; - export interface ChatMessage { text: string; reply: (reply: Reply) => void; } - /** * Initializes a WebSocket chat connection and processes incoming messages. * @param {Props} props - The properties for the chat session. @@ -98,7 +86,12 @@ export default async function openChat( props: Props, req: Request, ctx: AppContext, -): Promise[]; thread: string }> { +): Promise< + Response | { + replies: Reply[]; + thread: string; + } +> { if (!props.assistant) { notFound(); } @@ -106,13 +99,11 @@ export default async function openChat( if (!assistant) { notFound(); } - const threads = ctx.openAI.beta.threads; const threadId = props.thread; const threadPromise = threadId ? threads.retrieve(threadId) : threads.create(); - const processorPromise = assistant.then(async (aiAssistant) => messageProcessorFor(aiAssistant, ctx, await threadPromise) ); @@ -128,7 +119,6 @@ export default async function openChat( }); return { replies, thread: (await threadPromise).id }; } - const { socket, response } = Deno.upgradeWebSocket(req); const abort = new Notify(); const messagesQ = new Queue(); @@ -138,7 +128,6 @@ export default async function openChat( reply: (replyMsg) => socket.send(JSON.stringify(replyMsg)), }); } - /** * Handles the WebSocket connection on open event. */ @@ -156,19 +145,17 @@ export default async function openChat( }), ); assistant.then((aiAssistant) => { - socket.send( - JSON.stringify({ - isWelcomeMessage: true, - threadId: aiAssistant.threadId, - assistantId: aiAssistant.id, - type: "message", - content: [{ - type: "text", - value: aiAssistant.welcomeMessage ?? "Welcome to the chat!", - }], - role: "assistant", - }), - ); + socket.send(JSON.stringify({ + isWelcomeMessage: true, + threadId: aiAssistant.threadId, + assistantId: aiAssistant.id, + type: "message", + content: [{ + type: "text", + value: aiAssistant.welcomeMessage ?? "Welcome to the chat!", + }], + role: "assistant", + })); }); }; /** @@ -177,7 +164,6 @@ export default async function openChat( socket.onclose = () => { abort.notifyAll(); }; - /** * Handles the WebSocket connection on message event. * @param {MessageEvent} event - The WebSocket message event. diff --git a/ai-assistants/actions/describeImage.ts b/ai-assistants/actions/describeImage.ts index edaa5d76d..22296dc35 100644 --- a/ai-assistants/actions/describeImage.ts +++ b/ai-assistants/actions/describeImage.ts @@ -1,10 +1,7 @@ -import { logger } from "deco/observability/otel/config.ts"; -import { meter } from "deco/observability/otel/metrics.ts"; import { AssistantIds } from "../types.ts"; -import { ValueType } from "deco/deps.ts"; import { AppContext } from "../mod.ts"; -import { shortcircuit } from "deco/engine/errors.ts"; - +import { logger, meter, ValueType } from "@deco/deco/o11y"; +import { shortcircuit } from "@deco/deco"; const stats = { promptTokens: meter.createHistogram("assistant_image_prompt_tokens", { description: "Tokens used in Sales Assistant Describe Image Input - OpenAI", @@ -20,13 +17,11 @@ const stats = { valueType: ValueType.INT, }), }; - export interface DescribeImageProps { uploadURL: string; userPrompt: string; assistantIds?: AssistantIds; } - // TODO(ItamarRocha): Rate limit // TODO(@ItamarRocha): Refactor to use https://github.com/deco-cx/apps/blob/main/openai/loaders/vision.ts export default async function describeImage( diff --git a/ai-assistants/actions/transcribeAudio.ts b/ai-assistants/actions/transcribeAudio.ts index f2489a311..453417b22 100644 --- a/ai-assistants/actions/transcribeAudio.ts +++ b/ai-assistants/actions/transcribeAudio.ts @@ -1,10 +1,7 @@ -import { logger } from "deco/observability/otel/config.ts"; import base64ToBlob from "../utils/blobConversion.ts"; -import { meter } from "deco/observability/otel/metrics.ts"; import { AssistantIds } from "../types.ts"; -import { ValueType } from "deco/deps.ts"; import { AppContext } from "../mod.ts"; - +import { logger, meter, ValueType } from "@deco/deco/o11y"; const stats = { audioSize: meter.createHistogram("assistant_transcribe_audio_size", { description: @@ -20,13 +17,11 @@ const stats = { }, ), }; - export interface TranscribeAudioProps { file: string | ArrayBuffer | null; assistantIds?: AssistantIds; audioDuration: number; } - // TODO(ItamarRocha): Rate limit export default async function transcribeAudio( transcribeAudioProps: TranscribeAudioProps, @@ -41,14 +36,12 @@ export default async function transcribeAudio( }); throw new Error("Audio file is empty"); } - const blobData = base64ToBlob( transcribeAudioProps.file, "audio", transcribeAudioProps.assistantIds, ); const file = new File([blobData], "input.wav", { type: "audio/wav" }); - stats.audioSize.record(transcribeAudioProps.audioDuration, { assistant_id: assistantId, }); diff --git a/ai-assistants/chat/messages.ts b/ai-assistants/chat/messages.ts index 0dc3a5327..169eab460 100644 --- a/ai-assistants/chat/messages.ts +++ b/ai-assistants/chat/messages.ts @@ -1,22 +1,20 @@ -import { - AssistantCreateParams, - RequiredActionFunctionToolCall, - Thread, -} from "../deps.ts"; -import { threadMessageToReply, Tokens } from "../loaders/messages.ts"; -import { JSONSchema7, ValueType, weakcache } from "deco/deps.ts"; -import { lazySchemaFor } from "deco/engine/schema/lazy.ts"; -import { Context } from "deco/live.ts"; -import { meter } from "deco/observability/otel/metrics.ts"; +import { Context, type JSONSchema7, lazySchemaFor } from "@deco/deco"; +import { meter, ValueType } from "@deco/deco/o11y"; +import { weakcache } from "../../utils/weakcache.ts"; import { ChatMessage, FunctionCallReply, Reply, ReplyMessage, } from "../actions/chat.ts"; +import { + AssistantCreateParams, + RequiredActionFunctionToolCall, + Thread, +} from "../deps.ts"; +import { threadMessageToReply, Tokens } from "../loaders/messages.ts"; import { AIAssistant, AppContext } from "../mod.ts"; import { dereferenceJsonSchema } from "../schema.ts"; - const stats = { latency: meter.createHistogram("assistant_latency", { description: @@ -25,24 +23,20 @@ const stats = { valueType: ValueType.DOUBLE, }), }; - // Max length of instructions. The maximum context of the assistant is 32K chars. We use 25K for instructions to be safe. const MAX_INSTRUCTIONS_LENGTH = 25000; - const notUndefined = (v: T | undefined): v is T => v !== undefined; - const toolsCache = new weakcache.WeakLRUCache({ cacheSize: 16, // up to 16 different schemas stored here. }); - /** * Builds assistant tools that can be used by OpenAI assistant to execute actions based on users requests. * @param assistant the assistant that will handle the request * @returns an array of available functions that can be used. */ -const appTools = async (assistant: AIAssistant): Promise< - AssistantCreateParams.AssistantToolsFunction[] -> => { +const appTools = async ( + assistant: AIAssistant, +): Promise => { const ctx = Context.active(); const assistantsKey = assistant.availableFunctions?.join(",") ?? "all"; const revision = await ctx.release!.revision(); @@ -56,60 +50,57 @@ const appTools = async (assistant: AIAssistant): Promise< ...runtime.manifest.loaders, ...runtime.manifest.actions, }); - const tools = functionKeys.map( - (functionKey) => { - const functionDefinition = btoa(functionKey); - const schema = schemas.definitions[functionDefinition]; - if ((schema as { ignoreAI?: boolean })?.ignoreAI) { - return undefined; - } - const propsRef = (schema?.allOf?.[0] as JSONSchema7)?.$ref; - if (!propsRef) { - return undefined; - } - const dereferenced = dereferenceJsonSchema({ - $ref: propsRef, - ...schemas, - }); - if ( - dereferenced.type !== "object" || - (dereferenced.oneOf || dereferenced.anyOf || - dereferenced?.allOf || dereferenced?.enum || dereferenced?.not) - ) { - return undefined; - } - return { - type: "function" as const, - function: { - name: functionKey, - description: - `Usage for: ${schema?.description}. Example: ${schema?.examples}`, - parameters: { - ...dereferenced, - definitions: undefined, - root: undefined, - }, + const tools = functionKeys.map((functionKey) => { + const functionDefinition = btoa(functionKey); + const schema = schemas.definitions[functionDefinition]; + if ( + (schema as { + ignoreAI?: boolean; + })?.ignoreAI + ) { + return undefined; + } + const propsRef = (schema?.allOf?.[0] as JSONSchema7)?.$ref; + if (!propsRef) { + return undefined; + } + const dereferenced = dereferenceJsonSchema({ + $ref: propsRef, + ...schemas, + }); + if ( + dereferenced.type !== "object" || + (dereferenced.oneOf || dereferenced.anyOf || + dereferenced?.allOf || dereferenced?.enum || dereferenced?.not) + ) { + return undefined; + } + return { + type: "function" as const, + function: { + name: functionKey, + description: + `Usage for: ${schema?.description}. Example: ${schema?.examples}`, + parameters: { + ...dereferenced, + definitions: undefined, + root: undefined, }, - }; - }, - ).filter(notUndefined); - + }, + }; + }).filter(notUndefined); toolsCache.set(ctx, tools); return tools; }); toolsCache.set(cacheKey, toolsPromise); return toolsPromise; }; - export interface ProcessorOpts { assistantId: string; instructions: string; } - const sleep = (ns: number) => new Promise((resolve) => setTimeout(resolve, ns)); - const cache: Record = {}; - const invokeFor = ( ctx: AppContext, assistant: AIAssistant, @@ -126,9 +117,7 @@ const invokeFor = ( return async (call: RequiredActionFunctionToolCall) => { try { const props = JSON.parse(call.function.arguments || "{}"); - const cacheKey = `${call.function.arguments}${call.function.name}`; - const assistantProps = assistant?.useProps?.(props) ?? props; cache[cacheKey] ??= ctx.invoke( // deno-lint-ignore no-explicit-any @@ -180,11 +169,9 @@ export const messageProcessorFor = async ( `; const assistantId = await ctx.assistant.then((assistant) => assistant.id); const tools = await appTools(assistant); - // Update the assistant object with the thread and assistant id assistant.threadId = thread.id; assistant.id = assistantId; - /** * Processes an incoming chat message. * @param {ChatMessage} message - The incoming chat message. @@ -206,11 +193,9 @@ export const messageProcessorFor = async ( instructions: instructions.slice(0, MAX_INSTRUCTIONS_LENGTH), tools, }); - const messageId = run.id; // Wait for the assistant answer const functionCallReplies: FunctionCallReply[] = []; - // Reply to the user const reply = (message: Reply) => { assistant.onMessageSent?.({ @@ -222,7 +207,6 @@ export const messageProcessorFor = async ( }); return _reply(message); }; - assistant.onMessageReceived?.({ assistantId: run.assistant_id, threadId: thread.id, @@ -230,7 +214,6 @@ export const messageProcessorFor = async ( model: run.model, message: { type: "text", value: content }, }); - const invoke = invokeFor(ctx, assistant, (call, props) => { reply({ threadId: thread.id, @@ -252,21 +235,13 @@ export const messageProcessorFor = async ( response, }); }); - let runStatus; do { - runStatus = await threads.runs.retrieve( - thread.id, - run.id, - ); - + runStatus = await threads.runs.retrieve(thread.id, run.id); if (runStatus.status === "requires_action") { const actions = runStatus.required_action!; const outputs = actions.submit_tool_outputs; - - const tool_outputs = await Promise.all( - outputs.tool_calls.map(invoke), - ); + const tool_outputs = await Promise.all(outputs.tool_calls.map(invoke)); if (tool_outputs.length === 0) { const message: ReplyMessage = { messageId: Date.now().toString(), @@ -278,28 +253,19 @@ export const messageProcessorFor = async ( reply(message); return; } - await threads.runs.submitToolOutputs( - thread.id, - run.id, - { - tool_outputs, - }, - ); - runStatus = await threads.runs.retrieve( - thread.id, - run.id, - ); + await threads.runs.submitToolOutputs(thread.id, run.id, { + tool_outputs, + }); + runStatus = await threads.runs.retrieve(thread.id, run.id); } await sleep(500); } while (["in_progress", "queued"].includes(runStatus.status)); - const messages = await threads.messages.list(thread.id); const threadMessages = messages.data; const lastMsg = threadMessages .findLast((message) => message.run_id == run.id && message.role === "assistant" ); - if (!lastMsg) { // TODO(@mcandeia) in some cases the bot didn't respond anything. const message: ReplyMessage = { @@ -312,9 +278,7 @@ export const messageProcessorFor = async ( reply(message); return; } - const replyMessage = threadMessageToReply(lastMsg); - // multi tool use parallel seems to be some sort of openai bug, and it seems to have no solution yet. // https://community.openai.com/t/model-tries-to-call-unknown-function-multi-tool-use-parallel/490653 // It's an error that only happens every now and then. Open ai tries to call "multi_tool_use.parallel" function that doesn't even exist and isn't even in the OpenAI documentation @@ -339,7 +303,6 @@ export const messageProcessorFor = async ( assistant_id: run.assistant_id, }); } - if (functionCallReplies.length > 0) { reply({ threadId: thread.id, diff --git a/ai-assistants/mod.ts b/ai-assistants/mod.ts index 8ff8e0fbe..ae3b64a21 100644 --- a/ai-assistants/mod.ts +++ b/ai-assistants/mod.ts @@ -1,9 +1,4 @@ import AWS from "https://esm.sh/aws-sdk@2.1585.0"; -import { asResolved, isDeferred } from "deco/engine/core/resolver.ts"; -import { isAwaitable } from "deco/engine/core/utils.ts"; -import type { App, AppContext as AC } from "deco/mod.ts"; -import { AvailableActions, AvailableLoaders } from "deco/utils/invoke.types.ts"; -import { AppManifest } from "deco/types.ts"; import { deferred } from "std/async/deferred.ts"; import openai, { Props as OpenAIProps, @@ -13,7 +8,16 @@ import { Assistant } from "./deps.ts"; import manifest, { Manifest } from "./manifest.gen.ts"; import { Secret } from "../website/loaders/secret.ts"; import { PreviewContainer } from "../utils/preview.tsx"; - +import { + type App, + type AppContext as AC, + type AppManifest, + asResolved, + type AvailableActions, + type AvailableLoaders, + isDeferred, +} from "@deco/deco"; +import { isAwaitable } from "@deco/deco/utils"; export type GPTModel = | "gpt-4-0613" | "gpt-4-0314" @@ -33,29 +37,24 @@ export interface AIAssistant { * The name of the AI Assistant. */ name: string; - /** * Optional instructions or guidelines for the AI Assistant. */ instructions?: string; - /** * Optional array of prompts to provide context for the AI Assistant. */ prompts?: Prompt[]; - /** * Optional welcome message to be displayed when the chat session starts. */ welcomeMessage?: string; - /** * Optional list of available functions (actions or loaders) that the AI Assistant can perform. */ availableFunctions?: Array< AvailableActions | AvailableLoaders >; - /** * Optional function to customize the handling of properties (props) passed to the AI Assistant. * It takes a set of properties and returns a modified set of properties. @@ -63,37 +62,33 @@ export interface AIAssistant { * @returns {unknown} - The modified properties. */ useProps?: (props: unknown) => unknown; - /** * Optional function to log the received messages from the user. * @param {Log} logInfo - User message / information. * @returns {void} - The modified properties. */ onMessageReceived?: (logInfo: Log) => void; - /** * Optional function to log the received messages sent by the assistant. * @param {Log} logInfo - Assistant message / information. * @returns {void} - The modified properties. */ onMessageSent?: (logInfo: Log) => void; - /** * The GPT model that will be used, if not specified the assistant model will be used. */ - model?: GPTModel | { custom: string }; - + model?: GPTModel | { + custom: string; + }; /** * The Id of the assistant */ id?: string; - /** * The Id of the assistant thread */ threadId?: string; } - export interface Log { assistantId: string; threadId: string; @@ -101,19 +96,16 @@ export interface Log { model: string; message: object; } - export interface Prompt { content: string; context: string; } - export interface AssistantAwsProps { assistantBucketRegion: Secret; accessKeyId: Secret; secretAccessKey: Secret; assistantBucketName: Secret; } - export interface Props extends OpenAIProps { /** * @description the assistant Id @@ -127,7 +119,6 @@ export interface Props extends OpenAIProps { assistantAwsProps?: AssistantAwsProps; s3?: AWS.S3; } - export interface State extends OpenAIState { instructions?: string; assistant: Promise; @@ -135,16 +126,15 @@ export interface State extends OpenAIState { assistantAwsProps?: AssistantAwsProps; s3?: AWS.S3; } - /** * @title Deco AI Assistant * @description Create AI assistants on deco.cx. * @category Tool * @logo https://raw.githubusercontent.com/deco-cx/apps/main/ai-assistants/logo.png */ -export default function App( - state: Props, -): App]> { +export default function App(state: Props): App, +]> { const openAIApp = openai(state); const assistantsAPI = openAIApp.state.openAI.beta.assistants; // Sets assistantId only if state.assistants exists @@ -189,10 +179,7 @@ export default function App( dependencies: [openAIApp], }; } - -export const onBeforeResolveProps = ( - props: Props, -) => { +export const onBeforeResolveProps = (props: Props) => { if (Array.isArray(props?.assistants)) { return { ...props, @@ -203,9 +190,7 @@ export const onBeforeResolveProps = ( } return props; }; - export type AppContext = AC>; - export const preview = () => { return { Component: PreviewContainer, diff --git a/ai-assistants/runtime.ts b/ai-assistants/runtime.ts index 41d65a98d..da42a2435 100644 --- a/ai-assistants/runtime.ts +++ b/ai-assistants/runtime.ts @@ -1,4 +1,3 @@ -import { proxy } from "deco/clients/withManifest.ts"; import { Manifest } from "./manifest.gen.ts"; - +import { proxy } from "@deco/deco/web"; export const invoke = proxy(); diff --git a/ai-assistants/schema.ts b/ai-assistants/schema.ts index 674d776db..493aff815 100644 --- a/ai-assistants/schema.ts +++ b/ai-assistants/schema.ts @@ -1,15 +1,13 @@ -import { JSONSchema7 } from "deco/deps.ts"; - -const isJSONSchema = ( - v: unknown | JSONSchema7, -): v is JSONSchema7 & { +import { type JSONSchema7 } from "@deco/deco"; +const isJSONSchema = (v: unknown | JSONSchema7): v is JSONSchema7 & { $ref: string; } => { return (typeof v === "object" && ((v as JSONSchema7)?.$ref !== undefined)); }; - export function dereferenceJsonSchema( - schema: JSONSchema7 & { definitions?: Record }, + schema: JSONSchema7 & { + definitions?: Record; + }, ) { const resolveReference = ( obj: unknown, @@ -30,6 +28,5 @@ export function dereferenceJsonSchema( } return obj as JSONSchema7; }; - return resolveReference(schema, {}); } diff --git a/ai-assistants/utils/blobConversion.ts b/ai-assistants/utils/blobConversion.ts index 2b08f6d4f..826cba88c 100644 --- a/ai-assistants/utils/blobConversion.ts +++ b/ai-assistants/utils/blobConversion.ts @@ -1,6 +1,5 @@ -import { logger } from "deco/observability/otel/config.ts"; import { AssistantIds } from "../types.ts"; - +import { logger } from "@deco/deco/o11y"; export default function base64ToBlob( base64: string | ArrayBuffer | null, context: string, @@ -23,7 +22,6 @@ export default function base64ToBlob( }`); throw new Error("Expected a base64 string"); } - const parts = base64.match(regex); if (!parts || parts.length !== 3) { logger.error(`${ @@ -38,21 +36,16 @@ export default function base64ToBlob( `${context} Base64 string is not properly formatted: ${parts}`, ); } - const mimeType = parts[1]; // e.g., 'audio/png' or 'video/mp4' or 'audio/mp3' or 'image/png' const mediaData = parts[2]; - // Convert the base64 encoded data to a binary string const binaryStr = atob(mediaData); - // Convert the binary string to an array of bytes (Uint8Array) const length = binaryStr.length; const arrayBuffer = new Uint8Array(new ArrayBuffer(length)); - for (let i = 0; i < length; i++) { arrayBuffer[i] = binaryStr.charCodeAt(i); } - // Create and return the Blob object return new Blob([arrayBuffer], { type: mimeType }); } diff --git a/algolia/mod.ts b/algolia/mod.ts index 7724656f2..e607bcef2 100644 --- a/algolia/mod.ts +++ b/algolia/mod.ts @@ -1,27 +1,23 @@ -import type { App, AppContext as AC } from "deco/mod.ts"; import algolia from "https://esm.sh/algoliasearch@4.20.0"; import { createFetchRequester } from "npm:@algolia/requester-fetch@4.20.0"; import { Markdown } from "../decohub/components/Markdown.tsx"; import { PreviewContainer } from "../utils/preview.tsx"; import type { Secret } from "../website/loaders/secret.ts"; import manifest, { Manifest } from "./manifest.gen.ts"; - +import { type App, type AppContext as AC } from "@deco/deco"; export type AppContext = AC>; - export interface State { /** * @title Your Algolia App ID * @description https://dashboard.algolia.com/account/api-keys/all */ applicationId: string; - /** * @title Search API Key * @description https://dashboard.algolia.com/account/api-keys/all * @format password */ searchApiKey: string; - /** * @title Admin API Key * @description https://dashboard.algolia.com/account/api-keys/all @@ -29,32 +25,24 @@ export interface State { */ adminApiKey: Secret; } - /** * @title Algolia * @description Product search & discovery that increases conversions at scale. * @category Search * @logo https://raw.githubusercontent.com/deco-cx/apps/main/algolia/logo.png */ -export default function App( - props: State, -) { +export default function App(props: State) { const { applicationId, adminApiKey, searchApiKey } = props; - if (!adminApiKey) { throw new Error("Missing admin API key"); } - const stringAdminApiKey = typeof adminApiKey === "string" ? adminApiKey : adminApiKey?.get?.() ?? ""; - const client = algolia(applicationId, stringAdminApiKey, { requester: createFetchRequester(), // Fetch makes it perform mutch better }); - const state = { client, applicationId, searchApiKey }; - const app: App = { manifest: { ...manifest, @@ -73,15 +61,12 @@ export default function App( }, state, }; - return app; } - export const preview = async () => { const markdownContent = await Markdown( new URL("./README.md", import.meta.url).href, ); - return { Component: PreviewContainer, props: { diff --git a/algolia/sections/Analytics/Algolia.tsx b/algolia/sections/Analytics/Algolia.tsx index 26d5a218b..d752c3038 100644 --- a/algolia/sections/Analytics/Algolia.tsx +++ b/algolia/sections/Analytics/Algolia.tsx @@ -1,5 +1,3 @@ -import { SectionProps } from "deco/blocks/section.ts"; -import { useScriptAsDataURI } from "deco/hooks/useScript.ts"; import insights from "npm:search-insights@2.9.0"; import { AddToCartEvent, @@ -8,13 +6,13 @@ import { ViewItemListEvent, } from "../../../commerce/types.ts"; import { AppContext } from "../../mod.ts"; - +import { type SectionProps } from "@deco/deco"; +import { useScriptAsDataURI } from "@deco/deco/hooks"; declare global { interface Window { aa: typeof insights.default; } } - const setupAndListen = (appId: string, apiKey: string, version: string) => { function setupScriptTag() { globalThis.window.AlgoliaAnalyticsObject = "aa"; @@ -26,7 +24,6 @@ const setupAndListen = (appId: string, apiKey: string, version: string) => { ); }; globalThis.window.aa.version = version; - const script = document.createElement("script"); script.setAttribute("async", ""); script.setAttribute( @@ -35,7 +32,6 @@ const setupAndListen = (appId: string, apiKey: string, version: string) => { ); document.head.appendChild(script); } - function createUserToken() { if ( typeof crypto !== "undefined" && @@ -43,67 +39,55 @@ const setupAndListen = (appId: string, apiKey: string, version: string) => { ) { return crypto.randomUUID(); } - return (Math.random() * 1e9).toFixed(); } - function setupSession() { globalThis.window.aa("init", { appId, apiKey }); - const userToken = localStorage.getItem("ALGOLIA_USER_TOKEN") || createUserToken(); localStorage.setItem("ALGOLIA_USER_TOKEN", userToken); globalThis.window.aa("setUserToken", userToken); } - function setupEventListeners() { function attributesFromURL(href: string) { const url = new URL(href); const queryID = url.searchParams.get("algoliaQueryID"); const indexName = url.searchParams.get("algoliaIndex"); - // Not comming from an algolia search page if (!queryID || !indexName) { return null; } - return { queryID, indexName }; } - // deno-lint-ignore no-explicit-any function isSelectItemEvent(event: any): event is SelectItemEvent { return event.name === "select_item"; } - // deno-lint-ignore no-explicit-any function isAddToCartEvent(event: any): event is AddToCartEvent { return event.name === "add_to_cart"; } - function isViewItem( // deno-lint-ignore no-explicit-any event: any, ): event is ViewItemEvent | ViewItemListEvent { return event.name === "view_item" || event.name === "view_item_list"; } - - type WithID = T & { item_id: string }; - + type WithID = T & { + item_id: string; + }; const hasItemId = (item: T): item is WithID => // deno-lint-ignore no-explicit-any typeof (item as any).item_id === "string"; - const PRODUCTS = "products"; const MAX_BATCH_SIZE = 20; - globalThis.window.DECO.events.subscribe((event) => { - if (!event) return; - + if (!event) { + return; + } const eventName = event.name; - if (isSelectItemEvent(event)) { const [item] = event.params.items; - if ( !item || !hasItemId(item) || @@ -115,9 +99,7 @@ const setupAndListen = (appId: string, apiKey: string, version: string) => { JSON.stringify(event, null, 2), ); } - const attr = attributesFromURL(item.item_url); - if (attr) { globalThis.window.aa("clickedObjectIDsAfterSearch", { eventName, @@ -134,16 +116,13 @@ const setupAndListen = (appId: string, apiKey: string, version: string) => { }); } } - if (isAddToCartEvent(event)) { const [item] = event.params.items; - const attr = attributesFromURL(globalThis.window.location.href) || attributesFromURL(item.item_url || ""); const objectIDs = event.params.items .filter(hasItemId) .map((i) => i.item_id); - if (attr) { globalThis.window.aa("convertedObjectIDsAfterSearch", { eventName, @@ -159,12 +138,10 @@ const setupAndListen = (appId: string, apiKey: string, version: string) => { }); } } - if (isViewItem(event)) { const objectIDs = event.params.items .filter(hasItemId) .map((i) => i.item_id); - for (let it = 0; it < objectIDs.length; it += MAX_BATCH_SIZE) { globalThis.window.aa("viewedObjectIDs", { eventName, @@ -175,16 +152,13 @@ const setupAndListen = (appId: string, apiKey: string, version: string) => { } }); } - setupScriptTag(); setupSession(); setupEventListeners(); }; - -function Analytics({ - applicationId, - searchApiKey, -}: SectionProps) { +function Analytics( + { applicationId, searchApiKey }: SectionProps, +) { return ( `; - const flagsScript = ``; - return dnsPrefetchLink + preconnectLink + plausibleScript + flagsScript; }; return ({ src: transformReq }); }; - export default loader; diff --git a/analytics/mod.ts b/analytics/mod.ts index c2c2de86d..24b6df52c 100644 --- a/analytics/mod.ts +++ b/analytics/mod.ts @@ -1,24 +1,18 @@ -import type { App, AppContext as AC } from "deco/mod.ts"; import manifest, { Manifest } from "./manifest.gen.ts"; import { PreviewContainer } from "../utils/preview.tsx"; - +import { type App, type AppContext as AC } from "@deco/deco"; export type AppContext = AC>; - // deno-lint-ignore no-explicit-any export type State = any; - /** * @title Deco Analytics * @description Measure your site traffic at a glance in a simple and modern web analytics dashboard. * @category Analytics * @logo https://raw.githubusercontent.com/deco-cx/apps/main/analytics/logo.png */ -export default function App( - state: State, -): App { +export default function App(state: State): App { return { manifest, state }; } - export const preview = () => { return { Component: PreviewContainer, diff --git a/anthropic/actions/code.ts b/anthropic/actions/code.ts index 80e312c78..3be3b01cb 100644 --- a/anthropic/actions/code.ts +++ b/anthropic/actions/code.ts @@ -1,6 +1,6 @@ -import { shortcircuit } from "deco/engine/errors.ts"; import { AppContext } from "../mod.ts"; import { Anthropic } from "../deps.ts"; +import { shortcircuit } from "@deco/deco"; export interface Props { /** * @description The system prompt to be used for the AI Assistant. @@ -29,27 +29,20 @@ export interface Props { */ max_tokens?: number; } - export default async function chat( - { - system, - messages, - model = "claude-3-opus-20240229", - max_tokens = 4096, - }: Props, + { system, messages, model = "claude-3-opus-20240229", max_tokens = 4096 }: + Props, _req: Request, ctx: AppContext, ) { if (!messages) { return shortcircuit(new Response("No messages provided", { status: 400 })); } - const msg = await ctx.anthropic.messages.create({ system, model, max_tokens, messages, }); - return msg; } diff --git a/anthropic/actions/stream.ts b/anthropic/actions/stream.ts index da45087f6..67e99e47f 100644 --- a/anthropic/actions/stream.ts +++ b/anthropic/actions/stream.ts @@ -1,12 +1,13 @@ -import { JSONSchema7 } from "deco/deps.ts"; -import { shortcircuit } from "deco/engine/errors.ts"; -import { lazySchemaFor } from "deco/engine/schema/lazy.ts"; -import { Context } from "deco/live.ts"; -import { readFromStream } from "deco/utils/http.ts"; import { dereferenceJsonSchema } from "../../ai-assistants/schema.ts"; import { Anthropic } from "../deps.ts"; import { AppContext } from "../mod.ts"; - +import { + Context, + type JSONSchema7, + lazySchemaFor, + shortcircuit, +} from "@deco/deco"; +import { readFromStream } from "@deco/deco/utils"; export interface Props { /** * @description The system prompt to be used for the AI Assistant. @@ -45,16 +46,13 @@ export interface Props { enableTools?: boolean; temperature?: number; } - const notUndefined = (v: T | undefined): v is T => v !== undefined; - const pathFormatter = { encode: (path: string): string => path.replace(/\.ts/g, "").replace(/\//g, "__"), decode: (encodedPath: string): string => encodedPath.replace(/__/g, "/") + ".ts", }; - /** * Retrieves the available tools for the AI Assistant. * @param availableFunctions List of functions available for the AI Assistant. @@ -66,32 +64,30 @@ const getAppTools = async ( const ctx = Context.active(); const runtime = await ctx.runtime!; const schemas = await lazySchemaFor(ctx).value; - const functionKeys = availableFunctions ?? Object.keys({ ...runtime.manifest.loaders, ...runtime.manifest.actions, }); - const tools = functionKeys .map((functionKey) => { const functionDefinition = btoa(functionKey); const schema = schemas.definitions[functionDefinition]; - - if ((schema as { ignoreAI?: boolean })?.ignoreAI) { + if ( + (schema as { + ignoreAI?: boolean; + })?.ignoreAI + ) { return undefined; } - const propsRef = (schema?.allOf?.[0] as JSONSchema7)?.$ref; if (!propsRef) { return undefined; } - const dereferenced = dereferenceJsonSchema({ $ref: propsRef, ...schemas, }); - if ( dereferenced.type !== "object" || dereferenced.oneOf || @@ -102,7 +98,6 @@ const getAppTools = async ( ) { return undefined; } - return { name: pathFormatter.encode(functionKey), description: @@ -116,10 +111,8 @@ const getAppTools = async ( }; }) .filter(notUndefined); - return tools as Anthropic.Beta.Tools.Tool[] | undefined; }; - /** * @title Anthropic chat streaming * @description Sends messages to the Anthropic API for processing. @@ -140,16 +133,13 @@ export default async function chat( if (!messages) { return shortcircuit(new Response("No messages provided", { status: 400 })); } - const tools = await getAppTools(availableFunctions ?? []); - const headers = { "anthropic-version": "2023-06-01", "content-type": "application/json", "anthropic-beta": "max-tokens-3-5-sonnet-2024-07-15", "x-api-key": ctx.token ?? "", }; - let payload: Anthropic.Beta.Tools.MessageCreateParamsStreaming = { system, messages, @@ -158,7 +148,6 @@ export default async function chat( temperature, stream: true, }; - if (enableTools) { payload = { ...payload, @@ -166,19 +155,16 @@ export default async function chat( tool_choice: { type: "auto" }, }; } - const response = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers, body: JSON.stringify(payload), }); - if (!response.ok) { return shortcircuit( new Response(await response.text(), { status: response.status }), ); } - return readFromStream(response, { shouldDecodeChunk: false, }); diff --git a/anthropic/mod.ts b/anthropic/mod.ts index c338c4453..aba45f11a 100644 --- a/anthropic/mod.ts +++ b/anthropic/mod.ts @@ -1,20 +1,17 @@ -import type { App, AppContext as AC } from "deco/mod.ts"; import { Secret } from "../website/loaders/secret.ts"; import { Anthropic } from "./deps.ts"; import manifest, { Manifest } from "./manifest.gen.ts"; - +import { type App, type AppContext as AC } from "@deco/deco"; export interface Props { /** * @title Anthropic API Key */ apiKey?: Secret; } - export interface State { anthropic: Anthropic; token?: string; } - /** * @title Anthropic * @description Interact with the Anthropic API. diff --git a/blog/mod.ts b/blog/mod.ts index 14c082add..257937f83 100644 --- a/blog/mod.ts +++ b/blog/mod.ts @@ -1,24 +1,18 @@ -import type { App, FnContext } from "deco/mod.ts"; import manifest, { Manifest } from "./manifest.gen.ts"; import { PreviewContainer } from "../utils/preview.tsx"; - +import { type App, type FnContext } from "@deco/deco"; // deno-lint-ignore no-explicit-any export type State = any; - export type AppContext = FnContext; - /** * @title Deco Blog * @description Manage your posts. * @category Tool * @logo https://raw.githubusercontent.com/deco-cx/apps/main/weather/logo.png */ -export default function App( - state: State, -): App { +export default function App(state: State): App { return { manifest, state }; } - export const preview = () => { return { Component: PreviewContainer, diff --git a/blog/utils/records.ts b/blog/utils/records.ts index 02744803c..6e19e463b 100644 --- a/blog/utils/records.ts +++ b/blog/utils/records.ts @@ -1,6 +1,5 @@ import { AppContext } from "../mod.ts"; -import { Resolvable } from "deco/engine/core/resolver.ts"; - +import { type Resolvable } from "@deco/deco"; export async function getRecordsByPath( ctx: AppContext, path: string, @@ -9,10 +8,8 @@ export async function getRecordsByPath( const resolvables: Record> = await ctx.get({ __resolveType: "resolvables", }); - const current = Object.entries(resolvables).flatMap(([key, value]) => { return key.startsWith(path) ? value : []; }); - return (current as Record[]).map((item) => item[accessor]); } diff --git a/brand-assistant/loaders/assistant.ts b/brand-assistant/loaders/assistant.ts index ea0295bd9..5d914dc94 100644 --- a/brand-assistant/loaders/assistant.ts +++ b/brand-assistant/loaders/assistant.ts @@ -1,12 +1,12 @@ // deno-lint-ignore-file ban-unused-ignore no-explicit-any -import type { ManifestOf } from "deco/mod.ts"; -import { logger } from "deco/observability/otel/config.ts"; import type { AIAssistant, Log, Prompt } from "../../ai-assistants/mod.ts"; import type { Category, Product, Suggestion } from "../../commerce/types.ts"; import type { Manifest as OpenAIManifest } from "../../openai/manifest.gen.ts"; import type vtex from "../../vtex/mod.ts"; import { Tokens } from "../../ai-assistants/loaders/messages.ts"; import type { AssistantPersonalization } from "../../ai-assistants/types.ts"; +import { type ManifestOf } from "@deco/deco"; +import { logger } from "@deco/deco/o11y"; export interface Props { name: string; productsSample?: Product[] | null; @@ -29,14 +29,11 @@ const removePropertiesRecursively = (category: T): T => { if (typeof category !== "object" || category === null) { return category; } - const { hasChildren: _ignoreHasChildren, url: _ignoreUrl, ...rest } = category as any; - rest.children = rest.children.map(removePropertiesRecursively); return rest; }; - type VTEXManifest = ManifestOf>; // TODO(ItamarRocha): Add store name in props or gather it from elsewhere. const BASE_INSTRUCTIONS = diff --git a/brand-assistant/mod.ts b/brand-assistant/mod.ts index f2c387253..eeb17be85 100644 --- a/brand-assistant/mod.ts +++ b/brand-assistant/mod.ts @@ -1,28 +1,22 @@ -import type { App, AppContext as AC } from "deco/mod.ts"; import manifest, { Manifest } from "./manifest.gen.ts"; import { PreviewContainer } from "../utils/preview.tsx"; - +import { type App, type AppContext as AC } from "@deco/deco"; // deno-lint-ignore no-empty-interface export interface Props { } - /** * @title Deco Brand Assistant * @description A concierge for your ecommerce. * @category Sales channel * @logo https://raw.githubusercontent.com/deco-cx/apps/main/brand-assistant/logo.png */ -export default function App( - state: Props, -): App { +export default function App(state: Props): App { return { manifest, state, }; } - export type AppContext = AC>; - export const preview = () => { return { Component: PreviewContainer, diff --git a/commerce/mod.ts b/commerce/mod.ts index d9ecc00b0..3155c2920 100644 --- a/commerce/mod.ts +++ b/commerce/mod.ts @@ -1,4 +1,3 @@ -import { App, FnContext } from "deco/mod.ts"; import shopify, { Props as ShopifyProps } from "../shopify/mod.ts"; import vnda, { Props as VNDAProps } from "../vnda/mod.ts"; import vtex, { Props as VTEXProps } from "../vtex/mod.ts"; @@ -6,44 +5,39 @@ import wake, { Props as WakeProps } from "../wake/mod.ts"; import website, { Props as WebsiteProps } from "../website/mod.ts"; import manifest, { Manifest } from "./manifest.gen.ts"; import { bgYellow } from "std/fmt/colors.ts"; - +import { type App, type FnContext } from "@deco/deco"; export type AppContext = FnContext; - type CustomPlatform = { platform: "other"; }; - export type Props = WebsiteProps & { /** @deprecated Use selected commerce instead */ - commerce?: - | VNDAProps - | VTEXProps - | ShopifyProps - | WakeProps - | CustomPlatform; + commerce?: VNDAProps | VTEXProps | ShopifyProps | WakeProps | CustomPlatform; }; - type WebsiteApp = ReturnType; type CommerceApp = | ReturnType | ReturnType | ReturnType | ReturnType; - -export default function Site( - state: Props, -): App { +export default function Site(state: Props): App< + Manifest, + Props, + [ + WebsiteApp, + ] | [ + WebsiteApp, + CommerceApp, + ] +> { const { commerce } = state; - const site = website(state); - if (commerce && commerce.platform !== "other") { console.warn( bgYellow("Deprecated"), "Commerce prop is now deprecated. Delete this prop and install the commerce platform app instead. This will be removed in the future", ); } - const ecommerce = commerce?.platform === "vnda" ? vnda(commerce) : commerce?.platform === "vtex" @@ -53,7 +47,6 @@ export default function Site( : commerce?.platform === "shopify" ? shopify(commerce) : null; - return { state, manifest: { @@ -81,5 +74,4 @@ export default function Site( dependencies: ecommerce ? [site, ecommerce] : [site], }; } - export { onBeforeResolveProps } from "../website/mod.ts"; diff --git a/commerce/types.ts b/commerce/types.ts index c489adfed..81967c7be 100644 --- a/commerce/types.ts +++ b/commerce/types.ts @@ -1,10 +1,8 @@ -import { type Flag } from "deco/types.ts"; - +import { type Flag } from "@deco/deco"; /** Used at the top-level node to indicate the context for the JSON-LD objects used. The context provided in this type is compatible with the keys and URLs in the rest of this generated file. */ export declare type WithContext = T & { "@context": "https://schema.org"; }; - /** * An store category */ @@ -23,9 +21,7 @@ export interface Category { */ children?: Category[]; } - export declare type Things = Thing | Product | BreadcrumbList; - export interface Thing { "@type": "Thing"; /** IRI identifying the canonical address of this object. */ @@ -52,7 +48,6 @@ export interface Thing { /** URL of the item. */ url?: string; } - export interface MediaObject { /** Media type typically expressed using a MIME format (see IANA site and MDN reference) */ encodingFormat?: string; @@ -61,12 +56,10 @@ export interface MediaObject { /** Actual bytes of the media object, for example the image file or video file. */ contentUrl?: string; } - export interface CreativeWork { /** A thumbnail image relevant to the Thing */ thumbnailUrl?: string; } - export interface VideoObject extends MediaObject, CreativeWork, Omit { /** @@ -83,7 +76,6 @@ export interface VideoObject */ duration?: string; } - export interface ImageObject extends MediaObject, CreativeWork, Omit { /** @@ -95,7 +87,6 @@ export interface ImageObject */ url?: string; } - export interface PropertyValue extends Omit { "@type": "PropertyValue"; /** The upper value of some characteristic or property. */ @@ -119,7 +110,6 @@ export interface PropertyValue extends Omit { /** A secondary value that provides additional information on the original value, e.g. a reference temperature or a type of measurement. */ valueReference?: string; } - export interface AggregateRating { "@type": "AggregateRating"; /** The count of total number of ratings. */ @@ -135,7 +125,6 @@ export interface AggregateRating { /** A short explanation (e.g. one to two sentences) providing background context and other information that led to the conclusion expressed in the rating. This is particularly applicable to ratings associated with "fact check" markup using ClaimReview. */ ratingExplanation?: string; } - export declare type ItemAvailability = | "https://schema.org/BackOrder" | "https://schema.org/Discontinued" @@ -147,17 +136,14 @@ export declare type ItemAvailability = | "https://schema.org/PreOrder" | "https://schema.org/PreSale" | "https://schema.org/SoldOut"; - export declare type OfferItemCondition = | "https://schema.org/DamagedCondition" | "https://schema.org/NewCondition" | "https://schema.org/RefurbishedCondition" | "https://schema.org/UsedCondition"; - export interface QuantitativeValue { value?: number; } - export declare type PriceTypeEnumeration = | "https://schema.org/InvoicePrice" | "https://schema.org/ListPrice" @@ -165,7 +151,6 @@ export declare type PriceTypeEnumeration = | "https://schema.org/MSRP" | "https://schema.org/SalePrice" | "https://schema.org/SRP"; - export declare type PriceComponentTypeEnumeration = | "https://schema.org/ActivationFee" | "https://schema.org/CleaningFee" @@ -173,26 +158,22 @@ export declare type PriceComponentTypeEnumeration = | "https://schema.org/Downpayment" | "https://schema.org/Installment" | "https://schema.org/Subscription"; - export declare type ReturnFeesEnumeration = | "https://schema.org/FreeReturn" | "https://schema.org/OriginalShippingFees" | "https://schema.org/RestockingFees" | "https://schema.org/ReturnFeesCustomerResponsibility" | "https://schema.org/ReturnShippingFees"; - export declare type ReturnMethodEnumeration = | "https://schema.org/KeepProduct" | "https://schema.org/ReturnAtKiosk" | "https://schema.org/ReturnByMail" | "https://schema.org/ReturnInStore"; - export declare type MerchantReturnEnumeration = | "https://schema.org/MerchantReturnFiniteReturnWindow" | "https://schema.org/MerchantReturnNotPermitted" | "https://schema.org/MerchantReturnUnlimitedWindow" | "https://schema.org/MerchantReturnUnspecified"; - export interface PriceSpecification extends Omit { "@type": "PriceSpecification"; /** The interval and unit of measurement of ordering quantities for which the offer or price specification is valid. This allows e.g. specifying that a certain freight charge is valid only for a certain quantity. */ @@ -214,7 +195,6 @@ export interface PriceSpecification extends Omit { */ priceCurrency?: string; } - export interface UnitPriceSpecification extends Omit { "@type": "UnitPriceSpecification"; @@ -227,28 +207,23 @@ export interface UnitPriceSpecification /** This property specifies the minimal quantity and rounding increment that will be the basis for the billing. The unit of measurement is specified by the unitCode property. */ billingIncrement?: number; } - export interface TeasersParameters { name: string; value: string; } - export interface TeasersConditions { minimumQuantity: number; parameters: TeasersParameters[]; } - export interface TeasersEffect { parameters: TeasersParameters[]; } - export interface Teasers { name: string; generalValues?: unknown; conditions: TeasersConditions; effects: TeasersEffect; } - export interface MonetaryAmount extends Omit { /** * The currency in which the monetary amount is expressed. @@ -269,7 +244,6 @@ export interface MonetaryAmount extends Omit { /** The value of a QuantitativeValue (including Observation) or property value node. */ value: boolean | number | string; } - export interface MerchantReturnPolicy extends Omit { "@type": "MerchantReturnPolicy"; /** Specifies either a fixed return date or the number of days (from the delivery date) that a product can be returned. Used when the returnPolicyCategory property is specified as MerchantReturnFiniteReturnWindow. Supersedes productReturnDays */ @@ -328,7 +302,6 @@ export interface Offer extends Omit { /** Specifies a MerchantReturnPolicy that may be applicable. */ hasMerchantReturnPolicy?: MerchantReturnPolicy; } - export interface AggregateOffer { "@type": "AggregateOffer"; /** @@ -360,7 +333,6 @@ export interface AggregateOffer { /** Specifies a MerchantReturnPolicy that may be applicable. */ hasMerchantReturnPolicy?: MerchantReturnPolicy; } - export interface ReviewPageResults { currentPageNumber?: number; nextPageUrl?: string; @@ -368,14 +340,12 @@ export interface ReviewPageResults { pagesTotal?: number; totalResults?: number; } - export interface ReviewPage { page: ReviewPageResults; id: string; review?: Review[]; aggregateRating?: AggregateRating; } - export interface Review extends Omit { "@type": "Review"; id?: string; @@ -404,7 +374,6 @@ export interface Review extends Omit { /** Medias */ media?: ReviewMedia[]; } - export interface ReviewMedia { type: "image" | "video"; url?: string; @@ -412,7 +381,6 @@ export interface ReviewMedia { likes?: number; unlikes?: number; } - export interface ReviewBrand { /** Brand Name */ name: string; @@ -421,14 +389,12 @@ export interface ReviewBrand { /** Brand website url */ url: string; } - export interface ReviewTag { /** Label of specific topic */ label?: string; /** Caracteristics about the topic */ value?: string[]; } - /** https://schema.org/Person */ export interface Person extends Omit { /** Email address. */ @@ -444,7 +410,6 @@ export interface Person extends Omit { /** The Tax / Fiscal ID of the organization or person, e.g. the TIN in the US or the CIF/NIF in Spain. */ taxID?: string; } - // NON SCHEMA.ORG Compliant. Should be removed ASAP export interface Author extends Omit { "@type": "Author"; @@ -457,11 +422,10 @@ export interface Author extends Omit { /** Author location */ location?: string; } - // TODO: fix this hack and use Product directly where it appears // Hack to prevent type self referencing and we end up with an infinite loop -export interface ProductLeaf extends Omit {} - +export interface ProductLeaf extends Omit { +} export interface ProductGroup extends Omit { "@type": "ProductGroup"; /** Indicates a {@link https://schema.org/Product Product} that is a member of this {@link https://schema.org/ProductGroup ProductGroup} (or {@link https://schema.org/ProductModel ProductModel}). */ @@ -477,13 +441,11 @@ export interface ProductGroup extends Omit { /** docs https://schema.org/gtin */ model?: string; } - export interface Brand extends Omit { "@type": "Brand"; /** Brand's image url */ logo?: string; } - export interface Answer extends Omit { text: string; /** The date that the anwser was published, in ISO 8601 date format.*/ @@ -493,7 +455,6 @@ export interface Answer extends Omit { /** Author of the */ author?: Author[]; } - export interface Question extends Omit { "@type": "Question"; answerCount: number; @@ -510,7 +471,6 @@ export interface Question extends Omit { /** Author of the */ author?: Author[]; } - export interface Product extends Omit { "@type": "Product"; /** @@ -552,10 +512,8 @@ export interface Product extends Omit { sku: string; /** A pointer to another product (or multiple products) for which this product is an accessory or spare part. */ isAccessoryOrSparePartFor?: Product[] | null; - questions?: Question[]; } - export interface ListItem extends Omit { "@type": "ListItem"; /** An entity represented by an entry in a list or data feed (e.g. an 'artist' in a list of 'artists')’. */ @@ -563,7 +521,6 @@ export interface ListItem extends Omit { /** The position of an item in a series or sequence of items. */ position: number; } - export interface ItemList extends Omit { "@type": "ItemList"; /** @@ -577,11 +534,9 @@ export interface ItemList extends Omit { /** The number of items in an ItemList. Note that some descriptions might not fully describe all items in a list (e.g., multi-page pagination); in such cases, the numberOfItems would be for the entire list. */ numberOfItems: number; } - export interface BreadcrumbList extends Omit { "@type": "BreadcrumbList"; } - export type DayOfWeek = | "Monday" | "Tuesday" @@ -591,7 +546,6 @@ export type DayOfWeek = | "Saturday" | "Sunday" | "PublicHolidays"; - export interface OpeningHoursSpecification extends Omit { "@type": "OpeningHoursSpecification"; /** The closing hour of the place or service on the given day(s) of the week. */ @@ -605,7 +559,6 @@ export interface OpeningHoursSpecification extends Omit { /** The date after when the item is not valid. For example the end of an offer, salary period, or a period of opening hours. */ validThrough?: string; } - export interface ContactPoint extends Omit { "@type": "ContactPoint"; /** The geographic area where a service or offered item is provided. */ @@ -627,7 +580,6 @@ export interface ContactPoint extends Omit { /** The telephone number. */ telephone?: string; } - export interface PostalAddress extends Omit { "@type": "PostalAddress"; /** The country. For example, USA. You can also provide the two-letter ISO 3166-1 alpha-2 country code. */ @@ -641,7 +593,6 @@ export interface PostalAddress extends Omit { /** The street address. For example, 1600 Amphitheatre Pkwy. */ streetAddress?: string; } - export interface LocationFeatureSpecification extends Omit { "@type": "LocationFeatureSpecification"; @@ -652,7 +603,6 @@ export interface LocationFeatureSpecification /** The date after when the item is not valid. For example the end of an offer, salary period, or a period of opening hours. */ validThrough?: string; } - export interface GeoCoordinates extends Omit { "@type": "GeoCoordinates"; /** The geographic area where a service or offered item is provided. */ @@ -668,7 +618,6 @@ export interface GeoCoordinates extends Omit { /** The postal code. For example, 94043. */ postalCode?: string; } - export interface GeoShape extends Omit { "@type": "GeoShape"; /** The GeoShape for the GeoCoordinates or GeoCircle. */ @@ -684,11 +633,9 @@ export interface GeoShape extends Omit { /** The postal code. For example, 94043. */ postalCode?: string; } - export interface About extends Omit { "@type": "About"; } - export interface Rating extends Omit { "@type": "Rating"; /** The author of this content or rating. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably. */ @@ -711,19 +658,15 @@ export interface Rating extends Omit { /** The lowest value allowed in this rating system. */ worstRating?: number; } - export interface Organization extends Omit { "@type": "Organization"; } - export interface AdministrativeArea extends Omit { "@type": "AdministrativeArea"; } - export type CertificationStatus = | "CertificationActive" | "CertificationInactive"; - export interface Certification extends Omit { "@type": "Certification"; /** The subject matter of the content. */ @@ -751,7 +694,6 @@ export interface Certification extends Omit { /** The geographic area where the item is valid. Applies for example to a Permit, a Certification, or an EducationalOccupationalCredential. */ validIn?: AdministrativeArea; } - export interface PlaceLeaf extends Omit { "@type": "Place"; /** A property-value pair representing an additional characteristics of the entitity, e.g. a product feature or another characteristic for which there is no matching property in schema.org. */ @@ -811,7 +753,6 @@ export interface PlaceLeaf extends Omit { /** A page providing information on how to book a tour of some Place, such as an Accommodation or ApartmentComplex in a real estate setting, as well as other kinds of tours as appropriate. */ tourBookingPage?: string; } - /** Entities that have a somewhat fixed, physical extension. */ export interface Place extends PlaceLeaf { /** The basic containment relation between a place and one that contains it. Supersedes containedIn. Inverse property: containsPlace. */ @@ -837,7 +778,6 @@ export interface Place extends PlaceLeaf { /** Represents a relationship between two geometries (or the places they represent), relating a geometry to another that lies on it. As defined in DE-9IM. */ geoWithin?: PlaceLeaf; } - export interface FilterToggleValue { quantity: number; label: string; @@ -846,37 +786,34 @@ export interface FilterToggleValue { url: string; children?: Filter | null; } - export interface FilterRangeValue { min: number; max: number; } - export interface FilterBase { label: string; key: string; } - export interface FilterToggle extends FilterBase { "@type": "FilterToggle"; values: FilterToggleValue[]; quantity: number; } - export interface FilterRange extends FilterBase { "@type": "FilterRange"; values: FilterRangeValue; } - export type Filter = FilterToggle | FilterRange; -export type SortOption = { value: string; label: string }; +export type SortOption = { + value: string; + label: string; +}; export interface ProductDetailsPage { "@type": "ProductDetailsPage"; breadcrumbList: BreadcrumbList; product: Product; seo?: Seo | null; } - export type PageType = | "Brand" | "Category" @@ -887,7 +824,6 @@ export type PageType = | "Cluster" | "Search" | "Unknown"; - export interface PageInfo { currentPage: number; nextPage: string | undefined; @@ -896,7 +832,6 @@ export interface PageInfo { recordPerPage?: number | undefined; pageTypes?: PageType[]; } - export interface ProductListingPage { "@type": "ProductListingPage"; breadcrumb: BreadcrumbList; @@ -906,27 +841,26 @@ export interface ProductListingPage { sortOptions: SortOption[]; seo?: Seo | null; } - export interface Seo { title: string; description: string; canonical: string; noIndexing?: boolean; } - export interface Search { term: string; href?: string; hits?: number; - facets?: Array<{ key: string; values: string[] }>; + facets?: Array<{ + key: string; + values: string[]; + }>; } - export interface Suggestion { searches?: Search[]; products?: Product[] | null; hits?: number; } - /** @titleBy url */ export interface SiteNavigationElementLeaf { /** @@ -944,7 +878,6 @@ export interface SiteNavigationElementLeaf { /** URL of the item. */ url?: string; } - export interface SiteNavigationElement extends SiteNavigationElementLeaf { // TODO: The schema generator is not handling recursive types leading to an infinite loop // Lets circunvent this issue by enumerating the max allowed depth @@ -966,41 +899,36 @@ export interface SiteNavigationElement extends SiteNavigationElementLeaf { } >; } - /** @deprecated Use SiteNavigationElement instead */ export interface NavItem { label: string; href: string; - image?: { src?: string; alt?: string }; + image?: { + src?: string; + alt?: string; + }; } - /** @deprecated Use SiteNavigationElement instead */ export interface Navbar extends NavItem { // TODO: The schema generator is not handling recursive types leading in a infinite recursion loop // deno-lint-ignore no-explicit-any children?: any[]; } - // deno-lint-ignore no-explicit-any export interface IEvent { name: string; params: Params; } - // 3 letter ISO 4217 - Doc: https://en.wikipedia.org/wiki/ISO_4217#Active_codes type Currency = string; type Value = number; - interface WithItemId { item_id: string; } - interface WithItemName { item_name: string; } - type ItemIdentifier = WithItemId | WithItemName; - interface AnalyticsItemWithoutIdentifier { affiliation?: string; coupon?: string; @@ -1021,9 +949,7 @@ interface AnalyticsItemWithoutIdentifier { price?: Value; quantity: number; } - export type AnalyticsItem = AnalyticsItemWithoutIdentifier & ItemIdentifier; - export interface AddShippingInfoParams { currency?: Currency; value?: Value; @@ -1031,46 +957,38 @@ export interface AddShippingInfoParams { shipping_tier?: string; items: AnalyticsItem[]; } - /** @docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtm#add_shipping_info */ export interface AddShippingInfoEvent extends IEvent { name: "add_shipping_info"; } - export interface AddToCartParams { currency?: Currency; value?: Value; items: AnalyticsItem[]; } - /** @docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtm#add_to_cart */ export interface AddToCartEvent extends IEvent { name: "add_to_cart"; } - export interface AddToWishlistParams { currency?: Currency; value?: Value; items: AnalyticsItem[]; } - /** @docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtm#add_to_wishlist */ export interface AddToWishlistEvent extends IEvent { name: "add_to_wishlist"; } - export interface BeginCheckoutParams { currency: Currency; value: Value; items: AnalyticsItem[]; coupon?: string; } - /** docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtm#begin_checkout */ export interface BeginCheckoutEvent extends IEvent { name: "begin_checkout"; } - export interface LoginParams { method?: string; } @@ -1078,37 +996,30 @@ export interface LoginParams { export interface LoginEvent extends IEvent { name: "login"; } - export interface RemoveFromCartParams { currency?: Currency; value?: Value; items: AnalyticsItem[]; } - /** @docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtm#remove_from_cart */ export interface RemoveFromCartEvent extends IEvent { name: "remove_from_cart"; } - export interface SearchParams { search_term: string; } - export interface SearchEvent extends IEvent { name: "search"; } - export interface SelectItemParams { item_list_id?: string; item_list_name?: string; items: AnalyticsItem[]; } - /** @docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtm#select_item */ export interface SelectItemEvent extends IEvent { name: "select_item"; } - export interface SelectPromotionParams { creative_name?: string; creative_slot?: string; @@ -1116,45 +1027,37 @@ export interface SelectPromotionParams { promotion_name?: string; items?: AnalyticsItem[]; } - /** @docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtm#select_promotion */ export interface SelectPromotionEvent extends IEvent { name: "select_promotion"; } - export interface ViewCartParams { currency: Currency; value: Value; items: AnalyticsItem[]; } - /** @docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtm#view_cart */ export interface ViewCartEvent extends IEvent { name: "view_cart"; } - export interface ViewItemParams { currency?: Currency; value?: Value; items: AnalyticsItem[]; } - /** @docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtag#view_item */ export interface ViewItemEvent extends IEvent { name: "view_item"; } - export interface ViewItemListParams { item_list_id?: string; item_list_name?: string; items: AnalyticsItem[]; } - /** @docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtm#view_item_list */ export interface ViewItemListEvent extends IEvent { name: "view_item_list"; } - export interface ViewPromotionParams { creative_name?: string; creative_slot?: string; @@ -1162,26 +1065,21 @@ export interface ViewPromotionParams { promotion_name?: string; items?: AnalyticsItem[]; } - /** @docs https://developers.google.com/analytics/devguides/collection/ga4/reference/events?client_type=gtm#view_promotion */ export interface ViewPromotionEvent extends IEvent { name: "view_promotion"; } - export interface Page { id: string | number; pathTemplate?: string; } - export interface Deco { flags: Flag[]; page: Page; } - export interface DecoEvent extends IEvent { name: "deco"; } - export type AnalyticsEvent = | AddShippingInfoEvent | AddToCartEvent diff --git a/compat/$live/handlers/devPage.ts b/compat/$live/handlers/devPage.ts index 4ee13a6b8..1fd994e21 100644 --- a/compat/$live/handlers/devPage.ts +++ b/compat/$live/handlers/devPage.ts @@ -1,14 +1,12 @@ -import { Page } from "deco/blocks/page.tsx"; -import { context } from "deco/live.ts"; -import { adminUrlFor, isAdmin } from "deco/utils/admin.ts"; import Fresh from "../../../website/handlers/fresh.ts"; import { pageIdFromMetadata } from "../../../website/pages/Page.tsx"; import { AppContext } from "../mod.ts"; - +import { type Page } from "@deco/deco/blocks"; +import { context } from "@deco/deco"; +import { adminUrlFor, isAdmin } from "@deco/deco/utils"; export interface DevConfig { page: Page; } - /** * @title Private Fresh Page * @description Useful for pages under development. @@ -19,18 +17,13 @@ export default function DevPage(devConfig: DevConfig, ctx: AppContext) { const referer = req.headers.get("origin") ?? req.headers.get("referer"); const isOnAdmin = referer && isAdmin(referer); const pageId = pageIdFromMetadata(devConfig.page.metadata); - - if ( - context.isDeploy - ) { + if (context.isDeploy) { if (!referer || !isOnAdmin) { if (pageId === -1) { return Response.error(); } // redirect - return Response.redirect( - adminUrlFor(pageId, context.siteId), - ); + return Response.redirect(adminUrlFor(pageId, context.siteId)); } } return freshHandler(req, ctx); diff --git a/compat/$live/handlers/router.ts b/compat/$live/handlers/router.ts index 08a5b9671..37205272a 100644 --- a/compat/$live/handlers/router.ts +++ b/compat/$live/handlers/router.ts @@ -1,19 +1,16 @@ -import { Handler } from "deco/blocks/handler.ts"; -import { FnContext } from "deco/types.ts"; import { Routes } from "../../../website/flags/audience.ts"; import { router } from "../../../website/handlers/router.ts"; - +import { type Handler } from "@deco/deco/blocks"; +import { type FnContext } from "@deco/deco"; export interface RouterConfig { base?: string; routes: Routes; } - -export default function Router({ - routes: entrypoints, - base, -}: RouterConfig, ctx: FnContext): Handler { +export default function Router( + { routes: entrypoints, base }: RouterConfig, + ctx: FnContext, +): Handler { let routes = entrypoints; - if (base) { routes = []; for (const route of routes) { @@ -24,6 +21,5 @@ export default function Router({ ]; } } - return router(routes, {}, ctx.get.bind(ctx)); } diff --git a/compat/$live/loaders/state.ts b/compat/$live/loaders/state.ts index be6bce1a5..029c4d81c 100644 --- a/compat/$live/loaders/state.ts +++ b/compat/$live/loaders/state.ts @@ -1,12 +1,12 @@ -import { Accounts } from "deco/blocks/account.ts"; -import { Flag } from "deco/blocks/flag.ts"; -import { Loader } from "deco/blocks/loader.ts"; -import { Page } from "deco/blocks/page.tsx"; -import { Section } from "deco/blocks/section.ts"; -import { Resolvable } from "deco/engine/core/resolver.ts"; -import { LoaderContext } from "deco/mod.ts"; -import { Apps } from "deco/blocks/app.ts"; - +import { + type Accounts, + type Apps, + type Flag, + type Loader, + type Page, + type Section, +} from "@deco/deco/blocks"; +import { type LoaderContext, type Resolvable } from "@deco/deco"; /** * @titleBy key */ @@ -18,7 +18,6 @@ export interface Props { state: StateProp[]; apps?: Apps[]; } - /** * @title Shared application State Loader. * @description Set the application state using resolvables. @@ -28,15 +27,19 @@ export default async function StateLoader( _req: Request, { get }: LoaderContext, ): Promise { - const mState: Promise<[string, Resolvable]>[] = []; - + const mState: Promise<[ + string, + Resolvable, + ]>[] = []; for (const { key, value } of state) { const resolved = get(value).then((resolved) => - [key, resolved] as [string, Resolvable] + [key, resolved] as [ + string, + Resolvable, + ] ); mState.push(resolved); } - return { state: Object.fromEntries(await Promise.all(mState)), apps, diff --git a/compat/$live/mod.ts b/compat/$live/mod.ts index 82ab8da5d..84e0687ac 100644 --- a/compat/$live/mod.ts +++ b/compat/$live/mod.ts @@ -1,29 +1,19 @@ -import type { App } from "deco/mod.ts"; - import webSite, { Props } from "../../website/mod.ts"; - -import { AppContext as AC } from "deco/blocks/app.ts"; import workflows from "../../workflows/mod.ts"; import manifest, { Manifest } from "./manifest.gen.ts"; - +import { type App, type AppContext as AC } from "@deco/deco"; export { onBeforeResolveProps } from "../../website/mod.ts"; - export type AppContext = AC>; - export type { Props }; /** * @title $live */ -export default function App( - state: Props, -): App< - Manifest, - Props, - [ReturnType, ReturnType] -> { +export default function App(state: Props): App, + ReturnType, +]> { const { resolvables: _ignoreResolvables, ...webSiteApp } = webSite(state); const workflowsApp = workflows({}); - return { state, manifest, diff --git a/compat/$live/sections/PageInclude.tsx b/compat/$live/sections/PageInclude.tsx index b1410bea1..52ab2a6a0 100644 --- a/compat/$live/sections/PageInclude.tsx +++ b/compat/$live/sections/PageInclude.tsx @@ -1,27 +1,21 @@ -/** TODO: Deprecate this file */ -import { Page } from "deco/blocks/page.tsx"; -import { notUndefined } from "deco/engine/core/utils.ts"; - import { Props as LivePageProps, renderSection, } from "../../../website/pages/Page.tsx"; - +import { type Page } from "@deco/deco/blocks"; +import { notUndefined } from "@deco/deco/utils"; export interface Props { page: Page; } - export const isLivePageProps = ( p: Page["props"] | LivePageProps, ): p is LivePageProps => { return (p as LivePageProps)?.sections !== undefined; }; - export default function PageInclude({ page }: Props) { if (!isLivePageProps(page?.props)) { return null; } - return ( <>{(page?.props?.sections ?? []).filter(notUndefined).map(renderSection)} ); diff --git a/compat/$live/sections/Slot.tsx b/compat/$live/sections/Slot.tsx index 227ecbacf..2f04cc1e6 100644 --- a/compat/$live/sections/Slot.tsx +++ b/compat/$live/sections/Slot.tsx @@ -1,5 +1,4 @@ -import { isSection, Section } from "deco/blocks/section.ts"; - +import { isSection, type Section } from "@deco/deco/blocks"; export type WellKnownSlots = | "content" | "footer" @@ -7,7 +6,6 @@ export type WellKnownSlots = | "analytics" | "design-system" | "SEO"; - export interface Props { /** * @description Enforces the slot to be fulfilled. @@ -19,29 +17,22 @@ export interface Props { */ name?: string | WellKnownSlots; } - export const CONTENT_SLOT_NAME = "content"; export const isContentSlot = (s: Section): boolean => { return isSection(s, "$live/sections/Slot.tsx") && s?.props?.name === CONTENT_SLOT_NAME; }; - export default function Slot(p: Props) { if (p?.required) { return ShowSlot(p); } return null; } - function ShowSlot(p: Props) { return ( -