Shared lexicon schemas for long-form publishing on AT Protocol. Uses typescript to json via prototypey.

Add author lexicon #1

closed opened by tylerjfisher.com targeting main from tylerjfisher.com/lexicons: main

This adds a site.standard.author lexicon and an optional array of references in site.standard.document to the author lexicon.

{
	"lexicon": 1,
	"id": "site.standard.author",
	"defs": {
		"main": {
			"type": "record",
			"key": "tid",
			"record": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"required": true,
						"description": "Full name of the author."
					},
					"title": {
						"type": "string",
						"maxLength": 1280,
						"maxGraphemes": 128,
						"description": "Author's title as it relates to the organization. e.g. Executive Editor."
					},
					"bio": {
						"type": "string",
						"maxLength": 3000,
						"maxGraphemes": 300,
						"description": "A short biography of the author."
					},
					"image": {
						"type": "blob",
						"maxSize": 1000000,
						"accept": [
							"image/*"
						],
						"description": "Optional image to use in reference to the author. Less than 1MB is size."
					},
					"atprotoIdRef": {
						"type": "ref",
						"ref": "com.atproto.repo.strongRef",
						"description": "Optional strong reference to an ATProto did representing the author."
					}
				},
				"required": [
					"name"
				]
			}
		}
	}
}
Labels

None yet.

assignee

None yet.

Participants 2
AT URI
at://did:plc:2hgmrwevidwsxundvejdeam5/sh.tangled.repo.pull/3mbtht2glny22
+116 -59
Diff #0
+36
src/lexicons/site.standard.author.ts
··· 1 + import { lx } from "prototypey"; 2 + import { MB } from "../constants.ts"; 3 + 4 + export const siteStandardAuthor = lx.lexicon("site.standard.author", { 5 + main: lx.record({ 6 + key: "tid", 7 + type: "record", 8 + record: lx.object({ 9 + name: lx.string({ 10 + required: true, 11 + description: "Full name of the author.", 12 + }), 13 + title: lx.string({ 14 + maxLength: 1280, 15 + maxGraphemes: 128, 16 + description: 17 + "Author's title as it relates to the organization. e.g. Executive Editor.", 18 + }), 19 + bio: lx.string({ 20 + maxLength: 3000, 21 + maxGraphemes: 300, 22 + description: "A short biography of the author.", 23 + }), 24 + image: lx.blob({ 25 + maxSize: 1 * MB, 26 + accept: ["image/*"], 27 + description: 28 + "Optional image to use in reference to the author. Less than 1MB is size.", 29 + }), 30 + atprotoIdRef: lx.ref("com.atproto.repo.strongRef", { 31 + description: 32 + "Optional strong reference to an ATProto did representing the author.", 33 + }), 34 + }), 35 + }), 36 + });
+80 -59
src/lexicons/site.standard.document.ts
··· 1 - import { lx } from 'prototypey' 2 - import { MB } from '../constants.ts' 1 + import { lx } from "prototypey"; 2 + import { siteStandardAuthor } from "./site.standard.author.ts"; 3 + import { MB } from "../constants.ts"; 3 4 4 - export const siteStandardDocument = lx.lexicon('site.standard.document', { 5 - main: lx.record({ 6 - key: 'tid', 7 - type: 'record', 8 - record: lx.object({ 9 - site: lx.string({ 10 - required: true, 11 - format: 'uri', 12 - description: 'Required URI for parent site or publication (https:// or at://). Use https:// for loose documents. Avoid trailing slashes.' 13 - }), 14 - path: lx.string({ 15 - description: 'Optional path, combined with site or publication url value to construct a full url to the document. Prepend with a leading slash.' 16 - }), 17 - title: lx.string({ 18 - required: true, 19 - maxLength: 1280, 20 - maxGraphemes: 128, 21 - description: 'Required title of the document.' 22 - }), 23 - description: lx.string({ 24 - maxLength: 3000, 25 - maxGraphemes: 300, 26 - description: 'Optional brief description or expert of the document.' 27 - }), 28 - coverImage: lx.blob({ 29 - maxSize: 1 * MB, 30 - accept: ['image/*'], 31 - description: 'Optional image to use as the documents cover. Less than 1MB is size.' 32 - }), 33 - content: lx.union([], { 34 - closed: false, 35 - description: 'Optional open union to construct content within the record. Can be extended with other lexicons to define any content format.' 36 - }), 37 - textContent: lx.string({ 38 - description: 'Optional plaintext representation of the documents contents. Useful for search and other cases.' 39 - }), 40 - bskyPostRef: lx.ref('com.atproto.repo.strongRef', { 41 - description: 'Optional strong reference to a Bluesky post. Useful to keep track of comments off-platform.' 42 - }), 43 - tags: lx.array({ 44 - type: 'string', 45 - }, { 46 - maxLength: 100, 47 - description: 'Optional array of strings used to tag/categorize the document. Avoid prepending tags with hashtags ("#").' 48 - }), 49 - publishedAt: lx.string({ 50 - required: true, 51 - format: 'datetime', 52 - description: 'Required timestamp of the documents publication.' 53 - }), 54 - updatedAt: lx.string({ 55 - format: 'datetime', 56 - description: 'Optional timestamp of the documents last edit.' 57 - }) 58 - }), 59 - }) 60 - }) 5 + export const siteStandardDocument = lx.lexicon("site.standard.document", { 6 + main: lx.record({ 7 + key: "tid", 8 + type: "record", 9 + record: lx.object({ 10 + site: lx.string({ 11 + required: true, 12 + format: "uri", 13 + description: 14 + "Required URI for parent site or publication (https:// or at://). Use https:// for loose documents. Avoid trailing slashes.", 15 + }), 16 + path: lx.string({ 17 + description: 18 + "Optional path, combined with site or publication url value to construct a full url to the document. Prepend with a leading slash.", 19 + }), 20 + title: lx.string({ 21 + required: true, 22 + maxLength: 1280, 23 + maxGraphemes: 128, 24 + description: "Required title of the document.", 25 + }), 26 + description: lx.string({ 27 + maxLength: 3000, 28 + maxGraphemes: 300, 29 + description: "Optional brief description or expert of the document.", 30 + }), 31 + coverImage: lx.blob({ 32 + maxSize: 1 * MB, 33 + accept: ["image/*"], 34 + description: 35 + "Optional image to use as the documents cover. Less than 1MB is size.", 36 + }), 37 + content: lx.union([], { 38 + closed: false, 39 + description: 40 + "Optional open union to construct content within the record. Can be extended with other lexicons to define any content format.", 41 + }), 42 + textContent: lx.string({ 43 + description: 44 + "Optional plaintext representation of the documents contents. Useful for search and other cases.", 45 + }), 46 + bskyPostRef: lx.ref("com.atproto.repo.strongRef", { 47 + description: 48 + "Optional strong reference to a Bluesky post. Useful to keep track of comments off-platform.", 49 + }), 50 + authors: lx.array( 51 + { 52 + type: "ref", 53 + ref: siteStandardAuthor.json.id, 54 + }, 55 + { 56 + description: 57 + "Optional array of strong references to site.standard.author records.", 58 + }, 59 + ), 60 + tags: lx.array( 61 + { 62 + type: "string", 63 + }, 64 + { 65 + maxLength: 100, 66 + description: 67 + 'Optional array of strings used to tag/categorize the document. Avoid prepending tags with hashtags ("#").', 68 + }, 69 + ), 70 + publishedAt: lx.string({ 71 + required: true, 72 + format: "datetime", 73 + description: "Required timestamp of the documents publication.", 74 + }), 75 + updatedAt: lx.string({ 76 + format: "datetime", 77 + description: "Optional timestamp of the documents last edit.", 78 + }), 79 + }), 80 + }), 81 + });

