@vdaluz/astro-affiliate 1.1.1 → 1.2.0
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/README.md
CHANGED
|
@@ -110,25 +110,44 @@ Two ways to consume a channel, depending on where the affiliate link lives:
|
|
|
110
110
|
|
|
111
111
|
## Markdown links (`remarkAffiliate`)
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
The plugin runs on the remark/rehype pipeline from `@astrojs/markdown-remark`. Astro 7 no longer
|
|
114
|
+
installs it by default (its default Markdown processor is Sätteri), so install it alongside this
|
|
115
|
+
package:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
npm install @astrojs/markdown-remark
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
On Astro 6.4 and later, including Astro 7, pass the plugin to the `unified()` processor in
|
|
122
|
+
`astro.config.mjs`:
|
|
114
123
|
|
|
115
124
|
```js
|
|
125
|
+
import { unified } from '@astrojs/markdown-remark';
|
|
116
126
|
import { remarkAffiliate } from '@vdaluz/astro-affiliate/remark';
|
|
117
127
|
import { affiliate } from './src/config/affiliate';
|
|
118
128
|
|
|
119
129
|
export default defineConfig({
|
|
120
130
|
markdown: {
|
|
121
|
-
|
|
131
|
+
processor: unified({
|
|
132
|
+
remarkPlugins: [[remarkAffiliate, affiliate]],
|
|
133
|
+
}),
|
|
122
134
|
},
|
|
123
135
|
});
|
|
124
136
|
```
|
|
125
137
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
>
|
|
138
|
+
On Astro 6.0 to 6.3, which predate `markdown.processor` and bundle `@astrojs/markdown-remark`
|
|
139
|
+
themselves, use the top-level option instead: `markdown: { remarkPlugins: [[remarkAffiliate, affiliate]] }`.
|
|
140
|
+
Astro 6.4+ still accepts that form but deprecates it, and Astro 7 fails at config load with it
|
|
141
|
+
unless `@astrojs/markdown-remark` is installed.
|
|
142
|
+
|
|
143
|
+
> **Use the `[plugin, options]` tuple, not `remarkAffiliate(affiliate)` pre-invoked.** unified
|
|
144
|
+
> calls the plugin function itself with the options. Passing an already-invoked transformer means
|
|
145
|
+
> unified calls *that* as the plugin, with no document, and the build fails with
|
|
146
|
+
> `remarkAffiliate was passed pre-invoked`. Always verify by checking rendered HTML for the real
|
|
147
|
+
> resolved URL, not just a passing build.
|
|
148
|
+
|
|
149
|
+
Components-only consumers (`<AffiliateLink>`, `<AffiliateDisclosure>`) don't need
|
|
150
|
+
`@astrojs/markdown-remark`; it's an optional peer dependency.
|
|
132
151
|
|
|
133
152
|
Then in a post's markdown body:
|
|
134
153
|
|
|
@@ -204,7 +223,8 @@ const { affiliates = [] } = entry.data;
|
|
|
204
223
|
```
|
|
205
224
|
|
|
206
225
|
Renders one paragraph joining the disclosure text for every program in `affiliates`, or nothing
|
|
207
|
-
if the array is empty.
|
|
226
|
+
if the array is empty. A program named more than once (for example, one entry per card in a
|
|
227
|
+
card list) is disclosed once. Default styling is `text-sm text-muted italic`; pass `class` to override,
|
|
208
228
|
see [Per-app glue](#per-app-glue) for the token variables this assumes.
|
|
209
229
|
|
|
210
230
|
### Localized disclosure text
|
|
@@ -244,7 +264,8 @@ import { affiliate } from '../config/affiliate';
|
|
|
244
264
|
const disclosures = resolveDisclosures(affiliate, entry.data.affiliates ?? [], locale);
|
|
245
265
|
```
|
|
246
266
|
|
|
247
|
-
It returns the resolved text for each program name in order
|
|
267
|
+
It returns the resolved text for each distinct program name, in first-seen order - a name passed
|
|
268
|
+
more than once appears once (see [Localized disclosure
|
|
248
269
|
text](#localized-disclosure-text) for how `locale` selects between entries), and throws if any
|
|
249
270
|
name isn't a program declared in `config.programs` - the same guarantee `<AffiliateDisclosure>`
|
|
250
271
|
relies on internally, so a plain-text consumer can't silently drop a disclosure for a typo'd
|
|
@@ -323,7 +344,8 @@ Publishing / OIDC, no token secret):
|
|
|
323
344
|
|
|
324
345
|
1. Test before tagging: `npm pack`, install the tarball into a scratch Astro app (or a consumer
|
|
325
346
|
locally), `astro check && astro build`.
|
|
326
|
-
2. Bump
|
|
347
|
+
2. Bump the version with `npm version X.Y.Z --no-git-tag-version`, which updates `package.json`
|
|
348
|
+
and `package-lock.json` together, then commit both.
|
|
327
349
|
3. Tag `vX.Y.Z` and push the tag. Pushing the tag runs `.github/workflows/publish.yml`, which
|
|
328
350
|
type-checks, tests, verifies the tag matches `package.json`'s version, and only then runs
|
|
329
351
|
`npm publish`.
|
|
@@ -336,6 +358,8 @@ Publishing / OIDC, no token secret):
|
|
|
336
358
|
- [imperfectsystems.com](https://imperfectsystems.com)
|
|
337
359
|
- [freetoolbox.net](https://freetoolbox.net)
|
|
338
360
|
- [vicstradamus.com](https://vicstradamus.com)
|
|
361
|
+
- [deepcutatlas.com](https://deepcutatlas.com)
|
|
362
|
+
- [roomforstars.com](https://roomforstars.com)
|
|
339
363
|
|
|
340
364
|
## License
|
|
341
365
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vdaluz/astro-affiliate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "FTC-compliant affiliate-link catalog resolver and disclosure components - proven in production on vdaluz.com and imperfectsystems.com.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro",
|
|
@@ -37,10 +37,17 @@
|
|
|
37
37
|
"./AffiliateDisclosure.astro": "./src/components/AffiliateDisclosure.astro"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
+
"@astrojs/markdown-remark": ">=7.0.0",
|
|
40
41
|
"astro": ">=6.0.0"
|
|
41
42
|
},
|
|
43
|
+
"peerDependenciesMeta": {
|
|
44
|
+
"@astrojs/markdown-remark": {
|
|
45
|
+
"optional": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
42
48
|
"devDependencies": {
|
|
43
49
|
"@astrojs/check": "^0.9.10",
|
|
50
|
+
"@astrojs/markdown-remark": "^7.3.1",
|
|
44
51
|
"@types/node": "^26.1.1",
|
|
45
52
|
"astro": "^7.3.2",
|
|
46
53
|
"typescript": "^6.0.3"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type { AffiliateConfig } from '../lib/types';
|
|
3
|
-
import { resolveDisclosures } from '../lib/disclosures';
|
|
2
|
+
import type { AffiliateConfig } from '../lib/types.ts';
|
|
3
|
+
import { resolveDisclosures } from '../lib/disclosures.ts';
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
6
|
config: AffiliateConfig;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type { AffiliateConfig } from '../lib/types';
|
|
3
|
-
import { resolveAffiliate } from '../lib/resolve';
|
|
2
|
+
import type { AffiliateConfig } from '../lib/types.ts';
|
|
3
|
+
import { resolveAffiliate } from '../lib/resolve.ts';
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
6
|
config: AffiliateConfig;
|
package/src/lib/disclosures.ts
CHANGED
|
@@ -5,10 +5,11 @@ import { resolveLocalized } from './i18n.ts';
|
|
|
5
5
|
* Resolves a post's `affiliates:` frontmatter names to their disclosure text.
|
|
6
6
|
* Throws on an unknown program name instead of silently omitting its
|
|
7
7
|
* disclosure - a typo'd/renamed program must fail the build, not ship a
|
|
8
|
-
* page that uses the program without disclosing it.
|
|
8
|
+
* page that uses the program without disclosing it. Repeated program names
|
|
9
|
+
* collapse to one entry, in first-seen order.
|
|
9
10
|
*/
|
|
10
11
|
export function resolveDisclosures(config: AffiliateConfig, affiliates: string[], locale?: string): string[] {
|
|
11
|
-
return affiliates.map((name) => {
|
|
12
|
+
return [...new Set(affiliates)].map((name) => {
|
|
12
13
|
const program = config.programs[name];
|
|
13
14
|
if (!program) {
|
|
14
15
|
throw new Error(
|
package/src/lib/remark.ts
CHANGED
|
@@ -68,14 +68,21 @@ function assertNoRemainingAffiliateUrls(node: MdastNode) {
|
|
|
68
68
|
* For a reference-style link (`[text][ref]`), "document order" follows the
|
|
69
69
|
* position of the `[ref]: affiliate:key` definition, not the in-prose usage.
|
|
70
70
|
*
|
|
71
|
+
* import { unified } from '@astrojs/markdown-remark';
|
|
71
72
|
* import { remarkAffiliate } from '@vdaluz/astro-affiliate/remark';
|
|
72
73
|
*
|
|
73
74
|
* export default defineConfig({
|
|
74
|
-
* markdown: { remarkPlugins: [[remarkAffiliate, affiliate]] },
|
|
75
|
+
* markdown: { processor: unified({ remarkPlugins: [[remarkAffiliate, affiliate]] }) },
|
|
75
76
|
* });
|
|
76
77
|
*/
|
|
77
78
|
export function remarkAffiliate(config: AffiliateConfig) {
|
|
78
79
|
return (tree: MdastNode, file: VFileWithAstroFrontmatter) => {
|
|
80
|
+
// unified calls a pre-invoked remarkAffiliate(config) as the plugin attacher, with no tree.
|
|
81
|
+
if (!tree) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
'remarkAffiliate was passed pre-invoked. Pass it as a [remarkAffiliate, config] tuple instead.'
|
|
84
|
+
);
|
|
85
|
+
}
|
|
79
86
|
const linkNodes: MdastNode[] = [];
|
|
80
87
|
collectAffiliateLinkNodes(tree, linkNodes);
|
|
81
88
|
|