0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-01-06 22:10:10 -05:00

feat: storage package

This commit is contained in:
Princesseuh 2024-05-16 18:18:23 +02:00
parent 00420a7a52
commit ef1230ae6d
No known key found for this signature in database
GPG key ID: 105BBD6D57F2B0C0
9 changed files with 315 additions and 0 deletions

View file

@ -0,0 +1,34 @@
# @astrojs/studio
This package manages the connection between a local Astro project and [Astro Studio](studio). At this time, this package is not intended for direct use by end users, but rather as a dependency of other Astro packages.
## Support
- Get help in the [Astro Discord][discord]. Post questions in our `#support` forum, or visit our dedicated `#dev` channel to discuss current development and more!
- Check our [Astro Integration Documentation][astro-integration] for more on integrations.
- Submit bug reports and feature requests as [GitHub issues][issues].
## Contributing
This package is maintained by Astro's Core team. You're welcome to submit an issue or PR! These links will help you get started:
- [Contributor Manual][contributing]
- [Code of Conduct][coc]
- [Community Guide][community]
## License
MIT
Copyright (c) 2023present [Astro][astro]
[astro]: https://astro.build/
[contributing]: https://github.com/withastro/astro/blob/main/CONTRIBUTING.md
[coc]: https://github.com/withastro/.github/blob/main/CODE_OF_CONDUCT.md
[community]: https://github.com/withastro/.github/blob/main/COMMUNITY_GUIDE.md
[discord]: https://astro.build/chat/
[issues]: https://github.com/withastro/astro/issues
[astro-integration]: https://docs.astro.build/en/guides/integrations-guide/
[studio]: https://studio.astro.build/

View file

@ -0,0 +1,48 @@
{
"name": "@astrojs/storage",
"version": "0.1.0",
"description": "Add libSQL and Astro Studio support to your Astro site",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/withastro/astro.git",
"directory": "packages/storage"
},
"bugs": "https://github.com/withastro/astro/issues",
"homepage": "https://docs.astro.build/en/guides/integrations-guide/studio/",
"type": "module",
"author": "withastro",
"types": "./dist/index.js",
"main": "./dist/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./package.json": "./package.json"
},
"files": [
"dist"
],
"keywords": [
"withastro",
"astro-integration"
],
"scripts": {
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
"build:ci": "astro-scripts build \"src/**/*.ts\"",
"dev": "astro-scripts dev \"src/**/*.ts\""
},
"dependencies": {
"ci-info": "^4.0.0",
"kleur": "^4.1.5",
"ora": "^8.0.1",
"@astrojs/studio": "^0.1.0"
},
"devDependencies": {
"astro": "workspace:*",
"astro-scripts": "workspace:*",
"typescript": "^5.4.5",
"vite": "^5.2.11"
}
}

View file

