diff --git a/docs/manifest/writing/assertions-actions.md b/docs/manifest/writing/assertions-actions.md
index 219c670..b46c09d 100644
--- a/docs/manifest/writing/assertions-actions.md
+++ b/docs/manifest/writing/assertions-actions.md
@@ -280,11 +280,6 @@ The [C2PA Technical Specification](https://c2pa.org/specifications/specification
V1 actions are fully specified in the `actions` array. However, a v2 action may either be fully specified in an element of the `actions` array or it may be derived from an element in the `templates` array with the same action name.
-
-The CAI APIs can read all v2 actions and write **most** v2 actions.
-We should document v2 actions that can it NOT write.
-
-
### Action names
The value of the `action` property must be either one of the pre-defined [standard C2PA action strings](https://c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_actions) of the form `c2pa.*` or a custom action name. The set of standard C2PA actions includes fundamental ones as `c2pa.created` for when an asset is first created, and others (`c2pa.cropped`, `c2pa.resized`, and so on) for when an asset's content is modified in some way.
diff --git a/docusaurus.config.js b/docusaurus.config.js
index d7f9f01..5fce0ea 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -9,6 +9,7 @@ const darkCodeTheme = require('prism-react-renderer').themes.dracula;
const remoteDocs = require('./remote-docs.json');
const { readFileSync } = require('fs');
const { resolve } = require('path');
+const remarkStripHiddenLinks = require('./src/remark/remark-strip-hidden-links');
const copyright = `
@@ -164,7 +165,10 @@ async function createConfig() {
/** @type {import('@docusaurus/preset-classic').Options} */
({
docs: {
- beforeDefaultRemarkPlugins: [remarkGithubAdmonitionsToDirectives],
+ beforeDefaultRemarkPlugins: [
+ remarkGithubAdmonitionsToDirectives,
+ remarkStripHiddenLinks,
+ ],
sidebarPath: require.resolve('./sidebars.js'),
editUrl: ({ docPath, versionDocsDirPath }) => {
const normalizedDocPath = docPath.toLowerCase();
diff --git a/remote-docs.json b/remote-docs.json
index c53b850..c11d739 100644
--- a/remote-docs.json
+++ b/remote-docs.json
@@ -167,11 +167,20 @@
"dest": "docs/rust-sdk/docs/release-notes.md",
"sidebar": {
"category": "rust-sdk",
- "label": "Release notes",
+ "label": "Release notes (Rust)",
"order": 10
}
},
-
+ {
+ "repo": "contentauth/c2pa-rs",
+ "path": "docs/instanceid_behavior.md",
+ "dest": "docs/rust-sdk/docs/instanceid-behavior.md",
+ "sidebar": {
+ "category": "rust-sdk",
+ "label": "InstanceID behavior",
+ "order": 11
+ }
+ },
{ "_comment": "Working with the SDK" },
{
"repo": "contentauth/c2pa-rs",
@@ -278,7 +287,7 @@
"dest": "docs/c2pa-python/docs/release-notes.md",
"sidebar": {
"category": "c2pa-python",
- "label": "Release notes",
+ "label": "Release notes (Python)",
"order": 9
}
},
@@ -326,7 +335,7 @@
"dest": "docs/c2pa-cpp/docs/context-settings.md",
"sidebar": {
"category": "c2pa-cpp",
- "label": "Configuring the SDK",
+ "label": "Configuring SDK settings",
"order": 3
}
},
@@ -376,7 +385,7 @@
"dest": "docs/c2pa-cpp/docs/release-notes.md",
"sidebar": {
"category": "c2pa-cpp",
- "label": "Release notes",
+ "label": "Release notes (C++",
"order": 8
}
},
diff --git a/src/remark/remark-strip-hidden-links.js b/src/remark/remark-strip-hidden-links.js
new file mode 100644
index 0000000..6ebf80b
--- /dev/null
+++ b/src/remark/remark-strip-hidden-links.js
@@ -0,0 +1,72 @@
+/**
+ * Docusaurus's broken-link checker collects links from rendered
elements
+ * regardless of CSS visibility, so links inside GitHub-only content (hidden on
+ * this site via the "github-only" class or a display:none style, but meant to
+ * work when the source markdown is viewed on GitHub) get flagged as broken.
+ *
+ * This plugin unwraps markdown links found inside such hidden containers,
+ * before they become elements, so they're never collected.
+ */
+
+const CLASS_RE = /(^|\s)github-only(\s|$)/;
+const DISPLAY_NONE_RE = /display\s*:\s*['"]none['"]/;
+
+function isHiddenDiv(node) {
+ if (
+ !node ||
+ (node.type !== 'mdxJsxFlowElement' && node.type !== 'mdxJsxTextElement') ||
+ node.name !== 'div'
+ ) {
+ return false;
+ }
+ const attributes = node.attributes || [];
+ return attributes.some((attr) => {
+ if (attr.type !== 'mdxJsxAttribute') return false;
+ if (
+ (attr.name === 'class' || attr.name === 'className') &&
+ typeof attr.value === 'string'
+ ) {
+ return CLASS_RE.test(attr.value);
+ }
+ if (attr.name === 'style') {
+ const raw =
+ attr.value && typeof attr.value === 'object'
+ ? attr.value.value
+ : attr.value;
+ return typeof raw === 'string' && DISPLAY_NONE_RE.test(raw);
+ }
+ return false;
+ });
+}
+
+// Replace link/linkReference nodes with their child content, in place.
+function stripLinks(node) {
+ if (!node || !Array.isArray(node.children)) return;
+ node.children = node.children.flatMap((child) => {
+ stripLinks(child);
+ if (child.type === 'link' || child.type === 'linkReference') {
+ return child.children || [];
+ }
+ return [child];
+ });
+}
+
+function visit(node) {
+ if (!node) return;
+ if (isHiddenDiv(node)) {
+ // stripLinks recurses through the whole hidden subtree itself.
+ stripLinks(node);
+ return;
+ }
+ if (Array.isArray(node.children)) {
+ node.children.forEach((child) => visit(child));
+ }
+}
+
+function remarkStripHiddenLinks() {
+ return (tree) => {
+ visit(tree);
+ };
+}
+
+module.exports = remarkStripHiddenLinks;