mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-29 12:50:59 +00:00
fix: extensions (#2926)
This commit is contained in:
+25
-22
@@ -99,35 +99,38 @@ async function decodeAndValidateThumbnail(
|
||||
// Intercept data-URL thumbnails before they hit the DB: upload to S3
|
||||
// and replace the URL with an s3:// pointer.
|
||||
|
||||
extension.on('thumbnail.created', async (event: Record<string, unknown>) => {
|
||||
const url = event.url;
|
||||
if (typeof url !== 'string' || !url.startsWith('data:')) return;
|
||||
extension.on(
|
||||
'thumbnail.created',
|
||||
async (_key, event: Record<string, unknown>) => {
|
||||
const url = event.url;
|
||||
if (typeof url !== 'string' || !url.startsWith('data:')) return;
|
||||
|
||||
const decoded = await decodeAndValidateThumbnail(url);
|
||||
if (!decoded) {
|
||||
event.url = null;
|
||||
return;
|
||||
}
|
||||
const decoded = await decodeAndValidateThumbnail(url);
|
||||
if (!decoded) {
|
||||
event.url = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const key = crypto.randomUUID();
|
||||
event.url = `s3://${thumbnailBucketName}/${key}`;
|
||||
const key = crypto.randomUUID();
|
||||
event.url = `s3://${thumbnailBucketName}/${key}`;
|
||||
|
||||
await getClient().send(
|
||||
new PutObjectCommand({
|
||||
Bucket: thumbnailBucketName,
|
||||
Key: key,
|
||||
Body: decoded.data,
|
||||
ContentType: decoded.mimeType,
|
||||
}),
|
||||
);
|
||||
});
|
||||
await getClient().send(
|
||||
new PutObjectCommand({
|
||||
Bucket: thumbnailBucketName,
|
||||
Key: key,
|
||||
Body: decoded.data,
|
||||
ContentType: decoded.mimeType,
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// ── thumbnail.upload.prepare ────────────────────────────────────────
|
||||
// Generate pre-signed upload URLs so the client can PUT directly to S3.
|
||||
|
||||
extension.on(
|
||||
'thumbnail.upload.prepare',
|
||||
async (event: Record<string, unknown>) => {
|
||||
async (_key, event: Record<string, unknown>) => {
|
||||
if (!event || !Array.isArray(event.items)) return;
|
||||
const presignClient = getPresignClient();
|
||||
|
||||
@@ -169,7 +172,7 @@ extension.on(
|
||||
// ── thumbnail.read ──────────────────────────────────────────────────
|
||||
// Convert s3:// or legacy https:// thumbnails to signed URLs.
|
||||
|
||||
extension.on('thumbnail.read', async (entry: Record<string, unknown>) => {
|
||||
extension.on('thumbnail.read', async (_key, entry: Record<string, unknown>) => {
|
||||
const thumb = entry.thumbnail;
|
||||
if (typeof thumb !== 'string' || !thumb) return;
|
||||
const presignClient = getPresignClient();
|
||||
@@ -233,7 +236,7 @@ extension.on('thumbnail.read', async (entry: Record<string, unknown>) => {
|
||||
|
||||
extension.on(
|
||||
'fs.remove.node',
|
||||
async ({ target }: { target: Record<string, unknown> }) => {
|
||||
async (_key, { target }: { target: Record<string, unknown> }) => {
|
||||
const thumbnailUrl = target.thumbnail as string | undefined;
|
||||
if (!thumbnailUrl || !thumbnailUrl.startsWith('s3://')) return;
|
||||
|
||||
|
||||
@@ -56,8 +56,10 @@ export const extensionStore = {
|
||||
controllers: {} as IPuterControllerRegistry,
|
||||
drivers: {} as IPuterDriverRegistry,
|
||||
globalMiddlewares: [] as RequestHandler[],
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
events: {} as Record<string, ((...args: any[]) => void)[]>,
|
||||
events: {} as Record<
|
||||
string,
|
||||
((key: string, data: unknown, meta: unknown) => void)[]
|
||||
>,
|
||||
/**
|
||||
* Extension-declared routes. Shape matches the controller-layer
|
||||
* `RouteDescriptor`, so both flow through the same materializer
|
||||
@@ -192,8 +194,11 @@ export const extension = {
|
||||
|
||||
// ── Event subscription ───────────────────────────────────────────
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
on: (event: string, handler: (...args: any[]) => void) => {
|
||||
on: (
|
||||
event: string,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
handler: (key: string, data: any, meta: any) => void,
|
||||
) => {
|
||||
if (!extensionStore.events[event]) {
|
||||
extensionStore.events[event] = [];
|
||||
}
|
||||
@@ -281,6 +286,7 @@ export const extension = {
|
||||
const proxyProxyHandler = {
|
||||
get: (_target2: object, prop2: string) => {
|
||||
const proxiedObj2 =
|
||||
// @ts-expect-error any type needed
|
||||
clientsContainers[prop][prop2];
|
||||
if (!proxiedObj2) {
|
||||
throw new Error(
|
||||
@@ -307,6 +313,7 @@ export const extension = {
|
||||
const proxyProxyHandler = {
|
||||
get: (_target2: object, prop2: string) => {
|
||||
const proxiedObj2 =
|
||||
// @ts-expect-error any type needed
|
||||
clientsContainers[prop][prop2];
|
||||
if (!proxiedObj2) {
|
||||
throw new Error(
|
||||
@@ -333,6 +340,7 @@ export const extension = {
|
||||
const proxyProxyHandler = {
|
||||
get: (_target2: object, prop2: string) => {
|
||||
const proxiedObj2 =
|
||||
// @ts-expect-error any type needed
|
||||
clientsContainers[prop][prop2];
|
||||
if (!proxiedObj2) {
|
||||
throw new Error(
|
||||
@@ -359,6 +367,7 @@ export const extension = {
|
||||
const proxyProxyHandler = {
|
||||
get: (_target2: object, prop2: string) => {
|
||||
const proxiedObj2 =
|
||||
// @ts-expect-error any type needed
|
||||
clientsContainers[prop][prop2];
|
||||
if (!proxiedObj2) {
|
||||
throw new Error(
|
||||
@@ -385,6 +394,7 @@ export const extension = {
|
||||
const proxyProxyHandler = {
|
||||
get: (_target2: object, prop2: string) => {
|
||||
const proxiedObj2 =
|
||||
// @ts-expect-error any type needed
|
||||
clientsContainers[prop][prop2];
|
||||
if (!proxiedObj2) {
|
||||
throw new Error(
|
||||
|
||||
Reference in New Issue
Block a user