From e5afae0f981304e0abdb281619e60d6f611aed06 Mon Sep 17 00:00:00 2001 From: Gabriel Massadas <5445926+G4brym@users.noreply.github.com> Date: Thu, 25 Jul 2024 13:35:04 +0100 Subject: [PATCH] Remove constellation commands from wrangler (#4545) --- .changeset/five-berries-rest.md | 6 + .../src/__tests__/configuration.test.ts | 98 ----- .../src/__tests__/constellation.test.ts | 375 ------------------ .../wrangler/src/__tests__/deploy.test.ts | 4 +- .../src/__tests__/type-generation.test.ts | 2 +- packages/wrangler/src/__tests__/user.test.ts | 4 +- .../pages/create-worker-bundle-contents.ts | 1 - .../wrangler/src/api/startDevWorker/types.ts | 2 - .../wrangler/src/api/startDevWorker/utils.ts | 10 - packages/wrangler/src/config/config.ts | 1 - packages/wrangler/src/config/environment.ts | 17 - packages/wrangler/src/config/index.ts | 13 - packages/wrangler/src/config/validation.ts | 57 --- .../src/constellation/createProject.tsx | 52 --- .../src/constellation/deleteProject.ts | 51 --- .../src/constellation/deleteProjectModel.ts | 76 ---- packages/wrangler/src/constellation/index.ts | 79 ---- .../src/constellation/listCatalog.tsx | 35 -- .../wrangler/src/constellation/listModel.tsx | 49 --- .../src/constellation/listProject.tsx | 28 -- .../src/constellation/listRuntime.tsx | 28 -- .../wrangler/src/constellation/options.ts | 9 - packages/wrangler/src/constellation/types.ts | 17 - .../src/constellation/uploadModel.tsx | 85 ---- packages/wrangler/src/constellation/utils.ts | 91 ----- packages/wrangler/src/deploy/deploy.ts | 1 - .../create-worker-upload-form.ts | 9 - .../wrangler/src/deployment-bundle/worker.ts | 6 - packages/wrangler/src/dev.tsx | 9 - .../src/environment-variables/factory.ts | 1 - packages/wrangler/src/index.ts | 6 - packages/wrangler/src/secret/index.ts | 1 - .../wrangler/src/type-generation/index.ts | 7 - packages/wrangler/src/user/user.ts | 1 - packages/wrangler/src/versions/upload.ts | 1 - 35 files changed, 11 insertions(+), 1221 deletions(-) create mode 100644 .changeset/five-berries-rest.md delete mode 100644 packages/wrangler/src/__tests__/constellation.test.ts delete mode 100644 packages/wrangler/src/constellation/createProject.tsx delete mode 100644 packages/wrangler/src/constellation/deleteProject.ts delete mode 100644 packages/wrangler/src/constellation/deleteProjectModel.ts delete mode 100644 packages/wrangler/src/constellation/index.ts delete mode 100644 packages/wrangler/src/constellation/listCatalog.tsx delete mode 100644 packages/wrangler/src/constellation/listModel.tsx delete mode 100644 packages/wrangler/src/constellation/listProject.tsx delete mode 100644 packages/wrangler/src/constellation/listRuntime.tsx delete mode 100644 packages/wrangler/src/constellation/options.ts delete mode 100644 packages/wrangler/src/constellation/types.ts delete mode 100644 packages/wrangler/src/constellation/uploadModel.tsx delete mode 100644 packages/wrangler/src/constellation/utils.ts diff --git a/.changeset/five-berries-rest.md b/.changeset/five-berries-rest.md new file mode 100644 index 000000000000..c9ae23424316 --- /dev/null +++ b/.changeset/five-berries-rest.md @@ -0,0 +1,6 @@ +--- +"wrangler": minor +--- + +Remove experimental/beta constellation commands and binding, please migrate to Workers AI, learn more here https://developers.cloudflare.com/workers-ai/. +This is not deemed a major version bump for Wrangler since these commands were never generally available. diff --git a/packages/wrangler/src/__tests__/configuration.test.ts b/packages/wrangler/src/__tests__/configuration.test.ts index e799119f44fa..1b00d3f776a3 100644 --- a/packages/wrangler/src/__tests__/configuration.test.ts +++ b/packages/wrangler/src/__tests__/configuration.test.ts @@ -27,7 +27,6 @@ describe("normalizeAndValidateConfig()", () => { configPath: undefined, d1_databases: [], vectorize: [], - constellation: [], hyperdrive: [], dev: { ip: process.platform === "win32" ? "127.0.0.1" : "localhost", @@ -2218,103 +2217,6 @@ describe("normalizeAndValidateConfig()", () => { }); }); - describe("[constellation]", () => { - it("should error if constellation is an object", () => { - const { diagnostics } = normalizeAndValidateConfig( - { constellation: {} } as unknown as RawConfig, - undefined, - { env: undefined } - ); - - expect(diagnostics.hasWarnings()).toBe(false); - expect(diagnostics.renderErrors()).toMatchInlineSnapshot(` - "Processing wrangler configuration: - - The field \\"constellation\\" should be an array but got {}." - `); - }); - - it("should error if constellation is a string", () => { - const { diagnostics } = normalizeAndValidateConfig( - { constellation: "BAD" } as unknown as RawConfig, - undefined, - { env: undefined } - ); - - expect(diagnostics.hasWarnings()).toBe(false); - expect(diagnostics.renderErrors()).toMatchInlineSnapshot(` - "Processing wrangler configuration: - - The field \\"constellation\\" should be an array but got \\"BAD\\"." - `); - }); - - it("should error if constellation is a number", () => { - const { diagnostics } = normalizeAndValidateConfig( - { constellation: 999 } as unknown as RawConfig, - undefined, - { env: undefined } - ); - - expect(diagnostics.hasWarnings()).toBe(false); - expect(diagnostics.renderErrors()).toMatchInlineSnapshot(` - "Processing wrangler configuration: - - The field \\"constellation\\" should be an array but got 999." - `); - }); - - it("should error if constellation is null", () => { - const { diagnostics } = normalizeAndValidateConfig( - { constellation: null } as unknown as RawConfig, - undefined, - { env: undefined } - ); - - expect(diagnostics.hasWarnings()).toBe(false); - expect(diagnostics.renderErrors()).toMatchInlineSnapshot(` - "Processing wrangler configuration: - - The field \\"constellation\\" should be an array but got null." - `); - }); - - it("should accept valid bindings", () => { - const { diagnostics } = normalizeAndValidateConfig( - { - constellation: [{ binding: "VALID", project_id: "ID" }], - } as unknown as RawConfig, - undefined, - { env: undefined } - ); - - expect(diagnostics.hasErrors()).toBe(false); - }); - - it("should error if constellation.bindings are not valid", () => { - const { diagnostics } = normalizeAndValidateConfig( - { - constellation: [ - {}, - { binding: "VALID" }, - { binding: 2000, project: 2111 }, - ], - } as unknown as RawConfig, - undefined, - { env: undefined } - ); - expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(` - "Processing wrangler configuration: - - Unexpected fields found in constellation[2] field: \\"project\\"" - `); - expect(diagnostics.hasWarnings()).toBe(true); - expect(diagnostics.renderErrors()).toMatchInlineSnapshot(` - "Processing wrangler configuration: - - \\"constellation[0]\\" bindings should have a string \\"binding\\" field but got {}. - - \\"constellation[0]\\" bindings must have a \\"project_id\\" field but got {}. - - \\"constellation[1]\\" bindings must have a \\"project_id\\" field but got {\\"binding\\":\\"VALID\\"}. - - \\"constellation[2]\\" bindings should have a string \\"binding\\" field but got {\\"binding\\":2000,\\"project\\":2111}. - - \\"constellation[2]\\" bindings must have a \\"project_id\\" field but got {\\"binding\\":2000,\\"project\\":2111}." - `); - }); - }); - describe("[hyperdrive]", () => { it("should error if hyperdrive is an object", () => { const { diagnostics } = normalizeAndValidateConfig( diff --git a/packages/wrangler/src/__tests__/constellation.test.ts b/packages/wrangler/src/__tests__/constellation.test.ts deleted file mode 100644 index b2aad6131d11..000000000000 --- a/packages/wrangler/src/__tests__/constellation.test.ts +++ /dev/null @@ -1,375 +0,0 @@ -import * as fs from "node:fs"; -import { http, HttpResponse } from "msw"; -import { vi } from "vitest"; -import { endEventLoop } from "./helpers/end-event-loop"; -import { mockAccountId, mockApiToken } from "./helpers/mock-account-id"; -import { mockConsoleMethods } from "./helpers/mock-console"; -import { clearDialogs, mockConfirm } from "./helpers/mock-dialogs"; -import { useMockIsTTY } from "./helpers/mock-istty"; -import { createFetchResult, msw } from "./helpers/msw"; -import { runInTempDir } from "./helpers/run-in-tmp"; -import { runWrangler } from "./helpers/run-wrangler"; - -describe("constellation help", () => { - const std = mockConsoleMethods(); - runInTempDir(); - - it("should show help when no argument is passed", async () => { - await runWrangler("constellation"); - await endEventLoop(); - - expect(std.out).toMatchInlineSnapshot(` - "wrangler constellation - - COMMANDS - wrangler constellation project Manage your projects - wrangler constellation model Manage your models - wrangler constellation catalog Check the curated model catalog - wrangler constellation runtime Check the suported runtimes - - GLOBAL FLAGS - -j, --experimental-json-config Experimental: support wrangler.json [boolean] - -c, --config Path to .toml configuration file [string] - -e, --env Environment to use for operations and .env files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" - `); - }); - - it("should show help when an invalid argument is passed", async () => { - await expect(() => runWrangler("constellation asdf")).rejects.toThrow( - "Unknown argument: asdf" - ); - - expect(std.err).toMatchInlineSnapshot(` - "X [ERROR] Unknown argument: asdf - - " - `); - expect(std.out).toMatchInlineSnapshot(` - " - wrangler constellation - - COMMANDS - wrangler constellation project Manage your projects - wrangler constellation model Manage your models - wrangler constellation catalog Check the curated model catalog - wrangler constellation runtime Check the suported runtimes - - GLOBAL FLAGS - -j, --experimental-json-config Experimental: support wrangler.json [boolean] - -c, --config Path to .toml configuration file [string] - -e, --env Environment to use for operations and .env files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" - `); - }); -}); - -describe("constellation commands", () => { - mockAccountId(); - mockApiToken(); - runInTempDir(); - const { setIsTTY } = useMockIsTTY(); - - const std = mockConsoleMethods(); - - beforeEach(() => { - // @ts-expect-error we're using a very simple setTimeout mock here - vi.spyOn(global, "setTimeout").mockImplementation((fn, _period) => { - setImmediate(fn); - }); - setIsTTY(true); - }); - - afterEach(() => { - clearDialogs(); - }); - - it("should handle project creation", async () => { - mockConstellationRequest(); - await runWrangler("constellation project create new_project ONNX"); - expect(std.out).toMatchInlineSnapshot(` - "-------------------- - šŸš§ Constellation is currently in open alpha and is not recommended for production data and traffic - šŸš§ Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose - šŸš§ To give feedback, visit https://discord.cloudflare.com - -------------------- - - āœ… Successfully created Project \\"new_project3\\"!" - `); - }); - - it("should handle project listing", async () => { - mockConstellationRequest(); - await runWrangler("constellation project list"); - expect(std.out).toMatchInlineSnapshot(` - "-------------------- - šŸš§ Constellation is currently in open alpha and is not recommended for production data and traffic - šŸš§ Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose - šŸš§ To give feedback, visit https://discord.cloudflare.com - -------------------- - - ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” - ā”‚ id ā”‚ name ā”‚ runtime ā”‚ created_at ā”‚ - ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ - ā”‚ 4806cdcf-9aa7-4fa2-b6a1-77fe9e196680 ā”‚ new_project3 ā”‚ ONNX ā”‚ 2023-04-28T13:25:58.513105Z ā”‚ - ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜" - `); - }); - - it("should handle project deletion", async () => { - mockConstellationRequest(); - mockConfirm({ - text: "Ok to proceed?", - result: true, - }); - - await runWrangler("constellation project delete new_project3"); - expect(std.out).toMatchInlineSnapshot(` - "-------------------- - šŸš§ Constellation is currently in open alpha and is not recommended for production data and traffic - šŸš§ Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose - šŸš§ To give feedback, visit https://discord.cloudflare.com - -------------------- - - About to delete Project 'new_project3' (4806cdcf-9aa7-4fa2-b6a1-77fe9e196680). - Deleting... - Deleted 'new_project3' successfully." - `); - }); - - it("should handle catalog list", async () => { - mockConstellationRequest(); - await runWrangler("constellation catalog list"); - expect(std.out).toMatchInlineSnapshot(` - "-------------------- - šŸš§ Constellation is currently in open alpha and is not recommended for production data and traffic - šŸš§ Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose - šŸš§ To give feedback, visit https://discord.cloudflare.com - -------------------- - - ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” - ā”‚ project_id ā”‚ project_name ā”‚ project_runtime ā”‚ models ā”‚ - ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ - ā”‚ b162a29d-0a6d-4155-bedf-54a01fc8d0ef ā”‚ image-classification ā”‚ ONNX ā”‚ squeezenet1_1 ā”‚ - ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜" - `); - }); - - it("should handle runtime list", async () => { - mockConstellationRequest(); - await runWrangler("constellation runtime list"); - expect(std.out).toMatchInlineSnapshot(` - "-------------------- - šŸš§ Constellation is currently in open alpha and is not recommended for production data and traffic - šŸš§ Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose - šŸš§ To give feedback, visit https://discord.cloudflare.com - -------------------- - - ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” - ā”‚ name ā”‚ - ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ - ā”‚ ONNX ā”‚ - ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ - ā”‚ XGBoost ā”‚ - ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜" - `); - }); - - it("should handle model upload", async () => { - mockConstellationRequest(); - await fs.promises.writeFile("model.onnx", `model`); - await runWrangler( - "constellation model upload new_project3 model2 model.onnx" - ); - expect(std.out).toMatchInlineSnapshot(` - "-------------------- - šŸš§ Constellation is currently in open alpha and is not recommended for production data and traffic - šŸš§ Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose - šŸš§ To give feedback, visit https://discord.cloudflare.com - -------------------- - - āœ… Successfully uploaded Model \\"model2\\"!" - `); - }); - - it("should handle model list", async () => { - mockConstellationRequest(); - await runWrangler("constellation model list new_project3"); - expect(std.out).toMatchInlineSnapshot(` - "-------------------- - šŸš§ Constellation is currently in open alpha and is not recommended for production data and traffic - šŸš§ Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose - šŸš§ To give feedback, visit https://discord.cloudflare.com - -------------------- - - ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” - ā”‚ id ā”‚ project_id ā”‚ name ā”‚ description ā”‚ created_at ā”‚ - ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ - ā”‚ 450bb086-3c09-4991-a0cc-eed48c504ae0 ā”‚ 9d478427-dea6-4988-9b16-f6f8888d974c ā”‚ model1 ā”‚ ā”‚ 2023-04-28T11:15:14.806217Z ā”‚ - ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ - ā”‚ 2dd35b4e-0c7a-4c7a-a9e2-e33c0e17bc02 ā”‚ 9d478427-dea6-4988-9b16-f6f8888d974c ā”‚ model2 ā”‚ ā”‚ 2023-04-28T13:50:37.494090Z ā”‚ - ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜" - `); - }); - - it("should handle model deletion", async () => { - mockConstellationRequest(); - mockConfirm({ - text: "Ok to proceed?", - result: true, - }); - - await runWrangler("constellation model delete new_project3 model2"); - expect(std.out).toMatchInlineSnapshot(` - "-------------------- - šŸš§ Constellation is currently in open alpha and is not recommended for production data and traffic - šŸš§ Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose - šŸš§ To give feedback, visit https://discord.cloudflare.com - -------------------- - - About to delete Model 'model2' (2dd35b4e-0c7a-4c7a-a9e2-e33c0e17bc02). - Deleting... - Deleted 'model2' successfully." - `); - }); -}); - -/** Create a mock handler for Constellation API */ -function mockConstellationRequest() { - msw.use( - http.get( - "*/accounts/:accountId/constellation/project", - () => { - return HttpResponse.json( - createFetchResult( - [ - { - id: "4806cdcf-9aa7-4fa2-b6a1-77fe9e196680", - name: "new_project3", - runtime: "ONNX", - created_at: "2023-04-28T13:25:58.513105Z", - }, - ], - true - ) - ); - }, - { once: true } - ), - http.post( - "*/accounts/:accountId/constellation/project", - () => { - return HttpResponse.json( - createFetchResult( - { - id: "4806cdcf-9aa7-4fa2-b6a1-77fe9e196680", - name: "new_project3", - runtime: "ONNX", - created_at: "2023-04-28T13:25:58.513105Z", - }, - true - ) - ); - }, - { once: true } - ), - http.delete( - "*/accounts/:accountId/constellation/project/4806cdcf-9aa7-4fa2-b6a1-77fe9e196680", - () => { - return HttpResponse.json(createFetchResult(null, true)); - }, - { once: true } - ), - http.get( - "*/accounts/:accountId/constellation/catalog", - () => { - return HttpResponse.json( - createFetchResult( - [ - { - project: { - id: "b162a29d-0a6d-4155-bedf-54a01fc8d0ef", - name: "image-classification", - runtime: "ONNX", - created_at: "2023-04-27T18:55:38.417187Z", - }, - models: [ - { - id: "edb202d3-f4ac-43ab-8762-3ae6b43c4c57", - project_id: "b162a29d-0a6d-4155-bedf-54a01fc8d0ef", - name: "squeezenet1_1", - description: null, - created_at: "2023-04-27T18:56:15.305087Z", - }, - ], - }, - ], - true - ) - ); - }, - { once: true } - ), - http.get( - "*/accounts/:accountId/constellation/runtime", - () => { - return HttpResponse.json(createFetchResult(["ONNX", "XGBoost"], true)); - }, - { once: true } - ), - http.post( - "*/accounts/:accountId/constellation/project/4806cdcf-9aa7-4fa2-b6a1-77fe9e196680/model", - () => { - return HttpResponse.json( - createFetchResult( - { - id: "2dd35b4e-0c7a-4c7a-a9e2-e33c0e17bc02", - project_id: "4806cdcf-9aa7-4fa2-b6a1-77fe9e196680", - name: "model2", - description: null, - created_at: "2023-04-28T13:50:37.494090Z", - }, - true - ) - ); - }, - { once: true } - ), - http.get( - "*/accounts/:accountId/constellation/project/4806cdcf-9aa7-4fa2-b6a1-77fe9e196680/model", - () => { - return HttpResponse.json( - createFetchResult( - [ - { - id: "450bb086-3c09-4991-a0cc-eed48c504ae0", - project_id: "9d478427-dea6-4988-9b16-f6f8888d974c", - name: "model1", - description: null, - created_at: "2023-04-28T11:15:14.806217Z", - }, - { - id: "2dd35b4e-0c7a-4c7a-a9e2-e33c0e17bc02", - project_id: "9d478427-dea6-4988-9b16-f6f8888d974c", - name: "model2", - description: null, - created_at: "2023-04-28T13:50:37.494090Z", - }, - ], - true - ) - ); - }, - { once: true } - ), - http.delete( - "*/accounts/:accountId/constellation/project/4806cdcf-9aa7-4fa2-b6a1-77fe9e196680/model/2dd35b4e-0c7a-4c7a-a9e2-e33c0e17bc02", - () => { - return HttpResponse.json(createFetchResult(null, true)); - }, - { once: true } - ) - ); -} diff --git a/packages/wrangler/src/__tests__/deploy.test.ts b/packages/wrangler/src/__tests__/deploy.test.ts index d3b3a05e340c..6a7c137ad744 100644 --- a/packages/wrangler/src/__tests__/deploy.test.ts +++ b/packages/wrangler/src/__tests__/deploy.test.ts @@ -338,7 +338,7 @@ describe("deploy", () => { expect(std.out).toMatchInlineSnapshot(` "Attempting to login via OAuth... - Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20constellation%3Awrite%20ai%3Awrite%20queues%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256 + Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20ai%3Awrite%20queues%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256 Successfully logged in. Total Upload: xx KiB / gzip: xx KiB Uploaded test-name (TIMINGS) @@ -382,7 +382,7 @@ describe("deploy", () => { expect(std.out).toMatchInlineSnapshot(` "Attempting to login via OAuth... - Opening a link in your default browser: https://dash.staging.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20constellation%3Awrite%20ai%3Awrite%20queues%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256 + Opening a link in your default browser: https://dash.staging.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20ai%3Awrite%20queues%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256 Successfully logged in. Total Upload: xx KiB / gzip: xx KiB Uploaded test-name (TIMINGS) diff --git a/packages/wrangler/src/__tests__/type-generation.test.ts b/packages/wrangler/src/__tests__/type-generation.test.ts index 8349226a4429..f1207fc7ae35 100644 --- a/packages/wrangler/src/__tests__/type-generation.test.ts +++ b/packages/wrangler/src/__tests__/type-generation.test.ts @@ -105,7 +105,7 @@ describe("generateImportSpecifier", () => { const bindingsConfigMock: Omit< EnvironmentNonInheritable, - "define" | "tail_consumers" | "constellation" | "cloudchamber" + "define" | "tail_consumers" | "cloudchamber" > & Record = { kv_namespaces: [{ binding: "TEST_KV_NAMESPACE", id: "1234" }], diff --git a/packages/wrangler/src/__tests__/user.test.ts b/packages/wrangler/src/__tests__/user.test.ts index 5a5b7477d890..95f92125d488 100644 --- a/packages/wrangler/src/__tests__/user.test.ts +++ b/packages/wrangler/src/__tests__/user.test.ts @@ -70,7 +70,7 @@ describe("User", () => { expect(counter).toBe(1); expect(std.out).toMatchInlineSnapshot(` "Attempting to login via OAuth... - Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20constellation%3Awrite%20ai%3Awrite%20queues%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256 + Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20ai%3Awrite%20queues%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256 Successfully logged in." `); expect(readAuthConfigFile()).toEqual({ @@ -109,7 +109,7 @@ describe("User", () => { expect(counter).toBe(1); expect(std.out).toMatchInlineSnapshot(` "Attempting to login via OAuth... - Opening a link in your default browser: https://dash.staging.cloudflare.com/oauth2/auth?response_type=code&client_id=4b2ea6cc-9421-4761-874b-ce550e0e3def&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20constellation%3Awrite%20ai%3Awrite%20queues%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256 + Opening a link in your default browser: https://dash.staging.cloudflare.com/oauth2/auth?response_type=code&client_id=4b2ea6cc-9421-4761-874b-ce550e0e3def&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20ai%3Awrite%20queues%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256 Successfully logged in." `); diff --git a/packages/wrangler/src/api/pages/create-worker-bundle-contents.ts b/packages/wrangler/src/api/pages/create-worker-bundle-contents.ts index 19948e1f6830..bfb87c2a39be 100644 --- a/packages/wrangler/src/api/pages/create-worker-bundle-contents.ts +++ b/packages/wrangler/src/api/pages/create-worker-bundle-contents.ts @@ -65,7 +65,6 @@ function createWorkerBundleFormData( wasm_modules: undefined, text_blobs: undefined, data_blobs: undefined, - constellation: undefined, dispatch_namespaces: undefined, logfwdr: undefined, unsafe: undefined, diff --git a/packages/wrangler/src/api/startDevWorker/types.ts b/packages/wrangler/src/api/startDevWorker/types.ts index cafed479fe2d..aa45767a92b3 100644 --- a/packages/wrangler/src/api/startDevWorker/types.ts +++ b/packages/wrangler/src/api/startDevWorker/types.ts @@ -8,7 +8,6 @@ import type { import type { NodeJSCompatMode } from "../../deployment-bundle/node-compat"; import type { CfAnalyticsEngineDataset, - CfConstellation, CfD1Database, CfDispatchNamespace, CfDurableObject, @@ -252,7 +251,6 @@ export type Binding = | ({ type: "r2_bucket" } & BindingOmit) | ({ type: "d1" } & Omit) | ({ type: "vectorize" } & Omit) - | ({ type: "constellation" } & Omit) | ({ type: "hyperdrive" } & Omit) | ({ type: "service" } & Omit) | { type: "fetcher"; fetcher: ServiceFetch } diff --git a/packages/wrangler/src/api/startDevWorker/utils.ts b/packages/wrangler/src/api/startDevWorker/utils.ts index 69fa1fc39f15..80f2387e8675 100644 --- a/packages/wrangler/src/api/startDevWorker/utils.ts +++ b/packages/wrangler/src/api/startDevWorker/utils.ts @@ -182,12 +182,6 @@ export function convertCfWorkerInitBindingstoBindings( } break; } - case "constellation": { - for (const { binding, ...x } of info) { - output[binding] = { type: "constellation", ...x }; - } - break; - } case "services": { for (const { binding, ...x } of info) { output[binding] = { type: "service", ...x }; @@ -276,7 +270,6 @@ export async function convertBindingsToCfWorkerInitBindings( r2_buckets: undefined, d1_databases: undefined, vectorize: undefined, - constellation: undefined, hyperdrive: undefined, services: undefined, analytics_engine_datasets: undefined, @@ -339,9 +332,6 @@ export async function convertBindingsToCfWorkerInitBindings( } else if (binding.type === "vectorize") { bindings.vectorize ??= []; bindings.vectorize.push({ ...binding, binding: name }); - } else if (binding.type === "constellation") { - bindings.constellation ??= []; - bindings.constellation.push({ ...binding, binding: name }); } else if (binding.type === "hyperdrive") { bindings.hyperdrive ??= []; bindings.hyperdrive.push({ ...binding, binding: name }); diff --git a/packages/wrangler/src/config/config.ts b/packages/wrangler/src/config/config.ts index 78aaaf9b0122..263051fc9f22 100644 --- a/packages/wrangler/src/config/config.ts +++ b/packages/wrangler/src/config/config.ts @@ -394,7 +394,6 @@ export const defaultWranglerConfig: Config = { define: {}, cloudchamber: {}, send_email: [], - constellation: [], browser: undefined, unsafe: { bindings: undefined, diff --git a/packages/wrangler/src/config/environment.ts b/packages/wrangler/src/config/environment.ts index 44392a6d3555..9ae1dcd9eccd 100644 --- a/packages/wrangler/src/config/environment.ts +++ b/packages/wrangler/src/config/environment.ts @@ -556,23 +556,6 @@ export interface EnvironmentNonInheritable { index_name: string; }[]; - // Q: is this still relevant? what abt the `ai` key? is there a diff between them? - /** - * Specifies Constellation projects that are bound to this Worker environment. - * - * NOTE: This field is not automatically inherited from the top level environment, - * and so must be specified in every named environment. - * - * @default `[]` - * @nonInheritable - */ - constellation: { - /** The binding name used to refer to the project in the Worker. */ - binding: string; - /** The id of the project. */ - project_id: string; - }[]; - /** * Specifies Hyperdrive configs that are bound to this Worker environment. * diff --git a/packages/wrangler/src/config/index.ts b/packages/wrangler/src/config/index.ts index e23dd4383723..3248ea08aa4f 100644 --- a/packages/wrangler/src/config/index.ts +++ b/packages/wrangler/src/config/index.ts @@ -206,7 +206,6 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) { queues, d1_databases, vectorize, - constellation, hyperdrive, r2_buckets, logfwdr, @@ -330,18 +329,6 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) { }); } - if (constellation !== undefined && constellation.length > 0) { - output.push({ - type: "Constellation Projects", - entries: constellation.map(({ binding, project_id }) => { - return { - key: binding, - value: project_id, - }; - }), - }); - } - if (hyperdrive !== undefined && hyperdrive.length > 0) { output.push({ type: "Hyperdrive Configs", diff --git a/packages/wrangler/src/config/validation.ts b/packages/wrangler/src/config/validation.ts index 8d1dfbf7cb2a..486e60b4073a 100644 --- a/packages/wrangler/src/config/validation.ts +++ b/packages/wrangler/src/config/validation.ts @@ -2,7 +2,6 @@ import assert from "node:assert"; import path from "node:path"; import TOML from "@iarna/toml"; import { dedent } from "ts-dedent"; -import { getConstellationWarningFromEnv } from "../constellation/utils"; import { Diagnostics } from "./diagnostics"; import { all, @@ -1345,16 +1344,6 @@ function normalizeAndValidateEnvironment( validateBindingArray(envName, validateVectorizeBinding), [] ), - constellation: notInheritable( - diagnostics, - topLevelEnv, - rawConfig, - rawEnv, - envName, - "constellation", - validateBindingArray(envName, validateConstellationBinding), - [] - ), hyperdrive: notInheritable( diagnostics, topLevelEnv, @@ -2145,7 +2134,6 @@ const validateUnsafeBinding: ValidatorFn = (diagnostics, field, value) => { "kv_namespace", "durable_object_namespace", "d1_database", - "constellation", "r2_bucket", "service", "logfwdr", @@ -2560,51 +2548,6 @@ const validateVectorizeBinding: ValidatorFn = (diagnostics, field, value) => { return isValid; }; -const validateConstellationBinding: ValidatorFn = ( - diagnostics, - field, - value -) => { - if (typeof value !== "object" || value === null) { - diagnostics.errors.push( - `"constellation" bindings should be objects, but got ${JSON.stringify( - value - )}` - ); - return false; - } - let isValid = true; - // Constellation bindings must have a binding and a project. - if (!isRequiredProperty(value, "binding", "string")) { - diagnostics.errors.push( - `"${field}" bindings should have a string "binding" field but got ${JSON.stringify( - value - )}.` - ); - isValid = false; - } - if (!isRequiredProperty(value, "project_id", "string")) { - diagnostics.errors.push( - `"${field}" bindings must have a "project_id" field but got ${JSON.stringify( - value - )}.` - ); - isValid = false; - } - if (isValid && getConstellationWarningFromEnv() === undefined) { - diagnostics.warnings.push( - "Constellation Bindings are currently in beta to allow the API to evolve before general availability.\nPlease report any issues to https://github.com/cloudflare/workers-sdk/issues/new/choose\nNote: Run this command with the environment variable NO_CONSTELLATION_WARNING=true to hide this message\n\nFor example: `export NO_CONSTELLATION_WARNING=true && wrangler `" - ); - } - - validateAdditionalProperties(diagnostics, field, Object.keys(value), [ - "binding", - "project_id", - ]); - - return isValid; -}; - const validateHyperdriveBinding: ValidatorFn = (diagnostics, field, value) => { if (typeof value !== "object" || value === null) { diagnostics.errors.push( diff --git a/packages/wrangler/src/constellation/createProject.tsx b/packages/wrangler/src/constellation/createProject.tsx deleted file mode 100644 index 490a759ca9a0..000000000000 --- a/packages/wrangler/src/constellation/createProject.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { fetchResult } from "../cfetch"; -import { withConfig } from "../config"; -import { UserError } from "../errors"; -import { logger } from "../logger"; -import { requireAuth } from "../user"; -import { takeName } from "./options"; -import { constellationBetaWarning } from "./utils"; -import type { - CommonYargsArgv, - StrictYargsOptionsToInterface, -} from "../yargs-types"; -import type { Project } from "./types"; - -export function options(yargs: CommonYargsArgv) { - return takeName(yargs) - .positional("runtime", { - describe: "The name of the runtime to use", - type: "string", - demandOption: true, - }) - .epilogue(constellationBetaWarning); -} - -type HandlerOptions = StrictYargsOptionsToInterface; -export const handler = withConfig( - async ({ name, runtime, config }): Promise => { - const accountId = await requireAuth(config); - - logger.log(constellationBetaWarning); - - let proj: Project; - try { - proj = await fetchResult(`/accounts/${accountId}/constellation/project`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - name, - runtime, - }), - }); - } catch (e) { - if ((e as { code: number }).code === 7409) { - throw new UserError("A project with that name already exists"); - } - throw e; - } - - logger.log(`āœ… Successfully created Project "${proj.name}"!`); - } -); diff --git a/packages/wrangler/src/constellation/deleteProject.ts b/packages/wrangler/src/constellation/deleteProject.ts deleted file mode 100644 index 8fdbedf8ba4e..000000000000 --- a/packages/wrangler/src/constellation/deleteProject.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { fetchResult } from "../cfetch"; -import { withConfig } from "../config"; -import { confirm } from "../dialogs"; -import { logger } from "../logger"; -import { requireAuth } from "../user"; -import { takeName } from "./options"; -import { constellationBetaWarning, getProjectByName } from "./utils"; -import type { - CommonYargsArgv, - StrictYargsOptionsToInterface, -} from "../yargs-types"; - -export function options(yargs: CommonYargsArgv) { - return takeName(yargs) - .option("force", { - describe: "Skip confirmation", - type: "boolean", - alias: "f", - default: false, - }) - .epilogue(constellationBetaWarning); -} -type HandlerOptions = StrictYargsOptionsToInterface; -export const handler = withConfig( - async ({ name, force, config }): Promise => { - const accountId = await requireAuth(config); - logger.log(constellationBetaWarning); - - const proj = await getProjectByName(config, accountId, name); - - logger.log(`About to delete Project '${name}' (${proj.id}).`); - if (!force) { - const response = await confirm(`Ok to proceed?`); - if (!response) { - logger.log(`Not deleting.`); - return; - } - - logger.log("Deleting..."); - } - - await fetchResult( - `/accounts/${accountId}/constellation/project/${proj.id}`, - { - method: "DELETE", - } - ); - - logger.log(`Deleted '${name}' successfully.`); - } -); diff --git a/packages/wrangler/src/constellation/deleteProjectModel.ts b/packages/wrangler/src/constellation/deleteProjectModel.ts deleted file mode 100644 index 59a32f387613..000000000000 --- a/packages/wrangler/src/constellation/deleteProjectModel.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { fetchResult } from "../cfetch"; -import { withConfig } from "../config"; -import { confirm } from "../dialogs"; -import { logger } from "../logger"; -import { requireAuth } from "../user"; -import { - constellationBetaWarning, - getProjectByName, - getProjectModelByName, -} from "./utils"; -import type { - CommonYargsArgv, - StrictYargsOptionsToInterface, -} from "../yargs-types"; -import type { Model, Project } from "./types"; - -export function options(yargs: CommonYargsArgv) { - return yargs - .positional("projectName", { - describe: "The name of the project", - type: "string", - demandOption: true, - }) - .positional("modelName", { - describe: "The name of the uploaded model", - type: "string", - demandOption: true, - }) - .option("force", { - describe: "Skip confirmation", - type: "boolean", - alias: "f", - default: false, - }) - .epilogue(constellationBetaWarning); -} -type HandlerOptions = StrictYargsOptionsToInterface; -export const handler = withConfig( - async ({ projectName, modelName, force, config }): Promise => { - const accountId = await requireAuth(config); - logger.log(constellationBetaWarning); - - const proj: Project = await getProjectByName( - config, - accountId, - projectName - ); - - const model: Model = await getProjectModelByName( - config, - accountId, - proj, - modelName - ); - - logger.log(`About to delete Model '${modelName}' (${model.id}).`); - if (!force) { - const response = await confirm(`Ok to proceed?`); - if (!response) { - logger.log(`Not deleting.`); - return; - } - - logger.log("Deleting..."); - } - - await fetchResult( - `/accounts/${accountId}/constellation/project/${proj.id}/model/${model.id}`, - { - method: "DELETE", - } - ); - - logger.log(`Deleted '${modelName}' successfully.`); - } -); diff --git a/packages/wrangler/src/constellation/index.ts b/packages/wrangler/src/constellation/index.ts deleted file mode 100644 index f0d6278ed4e9..000000000000 --- a/packages/wrangler/src/constellation/index.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { logger } from "../logger"; -import * as CreateProject from "./createProject"; -import * as DeleteProject from "./deleteProject"; -import * as DeleteProjectModel from "./deleteProjectModel"; -import * as ListCatalog from "./listCatalog"; -import * as ListModel from "./listModel"; -import * as ListProject from "./listProject"; -import * as ListRuntime from "./listRuntime"; -import * as UploadModel from "./uploadModel"; -import type { CommonYargsArgv } from "../yargs-types"; - -export function constellation(yargs: CommonYargsArgv) { - logger.warn( - "`wrangler constellation` is deprecated and will be removed in the next major version.\nPlease migrate to Workers AI, learn more here https://developers.cloudflare.com/workers-ai/." - ); - return yargs - .command("project", "Manage your projects", (constProjYargs) => { - return constProjYargs - .command( - "list", - "List your projects", - ListProject.options, - ListProject.handler - ) - .command( - "create ", - "Create project", - CreateProject.options, - CreateProject.handler - ) - .command( - "delete ", - "Delete project", - DeleteProject.options, - DeleteProject.handler - ); - }) - .command("model", "Manage your models", (constModelYargs) => { - return constModelYargs - .command( - "upload ", - "Upload a model for an existing project", - UploadModel.options, - UploadModel.handler - ) - .command( - "list ", - "List models of a project", - ListModel.options, - ListModel.handler - ) - .command( - "delete ", - "Delete a model of a project", - DeleteProjectModel.options, - DeleteProjectModel.handler - ); - }) - .command( - "catalog", - "Check the curated model catalog", - (constCatalogYargs) => { - return constCatalogYargs.command( - "list", - "List catalog models", - ListCatalog.options, - ListCatalog.handler - ); - } - ) - .command("runtime", "Check the suported runtimes", (constRuntimeYargs) => { - return constRuntimeYargs.command( - "list", - "List suported runtimes", - ListRuntime.options, - ListRuntime.handler - ); - }); -} diff --git a/packages/wrangler/src/constellation/listCatalog.tsx b/packages/wrangler/src/constellation/listCatalog.tsx deleted file mode 100644 index 74a77888022c..000000000000 --- a/packages/wrangler/src/constellation/listCatalog.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { withConfig } from "../config"; -import { logger } from "../logger"; -import { requireAuth } from "../user"; -import { asJson } from "../yargs-types"; -import { constellationBetaWarning, listCatalogEntries } from "./utils"; -import type { - CommonYargsArgv, - StrictYargsOptionsToInterface, -} from "../yargs-types"; - -export function options(yargs: CommonYargsArgv) { - return asJson(yargs).epilogue(constellationBetaWarning); -} - -type HandlerOptions = StrictYargsOptionsToInterface; -export const handler = withConfig( - async ({ json, config }): Promise => { - const accountId = await requireAuth(config); - const entries = await listCatalogEntries(accountId); - - if (json) { - logger.log(JSON.stringify(entries, null, 2)); - } else { - logger.log(constellationBetaWarning); - logger.table( - entries.map((entry) => ({ - project_id: entry.project.id, - project_name: entry.project.name, - project_runtime: entry.project.runtime, - models: entry.models.map((model) => model.name).join(","), - })) - ); - } - } -); diff --git a/packages/wrangler/src/constellation/listModel.tsx b/packages/wrangler/src/constellation/listModel.tsx deleted file mode 100644 index 743feb24ca92..000000000000 --- a/packages/wrangler/src/constellation/listModel.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { withConfig } from "../config"; -import { logger } from "../logger"; -import { requireAuth } from "../user"; -import { - constellationBetaWarning, - getProjectByName, - listModels, -} from "./utils"; -import type { - CommonYargsArgv, - StrictYargsOptionsToInterface, -} from "../yargs-types"; -import type { Project } from "./types"; - -export function options(yargs: CommonYargsArgv) { - return yargs - .positional("projectName", { - describe: "The name of the project", - type: "string", - demandOption: true, - }) - .option("json", { - describe: "return output as clean JSON", - type: "boolean", - default: false, - }) - .epilogue(constellationBetaWarning); -} - -type HandlerOptions = StrictYargsOptionsToInterface; -export const handler = withConfig( - async ({ projectName, json, config }): Promise => { - const accountId = await requireAuth(config); - const proj: Project = await getProjectByName( - config, - accountId, - projectName - ); - - const models = await listModels(accountId, proj); - - if (json) { - logger.log(JSON.stringify(models, null, 2)); - } else { - logger.log(constellationBetaWarning); - logger.table(models); - } - } -); diff --git a/packages/wrangler/src/constellation/listProject.tsx b/packages/wrangler/src/constellation/listProject.tsx deleted file mode 100644 index 8d57e5337781..000000000000 --- a/packages/wrangler/src/constellation/listProject.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { withConfig } from "../config"; -import { logger } from "../logger"; -import { requireAuth } from "../user"; -import { asJson } from "../yargs-types"; -import { constellationBetaWarning, listProjects } from "./utils"; -import type { - CommonYargsArgv, - StrictYargsOptionsToInterface, -} from "../yargs-types"; - -export function options(yargs: CommonYargsArgv) { - return asJson(yargs).epilogue(constellationBetaWarning); -} - -type HandlerOptions = StrictYargsOptionsToInterface; -export const handler = withConfig( - async ({ json, config }): Promise => { - const accountId = await requireAuth(config); - const projs = await listProjects(accountId); - - if (json) { - logger.log(JSON.stringify(projs, null, 2)); - } else { - logger.log(constellationBetaWarning); - logger.table(projs); - } - } -); diff --git a/packages/wrangler/src/constellation/listRuntime.tsx b/packages/wrangler/src/constellation/listRuntime.tsx deleted file mode 100644 index be2acba6392b..000000000000 --- a/packages/wrangler/src/constellation/listRuntime.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { withConfig } from "../config"; -import { logger } from "../logger"; -import { requireAuth } from "../user"; -import { asJson } from "../yargs-types"; -import { constellationBetaWarning, listRuntimes } from "./utils"; -import type { - CommonYargsArgv, - StrictYargsOptionsToInterface, -} from "../yargs-types"; - -export function options(yargs: CommonYargsArgv) { - return asJson(yargs).epilogue(constellationBetaWarning); -} - -type HandlerOptions = StrictYargsOptionsToInterface; -export const handler = withConfig( - async ({ json, config }): Promise => { - const accountId = await requireAuth(config); - const runtimes = await listRuntimes(accountId); - - if (json) { - logger.log(JSON.stringify(runtimes, null, 2)); - } else { - logger.log(constellationBetaWarning); - logger.table(runtimes.map((runtime) => ({ name: runtime }))); - } - } -); diff --git a/packages/wrangler/src/constellation/options.ts b/packages/wrangler/src/constellation/options.ts deleted file mode 100644 index ed10286e93ca..000000000000 --- a/packages/wrangler/src/constellation/options.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { CommonYargsArgv } from "../yargs-types"; - -export function takeName(yargs: CommonYargsArgv) { - return yargs.positional("name", { - describe: "The name of the project", - type: "string", - demandOption: true, - }); -} diff --git a/packages/wrangler/src/constellation/types.ts b/packages/wrangler/src/constellation/types.ts deleted file mode 100644 index bfc265a19b30..000000000000 --- a/packages/wrangler/src/constellation/types.ts +++ /dev/null @@ -1,17 +0,0 @@ -export type Project = { - id: string; - name: string; - runtime: string; -}; - -export type Model = { - id: string; - project_id: string; - name: string; - description: string; -}; - -export type CatalogEntry = { - project: Project; - models: Model[]; -}; diff --git a/packages/wrangler/src/constellation/uploadModel.tsx b/packages/wrangler/src/constellation/uploadModel.tsx deleted file mode 100644 index 47cbbeda58a8..000000000000 --- a/packages/wrangler/src/constellation/uploadModel.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { readFileSync } from "node:fs"; -import { File, FormData } from "undici"; -import { fetchResult } from "../cfetch"; -import { withConfig } from "../config"; -import { UserError } from "../errors"; -import { logger } from "../logger"; -import { requireAuth } from "../user"; -import { constellationBetaWarning, getProjectByName } from "./utils"; -import type { - CommonYargsArgv, - StrictYargsOptionsToInterface, -} from "../yargs-types"; -import type { Model } from "./types"; - -export function options(yargs: CommonYargsArgv) { - return yargs - .positional("projectName", { - describe: "The name of the project", - type: "string", - demandOption: true, - }) - .positional("modelName", { - describe: "The name of the uploaded model", - type: "string", - demandOption: true, - }) - .positional("modelFile", { - describe: "The name of the local file with the model contents", - type: "string", - demandOption: true, - }) - .option("description", { - describe: "include a description of the model", - type: "string", - demandOption: false, - alias: "d", - }) - .epilogue(constellationBetaWarning); -} -type HandlerOptions = StrictYargsOptionsToInterface; -export const handler = withConfig( - async ({ - projectName, - modelName, - modelFile, - description, - config, - }): Promise => { - const accountId = await requireAuth(config); - logger.log(constellationBetaWarning); - - const proj = await getProjectByName(config, accountId, projectName); - - const formData = new FormData(); - formData.set( - "file", - new File([readFileSync(modelFile)], modelFile, { - type: "application/octet-stream", - }) - ); - formData.set("name", modelName); - - if (description !== undefined) { - formData.set("description", description); - } - - let model: Model; - try { - model = await fetchResult( - `/accounts/${accountId}/constellation/project/${proj.id}/model`, - { - method: "POST", - body: formData, - } - ); - } catch (e) { - if ((e as { code: number }).code === 7408) { - throw new UserError("A model with that name already exists"); - } - throw e; - } - - logger.log(`āœ… Successfully uploaded Model "${model.name}"!`); - } -); diff --git a/packages/wrangler/src/constellation/utils.ts b/packages/wrangler/src/constellation/utils.ts deleted file mode 100644 index 342106316229..000000000000 --- a/packages/wrangler/src/constellation/utils.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { fetchResult } from "../cfetch"; -import { getEnvironmentVariableFactory } from "../environment-variables/factory"; -import { UserError } from "../errors"; -import type { Config } from "../config"; -import type { CatalogEntry, Model, Project } from "./types"; - -export const getConstellationWarningFromEnv = getEnvironmentVariableFactory({ - variableName: "NO_CONSTELLATION_WARNING", -}); - -export const constellationBetaWarning = - getConstellationWarningFromEnv() !== undefined - ? "" - : "--------------------\nšŸš§ Constellation is currently in open alpha and is not recommended for production data and traffic\nšŸš§ Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose\nšŸš§ To give feedback, visit https://discord.cloudflare.com\n--------------------\n"; - -export const getProjectByName = async ( - config: Config, - accountId: string, - name: string -): Promise => { - const allProjects = await listProjects(accountId); - const matchingProj = allProjects.find((proj) => proj.name === name); - if (!matchingProj) { - throw new UserError(`Couldn't find Project with name '${name}'`); - } - return matchingProj; -}; - -export const getProjectModelByName = async ( - config: Config, - accountId: string, - proj: Project, - modelName: string -): Promise => { - const allModels = await listModels(accountId, proj); - const matchingModel = allModels.find((model) => model.name === modelName); - if (!matchingModel) { - throw new UserError(`Couldn't find Model with name '${modelName}'`); - } - return matchingModel; -}; - -export async function constellationList( - accountId: string, - partialUrl: string -): Promise> { - const pageSize = 50; - let page = 1; - const results = []; - while (results.length % pageSize === 0) { - const json: Array = await fetchResult( - `/accounts/${accountId}/constellation/${partialUrl}`, - {}, - new URLSearchParams({ - per_page: pageSize.toString(), - page: page.toString(), - }) - ); - page++; - results.push(...json); - if (json.length < pageSize) { - break; - } - } - return results; -} - -export const listCatalogEntries = async ( - accountId: string -): Promise> => { - return await constellationList(accountId, "catalog"); -}; - -export const listModels = async ( - accountId: string, - proj: Project -): Promise> => { - return constellationList(accountId, `project/${proj.id}/model`); -}; - -export const listProjects = async ( - accountId: string -): Promise> => { - return await constellationList(accountId, "project"); -}; - -export const listRuntimes = async ( - accountId: string -): Promise> => { - return await constellationList(accountId, "runtime"); -}; diff --git a/packages/wrangler/src/deploy/deploy.ts b/packages/wrangler/src/deploy/deploy.ts index 3b102672486a..22b2c9e05e43 100644 --- a/packages/wrangler/src/deploy/deploy.ts +++ b/packages/wrangler/src/deploy/deploy.ts @@ -627,7 +627,6 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m r2_buckets: config.r2_buckets, d1_databases: config.d1_databases, vectorize: config.vectorize, - constellation: config.constellation, hyperdrive: config.hyperdrive, services: config.services, analytics_engine_datasets: config.analytics_engine_datasets, diff --git a/packages/wrangler/src/deployment-bundle/create-worker-upload-form.ts b/packages/wrangler/src/deployment-bundle/create-worker-upload-form.ts index 6e2adc1f13d9..e89c24062bb9 100644 --- a/packages/wrangler/src/deployment-bundle/create-worker-upload-form.ts +++ b/packages/wrangler/src/deployment-bundle/create-worker-upload-form.ts @@ -88,7 +88,6 @@ export type WorkerMetadataBinding = index_name: string; internalEnv?: string; } - | { type: "constellation"; name: string; project: string } | { type: "hyperdrive"; name: string; id: string } | { type: "service"; @@ -252,14 +251,6 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData { }); }); - bindings.constellation?.forEach(({ binding, project_id }) => { - metadataBindings.push({ - name: binding, - type: "constellation", - project: project_id, - }); - }); - bindings.hyperdrive?.forEach(({ binding, id }) => { metadataBindings.push({ name: binding, diff --git a/packages/wrangler/src/deployment-bundle/worker.ts b/packages/wrangler/src/deployment-bundle/worker.ts index cd2483540ab8..3e685c0e41f9 100644 --- a/packages/wrangler/src/deployment-bundle/worker.ts +++ b/packages/wrangler/src/deployment-bundle/worker.ts @@ -179,11 +179,6 @@ export interface CfVectorize { index_name: string; } -export interface CfConstellation { - binding: string; - project_id: string; -} - export interface CfHyperdrive { binding: string; id: string; @@ -315,7 +310,6 @@ export interface CfWorkerInit { r2_buckets: CfR2Bucket[] | undefined; d1_databases: CfD1Database[] | undefined; vectorize: CfVectorize[] | undefined; - constellation: CfConstellation[] | undefined; hyperdrive: CfHyperdrive[] | undefined; services: CfService[] | undefined; analytics_engine_datasets: CfAnalyticsEngineDataset[] | undefined; diff --git a/packages/wrangler/src/dev.tsx b/packages/wrangler/src/dev.tsx index 5a046fc74078..9629e3aa2eba 100644 --- a/packages/wrangler/src/dev.tsx +++ b/packages/wrangler/src/dev.tsx @@ -448,7 +448,6 @@ export type AdditionalDevProps = { additionalModules?: CfModule[]; moduleRoot?: string; rules?: Rule[]; - constellation?: Environment["constellation"]; showInteractiveDevSession?: boolean; }; @@ -663,7 +662,6 @@ export async function startDev(args: StartDevOptions) { r2_buckets: args.r2, d1_databases: args.d1Databases, vectorize: undefined, - constellation: args.constellation, hyperdrive: undefined, services: args.services, analytics_engine_datasets: undefined, @@ -1433,7 +1431,6 @@ export function getBindings( r2_buckets: mergedR2Bindings, d1_databases: mergedD1Bindings, vectorize: configParam.vectorize, - constellation: configParam.constellation, hyperdrive: hyperdriveBindings, services: mergedServiceBindings, analytics_engine_datasets: configParam.analytics_engine_datasets, @@ -1449,11 +1446,5 @@ export function getBindings( send_email: configParam.send_email, }; - if (bindings.constellation && bindings.constellation.length > 0) { - logger.warn( - "`constellation` is deprecated and will be removed in the next major version.\nPlease migrate to Workers AI, learn more here https://developers.cloudflare.com/workers-ai/." - ); - } - return bindings; } diff --git a/packages/wrangler/src/environment-variables/factory.ts b/packages/wrangler/src/environment-variables/factory.ts index e9367c632a50..09c08611a941 100644 --- a/packages/wrangler/src/environment-variables/factory.ts +++ b/packages/wrangler/src/environment-variables/factory.ts @@ -5,7 +5,6 @@ type VariableNames = | "CLOUDFLARE_API_TOKEN" | "CLOUDFLARE_EMAIL" | `WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_${string}` - | "NO_CONSTELLATION_WARNING" | "NO_HYPERDRIVE_WARNING" | "WRANGLER_API_ENVIRONMENT" | "WRANGLER_AUTH_DOMAIN" diff --git a/packages/wrangler/src/index.ts b/packages/wrangler/src/index.ts index c34c0279fea0..576a2d9356c5 100644 --- a/packages/wrangler/src/index.ts +++ b/packages/wrangler/src/index.ts @@ -8,7 +8,6 @@ import { version as wranglerVersion } from "../package.json"; import { ai } from "./ai"; import { cloudchamber } from "./cloudchamber"; import { loadDotEnv, readConfig } from "./config"; -import { constellation } from "./constellation"; import { d1 } from "./d1"; import { deleteHandler, deleteOptions } from "./delete"; import { deployHandler, deployOptions } from "./deploy"; @@ -730,11 +729,6 @@ export function createCLIParser(argv: string[]) { subdomainHandler ); - // [DEPRECATED] constellation - wrangler.command("constellation", false, (aiYargs) => { - return constellation(aiYargs.command(subHelp)); - }); - // [DEPRECATED] secret:bulk wrangler.command( "secret:bulk [json]", diff --git a/packages/wrangler/src/secret/index.ts b/packages/wrangler/src/secret/index.ts index b6231facbb02..80ba9b3ee097 100644 --- a/packages/wrangler/src/secret/index.ts +++ b/packages/wrangler/src/secret/index.ts @@ -82,7 +82,6 @@ async function createDraftWorker({ d1_databases: [], vectorize: [], hyperdrive: [], - constellation: [], services: [], analytics_engine_datasets: [], wasm_modules: {}, diff --git a/packages/wrangler/src/type-generation/index.ts b/packages/wrangler/src/type-generation/index.ts index 4368459530ba..36167de5d837 100644 --- a/packages/wrangler/src/type-generation/index.ts +++ b/packages/wrangler/src/type-generation/index.ts @@ -123,7 +123,6 @@ export async function typesHandler( unsafe: config.unsafe, rules: config.rules, queues: config.queues, - constellation: config.constellation, send_email: config.send_email, vectorize: config.vectorize, hyperdrive: config.hyperdrive, @@ -311,12 +310,6 @@ async function generateTypes( } } - if (configToDTS.constellation) { - for (const service of configToDTS.constellation) { - envTypeStructure.push(constructType(service.binding, "Fetcher")); - } - } - if (configToDTS.analytics_engine_datasets) { for (const analyticsEngine of configToDTS.analytics_engine_datasets) { envTypeStructure.push( diff --git a/packages/wrangler/src/user/user.ts b/packages/wrangler/src/user/user.ts index dc07a36736f9..00315b89dbe6 100644 --- a/packages/wrangler/src/user/user.ts +++ b/packages/wrangler/src/user/user.ts @@ -350,7 +350,6 @@ const DefaultScopes = { "See and change Cloudflare Pages projects, settings and deployments.", "zone:read": "Grants read level access to account zone.", "ssl_certs:write": "See and manage mTLS certificates for your account", - "constellation:write": "Manage Constellation projects/models", "ai:write": "See and change Workers AI catalog and assets", "queues:write": "See and change Cloudflare Queues settings and data", } as const; diff --git a/packages/wrangler/src/versions/upload.ts b/packages/wrangler/src/versions/upload.ts index 734f2c56575b..f24f0b968a94 100644 --- a/packages/wrangler/src/versions/upload.ts +++ b/packages/wrangler/src/versions/upload.ts @@ -344,7 +344,6 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m r2_buckets: config.r2_buckets, d1_databases: config.d1_databases, vectorize: config.vectorize, - constellation: config.constellation, hyperdrive: config.hyperdrive, services: config.services, analytics_engine_datasets: config.analytics_engine_datasets,