@link-assistant/web-capture 1.1.2 → 1.4.2
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.
- package/CHANGELOG.md +17 -14
- package/README.md +256 -146
- package/bin/web-capture.js +403 -6
- package/package.json +11 -4
- package/src/animation.js +283 -0
- package/src/archive.js +212 -0
- package/src/batch.js +180 -0
- package/src/browser.js +150 -111
- package/src/docx.js +182 -0
- package/src/figures.js +208 -0
- package/src/gdocs.js +333 -0
- package/src/image.js +65 -8
- package/src/index.js +15 -0
- package/src/latex.js +127 -0
- package/src/lib.js +226 -1
- package/src/localize-images.js +202 -0
- package/src/metadata.js +333 -0
- package/src/pdf.js +76 -0
- package/src/popups.js +171 -0
- package/src/postprocess.js +265 -0
- package/src/retry.js +48 -0
- package/src/themed-image.js +167 -0
- package/src/verify.js +312 -0
- package/tests/e2e/docker.test.js +51 -12
- package/tests/e2e/process.test.js +34 -10
- package/tests/fixtures/habr-articles.js +45 -0
- package/tests/integration/api-endpoints.test.js +231 -0
- package/tests/integration/habr-article.test.js +337 -0
- package/tests/mock/index.test.js +5 -3
- package/tests/unit/animation.test.js +33 -0
- package/tests/unit/batch.test.js +114 -0
- package/tests/unit/browser.test.js +38 -2
- package/tests/unit/figures.test.js +74 -0
- package/tests/unit/gdocs.test.js +203 -0
- package/tests/unit/latex.test.js +123 -0
- package/tests/unit/localize-images.test.js +78 -0
- package/tests/unit/metadata.test.js +140 -0
- package/tests/unit/postprocess.test.js +108 -0
- package/tests/unit/retry.test.js +111 -0
- package/tests/unit/verify.test.js +182 -0
- package/.github/workflows/release.yml +0 -294
- package/ARCHITECTURE.md +0 -982
- package/LICENSE +0 -24
- package/apply.sh +0 -166
- package/docs/market-analysis-2025-05-13.md +0 -64
- package/scripts/changeset-version.mjs +0 -38
- package/scripts/create-github-release.mjs +0 -93
- package/scripts/create-manual-changeset.mjs +0 -88
- package/scripts/format-github-release.mjs +0 -83
- package/scripts/format-release-notes.mjs +0 -218
- package/scripts/instant-version-bump.mjs +0 -121
- package/scripts/publish-to-npm.mjs +0 -128
- package/scripts/setup-npm.mjs +0 -37
- package/scripts/validate-changeset.mjs +0 -106
- package/scripts/version-and-commit.mjs +0 -237
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Script to format GitHub release notes with proper formatting:
|
|
5
|
-
* - Fix special characters like \n
|
|
6
|
-
* - Add link to PR that contains the release commit (if found)
|
|
7
|
-
* - Add shields.io NPM version badge
|
|
8
|
-
* - Format nicely with proper markdown
|
|
9
|
-
*
|
|
10
|
-
* IMPORTANT: Update the PACKAGE_NAME constant below to match your package.json
|
|
11
|
-
*
|
|
12
|
-
* PR Detection Logic:
|
|
13
|
-
* 1. Extract commit hash from changelog entry (if present)
|
|
14
|
-
* 2. Fall back to --commit-sha argument (passed from workflow)
|
|
15
|
-
* 3. Look up PRs that contain the commit via GitHub API
|
|
16
|
-
* 4. If no PR found, simply don't display any PR link (no guessing)
|
|
17
|
-
*
|
|
18
|
-
* Uses link-foundation libraries:
|
|
19
|
-
* - use-m: Dynamic package loading without package.json dependencies
|
|
20
|
-
* - command-stream: Modern shell command execution with streaming support
|
|
21
|
-
* - lino-arguments: Unified configuration from CLI args, env vars, and .lenv files
|
|
22
|
-
*
|
|
23
|
-
* Note: Uses --release-version instead of --version to avoid conflict with yargs' built-in --version flag.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
const PACKAGE_NAME = '@link-assistant/web-capture';
|
|
27
|
-
|
|
28
|
-
// Load use-m dynamically
|
|
29
|
-
const { use } = eval(
|
|
30
|
-
await (await fetch('https://unpkg.com/use-m/use.js')).text()
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
// Import link-foundation libraries
|
|
34
|
-
const { $ } = await use('command-stream');
|
|
35
|
-
const { makeConfig } = await use('lino-arguments');
|
|
36
|
-
|
|
37
|
-
// Parse CLI arguments using lino-arguments
|
|
38
|
-
// Note: Using --release-version instead of --version to avoid conflict with yargs' built-in --version flag
|
|
39
|
-
const config = makeConfig({
|
|
40
|
-
yargs: ({ yargs, getenv }) =>
|
|
41
|
-
yargs
|
|
42
|
-
.option('release-version', {
|
|
43
|
-
type: 'string',
|
|
44
|
-
default: getenv('VERSION', ''),
|
|
45
|
-
describe: 'Version number (e.g., v0.8.36)',
|
|
46
|
-
})
|
|
47
|
-
.option('release-id', {
|
|
48
|
-
type: 'string',
|
|
49
|
-
default: getenv('RELEASE_ID', ''),
|
|
50
|
-
describe: 'GitHub release ID',
|
|
51
|
-
})
|
|
52
|
-
.option('repository', {
|
|
53
|
-
type: 'string',
|
|
54
|
-
default: getenv('REPOSITORY', ''),
|
|
55
|
-
describe: 'GitHub repository (e.g., owner/repo)',
|
|
56
|
-
})
|
|
57
|
-
.option('commit-sha', {
|
|
58
|
-
type: 'string',
|
|
59
|
-
default: getenv('COMMIT_SHA', ''),
|
|
60
|
-
describe: 'Commit SHA for PR detection',
|
|
61
|
-
}),
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
const releaseId = config.releaseId;
|
|
65
|
-
const version = config.releaseVersion;
|
|
66
|
-
const repository = config.repository;
|
|
67
|
-
const passedCommitSha = config.commitSha;
|
|
68
|
-
|
|
69
|
-
if (!releaseId || !version || !repository) {
|
|
70
|
-
console.error(
|
|
71
|
-
'Usage: format-release-notes.mjs --release-id <releaseId> --release-version <version> --repository <repository> [--commit-sha <sha>]'
|
|
72
|
-
);
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
// Get current release body
|
|
78
|
-
const result = await $`gh api repos/${repository}/releases/${releaseId}`.run({
|
|
79
|
-
capture: true,
|
|
80
|
-
});
|
|
81
|
-
const releaseData = JSON.parse(result.stdout);
|
|
82
|
-
|
|
83
|
-
const currentBody = releaseData.body || '';
|
|
84
|
-
|
|
85
|
-
// Skip if already formatted (has shields.io badge image)
|
|
86
|
-
if (currentBody.includes('img.shields.io')) {
|
|
87
|
-
console.log('ℹ️ Release notes already formatted');
|
|
88
|
-
process.exit(0);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Extract changes section (Major, Minor, or Patch)
|
|
92
|
-
// This regex handles multiple formats:
|
|
93
|
-
// 1. With commit hash: "### [Major|Minor|Patch] Changes\n- abc1234: Description"
|
|
94
|
-
// 2. Without commit hash: "### [Major|Minor|Patch] Changes\n- Description"
|
|
95
|
-
const changesPattern =
|
|
96
|
-
/### (Major|Minor|Patch) Changes\s*\n\s*-\s+(?:([a-f0-9]+):\s+)?(.+?)$/s;
|
|
97
|
-
const changesMatch = currentBody.match(changesPattern);
|
|
98
|
-
|
|
99
|
-
let commitHash = null;
|
|
100
|
-
let rawDescription = null;
|
|
101
|
-
let changeType = null;
|
|
102
|
-
|
|
103
|
-
if (changesMatch) {
|
|
104
|
-
// Extract: [full match, changeType, commitHash (optional), description]
|
|
105
|
-
[, changeType, commitHash, rawDescription] = changesMatch;
|
|
106
|
-
console.log(`ℹ️ Found ${changeType} Changes section`);
|
|
107
|
-
|
|
108
|
-
// If commitHash is undefined and description contains it, try to extract
|
|
109
|
-
if (!commitHash && rawDescription) {
|
|
110
|
-
// This handles the case where description itself might be null/undefined
|
|
111
|
-
// and we need to safely check for commit hash at the start
|
|
112
|
-
const descWithHashMatch = rawDescription.match(/^([a-f0-9]+):\s+(.+)$/s);
|
|
113
|
-
if (descWithHashMatch) {
|
|
114
|
-
[, commitHash, rawDescription] = descWithHashMatch;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
console.log('⚠️ Could not parse changes from release notes');
|
|
119
|
-
console.log(' Looking for pattern: ### [Major|Minor|Patch] Changes');
|
|
120
|
-
process.exit(0);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Clean up the description:
|
|
124
|
-
// 1. Convert literal \n sequences (escaped newlines from GitHub API) to actual newlines
|
|
125
|
-
// 2. Remove leading/trailing quotes (including escaped quotes from command-stream shell escaping)
|
|
126
|
-
// 3. Remove any trailing npm package links or markdown that might be there
|
|
127
|
-
// 4. Normalize whitespace while preserving line breaks
|
|
128
|
-
const cleanDescription = rawDescription
|
|
129
|
-
.replace(/\\n/g, '\n') // Convert escaped \n to actual newlines
|
|
130
|
-
.replace(/^(\\['"])+/g, '') // Remove leading escaped quotes (e.g., \', \", \'', \'')
|
|
131
|
-
.replace(/(['"])+$/g, '') // Remove trailing unescaped quotes (e.g., ', ", '', '')
|
|
132
|
-
.replace(/^(['"])+/g, '') // Remove leading unescaped quotes
|
|
133
|
-
.replace(/📦.*$/s, '') // Remove any existing npm package info
|
|
134
|
-
.replace(/---.*$/s, '') // Remove any existing separators and everything after
|
|
135
|
-
.trim()
|
|
136
|
-
.split('\n') // Split by lines
|
|
137
|
-
.map((line) => line.trim()) // Trim whitespace from each line
|
|
138
|
-
.join('\n') // Rejoin with newlines
|
|
139
|
-
.replace(/\n{3,}/g, '\n\n'); // Normalize excessive blank lines (3+ becomes 2)
|
|
140
|
-
|
|
141
|
-
// Find the PR that contains the release commit
|
|
142
|
-
// Uses commit hash from changelog or passed commit SHA from workflow
|
|
143
|
-
let prNumber = null;
|
|
144
|
-
|
|
145
|
-
// Determine which commit SHA to use for PR lookup
|
|
146
|
-
const commitShaToLookup = commitHash || passedCommitSha;
|
|
147
|
-
|
|
148
|
-
if (commitShaToLookup) {
|
|
149
|
-
const source = commitHash ? 'changelog' : 'workflow';
|
|
150
|
-
console.log(
|
|
151
|
-
`ℹ️ Looking up PR for commit ${commitShaToLookup} (from ${source})`
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
const prResult =
|
|
156
|
-
await $`gh api "repos/${repository}/commits/${commitShaToLookup}/pulls"`.run(
|
|
157
|
-
{ capture: true }
|
|
158
|
-
);
|
|
159
|
-
const prsData = JSON.parse(prResult.stdout);
|
|
160
|
-
|
|
161
|
-
// Find the PR that's not the version bump PR (not "chore: version packages")
|
|
162
|
-
const relevantPr = prsData.find(
|
|
163
|
-
(pr) => !pr.title.includes('version packages')
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
if (relevantPr) {
|
|
167
|
-
prNumber = relevantPr.number;
|
|
168
|
-
console.log(`✅ Found PR #${prNumber} containing commit`);
|
|
169
|
-
} else if (prsData.length > 0) {
|
|
170
|
-
console.log(
|
|
171
|
-
'⚠️ Found PRs but all are version bump PRs, not linking any'
|
|
172
|
-
);
|
|
173
|
-
} else {
|
|
174
|
-
console.log(
|
|
175
|
-
'ℹ️ No PR found containing this commit - not adding PR link'
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
} catch (error) {
|
|
179
|
-
console.log('⚠️ Could not find PR for commit', commitShaToLookup);
|
|
180
|
-
console.log(' Error:', error.message);
|
|
181
|
-
if (process.env.DEBUG) {
|
|
182
|
-
console.error(error);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
} else {
|
|
186
|
-
// No commit hash available from any source
|
|
187
|
-
console.log('ℹ️ No commit SHA available - not adding PR link');
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Build formatted release notes
|
|
191
|
-
const versionWithoutV = version.replace(/^v/, '');
|
|
192
|
-
const npmBadge = `[](https://www.npmjs.com/package/${PACKAGE_NAME}/v/${versionWithoutV})`;
|
|
193
|
-
|
|
194
|
-
let formattedBody = `${cleanDescription}`;
|
|
195
|
-
|
|
196
|
-
// Add PR link if available
|
|
197
|
-
if (prNumber) {
|
|
198
|
-
formattedBody += `\n\n**Related Pull Request:** #${prNumber}`;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
formattedBody += `\n\n---\n\n${npmBadge}`;
|
|
202
|
-
|
|
203
|
-
// Update the release using JSON input to properly handle special characters
|
|
204
|
-
const updatePayload = JSON.stringify({ body: formattedBody });
|
|
205
|
-
await $`gh api repos/${repository}/releases/${releaseId} -X PATCH --input -`.run(
|
|
206
|
-
{ stdin: updatePayload }
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
console.log(`✅ Formatted release notes for v${versionWithoutV}`);
|
|
210
|
-
if (prNumber) {
|
|
211
|
-
console.log(` - Added link to PR #${prNumber}`);
|
|
212
|
-
}
|
|
213
|
-
console.log(' - Added shields.io npm badge');
|
|
214
|
-
console.log(' - Cleaned up formatting');
|
|
215
|
-
} catch (error) {
|
|
216
|
-
console.error('❌ Error formatting release notes:', error.message);
|
|
217
|
-
process.exit(1);
|
|
218
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Instant version bump script for manual releases
|
|
5
|
-
* Bypasses the changeset workflow and directly updates version and changelog
|
|
6
|
-
*
|
|
7
|
-
* Usage: node scripts/instant-version-bump.mjs --bump-type <major|minor|patch> [--description <description>]
|
|
8
|
-
*
|
|
9
|
-
* Uses link-foundation libraries:
|
|
10
|
-
* - use-m: Dynamic package loading without package.json dependencies
|
|
11
|
-
* - command-stream: Modern shell command execution with streaming support
|
|
12
|
-
* - lino-arguments: Unified configuration from CLI args, env vars, and .lenv files
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { readFileSync, writeFileSync } from 'fs';
|
|
16
|
-
|
|
17
|
-
// Load use-m dynamically
|
|
18
|
-
const { use } = eval(
|
|
19
|
-
await (await fetch('https://unpkg.com/use-m/use.js')).text()
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
// Import link-foundation libraries
|
|
23
|
-
const { $ } = await use('command-stream');
|
|
24
|
-
const { makeConfig } = await use('lino-arguments');
|
|
25
|
-
|
|
26
|
-
// Parse CLI arguments using lino-arguments
|
|
27
|
-
const config = makeConfig({
|
|
28
|
-
yargs: ({ yargs, getenv }) =>
|
|
29
|
-
yargs
|
|
30
|
-
.option('bump-type', {
|
|
31
|
-
type: 'string',
|
|
32
|
-
default: getenv('BUMP_TYPE', ''),
|
|
33
|
-
describe: 'Version bump type: major, minor, or patch',
|
|
34
|
-
choices: ['major', 'minor', 'patch'],
|
|
35
|
-
})
|
|
36
|
-
.option('description', {
|
|
37
|
-
type: 'string',
|
|
38
|
-
default: getenv('DESCRIPTION', ''),
|
|
39
|
-
describe: 'Description for the version bump',
|
|
40
|
-
}),
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const { bumpType, description } = config;
|
|
45
|
-
const finalDescription = description || `Manual ${bumpType} release`;
|
|
46
|
-
|
|
47
|
-
if (!bumpType || !['major', 'minor', 'patch'].includes(bumpType)) {
|
|
48
|
-
console.error(
|
|
49
|
-
'Usage: node scripts/instant-version-bump.mjs --bump-type <major|minor|patch> [--description <description>]'
|
|
50
|
-
);
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
console.log(`\nBumping version (${bumpType})...`);
|
|
55
|
-
|
|
56
|
-
// Get current version
|
|
57
|
-
const packageJson = JSON.parse(readFileSync('package.json', 'utf-8'));
|
|
58
|
-
const oldVersion = packageJson.version;
|
|
59
|
-
console.log(`Current version: ${oldVersion}`);
|
|
60
|
-
|
|
61
|
-
// Bump version using npm version (doesn't create git tag)
|
|
62
|
-
await $`npm version ${bumpType} --no-git-tag-version`;
|
|
63
|
-
|
|
64
|
-
// Get new version
|
|
65
|
-
const updatedPackageJson = JSON.parse(readFileSync('package.json', 'utf-8'));
|
|
66
|
-
const newVersion = updatedPackageJson.version;
|
|
67
|
-
console.log(`New version: ${newVersion}`);
|
|
68
|
-
|
|
69
|
-
// Update CHANGELOG.md
|
|
70
|
-
console.log('\nUpdating CHANGELOG.md...');
|
|
71
|
-
const changelogPath = 'CHANGELOG.md';
|
|
72
|
-
let changelog = readFileSync(changelogPath, 'utf-8');
|
|
73
|
-
|
|
74
|
-
// Create new changelog entry
|
|
75
|
-
const newEntry = `## ${newVersion}
|
|
76
|
-
|
|
77
|
-
### ${bumpType.charAt(0).toUpperCase() + bumpType.slice(1)} Changes
|
|
78
|
-
|
|
79
|
-
- ${finalDescription}
|
|
80
|
-
|
|
81
|
-
`;
|
|
82
|
-
|
|
83
|
-
// Insert new entry after the first heading (# Changelog or similar)
|
|
84
|
-
// Look for the first ## heading and insert before it
|
|
85
|
-
const firstVersionMatch = changelog.match(/^## /m);
|
|
86
|
-
|
|
87
|
-
if (firstVersionMatch) {
|
|
88
|
-
const insertPosition = firstVersionMatch.index;
|
|
89
|
-
changelog =
|
|
90
|
-
changelog.slice(0, insertPosition) +
|
|
91
|
-
newEntry +
|
|
92
|
-
changelog.slice(insertPosition);
|
|
93
|
-
} else {
|
|
94
|
-
// If no version headings exist, append after the main heading
|
|
95
|
-
const mainHeadingMatch = changelog.match(/^# .+$/m);
|
|
96
|
-
if (mainHeadingMatch) {
|
|
97
|
-
const insertPosition =
|
|
98
|
-
mainHeadingMatch.index + mainHeadingMatch[0].length;
|
|
99
|
-
changelog = `${changelog.slice(0, insertPosition)}\n\n${newEntry}${changelog.slice(insertPosition)}`;
|
|
100
|
-
} else {
|
|
101
|
-
// If no headings at all, prepend
|
|
102
|
-
changelog = `${newEntry}\n${changelog}`;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
writeFileSync(changelogPath, changelog, 'utf-8');
|
|
107
|
-
console.log('✅ CHANGELOG.md updated');
|
|
108
|
-
|
|
109
|
-
// Synchronize package-lock.json
|
|
110
|
-
console.log('\nSynchronizing package-lock.json...');
|
|
111
|
-
await $`npm install --package-lock-only`;
|
|
112
|
-
|
|
113
|
-
console.log('\n✅ Instant version bump complete');
|
|
114
|
-
console.log(`Version: ${oldVersion} → ${newVersion}`);
|
|
115
|
-
} catch (error) {
|
|
116
|
-
console.error('Error during instant version bump:', error.message);
|
|
117
|
-
if (process.env.DEBUG) {
|
|
118
|
-
console.error('Stack trace:', error.stack);
|
|
119
|
-
}
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Publish to npm using OIDC trusted publishing
|
|
5
|
-
* Usage: node scripts/publish-to-npm.mjs [--should-pull]
|
|
6
|
-
* should_pull: Optional flag to pull latest changes before publishing (for release job)
|
|
7
|
-
*
|
|
8
|
-
* IMPORTANT: Update the PACKAGE_NAME constant below to match your package.json
|
|
9
|
-
*
|
|
10
|
-
* Uses link-foundation libraries:
|
|
11
|
-
* - use-m: Dynamic package loading without package.json dependencies
|
|
12
|
-
* - command-stream: Modern shell command execution with streaming support
|
|
13
|
-
* - lino-arguments: Unified configuration from CLI args, env vars, and .lenv files
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { readFileSync, appendFileSync } from 'fs';
|
|
17
|
-
|
|
18
|
-
const PACKAGE_NAME = '@link-assistant/web-capture';
|
|
19
|
-
|
|
20
|
-
// Load use-m dynamically
|
|
21
|
-
const { use } = eval(
|
|
22
|
-
await (await fetch('https://unpkg.com/use-m/use.js')).text()
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
// Import link-foundation libraries
|
|
26
|
-
const { $ } = await use('command-stream');
|
|
27
|
-
const { makeConfig } = await use('lino-arguments');
|
|
28
|
-
|
|
29
|
-
// Parse CLI arguments using lino-arguments
|
|
30
|
-
const config = makeConfig({
|
|
31
|
-
yargs: ({ yargs, getenv }) =>
|
|
32
|
-
yargs.option('should-pull', {
|
|
33
|
-
type: 'boolean',
|
|
34
|
-
default: getenv('SHOULD_PULL', false),
|
|
35
|
-
describe: 'Pull latest changes before publishing',
|
|
36
|
-
}),
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const { shouldPull } = config;
|
|
40
|
-
const MAX_RETRIES = 3;
|
|
41
|
-
const RETRY_DELAY = 10000; // 10 seconds
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Sleep for specified milliseconds
|
|
45
|
-
* @param {number} ms
|
|
46
|
-
*/
|
|
47
|
-
function sleep(ms) {
|
|
48
|
-
return new Promise((resolve) => globalThis.setTimeout(resolve, ms));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Append to GitHub Actions output file
|
|
53
|
-
* @param {string} key
|
|
54
|
-
* @param {string} value
|
|
55
|
-
*/
|
|
56
|
-
function setOutput(key, value) {
|
|
57
|
-
const outputFile = process.env.GITHUB_OUTPUT;
|
|
58
|
-
if (outputFile) {
|
|
59
|
-
appendFileSync(outputFile, `${key}=${value}\n`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function main() {
|
|
64
|
-
try {
|
|
65
|
-
if (shouldPull) {
|
|
66
|
-
// Pull the latest changes we just pushed
|
|
67
|
-
await $`git pull origin main`;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Get current version
|
|
71
|
-
const packageJson = JSON.parse(readFileSync('./package.json', 'utf8'));
|
|
72
|
-
const currentVersion = packageJson.version;
|
|
73
|
-
console.log(`Current version to publish: ${currentVersion}`);
|
|
74
|
-
|
|
75
|
-
// Check if this version is already published on npm
|
|
76
|
-
console.log(
|
|
77
|
-
`Checking if version ${currentVersion} is already published...`
|
|
78
|
-
);
|
|
79
|
-
const checkResult =
|
|
80
|
-
await $`npm view "${PACKAGE_NAME}@${currentVersion}" version`.run({
|
|
81
|
-
capture: true,
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
// command-stream returns { code: 0 } on success, { code: 1 } on failure (e.g., E404)
|
|
85
|
-
// Exit code 0 means version exists, non-zero means version not found
|
|
86
|
-
if (checkResult.code === 0) {
|
|
87
|
-
console.log(`Version ${currentVersion} is already published to npm`);
|
|
88
|
-
setOutput('published', 'true');
|
|
89
|
-
setOutput('published_version', currentVersion);
|
|
90
|
-
setOutput('already_published', 'true');
|
|
91
|
-
return;
|
|
92
|
-
} else {
|
|
93
|
-
// Version not found on npm (E404), proceed with publish
|
|
94
|
-
console.log(
|
|
95
|
-
`Version ${currentVersion} not found on npm, proceeding with publish...`
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Publish to npm using OIDC trusted publishing with retry logic
|
|
100
|
-
for (let i = 1; i <= MAX_RETRIES; i++) {
|
|
101
|
-
console.log(`Publish attempt ${i} of ${MAX_RETRIES}...`);
|
|
102
|
-
try {
|
|
103
|
-
await $`npm run changeset:publish`;
|
|
104
|
-
setOutput('published', 'true');
|
|
105
|
-
setOutput('published_version', currentVersion);
|
|
106
|
-
console.log(
|
|
107
|
-
`\u2705 Published ${PACKAGE_NAME}@${currentVersion} to npm`
|
|
108
|
-
);
|
|
109
|
-
return;
|
|
110
|
-
} catch (error) {
|
|
111
|
-
if (i < MAX_RETRIES) {
|
|
112
|
-
console.log(
|
|
113
|
-
`Publish failed: ${error.message}, waiting ${RETRY_DELAY / 1000}s before retry...`
|
|
114
|
-
);
|
|
115
|
-
await sleep(RETRY_DELAY);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
console.error(`\u274C Failed to publish after ${MAX_RETRIES} attempts`);
|
|
121
|
-
process.exit(1);
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.error('Error:', error.message);
|
|
124
|
-
process.exit(1);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
main();
|
package/scripts/setup-npm.mjs
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Update npm for OIDC trusted publishing
|
|
5
|
-
* npm trusted publishing requires npm >= 11.5.1
|
|
6
|
-
* Node.js 20.x ships with npm 10.x, so we need to update
|
|
7
|
-
*
|
|
8
|
-
* Uses link-foundation libraries:
|
|
9
|
-
* - use-m: Dynamic package loading without package.json dependencies
|
|
10
|
-
* - command-stream: Modern shell command execution with streaming support
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// Load use-m dynamically
|
|
14
|
-
const { use } = eval(
|
|
15
|
-
await (await fetch('https://unpkg.com/use-m/use.js')).text()
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
// Import command-stream for shell command execution
|
|
19
|
-
const { $ } = await use('command-stream');
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
// Get current npm version
|
|
23
|
-
const currentResult = await $`npm --version`.run({ capture: true });
|
|
24
|
-
const currentVersion = currentResult.stdout.trim();
|
|
25
|
-
console.log(`Current npm version: ${currentVersion}`);
|
|
26
|
-
|
|
27
|
-
// Update npm to latest
|
|
28
|
-
await $`npm install -g npm@latest`;
|
|
29
|
-
|
|
30
|
-
// Get updated npm version
|
|
31
|
-
const updatedResult = await $`npm --version`.run({ capture: true });
|
|
32
|
-
const updatedVersion = updatedResult.stdout.trim();
|
|
33
|
-
console.log(`Updated npm version: ${updatedVersion}`);
|
|
34
|
-
} catch (error) {
|
|
35
|
-
console.error('Error updating npm:', error.message);
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Validate changeset for CI - ensures exactly one valid changeset exists
|
|
5
|
-
*
|
|
6
|
-
* IMPORTANT: Update the package name below to match your package.json
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { readdirSync, readFileSync } from 'fs';
|
|
10
|
-
import { join } from 'path';
|
|
11
|
-
|
|
12
|
-
const PACKAGE_NAME = '@link-assistant/web-capture';
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
// Count changeset files (excluding README.md and config.json)
|
|
16
|
-
const changesetDir = '.changeset';
|
|
17
|
-
const changesetFiles = readdirSync(changesetDir).filter(
|
|
18
|
-
(file) => file.endsWith('.md') && file !== 'README.md'
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
const changesetCount = changesetFiles.length;
|
|
22
|
-
console.log(`Found ${changesetCount} changeset file(s)`);
|
|
23
|
-
|
|
24
|
-
// Ensure exactly one changeset file exists
|
|
25
|
-
if (changesetCount === 0) {
|
|
26
|
-
console.error(
|
|
27
|
-
"::error::No changeset found. Please add a changeset by running 'npm run changeset' and commit the result."
|
|
28
|
-
);
|
|
29
|
-
process.exit(1);
|
|
30
|
-
} else if (changesetCount > 1) {
|
|
31
|
-
console.error(
|
|
32
|
-
`::error::Multiple changesets found (${changesetCount}). Each PR should have exactly ONE changeset.`
|
|
33
|
-
);
|
|
34
|
-
console.error('::error::Found changeset files:');
|
|
35
|
-
changesetFiles.forEach((file) => console.error(` ${file}`));
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Get the changeset file
|
|
40
|
-
const changesetFile = join(changesetDir, changesetFiles[0]);
|
|
41
|
-
console.log(`Validating changeset: ${changesetFile}`);
|
|
42
|
-
|
|
43
|
-
// Read the changeset file
|
|
44
|
-
const content = readFileSync(changesetFile, 'utf-8');
|
|
45
|
-
|
|
46
|
-
// Check if changeset has a valid type (major, minor, or patch)
|
|
47
|
-
const versionTypeRegex = new RegExp(
|
|
48
|
-
`^['"]${PACKAGE_NAME}['"]:\\s+(major|minor|patch)`,
|
|
49
|
-
'm'
|
|
50
|
-
);
|
|
51
|
-
if (!versionTypeRegex.test(content)) {
|
|
52
|
-
console.error(
|
|
53
|
-
'::error::Changeset must specify a version type: major, minor, or patch'
|
|
54
|
-
);
|
|
55
|
-
console.error(`::error::Expected format in ${changesetFile}:`);
|
|
56
|
-
console.error('::error::---');
|
|
57
|
-
console.error(`::error::'${PACKAGE_NAME}': patch`);
|
|
58
|
-
console.error('::error::---');
|
|
59
|
-
console.error('::error::');
|
|
60
|
-
console.error('::error::Your description here');
|
|
61
|
-
console.error('\nFile content:');
|
|
62
|
-
console.error(content);
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Extract description (everything after the closing ---) and check it's not empty
|
|
67
|
-
const parts = content.split('---');
|
|
68
|
-
if (parts.length < 3) {
|
|
69
|
-
console.error(
|
|
70
|
-
'::error::Changeset must include a description of the changes'
|
|
71
|
-
);
|
|
72
|
-
console.error(
|
|
73
|
-
"::error::The description should appear after the closing '---' in the changeset file"
|
|
74
|
-
);
|
|
75
|
-
console.error(`::error::Current content of ${changesetFile}:`);
|
|
76
|
-
console.error(content);
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const description = parts.slice(2).join('---').trim();
|
|
81
|
-
if (!description) {
|
|
82
|
-
console.error(
|
|
83
|
-
'::error::Changeset must include a description of the changes'
|
|
84
|
-
);
|
|
85
|
-
console.error(
|
|
86
|
-
"::error::The description should appear after the closing '---' in the changeset file"
|
|
87
|
-
);
|
|
88
|
-
console.error(`::error::Current content of ${changesetFile}:`);
|
|
89
|
-
console.error(content);
|
|
90
|
-
process.exit(1);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Extract version type
|
|
94
|
-
const versionTypeMatch = content.match(versionTypeRegex);
|
|
95
|
-
const versionType = versionTypeMatch ? versionTypeMatch[1] : 'unknown';
|
|
96
|
-
|
|
97
|
-
console.log('✅ Changeset validation passed');
|
|
98
|
-
console.log(` Type: ${versionType}`);
|
|
99
|
-
console.log(` Description: ${description}`);
|
|
100
|
-
} catch (error) {
|
|
101
|
-
console.error('Error during changeset validation:', error.message);
|
|
102
|
-
if (process.env.DEBUG) {
|
|
103
|
-
console.error('Stack trace:', error.stack);
|
|
104
|
-
}
|
|
105
|
-
process.exit(1);
|
|
106
|
-
}
|