Files
the_order/packages/storage/src/storage.js
defiQUG 92cc41d26d Add Legal Office seal and complete Azure CDN deployment
- Add Legal Office of the Master seal (SVG design with Maltese Cross, scales of justice, legal scroll)
- Create legal-office-manifest-template.json for Legal Office credentials
- Update SEAL_MAPPING.md and DESIGN_GUIDE.md with Legal Office seal documentation
- Complete Azure CDN infrastructure deployment:
  - Resource group, storage account, and container created
  - 17 PNG seal files uploaded to Azure Blob Storage
  - All manifest templates updated with Azure URLs
  - Configuration files generated (azure-cdn-config.env)
- Add comprehensive Azure CDN setup scripts and documentation
- Fix manifest URL generation to prevent double slashes
- Verify all seals accessible via HTTPS
2025-11-12 22:03:42 -08:00

83 lines
2.6 KiB
JavaScript

/**
* Storage abstraction for S3/GCS
*/
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, HeadObjectCommand, } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
export class StorageClient {
config;
s3Client;
bucket;
constructor(config) {
this.config = config;
this.bucket = config.bucket;
this.s3Client = new S3Client({
region: config.region || 'us-east-1',
credentials: config.accessKeyId && config.secretAccessKey
? {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
}
: undefined,
});
}
async upload(object) {
const command = new PutObjectCommand({
Bucket: this.bucket,
Key: object.key,
Body: typeof object.content === 'string' ? Buffer.from(object.content) : object.content,
ContentType: object.contentType,
Metadata: object.metadata,
});
await this.s3Client.send(command);
return object.key;
}
async download(key) {
const command = new GetObjectCommand({
Bucket: this.bucket,
Key: key,
});
const response = await this.s3Client.send(command);
if (!response.Body) {
throw new Error(`Object ${key} not found or empty`);
}
const chunks = [];
if (response.Body) {
const body = response.Body;
for await (const chunk of body) {
chunks.push(chunk);
}
}
return Buffer.concat(chunks);
}
async delete(key) {
const command = new DeleteObjectCommand({
Bucket: this.bucket,
Key: key,
});
await this.s3Client.send(command);
}
async getPresignedUrl(key, expiresIn) {
const command = new GetObjectCommand({
Bucket: this.bucket,
Key: key,
});
return getSignedUrl(this.s3Client, command, { expiresIn });
}
async objectExists(key) {
try {
const command = new HeadObjectCommand({
Bucket: this.bucket,
Key: key,
});
await this.s3Client.send(command);
return true;
}
catch (error) {
if (error && typeof error === 'object' && 'name' in error && error.name === 'NotFound') {
return false;
}
throw error;
}
}
}
//# sourceMappingURL=storage.js.map