import { HttpMethod, RootAPIHelper } from '../root-api'; import { NetworkPath, NetworkPathWithUrl } from '../../domain/collection-modules/collection-module-definition'; import { S3Operation } from './code-file-helpers'; import { fetchCollectionModuleCodeId } from './fetch-collection-module-code-id'; /** * Get a signed URL for uploading the Lambda package to S3 * The backend automatically constructs the S3 key from code_id + path_segments * Resulting S3 key will be: collection-module-code/{codeId}/lambda-package.zip */ export const getLambdaPackageSignedUrl = async (params: { collectionModuleKey: string; host: string; apiKey: string; }): Promise<{ signedUrl: string; codeId: string }> => { const { collectionModuleKey, host, apiKey } = params; const rootApiHelper = new RootAPIHelper({ apiKey, host, throwResponseErrors: true }); // Fetch the code_id first const codeId = await fetchCollectionModuleCodeId({ collectionModuleKey, host, apiKey, }); // Request signed URL for Lambda package upload // Backend will automatically construct: collection-module-code/{codeId}/lambda-package.zip const body: { paths: NetworkPath[]; operation: S3Operation; } = { paths: [{ path_segments: ['lambda-package.zip'] }], operation: S3Operation.PutObject, }; const response: NetworkPathWithUrl[] = await rootApiHelper.send({ path: `/cli/collection-modules/${collectionModuleKey}/code-files-signed-urls`, method: HttpMethod.Post, body, searchParams: { live_version: 'false' }, // Always use draft version }); if (!response || response.length === 0 || !response[0].signed_url) { throw new Error('Failed to get signed URL for Lambda package upload'); } return { signedUrl: response[0].signed_url, codeId, }; }; /** * Upload Lambda package to S3 using a signed URL */ export const uploadLambdaPackageToS3 = async (params: { signedUrl: string; lambdaPackage: Buffer }): Promise => { const { signedUrl, lambdaPackage } = params; const response = await fetch(signedUrl, { method: 'PUT', body: lambdaPackage, headers: { 'Content-Type': 'application/zip', }, }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to upload Lambda package to S3: ${response.statusText}. ${errorText}`); } }; /** * Get a signed URL for uploading the source package (source.zip) to S3 * The backend automatically constructs the S3 key from code_id + path_segments * Resulting S3 key will be: collection-module-code/{codeId}/source.zip */ export const getSourcePackageSignedUrl = async (params: { collectionModuleKey: string; host: string; apiKey: string; }): Promise => { const { collectionModuleKey, host, apiKey } = params; const rootApiHelper = new RootAPIHelper({ apiKey, host, throwResponseErrors: true }); const body: { paths: NetworkPath[]; operation: S3Operation; } = { paths: [{ path_segments: ['source.zip'] }], operation: S3Operation.PutObject, }; const response: NetworkPathWithUrl[] = await rootApiHelper.send({ path: `/cli/collection-modules/${collectionModuleKey}/code-files-signed-urls`, method: HttpMethod.Post, body, searchParams: { live_version: 'false' }, }); if (!response || response.length === 0 || !response[0].signed_url) { throw new Error('Failed to get signed URL for source package upload'); } return response[0].signed_url; }; /** * Upload source package to S3 using a signed URL */ export const uploadSourcePackageToS3 = async (params: { signedUrl: string; sourcePackage: Buffer }): Promise => { const { signedUrl, sourcePackage } = params; const response = await fetch(signedUrl, { method: 'PUT', body: sourcePackage, headers: { 'Content-Type': 'application/zip', }, }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to upload source package to S3: ${response.statusText}. ${errorText}`); } };