History

3 rounds 3 comments
sign up or login to add to the discussion
3 commits
expand
add author lexicon
properly reference did in author
rename to did
expand 3 comments

My bad, atProtoIdRef makes more sense as just a did string. Here's the updaed lexicon:

{
	"lexicon": 1,
	"id": "site.standard.author",
	"defs": {
		"main": {
			"type": "record",
			"key": "tid",
			"record": {
				"type": "object",
				"properties": {
					"name": {
						"type": "string",
						"required": true,
						"description": "Full name of the author."
					},
					"title": {
						"type": "string",
						"maxLength": 1280,
						"maxGraphemes": 128,
						"description": "Author's title as it relates to the organization. e.g. Executive Editor."
					},
					"bio": {
						"type": "string",
						"maxLength": 3000,
						"maxGraphemes": 300,
						"description": "A short biography of the author."
					},
					"image": {
						"type": "blob",
						"maxSize": 1000000,
						"accept": [
							"image/*"
						],
						"description": "Optional image to use in reference to the author. Less than 1MB is size."
					},
					"did": {
						"type": "string",
						"format": "did",
						"description": "Optional DID representing the author"
					}
				},
				"required": [
					"name"
				]
			}
		}
	}
}

this is a great conversation to start. i have been trying to figure out how to solve this for @offprint.app and wrote down a proposal here: https://dad.leaflet.pub/3mburumcnbs2m

guest and multi-authorship ends up touching permissions, verification, ownership, and persistence in ways that need some careful thought. i think this deserves a larger discussion and some experimentation on individual publications and platforms before we converge on a standard.

i'd love to get something like this into the lexicon set. it just needs a little more coordination before we do.

Thanks for the thoughtful response! I realize this PR reads more final than I intended, I also think the project should have a larger discussion before accepting a new lexicon. If an issue would be a more appropriate place for the discussion, feel free to reject this PR and move the conversation. I'll leave my thoughts on your proposal here for the sake of continuity.

I think your solutions on permissions and verification are smart! I'd love to see those as part of standard.site.

I have a question about ownership and persistence. For context, I'm thinking about how existing large publications, especially news organizations, might adopt site.standard for document metadata or even full content. I imagine this happening via CMS plugins (e.g. WordPress), or perhaps some form of RSS bridge. If this is not a goal for site.standard, then perhaps my question are irrelevant.

For most existing journalistic publications, the publication fully owns the document produced, whether by an employee or a freelance contributor. Every contract I have signed with a news organization has language to this effect. How would this model reconcile that with authors owning the documents in their PDS? Similarly, authors having complete control over the persistence of a document would be problematic in this traditional relationship between author and publication.

Thanks for all your work on this project and for responding to this proposal!

closed without merging
2 commits
expand
add author lexicon
properly reference did in author
expand 0 comments
tylerjfisher.com submitted #0
1 commit
expand
add author lexicon
expand 0 comments