@reshotdev/screenshot 0.0.1-beta.4 → 0.0.1-beta.7

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.
@@ -390,13 +390,13 @@ function resolveProjectContext({ settings, docSyncConfig, storageMode }) {
390
390
  if (!apiKey) {
391
391
  throw new Error(
392
392
  "No API key found. Set RESHOT_API_KEY in your environment or run `reshot auth` locally to create .reshot/settings.json.\n" +
393
- "Alternatively, configure BYOS (Bring Your Own Storage) in docsync.config.json to publish without authentication.",
393
+ "Alternatively, configure BYOS (Bring Your Own Storage) in reshot.config.json to publish without authentication.",
394
394
  );
395
395
  }
396
396
 
397
397
  if (!projectId) {
398
398
  throw new Error(
399
- "No project ID found. Set RESHOT_PROJECT_ID in your environment or ensure docsync.config.json contains _metadata.projectId.",
399
+ "No project ID found. Set RESHOT_PROJECT_ID in your environment or ensure reshot.config.json contains _metadata.projectId.",
400
400
  );
401
401
  }
402
402
 
@@ -578,6 +578,7 @@ async function publishWithTransactionalFlow(
578
578
  docSyncConfig,
579
579
  gitInfo,
580
580
  diffManifests = null,
581
+ { autoApprove = false } = {},
581
582
  ) {
582
583
  console.log(
583
584
  chalk.cyan(" šŸš€ Using transactional upload (direct to R2)...\n"),
@@ -807,7 +808,10 @@ async function publishWithTransactionalFlow(
807
808
  });
808
809
  }
809
810
 
810
- // Commit each group
811
+ // Build all commits for batch request
812
+ const MAX_BATCH_SIZE = 200;
813
+ const commits = [];
814
+
811
815
  for (const { group, scenarioConfig, assets } of groupMap.values()) {
812
816
  const contextObj = buildContextForVariation(
813
817
  scenarioConfig,
@@ -824,38 +828,58 @@ async function publishWithTransactionalFlow(
824
828
  });
825
829
 
826
830
  if (metadata.cli) {
827
- metadata.cli.features = ["steps", "transactional"];
831
+ metadata.cli.features = ["steps", "transactional", "batch"];
828
832
  }
829
833
 
834
+ commits.push({ metadata, assets });
835
+ }
836
+
837
+ // Send in batches
838
+ console.log(
839
+ chalk.gray(` Committing ${commits.length} scenario(s) to platform...`),
840
+ );
841
+
842
+ for (let i = 0; i < commits.length; i += MAX_BATCH_SIZE) {
843
+ const chunk = commits.slice(i, i + MAX_BATCH_SIZE);
844
+
830
845
  try {
831
- const result = await apiClient.publishTransactional(apiKey, {
832
- metadata,
833
- assets,
846
+ const batchResult = await apiClient.publishBatch(apiKey, {
847
+ commits: chunk,
848
+ autoApprove: autoApprove || false,
834
849
  });
835
850
 
836
- const processedCount = result?.assetsProcessed ?? assets.length;
837
- console.log(
838
- chalk.green(
839
- ` āœ” Committed "${group.scenarioKey}" (${group.variationSlug}): ${processedCount} asset(s)`,
840
- ),
841
- );
842
- successCount += processedCount;
851
+ for (const r of batchResult.results || []) {
852
+ if (r.status === "ok") {
853
+ const count = r.assetsProcessed || 0;
854
+ console.log(
855
+ chalk.green(
856
+ ` āœ” Committed "${r.scenario}" (${r.context}): ${count} asset(s)`,
857
+ ),
858
+ );
859
+ successCount += count;
843
860
 
844
- // Handle skipped assets (visual limit)
845
- if (result?.skippedAssets?.length > 0) {
846
- for (const key of result.skippedAssets) {
847
- console.log(chalk.yellow(` ⚠ Skipped "${key}" (plan limit reached)`));
861
+ if (r.skippedAssets?.length > 0) {
862
+ for (const key of r.skippedAssets) {
863
+ console.log(chalk.yellow(` ⚠ Skipped "${key}" (plan limit reached)`));
864
+ }
865
+ skippedCount += r.skippedAssets.length;
866
+ }
867
+ } else {
868
+ console.log(
869
+ chalk.red(
870
+ ` āœ– "${r.scenario}" (${r.context}): ${r.error || "Unknown error"}`,
871
+ ),
872
+ );
873
+ failCount++;
848
874
  }
849
- skippedCount += result.skippedAssets.length;
850
875
  }
851
876
 
852
- // Capture viewUrl from first successful response
853
- if (!viewUrl && result?.viewUrl) {
854
- viewUrl = result.viewUrl;
877
+ if (!viewUrl && batchResult.viewUrl) {
878
+ viewUrl = batchResult.viewUrl;
855
879
  }
856
880
  } catch (error) {
857
- console.log(chalk.red(` āœ– Commit failed: ${error.message}`));
858
- failCount += assets.length;
881
+ console.log(chalk.red(` āœ– Batch request failed: ${error.message}`));
882
+ failCount += chunk.length;
859
883
  }
860
884
  }
861
885
 
@@ -1167,70 +1191,6 @@ function getRecentCommits(lastCommitHash) {
1167
1191
  }
1168
1192
  }
1169
1193
 
1170
- /**
1171
- * Recursively find all markdown files matching include/exclude patterns
1172
- */
1173
- function findDocFiles(
1174
- docsRoot,
1175
- includePatterns = ["**/*.md", "**/*.mdx"],
1176
- excludePatterns = [],
1177
- ) {
1178
- const files = [];
1179
- const rootPath = path.resolve(process.cwd(), docsRoot);
1180
-
1181
- if (!fs.existsSync(rootPath)) {
1182
- return files;
1183
- }
1184
-
1185
- function walkDir(dir, relativePath = "") {
1186
- const items = fs.readdirSync(dir);
1187
-
1188
- for (const item of items) {
1189
- const fullPath = path.join(dir, item);
1190
- const relativeItemPath = path
1191
- .join(relativePath, item)
1192
- .replace(/\\/g, "/");
1193
- const stat = fs.statSync(fullPath);
1194
-
1195
- // Check exclude patterns
1196
- const shouldExclude = excludePatterns.some((pattern) => {
1197
- const regex = new RegExp(
1198
- pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"),
1199
- );
1200
- return regex.test(relativeItemPath) || regex.test(fullPath);
1201
- });
1202
-
1203
- if (shouldExclude) {
1204
- continue;
1205
- }
1206
-
1207
- if (stat.isDirectory()) {
1208
- walkDir(fullPath, relativeItemPath);
1209
- } else if (stat.isFile()) {
1210
- const ext = path.extname(item).toLowerCase();
1211
- const matchesInclude = includePatterns.some((pattern) => {
1212
- const regex = new RegExp(
1213
- pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*"),
1214
- );
1215
- return (
1216
- regex.test(relativeItemPath) || ext === ".md" || ext === ".mdx"
1217
- );
1218
- });
1219
-
1220
- if (matchesInclude && (ext === ".md" || ext === ".mdx")) {
1221
- files.push({
1222
- fullPath,
1223
- relativePath: relativeItemPath,
1224
- });
1225
- }
1226
- }
1227
- }
1228
- }
1229
-
1230
- walkDir(rootPath);
1231
- return files;
1232
- }
1233
-
1234
1194
  /**
1235
1195
  * Parse frontmatter from markdown content
1236
1196
  */
@@ -1268,7 +1228,7 @@ function parseFrontmatter(content) {
1268
1228
  }
1269
1229
 
1270
1230
  async function publishCommand(options = {}) {
1271
- const { tag, message, dryRun, force, video, outputJson } = options;
1231
+ const { tag, message, dryRun, force, video, outputJson, autoApprove } = options;
1272
1232
 
1273
1233
  // Result tracking for --output-json and programmatic callers
1274
1234
  const publishResult = {
@@ -1294,6 +1254,10 @@ async function publishCommand(options = {}) {
1294
1254
  console.log(chalk.yellow("šŸ” DRY RUN MODE - No assets will be uploaded\n"));
1295
1255
  }
1296
1256
 
1257
+ if (autoApprove) {
1258
+ console.log(chalk.cyan(" āœ… Auto-approve enabled: visuals will be approved immediately\n"));
1259
+ }
1260
+
1297
1261
  // Read config + settings (if available)
1298
1262
  const settings = readSettingsSafe();
1299
1263
  let docSyncConfig = null;
@@ -1368,8 +1332,6 @@ async function publishCommand(options = {}) {
1368
1332
  // Get feature toggles
1369
1333
  const features = docSyncConfig?._metadata?.features || {
1370
1334
  visuals: true,
1371
- docs: false,
1372
- changelog: true,
1373
1335
  };
1374
1336
 
1375
1337
  // Get git information
@@ -1479,6 +1441,7 @@ async function publishCommand(options = {}) {
1479
1441
  docSyncConfig,
1480
1442
  { commitHash, commitMessage, publishSessionId },
1481
1443
  diffManifests,
1444
+ { autoApprove },
1482
1445
  );
1483
1446
  successCount = result.successCount;
1484
1447
  failCount = result.failCount;
@@ -1558,141 +1521,6 @@ async function publishCommand(options = {}) {
1558
1521
  );
1559
1522
  }
1560
1523
 
1561
- // Stream B: Documentation
1562
- if (features.docs === true) {
1563
- console.log(chalk.cyan("\nšŸ“š Publishing documentation...\n"));
1564
-
1565
- if (!docSyncConfig || !docSyncConfig.docs) {
1566
- console.log(
1567
- chalk.yellow(
1568
- " ⚠ No docs configuration found in docsync.config.json. Skipping docs stream.",
1569
- ),
1570
- );
1571
- } else {
1572
- const docsConfig = docSyncConfig.docs;
1573
- const docsRoot = docsConfig.root || "./docs";
1574
- const includePatterns = docsConfig.include || ["**/*.md", "**/*.mdx"];
1575
- const excludePatterns = docsConfig.exclude || [
1576
- "**/node_modules/**",
1577
- "**/.git/**",
1578
- ];
1579
-
1580
- const docFiles = findDocFiles(docsRoot, includePatterns, excludePatterns);
1581
-
1582
- if (docFiles.length === 0) {
1583
- console.log(
1584
- chalk.yellow(" ⚠ No documentation files found to publish."),
1585
- );
1586
- } else {
1587
- console.log(
1588
- chalk.cyan(` Found ${docFiles.length} documentation file(s)\n`),
1589
- );
1590
-
1591
- const docsPayload = [];
1592
- for (const docFile of docFiles) {
1593
- const content = fs.readFileSync(docFile.fullPath, "utf-8");
1594
- const { frontmatter, content: docContent } =
1595
- parseFrontmatter(content);
1596
-
1597
- docsPayload.push({
1598
- path: docFile.relativePath,
1599
- content: docContent,
1600
- frontmatter:
1601
- Object.keys(frontmatter).length > 0 ? frontmatter : undefined,
1602
- status: frontmatter.status || "draft",
1603
- });
1604
- }
1605
-
1606
- // Docs publishing requires platform (no BYOS support yet)
1607
- if (resolvedMode === "byos") {
1608
- console.log(
1609
- chalk.yellow(
1610
- " ⚠ Documentation publishing requires Reshot platform.",
1611
- ),
1612
- );
1613
- console.log(
1614
- chalk.gray(
1615
- " Run 'reshot auth' to enable doc hosting with review workflow.",
1616
- ),
1617
- );
1618
- } else {
1619
- try {
1620
- const result = await apiClient.publishDocs(apiKey, {
1621
- projectId,
1622
- docs: docsPayload,
1623
- });
1624
- console.log(
1625
- chalk.green(
1626
- ` āœ” Published ${result.created || 0} new doc(s), updated ${
1627
- result.updated || 0
1628
- } doc(s)`,
1629
- ),
1630
- );
1631
- } catch (error) {
1632
- console.log(
1633
- chalk.red(` āœ– Failed to publish docs: ${error.message}`),
1634
- );
1635
- }
1636
- }
1637
- }
1638
- }
1639
- } else {
1640
- console.log(
1641
- chalk.yellow(
1642
- " ⚠ Documentation publishing is disabled for this project.",
1643
- ),
1644
- );
1645
- }
1646
-
1647
- // Stream C: Changelog
1648
- if (features.changelog === true) {
1649
- // Changelog requires platform (no BYOS support)
1650
- if (resolvedMode === "byos") {
1651
- console.log(chalk.cyan("\nšŸ“ Changelog drafts...\n"));
1652
- console.log(
1653
- chalk.yellow(
1654
- " ⚠ Changelog requires Reshot platform for tracking and publishing.",
1655
- ),
1656
- );
1657
- console.log(
1658
- chalk.gray(" Run 'reshot auth' to enable changelog generation."),
1659
- );
1660
- } else {
1661
- console.log(chalk.cyan("\nšŸ“ Posting changelog drafts...\n"));
1662
- const lastPublishedHash = settings?.lastPublishedCommitHash;
1663
- const recentCommits = getRecentCommits(lastPublishedHash);
1664
-
1665
- if (recentCommits.length > 0) {
1666
- try {
1667
- await apiClient.postChangelogDrafts(projectId, recentCommits, apiKey);
1668
- console.log(
1669
- chalk.green(
1670
- ` āœ” Posted ${recentCommits.length} changelog draft(s)`,
1671
- ),
1672
- );
1673
-
1674
- // Update last published commit hash
1675
- if (settings) {
1676
- settings.lastPublishedCommitHash = commitHash;
1677
- config.writeSettings(settings);
1678
- }
1679
- } catch (error) {
1680
- console.log(
1681
- chalk.yellow(
1682
- ` ⚠ Failed to post changelog drafts: ${error.message}`,
1683
- ),
1684
- );
1685
- }
1686
- } else {
1687
- console.log(chalk.gray(" No new commits to publish"));
1688
- }
1689
- }
1690
- } else {
1691
- console.log(
1692
- chalk.yellow(" ⚠ Changelog publishing is disabled for this project."),
1693
- );
1694
- }
1695
-
1696
1524
  // Print upgrade path for BYOS users
1697
1525
  if (resolvedMode === "byos") {
1698
1526
  console.log(chalk.cyan("\nšŸ’” Upgrade to Reshot Platform for:"));
@@ -1700,7 +1528,7 @@ async function publishCommand(options = {}) {
1700
1528
  console.log(chalk.gray(" • Unbreakable URLs that never change"));
1701
1529
  console.log(chalk.gray(" • Version history and rollback"));
1702
1530
  console.log(chalk.gray(" • Team collaboration and RBAC"));
1703
- console.log(chalk.gray(" • Automatic changelog generation"));
1531
+ console.log(chalk.gray(" • Drift detection and notifications"));
1704
1532
  console.log(chalk.gray("\n Run 'reshot auth' to connect your project."));
1705
1533
  }
1706
1534
 
@@ -112,7 +112,7 @@ async function pullCommand(options = {}) {
112
112
  projectConfig = config.readConfig();
113
113
  } catch (e) {
114
114
  console.error(
115
- chalk.red("Error: No docsync.config.json found. Run 'reshot init' first.")
115
+ chalk.red("Error: No reshot.config.json found. Run 'reshot init' first.")
116
116
  );
117
117
  process.exit(1);
118
118
  }
@@ -120,7 +120,7 @@ async function pullCommand(options = {}) {
120
120
  const projectId = projectConfig._metadata?.projectId || projectConfig.projectId;
121
121
  if (!projectId) {
122
122
  console.error(
123
- chalk.red("Error: No projectId found in docsync.config.json")
123
+ chalk.red("Error: No projectId found in reshot.config.json")
124
124
  );
125
125
  process.exit(1);
126
126
  }