Spaces:
Running
Running
| /** | |
| * AWS Configuration for Cognito-based S3 access | |
| * | |
| * This module handles AWS credentials through Cognito Identity Provider. | |
| * No AWS credentials are stored in code or exposed to the client. | |
| * | |
| * Environment Variables Required: | |
| * - VITE_AWS_REGION: AWS region (e.g., "us-east-2") | |
| * - VITE_AWS_COGNITO_IDENTITY_POOL_ID: Cognito Identity Pool ID (e.g., "us-east-2:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") | |
| * - VITE_S3_BUCKET: Default S3 bucket name (e.g., "ddy-first-bucket") | |
| */ | |
| import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"; | |
| import { fromCognitoIdentityPool } from "@aws-sdk/credential-provider-cognito-identity"; | |
| import { CognitoIdentityClient } from "@aws-sdk/client-cognito-identity"; | |
| export const AWS_REGION = import.meta.env.VITE_AWS_REGION || "us-east-2"; | |
| // Cognito pool ID is safe to embed in client code (not a secret) | |
| export const COGNITO_IDENTITY_POOL_ID = import.meta.env.VITE_AWS_COGNITO_IDENTITY_POOL_ID || "us-east-2:1387102d-5a87-4742-8a69-1baa70f37984"; | |
| export const DEFAULT_BUCKET = import.meta.env.VITE_S3_BUCKET || "ddy-first-bucket"; | |
| /** | |
| * Initialize S3 client with Cognito credentials | |
| * Uses unauthenticated Cognito Identity pool for public S3 access | |
| */ | |
| export function getS3Client() { | |
| const credentialsProvider = fromCognitoIdentityPool({ | |
| client: new CognitoIdentityClient({ region: AWS_REGION }), | |
| identityPoolId: COGNITO_IDENTITY_POOL_ID, | |
| }); | |
| return new S3Client({ | |
| region: AWS_REGION, | |
| credentials: credentialsProvider, | |
| }); | |
| } | |
| /** | |
| * Get S3 object as text (for JSON tilesets, metadata, etc.) | |
| */ | |
| export async function getS3ObjectAsText(bucket, key) { | |
| const s3Client = getS3Client(); | |
| if (!s3Client) { | |
| throw new Error("S3 client not initialized"); | |
| } | |
| try { | |
| const command = new GetObjectCommand({ | |
| Bucket: bucket, | |
| Key: key, | |
| }); | |
| const response = await s3Client.send(command); | |
| const text = await response.Body.transformToString(); | |
| return text; | |
| } catch (error) { | |
| console.error(`Failed to fetch S3 object s3://${bucket}/${key}:`, error); | |
| throw error; | |
| } | |
| } | |
| /** | |
| * Get S3 object as JSON | |
| */ | |
| export async function getS3ObjectAsJson(bucket, key) { | |
| const text = await getS3ObjectAsText(bucket, key); | |
| return JSON.parse(text); | |
| } | |
| /** | |
| * Build a direct S3 URL for tile assets | |
| * Note: This URL requires proper CORS configuration on S3 bucket | |
| * or the bucket must be public with proper authentication | |
| */ | |
| export function buildS3Url(bucket, key) { | |
| return `https://${bucket}.s3.${AWS_REGION}.amazonaws.com/${key}`; | |
| } | |
| /** | |
| * Rewrite URLs in a tileset JSON to use proper S3 paths | |
| * Handles both relative and absolute URLs | |
| */ | |
| export function rewriteTilesetUrls(tilesetJson, bucket, basePath) { | |
| const rewrite = (obj) => { | |
| if (!obj || typeof obj !== "object") return; | |
| if (Array.isArray(obj)) { | |
| obj.forEach(rewrite); | |
| return; | |
| } | |
| Object.keys(obj).forEach((key) => { | |
| const value = obj[key]; | |
| // Rewrite uri/url fields to point to S3 | |
| if ((key === "uri" || key === "url") && typeof value === "string") { | |
| // Skip external URLs | |
| if (value.startsWith("http://") || value.startsWith("https://")) { | |
| return; | |
| } | |
| // Skip data URLs | |
| if (value.startsWith("data:")) { | |
| return; | |
| } | |
| // Build S3 URL for relative paths | |
| const relativePath = value.startsWith("/") ? value.slice(1) : value; | |
| const s3Key = basePath | |
| ? `${basePath}/${relativePath}`.replace(/\/+/g, "/") | |
| : relativePath; | |
| obj[key] = buildS3Url(bucket, s3Key); | |
| } | |
| // Recursively rewrite nested objects | |
| if (typeof value === "object") { | |
| rewrite(value); | |
| } | |
| }); | |
| }; | |
| rewrite(tilesetJson); | |
| return tilesetJson; | |
| } | |
| /** | |
| * Load a tileset JSON file from S3 and rewrite its URLs | |
| */ | |
| export async function loadTilesetFromS3(bucket, tilesetPath, basePath) { | |
| try { | |
| const tilesetJson = await getS3ObjectAsJson(bucket, tilesetPath); | |
| return rewriteTilesetUrls(tilesetJson, bucket, basePath); | |
| } catch (error) { | |
| console.error(`Failed to load tileset from S3:`, error); | |
| throw error; | |
| } | |
| } | |
| /** | |
| * Get default S3 bucket name | |
| */ | |
| export function getDefaultBucket() { | |
| return DEFAULT_BUCKET; | |
| } | |
| /** | |
| * Get AWS region | |
| */ | |
| export function getAwsRegion() { | |
| return AWS_REGION; | |
| } | |
| /** | |
| * Validate AWS configuration | |
| */ | |
| export function validateAwsConfig() { | |
| return !!(AWS_REGION && COGNITO_IDENTITY_POOL_ID && DEFAULT_BUCKET); | |
| } | |