@ -0,0 +1,75 @@
import type { AstroConfig } from 'astro';
import { existsSync } from 'node:fs';
import { mkdir, writeFile } from 'node:fs/promises';
import { getAstroStudioStorageUrl } from './utils.js';
import { STORAGE_CODE_FILE, STORAGE_TYPES_FILE } from './consts.js';
import { getProjectIdFromFile, getSessionIdFromFile, safeFetch } from '@astrojs/studio';
export async function codegen(astroConfig: Pick<AstroConfig, 'root'>) {
await codegenInternal({ root: astroConfig.root });
}
async function codegenInternal({ root }: { root: URL }) {
const dotAstroDir = new URL('.astro/', root);
const images = await storageRequest('image');
const all = await storageRequest('all');
const code = `
// This file is auto-generated by Astro Studio. Do not modify this file directly.
export const images = ${JSON.stringify(images)};
export const all = ${JSON.stringify(all)};
export type Image = keyof typeof images | string & {};
export type File = keyof typeof all | string & {};
`;
const types = `
// This file is auto-generated by Astro Studio. Do not modify this file directly.
declare module 'astro:storage' {
export function getFile(name: import("./${STORAGE_CODE_FILE}").File);
export function getStudioImage(name: import("./${STORAGE_CODE_FILE}").Image);
}
`
if (!existsSync(dotAstroDir)) {
await mkdir(dotAstroDir);
}
await writeFile(new URL(STORAGE_CODE_FILE, dotAstroDir), code);
await writeFile(new URL(STORAGE_TYPES_FILE, dotAstroDir), types);
}
async function storageRequest(fileKind: 'all' | 'image' = 'all') {
const projectId = await getProjectIdFromFile();
const linkUrl = getAstroStudioStorageUrl();
const sessionToken = await getSessionIdFromFile();
const response = await safeFetch(
linkUrl,
{
method: 'POST',
headers: {
Authorization: `Bearer ${sessionToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ projectId, fileKind }),
},
(res) => {
// Unauthorized
if (res.status === 401) {
}
}
);
return groupDataByName((await response.json()).data);
}
function groupDataByName(data: any) {
const grouped: Record<string, any> = {};
for (const item of data) {
grouped[item.name] = item;
}
return grouped;
}

View file

@ -0,0 +1,2 @@
export const STORAGE_CODE_FILE = 'storage.ts';
export const STORAGE_TYPES_FILE = 'storage-types.d.ts';

View file

@ -0,0 +1 @@
export { storageIntegration as default } from './integration.js'

View file

@ -0,0 +1,115 @@
import type { AstroConfig, AstroIntegration, AstroIntegrationLogger } from "astro";
import { STORAGE_CODE_FILE, STORAGE_TYPES_FILE } from "./consts.js";
import { codegen } from "./codegen.js";
import { readFile, writeFile } from "node:fs/promises";
import { bold } from "kleur/colors";
import path from "node:path";
import { fileURLToPath } from "url";
import { normalizePath } from "vite";
import { existsSync } from "node:fs";
const VIRTUAL_MODULE_ID = 'astro:storage';
const RESOLVED_MODULE_ID = '\0' + 'astro:storage';
type VitePlugin = Required<AstroConfig['vite']>['plugins'][number];
function vitePluginStorage({ root }: { root: URL }): VitePlugin {
const dotAstroDir = new URL('.astro/', root);
return {
name: 'astro:storage',
async resolveId(id) {
if (id !== VIRTUAL_MODULE_ID) return;
return RESOLVED_MODULE_ID;
},
async load(id) {
if (id !== RESOLVED_MODULE_ID) return;
return `
import { images, all } from '${new URL(STORAGE_CODE_FILE, dotAstroDir)}';
export function getFile(name) {
return all[name];
}
export function getStudioImage(name) {
return images[name].id;
}
`
}
}
}
export function storageIntegration(): AstroIntegration {
return {
name: "astro:studio",
hooks: {
'astro:config:setup': async ({ config, updateConfig, logger }) => {
updateConfig({
vite: {
plugins: [vitePluginStorage({ root: config.root }), vitePluginInjectEnvTs({ srcDir: config.srcDir, root: config.root }, logger)]
}
})
},
'astro:config:done': async ({ config }) => {
await codegen({ root: config.root });
}
}
}
}
export function vitePluginInjectEnvTs(
{ srcDir, root }: { srcDir: URL; root: URL },
logger: AstroIntegrationLogger
): VitePlugin {
return {
name: 'storage-inject-env-ts',
enforce: 'post',
async config() {
await setUpEnvTs({ srcDir, root, logger });
},
};
}
export async function setUpEnvTs({
srcDir,
root,
logger,
}: {
srcDir: URL;
root: URL;
logger: AstroIntegrationLogger;
}) {
const envTsPath = getEnvTsPath({ srcDir });
const envTsPathRelativetoRoot = normalizePath(
path.relative(fileURLToPath(root), fileURLToPath(envTsPath))
);
if (existsSync(envTsPath)) {
let typesEnvContents = await readFile(envTsPath, 'utf-8');
const dotAstroDir = new URL('.astro/', root);
if (!existsSync(dotAstroDir)) return;
const dbTypeReference = getStorageTypeReference({ srcDir, dotAstroDir });
if (!typesEnvContents.includes(dbTypeReference)) {
typesEnvContents = `${dbTypeReference}\n${typesEnvContents}`;
await writeFile(envTsPath, typesEnvContents, 'utf-8');
logger.info(`Added ${bold(envTsPathRelativetoRoot)} types`);
}
}
}
function getStorageTypeReference({ srcDir, dotAstroDir }: { srcDir: URL; dotAstroDir: URL }) {
const storageTypesFile = new URL(STORAGE_TYPES_FILE, dotAstroDir);
const storageTypesRelativeToSrcDir = normalizePath(
path.relative(fileURLToPath(srcDir), fileURLToPath(storageTypesFile))
);
return `/// <reference path=${JSON.stringify(storageTypesRelativeToSrcDir)} />`;
}
function getEnvTsPath({ srcDir }: { srcDir: URL }) {
return new URL('env.d.ts', srcDir);
}

View file

@ -0,0 +1,5 @@
import { getAstroStudioUrl } from "@astrojs/studio";
export function getAstroStudioStorageUrl(): string {
return getAstroStudioUrl() + '/api/cli/files.list';
}

View file

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"include": ["src"],
"compilerOptions": {
"outDir": "./dist"
}
}

View file

@ -5536,6 +5536,34 @@ importers:
specifier: ^2.0.0
version: 2.0.0
packages/storage:
dependencies:
'@astrojs/studio':
specifier: ^0.1.0
version: link:../studio
ci-info:
specifier: ^4.0.0
version: 4.0.0
kleur:
specifier: ^4.1.5
version: 4.1.5
ora:
specifier: ^8.0.1
version: 8.0.1
devDependencies:
astro:
specifier: workspace:*
version: link:../astro
astro-scripts:
specifier: workspace:*
version: link:../../scripts
typescript:
specifier: ^5.4.5
version: 5.4.5
vite:
specifier: ^5.2.11
version: 5.2.11(@types/node@18.19.31)(sass@1.77.1)
packages/studio:
dependencies:
ci-info: