diff --git a/.github/semantic-release.md b/.github/semantic-release.md
new file mode 100644
index 0000000..86ba50d
--- /dev/null
+++ b/.github/semantic-release.md
@@ -0,0 +1,158 @@
+# Semantic Release Configuration
+
+This repository uses a custom semantic release configuration to provide enhanced changelog generation and GitHub interaction.
+
+## Features
+
+### ๐ Enhanced Changelog
+
+The changelog automatically categorizes commits with emojis and includes contributor information:
+
+- โจ **Features** - New functionality (`feat` commits)
+- ๐ฉน **Fixes** - Bug fixes (`fix` commits)
+- ๐ **Documentation** - Documentation updates (`docs` commits)
+- ๐ ๏ธ **Internals** - Internal changes (`refactor`, `style`, `test`, `build`, `ci`, `chore` commits)
+- โก **Performance** - Performance improvements (`perf` commits)
+- โฉ๏ธ **Reverts** - Reverted changes (`revert` commits)
+- โ ๏ธ **BREAKING CHANGES** - Breaking changes (commits with `BREAKING CHANGE` footer)
+
+Each commit entry includes:
+
+- Scope (if provided)
+- Commit message with linked issues and usernames
+- Commit hash link
+- Author attribution (@username)
+
+### ๐ฌ Custom GitHub Comments
+
+#### Issue Comments
+
+**For Pre-releases:**
+
+```
+๐ This issue is included in version X.X.X-next.X which is now available for testing! ๐งช
+
+๐ฆ NPM: astro-loader-pocketbase@X.X.X-next.X
+๐ GitHub Release: X.X.X-next.X
+
+@username Can you check if everything works as expected in your project with this new version? Any feedback is welcome.
+
+This change will be included in the next regular release.
+```
+
+**For Regular Releases:**
+
+```
+๐ This issue is included in version X.X.X which is now available! ๐
+
+๐ฆ NPM: astro-loader-pocketbase@X.X.X
+๐ GitHub Release: X.X.X
+```
+
+#### Pull Request Comments
+
+**For Pre-releases:**
+
+```
+๐ This PR is included in version X.X.X-next.X which is now available for testing! ๐งช
+
+๐ฆ NPM: astro-loader-pocketbase@X.X.X-next.X
+๐ GitHub Release: X.X.X-next.X
+
+@username Thank you for your contribution!
+
+This change will be included in the next regular release.
+```
+
+**For Regular Releases:**
+
+```
+๐ This PR is included in version X.X.X which is now available! ๐
+
+๐ฆ NPM: astro-loader-pocketbase@X.X.X
+๐ GitHub Release: X.X.X
+
+Thank you for your contribution!
+```
+
+### ๐ Documentation
+
+Added comprehensive documentation in `.github/semantic-release.md` explaining:
+
+- How the new changelog categories work
+- Examples of issue and PR comment templates
+- Configuration file structure
+- Commit types and their release impact
+
+### ๐ป Example Changelog Entry
+
+Here's an example of how a changelog entry would look for a release like [PR #48](https://github.com/pawcoding/astro-loader-pocketbase/pull/48):
+
+```markdown
+## 2.7.1 (2025-08-10)
+
+### ๐ฉน Fixes
+
+- Cleanup entries correctly when using `idField` configuration option ([a1b2c3d](https://github.com/pawcoding/astro-loader-pocketbase/commit/a1b2c3d)) by @pawcoding
+
+### ๐ ๏ธ Internals
+
+- Replace `eslint` with `oxlint` to make linting tasks even faster ([d4e5f6g](https://github.com/pawcoding/astro-loader-pocketbase/commit/d4e5f6g)) by @pawcoding
+- Setup for Copilot and other agents ([h7i8j9k](https://github.com/pawcoding/astro-loader-pocketbase/commit/h7i8j9k)) by @pawcoding
+- Add GitHub issue templates for better bug reporting and feature requests ([l0m1n2o](https://github.com/pawcoding/astro-loader-pocketbase/commit/l0m1n2o)) by @pawcoding
+- Update dependencies to latest versions ([p3q4r5s](https://github.com/pawcoding/astro-loader-pocketbase/commit/p3q4r5s)) by @pawcoding
+
+[2.7.1](https://github.com/pawcoding/astro-loader-pocketbase/compare/2.7.0...2.7.1) (5 commits)
+```
+
+## Configuration Files
+
+### `release.config.cjs`
+
+Main configuration file that sets up:
+
+- Commit analysis rules
+- Release notes generation with custom templates
+- Changelog generation
+- NPM publishing
+- Git asset updates
+- GitHub releases and comments
+
+### `.semantic-release/templates/`
+
+Custom Handlebars templates for changelog generation:
+
+- `template.hbs` - Main changelog template with emoji categories
+- `header.hbs` - Release header format
+- `commit.hbs` - Individual commit entry format with contributor attribution
+- `footer.hbs` - Release footer with links and commit count
+
+## Release Branches
+
+- **`master`** - Stable releases (latest)
+- **`next`** - Pre-releases for testing (next channel)
+
+## Commit Types and Release Impact
+
+| Type | Description | Release | Changelog Section |
+| ---------- | ---------------------------- | ------- | ----------------- |
+| `feat` | New feature | Minor | โจ Features |
+| `fix` | Bug fix | Patch | ๐ฉน Fixes |
+| `docs` | Documentation (README scope) | Patch | ๐ Documentation |
+| `docs` | Other documentation | None | ๐ Documentation |
+| `refactor` | Code refactoring | Patch | ๐ ๏ธ Internals |
+| `style` | Code style changes | Patch | ๐ ๏ธ Internals |
+| `test` | Adding/updating tests | None | ๐ ๏ธ Internals |
+| `build` | Build system (deps scope) | Patch | ๐ ๏ธ Internals |
+| `build` | Other build changes | None | ๐ ๏ธ Internals |
+| `ci` | CI configuration | None | ๐ ๏ธ Internals |
+| `chore` | Maintenance tasks | None | ๐ ๏ธ Internals |
+| `perf` | Performance improvements | Patch | โก Performance |
+
+## Breaking Changes
+
+Commits with `BREAKING CHANGE` or `BREAKING CHANGES` in the footer will:
+
+- Trigger a major release
+- Be listed in a special "โ ๏ธ BREAKING CHANGES" section
+- Include migration information from the commit footer
diff --git a/.prettierignore b/.prettierignore
index c2fe8b4..1696b31 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -31,3 +31,6 @@ pnpm-debug.log*
.prettierignore
.gitignore
.nvmrc
+
+# semantic-release templates (handlebars)
+.semantic-release/templates/
diff --git a/.semantic-release/templates/commit.hbs b/.semantic-release/templates/commit.hbs
new file mode 100644
index 0000000..2e86076
--- /dev/null
+++ b/.semantic-release/templates/commit.hbs
@@ -0,0 +1,24 @@
+*
+{{#if commit.scope}}**{{commit.scope}}:** {{/if}}{{#if
+ commit.subject
+}}{{commit.subject}}{{else}}{{commit.header}}{{/if}}
+
+{{~! commit link }}
+{{#if @root.linkReferences~}}
+ ([{{hash}}]({{@root.repository}}/{{@root.commit}}/{{hash}}))
+{{~else}}
+ {{~#if @root.repository}}
+ ([{{hash}}]({{@root.repository}}/{{@root.commit}}/{{hash}}))
+ {{~/if}}
+{{~/if}}
+
+{{~! commit references }}
+{{~#if references~}}
+ {{~#each references}}
+ {{#if
+ @root.linkReferences
+ }}([{{this.issue}}]({{@root.repository}}/{{@root.issue}}/{{this.issue}})){{else}}{{this.issue}}{{/if}}{{/each}}
+{{~/if}}
+
+{{~! commit author }}
+{{~#if commit.author.name}} by @{{commit.author.name}}{{/if}}
\ No newline at end of file
diff --git a/.semantic-release/templates/footer.hbs b/.semantic-release/templates/footer.hbs
new file mode 100644
index 0000000..5869f08
--- /dev/null
+++ b/.semantic-release/templates/footer.hbs
@@ -0,0 +1,35 @@
+{{#if host}}
+ {{~! release link }}
+ {{~#if linkCompare}}
+ {{~#if previousTag}}
+ {{~#if currentTag}}
+ [{{currentTag}}]({{host}}/{{owner}}/{{repository}}/{{compareUrlFormat}}/{{previousTag}}...{{currentTag}})
+ {{~else}}
+ {{~currentTag}}
+ {{~/if}}
+ {{~else}}
+ {{~#if currentTag}}
+ {{~currentTag}}
+ {{~/if}}
+ {{~/if}}
+ {{~else}}
+ {{~#if currentTag}}
+ {{~currentTag}}
+ {{~/if}}
+ {{~/if}}
+
+ {{~! commit range }}
+ {{~#if commitsUrl}}
+ {{~#if previousTag}}
+ ([{{shortHash}}.{{previousTag}}]({{host}}/{{owner}}/{{repository}}/{{commitsUrlFormat}}/{{previousTag}}..{{currentTag}}))
+ {{~else}}
+ ([{{shortHash}}]({{host}}/{{owner}}/{{repository}}/{{commitsUrlFormat}}/{{currentTag}}))
+ {{~/if}}
+ {{~/if}}
+
+ {{~! commit count }}
+ {{~#if (gt commits.length 0)}}
+ ({{commits.length}}
+ commit{{#unless (eq commits.length 1)}}s{{/unless}})
+ {{~/if}}
+{{~/if}}
\ No newline at end of file
diff --git a/.semantic-release/templates/header.hbs b/.semantic-release/templates/header.hbs
new file mode 100644
index 0000000..0f94dac
--- /dev/null
+++ b/.semantic-release/templates/header.hbs
@@ -0,0 +1,4 @@
+{{#if version~}}
+ ##
+ {{#if title}}{{title}}{{else}}{{version}}{{/if}}{{#if date}} ({{date}}){{/if}}
+{{~/if}}
\ No newline at end of file
diff --git a/.semantic-release/templates/template.hbs b/.semantic-release/templates/template.hbs
new file mode 100644
index 0000000..57eef04
--- /dev/null
+++ b/.semantic-release/templates/template.hbs
@@ -0,0 +1,40 @@
+{{> header}}
+
+{{#each commitGroups}}
+
+{{#if title}}
+{{#if (eq title 'Features')}}
+### โจ Features
+{{else if (eq title 'Bug Fixes')}}
+### ๐ฉน Fixes
+{{else if (eq title 'Documentation')}}
+### ๐ Documentation
+{{else if (eq title 'Internals')}}
+### ๐ ๏ธ Internals
+{{else if (eq title 'Performance Improvements')}}
+### โก Performance
+{{else if (eq title 'Reverts')}}
+### โฉ๏ธ Reverts
+{{else}}
+### {{title}}
+{{/if}}
+
+{{/if}}
+{{#each commits}}
+{{> commit root=@root}}
+{{/each}}
+
+{{/each}}
+
+{{#if noteGroups}}
+{{#each noteGroups}}
+
+### โ ๏ธ BREAKING CHANGES
+
+{{#each notes}}
+* {{#if commit.scope}}**{{commit.scope}}:** {{/if}}{{text}}
+{{/each}}
+{{/each}}
+
+{{/if}}
+{{> footer}}
\ No newline at end of file
diff --git a/.semantic-release/utils/transform-commit.js b/.semantic-release/utils/transform-commit.js
new file mode 100644
index 0000000..9851016
--- /dev/null
+++ b/.semantic-release/utils/transform-commit.js
@@ -0,0 +1,78 @@
+/**
+ * Transform function for semantic-release commit processing
+ * Categorizes commits and processes issue/PR links
+ */
+function transformCommit(commit, context) {
+ const issues = [];
+
+ commit.notes.forEach((note) => {
+ note.title = "BREAKING CHANGES";
+ });
+
+ // Group different commit types under appropriate categories
+ if (commit.type === "feat") {
+ commit.type = "Features";
+ } else if (commit.type === "fix") {
+ commit.type = "Bug Fixes";
+ } else if (commit.type === "docs") {
+ commit.type = "Documentation";
+ } else if (
+ ["style", "refactor", "test", "build", "ci", "chore"].includes(commit.type)
+ ) {
+ commit.type = "Internals";
+ } else if (commit.type === "perf") {
+ commit.type = "Performance Improvements";
+ } else if (commit.revert) {
+ commit.type = "Reverts";
+ } else {
+ return;
+ }
+
+ if (commit.scope === "*") {
+ commit.scope = "";
+ }
+
+ if (typeof commit.hash === "string") {
+ commit.shortHash = commit.hash.substring(0, 7);
+ }
+
+ if (typeof commit.subject === "string") {
+ let url = context.repository
+ ? `${context.host}/${context.owner}/${context.repository}`
+ : context.repoUrl;
+ if (url) {
+ url = `${url}/issues/`;
+ // Issue URLs.
+ commit.subject = commit.subject.replace(/#([0-9]+)/g, (_, issue) => {
+ issues.push(issue);
+ return `[#${issue}](${url}${issue})`;
+ });
+ }
+ if (context.host) {
+ // User URLs.
+ commit.subject = commit.subject.replace(
+ /\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g,
+ (_, username) => {
+ if (username.includes("/")) {
+ return `@${username}`;
+ }
+
+ return `[@${username}](${context.host}/${username})`;
+ }
+ );
+ }
+ }
+
+ // remove references that already appear in the subject
+ commit.references = commit.references.filter((reference) => {
+ if (issues.indexOf(reference.issue) === -1) {
+ return true;
+ }
+
+ return false;
+ });
+
+ return commit;
+}
+
+module.exports = { transformCommit };
diff --git a/release.config.cjs b/release.config.cjs
index ff3338b..e681896 100644
--- a/release.config.cjs
+++ b/release.config.cjs
@@ -1,3 +1,9 @@
+const fs = require("fs");
+const path = require("path");
+const {
+ transformCommit
+} = require("./.semantic-release/utils/transform-commit");
+
const branch = process.env.GITHUB_REF_NAME;
const assetsToUpdate = ["package.json", "package-lock.json"];
@@ -31,7 +37,27 @@ const config = {
noteKeywords: ["BREAKING CHANGE", "BREAKING CHANGES"]
},
writerOpts: {
- commitsSort: ["subject", "scope"]
+ commitsSort: ["subject", "scope"],
+ groupBy: "type",
+ commitGroupsSort: "title",
+ noteGroupsSort: "title",
+ mainTemplate: fs.readFileSync(
+ path.join(__dirname, ".semantic-release/templates/template.hbs"),
+ "utf-8"
+ ),
+ headerPartial: fs.readFileSync(
+ path.join(__dirname, ".semantic-release/templates/header.hbs"),
+ "utf-8"
+ ),
+ commitPartial: fs.readFileSync(
+ path.join(__dirname, ".semantic-release/templates/commit.hbs"),
+ "utf-8"
+ ),
+ footerPartial: fs.readFileSync(
+ path.join(__dirname, ".semantic-release/templates/footer.hbs"),
+ "utf-8"
+ ),
+ transform: transformCommit
}
}
],
@@ -52,7 +78,18 @@ const config = {
"@semantic-release/github",
{
successCommentCondition:
- '<% return issue.pull_request || !nextRelease.channel || !issue.labels.some(label => label.name === "released on @next"); %>'
+ '<% return issue.pull_request || !nextRelease.channel || !issue.labels.some(label => label.name === "released on @next"); %>',
+ successComment: `<% if (nextRelease.channel) { %>:tada: This <%= issue.pull_request ? 'PR' : 'issue' %> is included in version <%= nextRelease.version %> which is now available for testing! :test_tube:
+
+๐ฆ **NPM:** [\`<%= package.name %>@<%= nextRelease.version %>\`](https://www.npmjs.com/package/<%= package.name %>/v/<%= nextRelease.version %>)
+๐ **GitHub Release:** [<%= nextRelease.version %>](<%= releases[0].url %>)
+
+<%= issue.pull_request ? '@' + issue.pull_request.user.login + ' Thank you for your contribution!' : '@' + issue.user.login + ' Can you check if everything works as expected in your project with this new version? Any feedback is welcome.' %>
+
+This change will be included in the next regular release.<% } else { %>:tada: This <%= issue.pull_request ? 'PR' : 'issue' %> is included in version <%= nextRelease.version %> which is now available! :rocket:
+
+๐ฆ **NPM:** [\`<%= package.name %>@<%= nextRelease.version %>\`](https://www.npmjs.com/package/<%= package.name %>/v/<%= nextRelease.version %>)
+๐ **GitHub Release:** [<%= nextRelease.version %>](<%= releases[0].url %>)<%= issue.pull_request ? '\\n\\nThank you for your contribution!' : '' %><% } %>`
}
]
]