Skip to content

Commit

Permalink
Add Azure Blob Storage commands and update turbo.json configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
JackDevAU committed Jan 17, 2025
1 parent 99d80a1 commit b34f478
Show file tree
Hide file tree
Showing 19 changed files with 1,627 additions and 97 deletions.
8 changes: 8 additions & 0 deletions .changeset/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
11 changes: 11 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "restricted",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
90 changes: 0 additions & 90 deletions .github/workflows/publish.yml

This file was deleted.

34 changes: 34 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Release

on:
push:
branches:
- main

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v3

- name: Setup Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 20.x

- name: Install Dependencies
uses: pnpm/action-setup@v4

- name: Create Release Pull Request or Publish to npm
id: changesets
uses: changesets/action@v1
with:
# This expects you to have a script called release which does a build for your packages and calls changeset publish
publish: yarn release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"format": "biome check . --write",
"lint": "biome check .",
"cli": "turbo dev --filter=cli",
"watch": "turbo watch watch"
"watch": "turbo run watch"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/commands/add/absolute-imports/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// TODO: https://nextjs.org/docs/pages/building-your-application/configuring/absolute-imports-and-module-aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export const blobPOST = `import { BlobServiceClient } from '@azure/storage-blob';
import { NextResponse } from 'next/server';
export const POST = async (req: Request) => {
try {
const blobServiceClient = BlobServiceClient.fromConnectionString(
process.env.AZURE_STORAGE_CONNECTION_STRING!,
);
const containerName = process.env.AZURE_STORAGE_CONTAINER_NAME!;
const containerClient = blobServiceClient.getContainerClient(containerName);
const data = await req.formData();
const file = data.get("file");
if (!(file instanceof File) || !file) {
return NextResponse.json({ message: "Invalid file uploaded" }, { status: 400 });
}
// Convert the file to a buffer to upload it to Azure Blob Storage
const arrayBuffer = await file.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const blobName = file.name;
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
// Upload the file with proper content type
await blockBlobClient.uploadData(buffer, {
blobHTTPHeaders: {
blobContentType: file.type, // Ensures correct MIME type is set
},
});
return NextResponse.json({ message: "File uploaded successfully" });
} catch (error) {
console.error("Error during file upload:", error);
return NextResponse.json({ message: "Error uploading file", error: (error as Error).message }, { status: 500 });
}
};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export const blobDELETE = `
export const DELETE = async (req: Request) => {
try {
const blobServiceClient = BlobServiceClient.fromConnectionString(
process.env.AZURE_STORAGE_CONNECTION_STRING!,
);
const containerName = process.env.AZURE_STORAGE_CONTAINER_NAME!;
const containerClient = blobServiceClient.getContainerClient(containerName);
// Assuming the image path is passed as a query parameter, e.g., ?path=<container-name>/<image>.<extension eg.jpeg>
const urlParams = new URL(req.url).searchParams;
const imagePath = urlParams.get('path'); // Extract the image path
if (!imagePath) {
return NextResponse.json({ message: "No image path provided" }, { status: 400 });
}
// Get the blob client for the image path
const blobClient = containerClient.getBlobClient(imagePath);
await blobClient.delete();
return NextResponse.json({ message: "File deleted successfully" });
} catch (error) {
console.error(error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export const blobGET = `
export const GET = async (req: Request) => {
try {
const blobServiceClient = BlobServiceClient.fromConnectionString(
process.env.AZURE_STORAGE_CONNECTION_STRING!,
);
const containerName = process.env.AZURE_STORAGE_CONTAINER_NAME!;
const containerClient = blobServiceClient.getContainerClient(containerName);
const params = new URL(req.url);
let imagePath = params.pathname.startsWith("/")
? params.pathname.slice(1)
: params.pathname;
if (!imagePath) {
return NextResponse.json({ message: "no image" }, { status: 404 });
}
const blobClient = containerClient.getBlobClient(imagePath);
const downloadBlockBlobResponse = await blobClient.download();
const blobContentType = downloadBlockBlobResponse.contentType || "image/jpeg";
const buffer = await blobClient.downloadToBuffer();
return new Response(buffer, {
status: 200,
headers: {
"Content-Type": blobContentType,
},
});
} catch (error) {
console.error(error);
return NextResponse.json({ error });
}
};
`;
81 changes: 81 additions & 0 deletions packages/cli/src/commands/add/azure-blob-storage/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import consola from "consola";
import inquirer from "inquirer";
import {
AddPackageToConfig,
CheckConfig,
type ConfigOptions,
} from "../../../util/config.js";
import { TryWriteFileAndAppend } from "../../../util/index.js";
import { CommandName } from "../index.js";
import { blobPOST } from "./generators/blob-create.js";
import { blobDELETE } from "./generators/blob-delete.js";

export const description = "Add Azure Blob to your Next.js project";

export const addAzureBlobAction = async () => {
consola.log("Adding Azure Blob to your Next.js project...");
let config: ConfigOptions;
try {
config = await CheckConfig(CommandName.azureblob);
} catch (error) {
if (error instanceof Error) {
consola.error(error.message);
}
return;
}

try {
const { operations } = await inquirer.prompt([
{
type: "checkbox",
name: "operations",
message: "Select the operations to add:",
choices: [
{ name: "GET - Fetch Blob", value: "get" },
{ name: "CREATE - Upload Blob", value: "create" },
{ name: "DELETE - Remove Blob", value: "delete" },
],
},
]);

if (operations.length === 0) {
consola.warn(
"No operations selected. You must select at least one operation.",
);
return;
}

// Imports
await TryWriteFileAndAppend(
"app/api/blob",
"route.tsx",
`import { NextResponse } from "next/server";
import { BlobServiceClient } from "@azure/storage-blob";`,
);

if (operations.includes("get")) {
// app/api/blob/route.tsx + add blobGET
consola.warn(
"TODO: Implement logic for storage GET operation to the project",
);
// await TryWriteFileAndAppend("app/api/blob", "route.tsx", blobGET);
}

if (operations.includes("create")) {
// app/api/blob/route.tsx + add blobPOST
await TryWriteFileAndAppend("app/api/blob", "route.tsx", blobPOST);
}

if (operations.includes("delete")) {
// app/api/blob/route.tsx + add blobDELETE
await TryWriteFileAndAppend("app/api/blob", "route.tsx", blobDELETE);
}

consola.success("Azure Blob has been successfully initialized!");
await AddPackageToConfig(CommandName.azureblob);
} catch (error) {
if (error instanceof Error) {
consola.error("Failed to initialize the Azure Blob:", error.message);
}
}
};
2 changes: 2 additions & 0 deletions packages/cli/src/commands/add/debug/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// TODO: https://www.npmjs.com/package/@next/bundle-analyzer
//? This might be a collection of packages that can be added to debug all sorts of things
1 change: 1 addition & 0 deletions packages/cli/src/commands/add/drizzle-orm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// TODO: https://orm.drizzle.team/docs/get-started/postgresql-existing
5 changes: 5 additions & 0 deletions packages/cli/src/commands/add/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Command } from "commander";
import consola from "consola";
import { addAzureBlobAction } from "./azure-blob-storage/index.js";
import { addBiomejsAction } from "./biomejs/index.js";
import { addNextAuthAction } from "./next-auth/index.js";
import { addShadcnuiAction } from "./shadcnui/index.js";
Expand All @@ -12,6 +13,7 @@ export const CommandName = {
vscode: "vscode",
nextAuth: "nextAuth",
tinacms: "tinacms",
azureblob: "azureblob",
};

export function addCommand(program: Command) {
Expand All @@ -37,6 +39,9 @@ export function addCommand(program: Command) {
case CommandName.tinacms:
await addTinaCMSAction();
break;
case CommandName.azureblob:
await addAzureBlobAction();
break;
default:
consola.error(`Unknown package: ${input}`);
break;
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/commands/add/next-auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ export const addNextAuthAction = async () => {
}
return;
}

// TODO: Default the auth between plaintext and Discord
};
1 change: 1 addition & 0 deletions packages/cli/src/commands/add/t3-env/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// TODO: https://env.t3.gg/docs/core
1 change: 1 addition & 0 deletions packages/cli/src/commands/add/ts-reset/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// TODO: https://www.totaltypescript.com/ts-reset
Loading

0 comments on commit b34f478

Please sign in to comment.