@gannochenko/staticstripes 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/cli/ai-music-api-ai/ai-music-api-ai-generation-strategy.d.ts +3 -4
  2. package/dist/cli/ai-music-api-ai/ai-music-api-ai-generation-strategy.d.ts.map +1 -1
  3. package/dist/cli/ai-music-api-ai/ai-music-api-ai-generation-strategy.js +22 -32
  4. package/dist/cli/ai-music-api-ai/ai-music-api-ai-generation-strategy.js.map +1 -1
  5. package/dist/cli/credentials.d.ts +81 -0
  6. package/dist/cli/credentials.d.ts.map +1 -0
  7. package/dist/cli/credentials.js +109 -0
  8. package/dist/cli/credentials.js.map +1 -0
  9. package/dist/cli/instagram/instagram-upload-strategy.d.ts +3 -1
  10. package/dist/cli/instagram/instagram-upload-strategy.d.ts.map +1 -1
  11. package/dist/cli/instagram/instagram-upload-strategy.js +37 -26
  12. package/dist/cli/instagram/instagram-upload-strategy.js.map +1 -1
  13. package/dist/cli/s3/s3-upload-strategy.d.ts +3 -1
  14. package/dist/cli/s3/s3-upload-strategy.d.ts.map +1 -1
  15. package/dist/cli/s3/s3-upload-strategy.js +91 -44
  16. package/dist/cli/s3/s3-upload-strategy.js.map +1 -1
  17. package/dist/cli/youtube/youtube-upload-strategy.d.ts +3 -0
  18. package/dist/cli/youtube/youtube-upload-strategy.d.ts.map +1 -1
  19. package/dist/cli/youtube/youtube-upload-strategy.js +22 -20
  20. package/dist/cli/youtube/youtube-upload-strategy.js.map +1 -1
  21. package/dist/html-project-parser.d.ts +8 -0
  22. package/dist/html-project-parser.d.ts.map +1 -1
  23. package/dist/html-project-parser.js +71 -5
  24. package/dist/html-project-parser.js.map +1 -1
  25. package/dist/project.d.ts +3 -1
  26. package/dist/project.d.ts.map +1 -1
  27. package/dist/project.js +6 -1
  28. package/dist/project.js.map +1 -1
  29. package/dist/type.d.ts +1 -1
  30. package/dist/type.d.ts.map +1 -1
  31. package/package.json +1 -1
  32. package/src/cli/ai-music-api-ai/ai-music-api-ai-generation-strategy.ts +24 -55
  33. package/src/cli/credentials.ts +171 -0
  34. package/src/cli/instagram/instagram-upload-strategy.ts +38 -39
  35. package/src/cli/s3/s3-upload-strategy.ts +102 -57
  36. package/src/cli/youtube/youtube-upload-strategy.ts +22 -23
  37. package/src/html-project-parser.ts +84 -4
  38. package/src/project.ts +5 -0
  39. package/src/type.ts +1 -1
@@ -3,13 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.S3UploadStrategy = void 0;
4
4
  const client_s3_1 = require("@aws-sdk/client-s3");
5
5
  const fs_1 = require("fs");
6
- const path_1 = require("path");
6
+ const credentials_1 = require("../credentials");
7
7
  /**
8
8
  * S3 upload strategy implementation
9
9
  * Supports generic S3-compatible storage (AWS S3, DigitalOcean Spaces, etc.)
10
10
  */
11
11
  class S3UploadStrategy {
12
- constructor() { }
12
+ credentialsManager;
13
+ constructor(credentialsManager) {
14
+ this.credentialsManager = credentialsManager;
15
+ }
13
16
  getTag() {
14
17
  return 's3';
15
18
  }
@@ -21,7 +24,11 @@ class S3UploadStrategy {
21
24
  if (!upload.s3) {
22
25
  throw new Error(`❌ Error: S3 configuration missing for upload "${upload.name}"`);
23
26
  }
24
- const { endpoint, region, bucket, path, acl } = upload.s3;
27
+ const { endpoint, region, bucket, paths, acl } = upload.s3;
28
+ // Validate that we have a "file" path
29
+ if (!paths.has('file')) {
30
+ throw new Error(`❌ Error: S3 upload "${upload.name}" missing required <path name="file"> element`);
31
+ }
25
32
  // Validate ACL value if specified
26
33
  const allowedAcls = ['private', 'public-read', 'authenticated-read'];
27
34
  if (acl && !allowedAcls.includes(acl)) {
@@ -29,13 +36,21 @@ class S3UploadStrategy {
29
36
  `Allowed values: ${allowedAcls.join(', ')}\n` +
30
37
  `Note: "public-read-write" is not supported for security reasons.`);
31
38
  }
32
- // Load credentials from .auth/<upload-name>.json
33
- const authDir = (0, path_1.resolve)(projectPath, '.auth');
34
- const credentialsPath = (0, path_1.resolve)(authDir, `${upload.name}.json`);
35
- if (!(0, fs_1.existsSync)(credentialsPath)) {
36
- throw new Error(`❌ Error: S3 credentials not found\n\n` +
37
- `Expected location: ${credentialsPath}\n\n` +
38
- `💡 Create a JSON file with your S3 credentials:\n` +
39
+ // Load credentials from local .auth/<upload-name>.json or global ~/.staticstripes/auth/<upload-name>.json
40
+ const manager = this.credentialsManager ||
41
+ new credentials_1.CredentialsManager(projectPath, upload.name);
42
+ let credentials;
43
+ try {
44
+ credentials = manager.load([
45
+ 'accessKeyId',
46
+ 'secretAccessKey',
47
+ ]);
48
+ }
49
+ catch (error) {
50
+ // Add helpful context about S3 credentials format
51
+ const errorMessage = error instanceof Error ? error.message : String(error);
52
+ throw new Error(`${errorMessage}\n\n` +
53
+ `💡 S3 credentials file should contain:\n` +
39
54
  `{\n` +
40
55
  ` "accessKeyId": "YOUR_ACCESS_KEY",\n` +
41
56
  ` "secretAccessKey": "YOUR_SECRET_KEY"\n` +
@@ -44,20 +59,6 @@ class S3UploadStrategy {
44
59
  ` • AWS: IAM → Users → Security Credentials\n` +
45
60
  ` • DigitalOcean: API → Spaces Keys\n`);
46
61
  }
47
- console.log(`🔐 Loading credentials from: ${credentialsPath}`);
48
- let credentials;
49
- try {
50
- const credentialsJson = (0, fs_1.readFileSync)(credentialsPath, 'utf-8');
51
- credentials = JSON.parse(credentialsJson);
52
- if (!credentials.accessKeyId || !credentials.secretAccessKey) {
53
- throw new Error('Missing accessKeyId or secretAccessKey');
54
- }
55
- }
56
- catch (error) {
57
- throw new Error(`❌ Error: Failed to parse S3 credentials from ${credentialsPath}\n` +
58
- `Ensure the file contains valid JSON with accessKeyId and secretAccessKey.\n` +
59
- `Error: ${error instanceof Error ? error.message : String(error)}`);
60
- }
61
62
  // Get the output file
62
63
  const output = project.getOutput(upload.outputName);
63
64
  if (!output) {
@@ -67,20 +68,34 @@ class S3UploadStrategy {
67
68
  throw new Error(`❌ Error: Output file not found: ${output.path}\n` +
68
69
  '💡 Please generate the video first');
69
70
  }
70
- // Interpolate path variables
71
+ // Prepare interpolation variables
71
72
  const slug = this.slugify(project.getTitle());
72
73
  const outputName = output.name;
73
- const interpolatedPath = path
74
- .replace(/\$\{slug\}/g, slug)
75
- .replace(/\$\{output\}/g, outputName);
74
+ const date = project.getDate() || '';
75
+ const title = project.getTitle();
76
+ const tags = upload.tags;
77
+ // Helper function to interpolate path variables
78
+ const interpolatePath = (pathTemplate) => {
79
+ return pathTemplate
80
+ .replace(/\$\{slug\}/g, slug)
81
+ .replace(/\$\{output\}/g, outputName)
82
+ .replace(/\$\{date\}/g, date);
83
+ };
84
+ // Get and interpolate the file path
85
+ const filePath = interpolatePath(paths.get('file'));
76
86
  console.log(`\n📦 Preparing S3 upload...`);
77
87
  console.log(` Bucket: ${bucket}`);
78
88
  console.log(` Region: ${region}`);
79
89
  if (endpoint) {
80
90
  console.log(` Endpoint: ${endpoint}`);
81
91
  }
82
- console.log(` Path: ${interpolatedPath}`);
83
- console.log(` File: ${output.path}\n`);
92
+ console.log(` File path: ${filePath}`);
93
+ console.log(` Video file: ${output.path}`);
94
+ if (paths.has('metadata')) {
95
+ const metadataPath = interpolatePath(paths.get('metadata'));
96
+ console.log(` Metadata path: ${metadataPath}`);
97
+ }
98
+ console.log('');
84
99
  // Configure S3 client
85
100
  const s3Config = {
86
101
  region,
@@ -98,36 +113,68 @@ class S3UploadStrategy {
98
113
  s3Config.forcePathStyle = false;
99
114
  }
100
115
  const s3Client = new client_s3_1.S3Client(s3Config);
101
- // Read file
102
- console.log(`📤 Uploading to S3...`);
116
+ // Upload video file
117
+ console.log(`📤 Uploading video file...`);
103
118
  const fileBuffer = (0, fs_1.readFileSync)(output.path);
104
- // Upload file
105
- const uploadParams = {
119
+ const fileUploadParams = {
106
120
  Bucket: bucket,
107
- Key: interpolatedPath,
121
+ Key: filePath,
108
122
  Body: fileBuffer,
109
123
  ContentType: 'video/mp4',
110
124
  };
111
125
  // Add ACL if specified in configuration
112
126
  if (acl) {
113
- uploadParams.ACL = acl;
127
+ fileUploadParams.ACL = acl;
114
128
  }
115
- const command = new client_s3_1.PutObjectCommand(uploadParams);
116
129
  try {
117
- await s3Client.send(command);
118
- // Construct public URL
119
- let publicUrl;
130
+ await s3Client.send(new client_s3_1.PutObjectCommand(fileUploadParams));
131
+ // Construct public URL for video
132
+ let fileUrl;
120
133
  if (endpoint) {
121
134
  // For DigitalOcean Spaces and similar services
122
135
  // Format: https://{bucket}.{region}.{endpoint}/{path}
123
- publicUrl = `https://${bucket}.${region}.${endpoint}/${interpolatedPath}`;
136
+ fileUrl = `https://${bucket}.${region}.${endpoint}/${filePath}`;
124
137
  }
125
138
  else {
126
139
  // For AWS S3
127
- publicUrl = `https://${bucket}.s3.${region}.amazonaws.com/${interpolatedPath}`;
140
+ fileUrl = `https://${bucket}.s3.${region}.amazonaws.com/${filePath}`;
141
+ }
142
+ console.log(`✅ Video uploaded successfully!`);
143
+ console.log(`🔗 Video URL: ${fileUrl}`);
144
+ // Upload metadata file if specified
145
+ if (paths.has('metadata')) {
146
+ console.log(`\n📤 Uploading metadata file...`);
147
+ const metadataPath = interpolatePath(paths.get('metadata'));
148
+ // Create metadata JSON
149
+ const metadata = {
150
+ title,
151
+ date: date || null,
152
+ tags,
153
+ };
154
+ const metadataBuffer = Buffer.from(JSON.stringify(metadata, null, 2), 'utf-8');
155
+ const metadataUploadParams = {
156
+ Bucket: bucket,
157
+ Key: metadataPath,
158
+ Body: metadataBuffer,
159
+ ContentType: 'application/json',
160
+ };
161
+ // Add ACL if specified
162
+ if (acl) {
163
+ metadataUploadParams.ACL = acl;
164
+ }
165
+ await s3Client.send(new client_s3_1.PutObjectCommand(metadataUploadParams));
166
+ // Construct public URL for metadata
167
+ let metadataUrl;
168
+ if (endpoint) {
169
+ metadataUrl = `https://${bucket}.${region}.${endpoint}/${metadataPath}`;
170
+ }
171
+ else {
172
+ metadataUrl = `https://${bucket}.s3.${region}.amazonaws.com/${metadataPath}`;
173
+ }
174
+ console.log(`✅ Metadata uploaded successfully!`);
175
+ console.log(`🔗 Metadata URL: ${metadataUrl}`);
128
176
  }
129
- console.log(`\n✅ Upload successful!`);
130
- console.log(`🔗 Public URL: ${publicUrl}\n`);
177
+ console.log('');
131
178
  }
132
179
  catch (error) {
133
180
  throw new Error(`❌ Error: Failed to upload to S3\n` +
@@ -1 +1 @@
1
- {"version":3,"file":"s3-upload-strategy.js","sourceRoot":"","sources":["../../../src/cli/s3/s3-upload-strategy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"s3-upload-strategy.js","sourceRoot":"","sources":["../../../src/cli/s3/s3-upload-strategy.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { UploadStrategy } from '../upload-strategy';
2
2
  import { Project } from '../../project';
3
3
  import { YouTubeUpload } from '../../type';
4
+ import { CredentialsManager } from '../credentials';
4
5
  export interface YouTubeUploadOptions {
5
6
  uploadName: string;
6
7
  projectPath: string;
@@ -11,6 +12,8 @@ export interface YouTubeUploadOptions {
11
12
  * YouTube upload strategy implementation
12
13
  */
13
14
  export declare class YouTubeUploadStrategy implements UploadStrategy {
15
+ private credentialsManager?;
16
+ constructor(credentialsManager?: CredentialsManager | undefined);
14
17
  getTag(): string;
15
18
  validate(): void;
16
19
  execute(project: Project, upload: YouTubeUpload, projectPath: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"youtube-upload-strategy.d.ts","sourceRoot":"","sources":["../../../src/cli/youtube/youtube-upload-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAM3C,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,qBAAsB,YAAW,cAAc;IAC1D,MAAM,IAAI,MAAM;IAIhB,QAAQ,IAAI,IAAI;IAIV,OAAO,CACX,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;CAwCjB;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CA8Ff"}
1
+ {"version":3,"file":"youtube-upload-strategy.d.ts","sourceRoot":"","sources":["../../../src/cli/youtube/youtube-upload-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAI3C,OAAO,EAAE,kBAAkB,EAAsB,MAAM,gBAAgB,CAAC;AAExE,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,qBAAsB,YAAW,cAAc;IAC9C,OAAO,CAAC,kBAAkB,CAAC;gBAAnB,kBAAkB,CAAC,EAAE,kBAAkB,YAAA;IAE3D,MAAM,IAAI,MAAM;IAIhB,QAAQ,IAAI,IAAI;IAIV,OAAO,CACX,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;CAiCjB;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAkGf"}
@@ -8,11 +8,15 @@ exports.handleYouTubeUpload = handleYouTubeUpload;
8
8
  const path_1 = require("path");
9
9
  const youtube_uploader_1 = require("../../youtube-uploader");
10
10
  const ejs_1 = __importDefault(require("ejs"));
11
- const fs_1 = require("fs");
11
+ const credentials_1 = require("../credentials");
12
12
  /**
13
13
  * YouTube upload strategy implementation
14
14
  */
15
15
  class YouTubeUploadStrategy {
16
+ credentialsManager;
17
+ constructor(credentialsManager) {
18
+ this.credentialsManager = credentialsManager;
19
+ }
16
20
  getTag() {
17
21
  return 'youtube';
18
22
  }
@@ -20,29 +24,24 @@ class YouTubeUploadStrategy {
20
24
  // Validation now happens in execute() when we read credentials
21
25
  }
22
26
  async execute(project, upload, projectPath) {
23
- // Read credentials from .auth file
24
- const authDir = (0, path_1.resolve)(projectPath, '.auth');
25
- const credentialsPath = (0, path_1.resolve)(authDir, `${upload.name}.json`);
26
- if (!(0, fs_1.existsSync)(credentialsPath)) {
27
- throw new Error(`❌ Error: YouTube credentials not found\n\n` +
28
- `Expected location: ${credentialsPath}\n\n` +
29
- `💡 Run authentication wizard:\n` +
30
- ` staticstripes auth --upload-name ${upload.name}\n\n` +
31
- `📖 Or view setup instructions:\n` +
32
- ` staticstripes auth-help youtube\n`);
33
- }
27
+ // Load credentials from local .auth/<upload-name>.json or global ~/.staticstripes/auth/<upload-name>.json
28
+ const manager = this.credentialsManager ||
29
+ new credentials_1.CredentialsManager(projectPath, upload.name);
34
30
  let credentials;
35
31
  try {
36
- const credentialsJson = (0, fs_1.readFileSync)(credentialsPath, 'utf-8');
37
- credentials = JSON.parse(credentialsJson);
38
- if (!credentials.clientId || !credentials.clientSecret) {
39
- throw new Error('Missing clientId or clientSecret');
40
- }
32
+ credentials = manager.load([
33
+ 'clientId',
34
+ 'clientSecret',
35
+ ]);
41
36
  }
42
37
  catch (error) {
43
- throw new Error(`❌ Error: Failed to parse YouTube credentials from ${credentialsPath}\n` +
44
- `Ensure the file contains clientId and clientSecret.\n` +
45
- `Error: ${error instanceof Error ? error.message : String(error)}`);
38
+ // Add helpful context about YouTube credentials
39
+ const errorMessage = error instanceof Error ? error.message : String(error);
40
+ throw new Error(`${errorMessage}\n\n` +
41
+ `💡 Run authentication wizard:\n` +
42
+ ` staticstripes auth --upload-name ${upload.name}\n\n` +
43
+ `📖 Or view setup instructions:\n` +
44
+ ` staticstripes auth-help youtube\n`);
46
45
  }
47
46
  // Delegate to existing handler
48
47
  await handleYouTubeUpload(project, {
@@ -83,6 +82,8 @@ async function handleYouTubeUpload(project, options) {
83
82
  // Determine title (use upload-specific title or fall back to project title)
84
83
  const title = upload.title || project.getTitle();
85
84
  console.log(`📝 Title: ${title}\n`);
85
+ // Get date from project
86
+ const date = project.getDate();
86
87
  // Build the project to populate fragment times (needed for timecodes)
87
88
  console.log('🔨 Building project to calculate timecodes...');
88
89
  await project.build(upload.outputName);
@@ -94,6 +95,7 @@ async function handleYouTubeUpload(project, options) {
94
95
  const ejsDescription = upload.description.replace(/\$\{(\w+)\}/g, '<%= $1 %>');
95
96
  const processedDescription = ejs_1.default.render(ejsDescription, {
96
97
  title,
98
+ date,
97
99
  tags: formattedTags,
98
100
  timecodes: timecodes.join('\n'),
99
101
  });
@@ -1 +1 @@
1
- {"version":3,"file":"youtube-upload-strategy.js","sourceRoot":"","sources":["../../../src/cli/youtube/youtube-upload-strategy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"youtube-upload-strategy.js","sourceRoot":"","sources":["../../../src/cli/youtube/youtube-upload-strategy.ts"],"names":[],"mappings":"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"}
@@ -134,10 +134,18 @@ export declare class HTMLProjectParser {
134
134
  * Processes the title from the parsed HTML
135
135
  */
136
136
  private processTitle;
137
+ /**
138
+ * Processes the date from the parsed HTML
139
+ */
140
+ private processDate;
137
141
  /**
138
142
  * Finds all title elements in the HTML (top-level only, not inside uploads)
139
143
  */
140
144
  private findTitleElements;
145
+ /**
146
+ * Finds all date elements in the HTML (top-level only)
147
+ */
148
+ private findDateElements;
141
149
  /**
142
150
  * Finds all uploads elements in the HTML
143
151
  */
@@ -1 +1 @@
1
- {"version":3,"file":"html-project-parser.d.ts","sourceRoot":"","sources":["../src/html-project-parser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"html-project-parser.d.ts","sourceRoot":"","sources":["../src/html-project-parser.ts"],"names":[],"mappings":"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"}
@@ -67,11 +67,12 @@ class HTMLProjectParser {
67
67
  const outputs = this.processOutputs();
68
68
  const ffmpegOptions = this.processFfmpegOptions();
69
69
  const title = this.processTitle();
70
+ const date = this.processDate();
70
71
  const globalTags = this.processGlobalTags();
71
72
  const uploads = this.processUploads(title, globalTags);
72
73
  const sequences = this.processSequences(assets);
73
74
  const cssText = this.html.cssText;
74
- return new project_1.Project(sequences, assets, outputs, ffmpegOptions, uploads, aiProviders, title, cssText, this.projectPath);
75
+ return new project_1.Project(sequences, assets, outputs, ffmpegOptions, uploads, aiProviders, title, date, cssText, this.projectPath);
75
76
  }
76
77
  /**
77
78
  * Validates that all asset files exist on the filesystem
@@ -707,7 +708,7 @@ class HTMLProjectParser {
707
708
  let endpoint;
708
709
  let region = '';
709
710
  let bucket = '';
710
- let path = '';
711
+ const paths = new Map();
711
712
  let acl;
712
713
  if ('children' in element && element.children) {
713
714
  for (const child of element.children) {
@@ -728,7 +729,21 @@ class HTMLProjectParser {
728
729
  break;
729
730
  }
730
731
  case 'path': {
731
- path = childAttrs.get('name') || '';
732
+ // Extract path name from name attribute
733
+ const pathName = childAttrs.get('name') || 'file';
734
+ // Extract path value from text content
735
+ let pathValue = '';
736
+ if ('children' in childElement && childElement.children) {
737
+ for (const textNode of childElement.children) {
738
+ if (textNode.type === 'text' && 'data' in textNode) {
739
+ pathValue += textNode.data;
740
+ }
741
+ }
742
+ }
743
+ pathValue = pathValue.trim();
744
+ if (pathValue) {
745
+ paths.set(pathName, pathValue);
746
+ }
732
747
  break;
733
748
  }
734
749
  case 'acl': {
@@ -740,7 +755,7 @@ class HTMLProjectParser {
740
755
  }
741
756
  }
742
757
  // Validate required fields
743
- if (!region || !bucket || !path) {
758
+ if (!region || !bucket || paths.size === 0) {
744
759
  console.warn(`S3 upload "${name}" missing required fields (region, bucket, or path)`);
745
760
  return null;
746
761
  }
@@ -758,7 +773,7 @@ class HTMLProjectParser {
758
773
  endpoint,
759
774
  region,
760
775
  bucket,
761
- path,
776
+ paths,
762
777
  acl,
763
778
  },
764
779
  };
@@ -1010,6 +1025,26 @@ class HTMLProjectParser {
1010
1025
  }
1011
1026
  return title.trim() || 'Untitled Project';
1012
1027
  }
1028
+ /**
1029
+ * Processes the date from the parsed HTML
1030
+ */
1031
+ processDate() {
1032
+ const dateElements = this.findDateElements();
1033
+ if (dateElements.length === 0) {
1034
+ return undefined;
1035
+ }
1036
+ // Get text content from first date element
1037
+ const dateElement = dateElements[0];
1038
+ let date = '';
1039
+ if ('children' in dateElement && dateElement.children) {
1040
+ for (const textNode of dateElement.children) {
1041
+ if (textNode.type === 'text' && 'data' in textNode) {
1042
+ date += textNode.data;
1043
+ }
1044
+ }
1045
+ }
1046
+ return date.trim() || undefined;
1047
+ }
1013
1048
  /**
1014
1049
  * Finds all title elements in the HTML (top-level only, not inside uploads)
1015
1050
  */
@@ -1039,6 +1074,37 @@ class HTMLProjectParser {
1039
1074
  traverse(this.html.ast);
1040
1075
  return results;
1041
1076
  }
1077
+ /**
1078
+ * Finds all date elements in the HTML (top-level only)
1079
+ */
1080
+ findDateElements() {
1081
+ const results = [];
1082
+ const traverse = (node, insideProject = false) => {
1083
+ if (node.type === 'tag') {
1084
+ const element = node;
1085
+ // Find top-level <date> tags (not inside <project>, <uploads>, etc.)
1086
+ if (element.name === 'date' && !insideProject) {
1087
+ results.push(element);
1088
+ }
1089
+ // Mark that we're inside a project/uploads/outputs section
1090
+ const isProjectSection = element.name === 'project' ||
1091
+ element.name === 'uploads' ||
1092
+ element.name === 'outputs';
1093
+ if ('children' in node && node.children) {
1094
+ for (const child of node.children) {
1095
+ traverse(child, insideProject || isProjectSection);
1096
+ }
1097
+ }
1098
+ }
1099
+ else if ('children' in node && node.children) {
1100
+ for (const child of node.children) {
1101
+ traverse(child, insideProject);
1102
+ }
1103
+ }
1104
+ };
1105
+ traverse(this.html.ast);
1106
+ return results;
1107
+ }
1042
1108
  /**
1043
1109
  * Finds all uploads elements in the HTML
1044
1110
  */