Skip to content

Commit 7526982

Browse files
authored
Revert "Revert "(feat): Deployments" (#921)" (#922)
This reverts commit 6452342.
1 parent 6452342 commit 7526982

21 files changed

Lines changed: 394 additions & 136 deletions

apps/api/src/api.ts

Lines changed: 1 addition & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
AuthorizationClient,
77
createMCPToolsStub,
88
EMAIL_TOOLS,
9-
Entrypoint,
109
getPresignedReadUrl_WITHOUT_CHECKING_AUTHORIZATION,
1110
getWorkspaceBucketName,
1211
GLOBAL_TOOLS,
@@ -24,16 +23,15 @@ import { logger } from "hono/logger";
2423
import { endTime, startTime } from "hono/timing";
2524
import type { ContentfulStatusCode } from "hono/utils/http-status";
2625
import { z } from "zod";
27-
import { fetchScript } from "./apps.ts";
2826
import { ROUTES as loginRoutes } from "./auth/index.ts";
2927
import { withActorsStubMiddleware } from "./middlewares/actors-stub.ts";
3028
import { withActorsMiddleware } from "./middlewares/actors.ts";
3129
import { withContextMiddleware } from "./middlewares/context.ts";
3230
import { setUserMiddleware } from "./middlewares/user.ts";
31+
import { handleCodeExchange } from "./oauth/code.ts";
3332
import { type AppContext, type AppEnv, State } from "./utils/context.ts";
3433
import { handleStripeWebhook } from "./webhooks/stripe.ts";
3534
import { handleTrigger } from "./webhooks/trigger.ts";
36-
import { handleCodeExchange } from "./oauth/code.ts";
3735

3836
export const app = new Hono<AppEnv>();
3937
export const honoCtxToAppCtx = (c: Context<AppEnv>): AppContext => {
@@ -332,51 +330,6 @@ app.get("/apps/oauth", (c) => {
332330
// Health check endpoint
333331
app.get("/health", (c: Context) => c.json({ status: "ok" }));
334332

335-
const DECO_WORKSPACE_HEADER = "x-deco-workspace";
336-
const SENSITIVE_HEADERS = ["Cookie", "Authorization"];
337-
app.on([
338-
"GET",
339-
"POST",
340-
"PUT",
341-
"DELETE",
342-
"PATCH",
343-
"OPTIONS",
344-
], [
345-
"/:root/:slug/views/:script/:path{.+}?",
346-
"/views/:script/:path{.+}?",
347-
], (c: Context) => {
348-
const script = c.req.param("script");
349-
const path = c.req.param("path");
350-
const root = c.req.param("root");
351-
const slug = c.req.param("slug");
352-
const workspace = root && slug
353-
? `/${root}/${slug}`
354-
: c.req.header(DECO_WORKSPACE_HEADER);
355-
356-
const url = new URL(c.req.raw.url);
357-
url.protocol = "https:";
358-
url.port = "443";
359-
url.host = Entrypoint.host(script);
360-
url.pathname = `/${path || ""}`;
361-
362-
const headers = new Headers(c.req.header());
363-
SENSITIVE_HEADERS.forEach((header) => {
364-
headers.delete(header);
365-
});
366-
367-
workspace && headers.set(DECO_WORKSPACE_HEADER, workspace);
368-
return fetchScript(
369-
c,
370-
script,
371-
new Request(url, {
372-
redirect: c.req.raw.redirect,
373-
body: c.req.raw.body,
374-
method: c.req.raw.method,
375-
headers,
376-
}),
377-
);
378-
});
379-
380333
app.onError((err, c) => {
381334
console.error(err);
382335

apps/api/src/apps.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import { SWRCache } from "@deco/sdk/cache/swr";
2-
import { Entrypoint, HOSTING_APPS_DOMAIN } from "@deco/sdk/mcp";
2+
import { Entrypoint } from "@deco/sdk/mcp";
33
import { type Context, Hono } from "hono";
44
import { APPS_DOMAIN_QS, appsDomainOf } from "./app.ts";
55
import { withContextMiddleware } from "./middlewares/context.ts";
66
import type { AppEnv } from "./utils/context.ts";
77

88
const ONE_HOUR_SECONDS = 60 * 60;
9-
const domainSWRCache = new SWRCache<string>("domain-swr", ONE_HOUR_SECONDS);
9+
const domainSWRCache = new SWRCache<string | null>(
10+
"domain-swr",
11+
ONE_HOUR_SECONDS,
12+
);
1013
export type DispatcherFetch = typeof fetch;
1114
export const app = new Hono<AppEnv>();
1215

@@ -53,32 +56,46 @@ app.all("/*", async (c: Context<AppEnv>) => {
5356
if (!host) {
5457
return new Response("No host", { status: 400 });
5558
}
56-
let script = Entrypoint.script(host);
59+
const locator = Entrypoint.script(host);
60+
// if it has a deployment ID, we can use the script ID directly
61+
let script = locator?.isCanonical ? locator.slug : null;
5762
if (!script) {
5863
script = await domainSWRCache.cache(
59-
async () => {
64+
async (): Promise<string | null> => {
6065
const { data, error } = await c.var.db.from("deco_chat_hosting_routes")
61-
.select("*, deco_chat_hosting_apps(slug)").eq(
66+
.select(`
67+
*,
68+
deco_chat_hosting_apps_deployments!deployment_id(
69+
id,
70+
deco_chat_hosting_apps!hosting_app_id(slug)
71+
)
72+
`).eq(
6273
"route_pattern",
6374
host,
6475
).maybeSingle();
6576
if (error) {
6677
throw error;
6778
}
68-
const slug = data?.deco_chat_hosting_apps?.slug;
69-
if (!slug) {
70-
throw new Error("No slug found");
79+
if (!data && locator) {
80+
return locator.slug;
7181
}
72-
return slug;
82+
const deployment = data?.deco_chat_hosting_apps_deployments;
83+
const slug = deployment?.deco_chat_hosting_apps?.slug;
84+
const deploymentId = deployment?.id;
85+
if (!slug || !deploymentId) {
86+
throw new Error("No slug or deployment ID found");
87+
}
88+
return Entrypoint.id(slug, deploymentId);
7389
},
7490
host,
7591
false,
7692
).catch(() => null);
77-
host = `${script}${HOSTING_APPS_DOMAIN}`;
7893
}
94+
7995
if (!script) {
8096
return new Response("Not found", { status: 404 });
8197
}
98+
host = Entrypoint.host(script);
8299
if (url.host !== host) {
83100
url.host = host;
84101
url.protocol = "https";

apps/api/src/email.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export function email(
8181
msg.setSender(message.to);
8282
msg.setRecipient(message.from);
8383
const cc = message.headers.get("Cc");
84-
// @ts-expect-error - this exists
84+
// @ts-ignore: cc is not a valid property of the EmailMessage class
8585
cc && msg.setCc(message.cc);
8686
msg.setSubject(replySubject); // Use the threaded subject instead of generic text
8787

docs/server/deco.gen.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5644,7 +5644,7 @@ export interface Env {
56445644
* ]
56455645
* Important Notes:
56465646
* - You can access the app workspace by accessing env.DECO_CHAT_WORKSPACE
5647-
* - You can access the app script slug by accessing env.DECO_CHAT_SCRIPT_SLUG
5647+
* - You can access the app script slug by accessing env.DECO_CHAT_APP_SLUG
56485648
* - Token and workspace can be used to make authenticated requests to the Deco API under https://api.deco.chat
56495649
* - Always use Cloudflare Workers syntax with export default and proper fetch handler signature
56505650
* - When using template literals inside content strings, escape backticks with a backslash (\) or use string concatenation (+)

packages/cli/deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@deco/cli",
3-
"version": "0.9.8",
3+
"version": "0.9.9",
44
"description": "A CLI for interacting with deco.chat.",
55
"license": "MIT",
66
"exports": "./cli.ts",

packages/cli/src/hosting/deploy.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ export const deploy = async (
182182
throw new Error(errorTextJson ?? errorText ?? "Unknown error");
183183
}
184184

185-
const { entrypoint } = response.structuredContent as { entrypoint: string };
186-
console.log(`\n🎉 Deployed! Available at: ${entrypoint}\n`);
185+
const { hosts } = response.structuredContent as { hosts: string[] };
186+
console.log(`\n🎉 Deployed! Available at:`);
187+
hosts.forEach((host) => console.log(` ${host}`));
188+
console.log();
187189
};

packages/cli/src/typings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ export const genEnv = async (
166166
const apiClient = await createWorkspaceClient({ local });
167167

168168
const types = new Map<string, number>();
169+
types.set("Env", 1); // set the default env type
169170
let tsTypes = "";
170171
const props = await Promise.all(
171172
[

packages/runtime/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ export interface WorkspaceDB {
3030
export interface DefaultEnv<TSchema extends z.ZodTypeAny = any> {
3131
DECO_CHAT_REQUEST_CONTEXT: RequestContext<TSchema>;
3232
DECO_CHAT_APP_NAME: string;
33-
DECO_CHAT_SCRIPT_SLUG: string;
33+
DECO_CHAT_APP_SLUG: string;
3434
DECO_CHAT_APP_ENTRYPOINT: string;
3535
DECO_CHAT_API_URL?: string;
3636
DECO_CHAT_WORKSPACE: string;
3737
DECO_CHAT_API_JWT_PUBLIC_KEY: string;
38+
DECO_CHAT_APP_DEPLOYMENT_ID: string;
3839
DECO_CHAT_BINDINGS: string;
3940
DECO_CHAT_API_TOKEN: string;
4041
DECO_CHAT_WORKFLOW_DO: DurableObjectNamespace<WorkflowDO>;

packages/runtime/src/workflow.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ export const Workflow = (
107107
},
108108
telemetry: {
109109
enabled: true,
110-
serviceName: `app-${this.env.DECO_CHAT_SCRIPT_SLUG}`,
110+
serviceName: `app-${
111+
this.env.DECO_CHAT_SCRIPT_SLUG ?? this.env.DECO_CHAT_APP_SLUG
112+
}`,
111113
},
112114
});
113115
// since mastra workflows are thenables, so we need to wrap then into an object

packages/sdk/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
"@opentelemetry/semantic-conventions": "^1.21.0",
4545
"@opentelemetry/exporter-trace-otlp-proto": "^0.53.0",
4646
"@opentelemetry/otlp-exporter-base": "^0.53.0",
47-
"@opentelemetry/otlp-transformer": "^0.53.0"
47+
"@opentelemetry/otlp-transformer": "^0.53.0",
48+
"short-unique-id": "^5.3.2"
4849
},
4950
"devDependencies": {
5051
"@cloudflare/workers-types": "^4.20250510.0",

0 commit comments

Comments
 (0)