Add schema for Lexicon-defined API #3

closed
opened by hexmani.ac targeting main from lexicons-extension

This will build the foundations for a basic Lexicon-defined API to be used by the backend. Right now I'm focusing solely on implementing ways to get indexed content from the database as well as a basic "preferences" system similar to was Bluesky has, mainly for expanding private preferences in the future once we move to the frontend. There are also some search query lexicons in there, just for good measure.

+27
.idea/jsonSchemas.xml
···
+
<?xml version="1.0" encoding="UTF-8"?>
+
<project version="4">
+
<component name="JsonSchemaMappingsProjectConfiguration">
+
<state>
+
<map>
+
<entry key="Lexicon Schema">
+
<value>
+
<SchemaInfo>
+
<option name="generatedName" value="New Schema" />
+
<option name="name" value="Lexicon Schema" />
+
<option name="relativePathToSchema" value="https://cdn.justdavi.dev/lexiconschema.json" />
+
<option name="patterns">
+
<list>
+
<Item>
+
<option name="directory" value="true" />
+
<option name="path" value="lexdocs" />
+
<option name="mappingKind" value="Directory" />
+
</Item>
+
</list>
+
</option>
+
</SchemaInfo>
+
</value>
+
</entry>
+
</map>
+
</state>
+
</component>
+
</project>
+3 -3
backend/README.md
···
## current status
right now we're not running on bun because there are
-
[some issues with partysocket](https://github.com/oven-sh/bun/issues/18807), which haven't
-
been fixed yet and which the jetstream library we use depends on for the moment. once it has been fixed, we do plan
-
to use bun over node in the future.
+
[some issues with partysocket](https://github.com/oven-sh/bun/issues/18807), which haven't been
+
fixed yet and which the jetstream library we use depends on for the moment. once it has been fixed,
+
we do plan to use bun over node in the future.
### checklist before it's usable
+4 -3
lexdocs/social/clippr/actor/getPreferences.json
···
"defs": {
"main": {
"type": "query",
-
"description": "Get the private user preferences associated to the account.",
+
"description": "Get the private user preferences associated to the account.",
"parameters": {
"type": "params",
"properties": {}
···
"properties": {
"preferences": {
"type": "ref",
-
"ref": "social.clippr.actor.defs#preferences"
+
"ref": "social.clippr.actor.defs#preferences",
+
"description": "A ref to the user's preferences"
}
}
}
}
}
}
-
}
+
}
+29 -28
lexdocs/social/clippr/actor/getProfile.json
···
{
-
"lexicon": 1,
-
"id": "social.clippr.actor.getProfile",
-
"defs": {
-
"main": {
-
"type": "query",
-
"description": "Get profile view of an actor. Does not require auth.",
-
"parameters": {
-
"type": "params",
-
"required": [
-
"actor"
-
],
-
"properties": {
-
"actor": {
-
"type": "string",
-
"format": "at-identifier",
-
"description": "Handle or DID of account to fetch profile of."
-
}
-
}
-
},
-
"output": {
-
"encoding": "application/json",
-
"schema": {
-
"type": "ref",
-
"ref": "social.clippr.actor.defs#profileView"
-
}
-
}
-
}
-
}
+
"lexicon": 1,
+
"id": "social.clippr.actor.getProfile",
+
"defs": {
+
"main": {
+
"type": "query",
+
"description": "Get profile view of an actor. Does not require auth.",
+
"parameters": {
+
"type": "params",
+
"required": [
+
"actor"
+
],
+
"properties": {
+
"actor": {
+
"type": "string",
+
"format": "at-identifier",
+
"description": "Handle or DID of account to fetch profile of"
+
}
+
}
+
},
+
"output": {
+
"encoding": "application/json",
+
"schema": {
+
"type": "ref",
+
"ref": "social.clippr.actor.defs#profileView",
+
"description": "A reference to the profile view of the actor"
+
}
+
}
+
}
+
}
}
+46 -45
lexdocs/social/clippr/actor/profile.json
···
{
-
"lexicon": 1,
-
"id": "social.clippr.actor.profile",
-
"defs": {
-
"main": {
-
"type": "record",
-
"description": "A declaration of a Clippr account's profile.",
-
"key": "literal:self",
-
"record": {
-
"type": "object",
-
"required": [
-
"createdAt",
-
"displayName"
-
],
-
"properties": {
-
"displayName": {
-
"type": "string",
-
"description": "A display name to be shown on a profile.",
-
"minGraphemes": 1,
-
"minLength": 10,
-
"maxGraphemes": 64,
-
"maxLength": 640
-
},
-
"description": {
-
"type": "string",
-
"description": "Text for user to describe themselves",
-
"maxGraphemes": 500,
-
"maxLength": 5000
-
},
-
"avatar": {
-
"type": "blob",
-
"description": "Image to show on user's profiles.",
-
"accept": [
-
"image/png",
-
"image/jpeg"
-
],
-
"maxSize": 1000000
-
},
-
"createdAt": {
-
"type": "string",
-
"format": "datetime"
-
}
-
}
-
}
-
}
-
}
+
"lexicon": 1,
+
"id": "social.clippr.actor.profile",
+
"defs": {
+
"main": {
+
"type": "record",
+
"description": "A declaration of a Clippr account's profile.",
+
"key": "literal:self",
+
"record": {
+
"type": "object",
+
"required": [
+
"createdAt",
+
"displayName"
+
],
+
"properties": {
+
"displayName": {
+
"type": "string",
+
"description": "A display name to be shown on a profile",
+
"minGraphemes": 1,
+
"minLength": 10,
+
"maxGraphemes": 64,
+
"maxLength": 640
+
},
+
"description": {
+
"type": "string",
+
"description": "Text for user to describe themselves",
+
"maxGraphemes": 500,
+
"maxLength": 5000
+
},
+
"avatar": {
+
"type": "blob",
+
"description": "Image to show on user's profiles",
+
"accept": [
+
"image/png",
+
"image/jpeg"
+
],
+
"maxSize": 1000000
+
},
+
"createdAt": {
+
"type": "string",
+
"format": "datetime",
+
"description": "The creation date of the profile"
+
}
+
}
+
}
+
}
+
}
}
+6 -3
lexdocs/social/clippr/actor/putPreferences.json
···
"encoding": "application/json",
"schema": {
"type": "object",
-
"required": ["preferences"],
+
"required": [
+
"preferences"
+
],
"properties": {
"preferences": {
"type": "ref",
-
"ref": "social.clippr.actor.defs#preferences"
+
"ref": "social.clippr.actor.defs#preferences",
+
"description": "A ref to the user's preferences"
}
}
}
}
}
}
-
}
+
}
+51 -42
lexdocs/social/clippr/actor/searchProfiles.json
···
{
-
"lexicon": 1,
-
"id": "social.clippr.actor.searchProfiles",
-
"defs": {
-
"main": {
-
"type": "query",
-
"description": "Find profiles matching search criteria. Does not require auth.",
-
"parameters": {
-
"type": "params",
-
"properties": {
-
"q": {
-
"type": "string",
-
"description": "Search query string."
-
},
-
"limit": {
-
"type": "integer",
-
"minimum": 1,
-
"maximum": 100,
-
"default": 25
-
},
-
"cursor": { "type": "string" }
-
}
-
},
-
"output": {
-
"encoding": "application/json",
-
"schema": {
-
"type": "object",
-
"required": ["actors"],
-
"properties": {
-
"cursor": { "type": "string" },
-
"actors": {
-
"type": "array",
-
"items": {
-
"type": "ref",
-
"ref": "social.clippr.actor.defs#profileView"
-
}
-
}
-
}
-
}
-
}
-
}
-
}
-
}
+
"lexicon": 1,
+
"id": "social.clippr.actor.searchProfiles",
+
"defs": {
+
"main": {
+
"type": "query",
+
"description": "Find profiles matching search criteria. Does not require auth.",
+
"parameters": {
+
"type": "params",
+
"properties": {
+
"q": {
+
"type": "string",
+
"description": "Search query string"
+
},
+
"limit": {
+
"type": "integer",
+
"minimum": 1,
+
"maximum": 100,
+
"default": 25,
+
"description": "The number of profiles to be returned in the query"
+
},
+
"cursor": {
+
"type": "string",
+
"description": "A parameter used for pagination"
+
}
+
}
+
},
+
"output": {
+
"encoding": "application/json",
+
"schema": {
+
"type": "object",
+
"required": [
+
"actors"
+
],
+
"properties": {
+
"cursor": {
+
"type": "string",
+
"description": "A parameter used for pagination"
+
},
+
"actors": {
+
"type": "array",
+
"items": {
+
"type": "ref",
+
"ref": "social.clippr.actor.defs#profileView"
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+86 -86
lexdocs/social/clippr/feed/clip.json
···
{
-
"lexicon": 1,
-
"id": "social.clippr.feed.clip",
-
"defs": {
-
"main": {
-
"type": "record",
-
"description": "Record containing a bookmark item, or 'clip'.",
-
"key": "any",
-
"record": {
-
"type": "object",
-
"required": [
-
"url",
-
"title",
-
"description",
-
"unlisted",
-
"createdAt"
-
],
-
"properties": {
-
"url": {
-
"type": "string",
-
"format": "uri",
-
"description": "The URL of the bookmark. Cannot be left empty or be modified after creation.",
-
"minGraphemes": 3,
-
"minLength": 30,
-
"maxGraphemes": 2000,
-
"maxLength": 20000
-
},
-
"title": {
-
"type": "string",
-
"description": "The title of the bookmark. If left empty, reuse the URL.",
-
"minGraphemes": 1,
-
"minLength": 10,
-
"maxGraphemes": 2048,
-
"maxLength": 20480
-
},
-
"description": {
-
"type": "string",
-
"description": "A description of the bookmark's content. This should be ripped from the URL metadata and be static for all records using the URL.",
-
"minGraphemes": 1,
-
"minLength": 10,
-
"maxGraphemes": 4096,
-
"maxLength": 40960
-
},
-
"notes": {
-
"type": "string",
-
"description": "User-written notes for the bookmark. Public and personal.",
-
"minGraphemes": 1,
-
"minLength": 10,
-
"maxGraphemes": 10000,
-
"maxLength": 100000
-
},
-
"tags": {
-
"type": "array",
-
"description": "An array of tags. A format of solely alphanumeric characters and dashes should be used.",
-
"items": {
-
"type": "ref",
-
"ref": "com.atproto.repo.strongRef"
-
}
-
},
-
"unlisted": {
-
"type": "boolean",
-
"description": "Whether the bookmark can be used for feed indexing and aggregation.",
-
"default": false
-
},
-
"unread": {
-
"type": "boolean",
-
"description": "Whether the bookmark has been read by the user.",
-
"default": true
-
},
-
"languages": {
-
"type": "array",
-
"description": "Indicates human language of the given URL.",
-
"maxLength": 5,
-
"items": {
-
"type": "string",
-
"format": "language"
-
}
-
},
-
"createdAt": {
-
"type": "string",
-
"description": "Client-declared timestamp when the bookmark is created.",
-
"format": "datetime"
-
}
-
}
-
}
-
}
-
}
+
"lexicon": 1,
+
"id": "social.clippr.feed.clip",
+
"defs": {
+
"main": {
+
"type": "record",
+
"description": "Record containing a bookmarked item, or 'clip'.",
+
"key": "any",
+
"record": {
+
"type": "object",
+
"required": [
+
"url",
+
"title",
+
"description",
+
"unlisted",
+
"createdAt"
+
],
+
"properties": {
+
"url": {
+
"type": "string",
+
"format": "uri",
+
"description": "The URL of the bookmark. Cannot be left empty or be modified after creation.",
+
"minGraphemes": 3,
+
"minLength": 30,
+
"maxGraphemes": 2000,
+
"maxLength": 20000
+
},
+
"title": {
+
"type": "string",
+
"description": "The title of the bookmark. If left empty, reuse the URL.",
+
"minGraphemes": 1,
+
"minLength": 10,
+
"maxGraphemes": 2048,
+
"maxLength": 20480
+
},
+
"description": {
+
"type": "string",
+
"description": "A description of the bookmark's content. This should be ripped from the URL metadata and be static for all records using the URL.",
+
"minGraphemes": 1,
+
"minLength": 10,
+
"maxGraphemes": 4096,
+
"maxLength": 40960
+
},
+
"notes": {
+
"type": "string",
+
"description": "User-written notes for the bookmark. Public and personal.",
+
"minGraphemes": 1,
+
"minLength": 10,
+
"maxGraphemes": 10000,
+
"maxLength": 100000
+
},
+
"tags": {
+
"type": "array",
+
"description": "An array of tags. A format of solely alphanumeric characters and dashes should be used.",
+
"items": {
+
"type": "ref",
+
"ref": "com.atproto.repo.strongRef"
+
}
+
},
+
"unlisted": {
+
"type": "boolean",
+
"description": "Whether the bookmark can be used for feed indexing and aggregation",
+
"default": false
+
},
+
"unread": {
+
"type": "boolean",
+
"description": "Whether the bookmark has been read by the user",
+
"default": true
+
},
+
"languages": {
+
"type": "array",
+
"description": "Indicates human language of the given URL",
+
"maxLength": 5,
+
"items": {
+
"type": "string",
+
"format": "language"
+
}
+
},
+
"createdAt": {
+
"type": "string",
+
"description": "Client-declared timestamp when the bookmark is created",
+
"format": "datetime"
+
}
+
}
+
}
+
}
+
}
}
+65
lexdocs/social/clippr/feed/getProfileClips.json
···
+
{
+
"lexicon": 1,
+
"id": "social.clippr.feed.getProfileClips",
+
"defs": {
+
"main": {
+
"type": "query",
+
"description": "Get a view of a profile's reverse-chronological clips feed. Does not require auth.",
+
"parameters": {
+
"type": "params",
+
"required": [
+
"actor"
+
],
+
"properties": {
+
"actor": {
+
"type": "string",
+
"format": "at-identifier",
+
"description": "An actor to get feed data from"
+
},
+
"limit": {
+
"type": "integer",
+
"minimum": 1,
+
"maximum": 100,
+
"default": 50,
+
"description": "How many results to return with the query"
+
},
+
"cursor": {
+
"type": "string",
+
"description": "A parameter to paginate results"
+
},
+
"filter": {
+
"type": "string",
+
"knownValues": [
+
"all_clips",
+
"tagged_clips",
+
"untagged_clips"
+
],
+
"default": "all_clips",
+
"description": "What types to include in response"
+
}
+
}
+
},
+
"output": {
+
"encoding": "application/json",
+
"schema": {
+
"type": "object",
+
"required": [
+
"feed"
+
],
+
"properties": {
+
"cursor": {
+
"type": "string"
+
},
+
"feed": {
+
"type": "array",
+
"items": {
+
"type": "ref",
+
"ref": "social.clippr.feed.defs#clipView"
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+55
lexdocs/social/clippr/feed/getProfileTags.json
···
+
{
+
"lexicon": 1,
+
"id": "social.clippr.feed.getProfileTags",
+
"defs": {
+
"main": {
+
"type": "query",
+
"description": "Get a view of a profile's reverse-chronological clips feed. Does not require auth.",
+
"parameters": {
+
"type": "params",
+
"required": [
+
"actor"
+
],
+
"properties": {
+
"actor": {
+
"type": "string",
+
"format": "at-identifier",
+
"description": "An actor to get feed data from"
+
},
+
"limit": {
+
"type": "integer",
+
"minimum": 1,
+
"maximum": 100,
+
"default": 50,
+
"description": "How many results to return with the query"
+
},
+
"cursor": {
+
"type": "string",
+
"description": "A parameter to paginate results"
+
}
+
}
+
},
+
"output": {
+
"encoding": "application/json",
+
"schema": {
+
"type": "object",
+
"required": [
+
"feed"
+
],
+
"properties": {
+
"cursor": {
+
"type": "string"
+
},
+
"feed": {
+
"type": "array",
+
"items": {
+
"type": "ref",
+
"ref": "social.clippr.feed.defs#tagView"
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+
}
+47 -39
lexdocs/social/clippr/feed/tag.json
···
{
-
"lexicon": 1,
-
"id": "social.clippr.feed.tag",
-
"defs": {
-
"main": {
-
"type": "record",
-
"description": "A record containing a bookmark tag for organization.",
-
"key": "any",
-
"record": {
-
"type": "object",
-
"required": [
-
"name",
-
"createdAt"
-
],
-
"properties": {
-
"name": {
-
"type": "string",
-
"description": "A de-duplicated string containing the name of the tag.",
-
"minGraphemes": 1,
-
"minLength": 10,
-
"maxGraphemes": 64,
-
"maxLength": 640
-
},
-
"color": {
-
"type": "string",
-
"description": "A hexadecimal color code.",
-
"minGraphemes": 4,
-
"minLength": 40,
-
"maxGraphemes": 7,
-
"maxLength": 70
-
},
-
"createdAt": {
-
"type": "string",
-
"description": "A client-defined timestamp for the creation of the tag.",
-
"format": "datetime"
-
}
-
}
-
}
-
}
-
}
+
"lexicon": 1,
+
"id": "social.clippr.feed.tag",
+
"defs": {
+
"main": {
+
"type": "record",
+
"description": "A record containing a bookmark tag for organization.",
+
"key": "any",
+
"record": {
+
"type": "object",
+
"required": [
+
"name",
+
"createdAt"
+
],
+
"properties": {
+
"name": {
+
"type": "string",
+
"minGraphemes": 1,
+
"minLength": 10,
+
"maxGraphemes": 64,
+
"maxLength": 640,
+
"description": "A de-duplicated string containing the name of the tag"
+
},
+
"color": {
+
"type": "string",
+
"minGraphemes": 4,
+
"minLength": 40,
+
"maxGraphemes": 7,
+
"maxLength": 70,
+
"description": "A hexadecimal color code"
+
},
+
"description": {
+
"type": "string",
+
"minGraphemes": 1,
+
"minLength": 10,
+
"maxGraphemes": 5000,
+
"maxLength": 50000,
+
"description": "A description of the tag for additional context"
+
},
+
"createdAt": {
+
"type": "string",
+
"format": "datetime",
+
"description": "A client-defined timestamp for the creation of the tag"
+
}
+
}
+
}
+
}
+
}
}
+16 -16
lexicons/lex.config.js
···
import {defineLexiconConfig} from "@atcute/lex-cli";
export default defineLexiconConfig({
-
files: ["../lexdocs/**/*.json"],
-
outdir: "lib/lexicons",
-
mappings: [
-
{
-
nsid: ["com.atproto.*"],
-
imports: (nsid) => {
-
const specifier = nsid
-
.slice("com.atproto.".length)
-
.replaceAll(".", "/");
-
return {
-
type: "namespace",
-
from: `@atcute/atproto/types/${specifier}`,
-
};
-
},
-
},
-
],
+
files: ["../lexdocs/**/*.json"],
+
outdir: "lib/lexicons",
+
mappings: [
+
{
+
nsid: ["com.atproto.*"],
+
imports: (nsid) => {
+
const specifier = nsid
+
.slice("com.atproto.".length)
+
.replaceAll(".", "/");
+
return {
+
type: "namespace",
+
from: `@atcute/atproto/types/${specifier}`,
+
};
+
},
+
},
+
],
});
+10
lexicons/lib/lexicons/index.ts
···
*/
export * as SocialClipprActorDefs from "./types/social/clippr/actor/defs.js";
+
export * as SocialClipprActorGetPreferences from "./types/social/clippr/actor/getPreferences.js";
export * as SocialClipprActorGetProfile from "./types/social/clippr/actor/getProfile.js";
export * as SocialClipprActorProfile from "./types/social/clippr/actor/profile.js";
+
export * as SocialClipprActorPutPreferences from "./types/social/clippr/actor/putPreferences.js";
+
export * as SocialClipprActorSearchClips from "./types/social/clippr/actor/searchClips.js";
+
export * as SocialClipprActorSearchProfiles from "./types/social/clippr/actor/searchProfiles.js";
+
export * as SocialClipprActorSearchTags from "./types/social/clippr/actor/searchTags.js";
export * as SocialClipprFeedClip from "./types/social/clippr/feed/clip.js";
+
export * as SocialClipprFeedDefs from "./types/social/clippr/feed/defs.js";
+
export * as SocialClipprFeedGetClips from "./types/social/clippr/feed/getClips.js";
+
export * as SocialClipprFeedGetProfileClips from "./types/social/clippr/feed/getProfileClips.js";
+
export * as SocialClipprFeedGetProfileTags from "./types/social/clippr/feed/getProfileTags.js";
+
export * as SocialClipprFeedGetTagList from "./types/social/clippr/feed/getTagList.js";
export * as SocialClipprFeedTag from "./types/social/clippr/feed/tag.js";
+20
lexicons/lib/lexicons/types/social/clippr/actor/defs.ts
···
import type {} from "@atcute/lexicons";
import * as v from "@atcute/lexicons/validations";
+
const _preferencesSchema = /*#__PURE__*/ v.array(() => {
+
return /*#__PURE__*/ v.variant([publishingScopesPrefSchema]);
+
});
const _profileViewSchema = /*#__PURE__*/ v.object({
$type: /*#__PURE__*/ v.optional(
/*#__PURE__*/ v.literal("social.clippr.actor.defs#profileView"),
···
),
handle: /*#__PURE__*/ v.handleString(),
});
+
const _publishingScopesPrefSchema = /*#__PURE__*/ v.object({
+
$type: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.literal("social.clippr.actor.defs#publishingScopesPref"),
+
),
+
defaultScope: /*#__PURE__*/ v.string<"public" | "unlisted" | (string & {})>(),
+
});
+
type preferences$schematype = typeof _preferencesSchema;
type profileView$schematype = typeof _profileViewSchema;
+
type publishingScopesPref$schematype = typeof _publishingScopesPrefSchema;
+
export interface preferencesSchema extends preferences$schematype {}
export interface profileViewSchema extends profileView$schematype {}
+
export interface publishingScopesPrefSchema
+
extends publishingScopesPref$schematype {}
+
export const preferencesSchema = _preferencesSchema as preferencesSchema;
export const profileViewSchema = _profileViewSchema as profileViewSchema;
+
export const publishingScopesPrefSchema =
+
_publishingScopesPrefSchema as publishingScopesPrefSchema;
+
export interface Preferences extends v.InferInput<typeof preferencesSchema> {}
export interface ProfileView extends v.InferInput<typeof profileViewSchema> {}
+
export interface PublishingScopesPref
+
extends v.InferInput<typeof publishingScopesPrefSchema> {}
+40
lexicons/lib/lexicons/types/social/clippr/actor/getPreferences.ts
···
+
/*
+
* clippr: a social bookmarking service for the AT Protocol
+
* Copyright (c) 2025 clippr contributors.
+
* SPDX-License-Identifier: AGPL-3.0-only
+
*/
+
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
import type {} from "@atcute/lexicons/ambient";
+
import * as SocialClipprActorDefs from "./defs.js";
+
+
const _mainSchema = /*#__PURE__*/ v.query(
+
"social.clippr.actor.getPreferences",
+
{
+
params: /*#__PURE__*/ v.object({}),
+
output: {
+
type: "lex",
+
schema: /*#__PURE__*/ v.object({
+
get preferences() {
+
return SocialClipprActorDefs.preferencesSchema;
+
},
+
}),
+
},
+
},
+
);
+
+
type main$schematype = typeof _mainSchema;
+
+
export interface mainSchema extends main$schematype {}
+
+
export const mainSchema = _mainSchema as mainSchema;
+
+
export interface $params extends v.InferInput<mainSchema["params"]> {}
+
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
+
+
declare module "@atcute/lexicons/ambient" {
+
interface XRPCQueries {
+
"social.clippr.actor.getPreferences": mainSchema;
+
}
+
}
+41
lexicons/lib/lexicons/types/social/clippr/actor/putPreferences.ts
···
+
/*
+
* clippr: a social bookmarking service for the AT Protocol
+
* Copyright (c) 2025 clippr contributors.
+
* SPDX-License-Identifier: AGPL-3.0-only
+
*/
+
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
import type {} from "@atcute/lexicons/ambient";
+
import * as SocialClipprActorDefs from "./defs.js";
+
+
const _mainSchema = /*#__PURE__*/ v.procedure(
+
"social.clippr.actor.putPreferences",
+
{
+
params: null,
+
input: {
+
type: "lex",
+
schema: /*#__PURE__*/ v.object({
+
get preferences() {
+
return SocialClipprActorDefs.preferencesSchema;
+
},
+
}),
+
},
+
output: null,
+
},
+
);
+
+
type main$schematype = typeof _mainSchema;
+
+
export interface mainSchema extends main$schematype {}
+
+
export const mainSchema = _mainSchema as mainSchema;
+
+
export interface $params {}
+
export interface $input extends v.InferXRPCBodyInput<mainSchema["input"]> {}
+
+
declare module "@atcute/lexicons/ambient" {
+
interface XRPCProcedures {
+
"social.clippr.actor.putPreferences": mainSchema;
+
}
+
}
+48
lexicons/lib/lexicons/types/social/clippr/actor/searchClips.ts
···
+
/*
+
* clippr: a social bookmarking service for the AT Protocol
+
* Copyright (c) 2025 clippr contributors.
+
* SPDX-License-Identifier: AGPL-3.0-only
+
*/
+
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
import type {} from "@atcute/lexicons/ambient";
+
import * as SocialClipprFeedDefs from "../feed/defs.js";
+
+
const _mainSchema = /*#__PURE__*/ v.query("social.clippr.actor.searchClips", {
+
params: /*#__PURE__*/ v.object({
+
actor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.actorIdentifierString()),
+
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
limit: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.integer(), [
+
/*#__PURE__*/ v.integerRange(1, 100),
+
]),
+
25,
+
),
+
q: /*#__PURE__*/ v.string(),
+
}),
+
output: {
+
type: "lex",
+
schema: /*#__PURE__*/ v.object({
+
get clips() {
+
return /*#__PURE__*/ v.array(SocialClipprFeedDefs.clipViewSchema);
+
},
+
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
}),
+
},
+
});
+
+
type main$schematype = typeof _mainSchema;
+
+
export interface mainSchema extends main$schematype {}
+
+
export const mainSchema = _mainSchema as mainSchema;
+
+
export interface $params extends v.InferInput<mainSchema["params"]> {}
+
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
+
+
declare module "@atcute/lexicons/ambient" {
+
interface XRPCQueries {
+
"social.clippr.actor.searchClips": mainSchema;
+
}
+
}
+50
lexicons/lib/lexicons/types/social/clippr/actor/searchProfiles.ts
···
+
/*
+
* clippr: a social bookmarking service for the AT Protocol
+
* Copyright (c) 2025 clippr contributors.
+
* SPDX-License-Identifier: AGPL-3.0-only
+
*/
+
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
import type {} from "@atcute/lexicons/ambient";
+
import * as SocialClipprActorDefs from "./defs.js";
+
+
const _mainSchema = /*#__PURE__*/ v.query(
+
"social.clippr.actor.searchProfiles",
+
{
+
params: /*#__PURE__*/ v.object({
+
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
limit: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.integer(), [
+
/*#__PURE__*/ v.integerRange(1, 100),
+
]),
+
25,
+
),
+
q: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
}),
+
output: {
+
type: "lex",
+
schema: /*#__PURE__*/ v.object({
+
get actors() {
+
return /*#__PURE__*/ v.array(SocialClipprActorDefs.profileViewSchema);
+
},
+
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
}),
+
},
+
},
+
);
+
+
type main$schematype = typeof _mainSchema;
+
+
export interface mainSchema extends main$schematype {}
+
+
export const mainSchema = _mainSchema as mainSchema;
+
+
export interface $params extends v.InferInput<mainSchema["params"]> {}
+
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
+
+
declare module "@atcute/lexicons/ambient" {
+
interface XRPCQueries {
+
"social.clippr.actor.searchProfiles": mainSchema;
+
}
+
}
+48
lexicons/lib/lexicons/types/social/clippr/actor/searchTags.ts
···
+
/*
+
* clippr: a social bookmarking service for the AT Protocol
+
* Copyright (c) 2025 clippr contributors.
+
* SPDX-License-Identifier: AGPL-3.0-only
+
*/
+
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
import type {} from "@atcute/lexicons/ambient";
+
import * as SocialClipprFeedDefs from "../feed/defs.js";
+
+
const _mainSchema = /*#__PURE__*/ v.query("social.clippr.actor.searchTags", {
+
params: /*#__PURE__*/ v.object({
+
actor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.actorIdentifierString()),
+
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
limit: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.integer(), [
+
/*#__PURE__*/ v.integerRange(1, 100),
+
]),
+
25,
+
),
+
q: /*#__PURE__*/ v.string(),
+
}),
+
output: {
+
type: "lex",
+
schema: /*#__PURE__*/ v.object({
+
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
get tags() {
+
return /*#__PURE__*/ v.array(SocialClipprFeedDefs.tagViewSchema);
+
},
+
}),
+
},
+
});
+
+
type main$schematype = typeof _mainSchema;
+
+
export interface mainSchema extends main$schematype {}
+
+
export const mainSchema = _mainSchema as mainSchema;
+
+
export interface $params extends v.InferInput<mainSchema["params"]> {}
+
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
+
+
declare module "@atcute/lexicons/ambient" {
+
interface XRPCQueries {
+
"social.clippr.actor.searchTags": mainSchema;
+
}
+
}
+46
lexicons/lib/lexicons/types/social/clippr/feed/defs.ts
···
+
/*
+
* clippr: a social bookmarking service for the AT Protocol
+
* Copyright (c) 2025 clippr contributors.
+
* SPDX-License-Identifier: AGPL-3.0-only
+
*/
+
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
import * as SocialClipprActorDefs from "../actor/defs.js";
+
+
const _clipViewSchema = /*#__PURE__*/ v.object({
+
$type: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.literal("social.clippr.feed.defs#clipView"),
+
),
+
get author() {
+
return SocialClipprActorDefs.profileViewSchema;
+
},
+
cid: /*#__PURE__*/ v.cidString(),
+
indexedAt: /*#__PURE__*/ v.datetimeString(),
+
record: /*#__PURE__*/ v.unknown(),
+
uri: /*#__PURE__*/ v.resourceUriString(),
+
});
+
const _tagViewSchema = /*#__PURE__*/ v.object({
+
$type: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.literal("social.clippr.feed.defs#tagView"),
+
),
+
get author() {
+
return SocialClipprActorDefs.profileViewSchema;
+
},
+
cid: /*#__PURE__*/ v.cidString(),
+
indexedAt: /*#__PURE__*/ v.datetimeString(),
+
record: /*#__PURE__*/ v.unknown(),
+
uri: /*#__PURE__*/ v.resourceUriString(),
+
});
+
+
type clipView$schematype = typeof _clipViewSchema;
+
type tagView$schematype = typeof _tagViewSchema;
+
+
export interface clipViewSchema extends clipView$schematype {}
+
export interface tagViewSchema extends tagView$schematype {}
+
+
export const clipViewSchema = _clipViewSchema as clipViewSchema;
+
export const tagViewSchema = _tagViewSchema as tagViewSchema;
+
+
export interface ClipView extends v.InferInput<typeof clipViewSchema> {}
+
export interface TagView extends v.InferInput<typeof tagViewSchema> {}
+42
lexicons/lib/lexicons/types/social/clippr/feed/getClips.ts
···
+
/*
+
* clippr: a social bookmarking service for the AT Protocol
+
* Copyright (c) 2025 clippr contributors.
+
* SPDX-License-Identifier: AGPL-3.0-only
+
*/
+
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
import type {} from "@atcute/lexicons/ambient";
+
import * as SocialClipprFeedDefs from "./defs.js";
+
+
const _mainSchema = /*#__PURE__*/ v.query("social.clippr.feed.getClips", {
+
params: /*#__PURE__*/ v.object({
+
uris: /*#__PURE__*/ v.constrain(
+
/*#__PURE__*/ v.array(/*#__PURE__*/ v.resourceUriString()),
+
[/*#__PURE__*/ v.arrayLength(1, 25)],
+
),
+
}),
+
output: {
+
type: "lex",
+
schema: /*#__PURE__*/ v.object({
+
get tags() {
+
return /*#__PURE__*/ v.array(SocialClipprFeedDefs.tagViewSchema);
+
},
+
}),
+
},
+
});
+
+
type main$schematype = typeof _mainSchema;
+
+
export interface mainSchema extends main$schematype {}
+
+
export const mainSchema = _mainSchema as mainSchema;
+
+
export interface $params extends v.InferInput<mainSchema["params"]> {}
+
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
+
+
declare module "@atcute/lexicons/ambient" {
+
interface XRPCQueries {
+
"social.clippr.feed.getClips": mainSchema;
+
}
+
}
+56
lexicons/lib/lexicons/types/social/clippr/feed/getProfileClips.ts
···
+
/*
+
* clippr: a social bookmarking service for the AT Protocol
+
* Copyright (c) 2025 clippr contributors.
+
* SPDX-License-Identifier: AGPL-3.0-only
+
*/
+
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
import type {} from "@atcute/lexicons/ambient";
+
import * as SocialClipprFeedDefs from "./defs.js";
+
+
const _mainSchema = /*#__PURE__*/ v.query(
+
"social.clippr.feed.getProfileClips",
+
{
+
params: /*#__PURE__*/ v.object({
+
actor: /*#__PURE__*/ v.actorIdentifierString(),
+
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
filter: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.string<
+
"all_clips" | "tagged_clips" | "untagged_clips" | (string & {})
+
>(),
+
"all_clips",
+
),
+
limit: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.integer(), [
+
/*#__PURE__*/ v.integerRange(1, 100),
+
]),
+
50,
+
),
+
}),
+
output: {
+
type: "lex",
+
schema: /*#__PURE__*/ v.object({
+
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
get feed() {
+
return /*#__PURE__*/ v.array(SocialClipprFeedDefs.clipViewSchema);
+
},
+
}),
+
},
+
},
+
);
+
+
type main$schematype = typeof _mainSchema;
+
+
export interface mainSchema extends main$schematype {}
+
+
export const mainSchema = _mainSchema as mainSchema;
+
+
export interface $params extends v.InferInput<mainSchema["params"]> {}
+
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
+
+
declare module "@atcute/lexicons/ambient" {
+
interface XRPCQueries {
+
"social.clippr.feed.getProfileClips": mainSchema;
+
}
+
}
+47
lexicons/lib/lexicons/types/social/clippr/feed/getProfileTags.ts
···
+
/*
+
* clippr: a social bookmarking service for the AT Protocol
+
* Copyright (c) 2025 clippr contributors.
+
* SPDX-License-Identifier: AGPL-3.0-only
+
*/
+
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
import type {} from "@atcute/lexicons/ambient";
+
import * as SocialClipprFeedDefs from "./defs.js";
+
+
const _mainSchema = /*#__PURE__*/ v.query("social.clippr.feed.getProfileTags", {
+
params: /*#__PURE__*/ v.object({
+
actor: /*#__PURE__*/ v.actorIdentifierString(),
+
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
limit: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.integer(), [
+
/*#__PURE__*/ v.integerRange(1, 100),
+
]),
+
50,
+
),
+
}),
+
output: {
+
type: "lex",
+
schema: /*#__PURE__*/ v.object({
+
cursor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.string()),
+
get feed() {
+
return /*#__PURE__*/ v.array(SocialClipprFeedDefs.tagViewSchema);
+
},
+
}),
+
},
+
});
+
+
type main$schematype = typeof _mainSchema;
+
+
export interface mainSchema extends main$schematype {}
+
+
export const mainSchema = _mainSchema as mainSchema;
+
+
export interface $params extends v.InferInput<mainSchema["params"]> {}
+
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
+
+
declare module "@atcute/lexicons/ambient" {
+
interface XRPCQueries {
+
"social.clippr.feed.getProfileTags": mainSchema;
+
}
+
}
+39
lexicons/lib/lexicons/types/social/clippr/feed/getTagList.ts
···
+
/*
+
* clippr: a social bookmarking service for the AT Protocol
+
* Copyright (c) 2025 clippr contributors.
+
* SPDX-License-Identifier: AGPL-3.0-only
+
*/
+
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
import type {} from "@atcute/lexicons/ambient";
+
import * as SocialClipprFeedDefs from "./defs.js";
+
+
const _mainSchema = /*#__PURE__*/ v.query("social.clippr.feed.getTagList", {
+
params: /*#__PURE__*/ v.object({
+
actor: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.actorIdentifierString()),
+
}),
+
output: {
+
type: "lex",
+
schema: /*#__PURE__*/ v.object({
+
get tags() {
+
return /*#__PURE__*/ v.array(SocialClipprFeedDefs.tagViewSchema);
+
},
+
}),
+
},
+
});
+
+
type main$schematype = typeof _mainSchema;
+
+
export interface mainSchema extends main$schematype {}
+
+
export const mainSchema = _mainSchema as mainSchema;
+
+
export interface $params extends v.InferInput<mainSchema["params"]> {}
+
export interface $output extends v.InferXRPCBodyInput<mainSchema["output"]> {}
+
+
declare module "@atcute/lexicons/ambient" {
+
interface XRPCQueries {
+
"social.clippr.feed.getTagList": mainSchema;
+
}
+
}
+6
lexicons/lib/lexicons/types/social/clippr/feed/tag.ts
···
]),
),
createdAt: /*#__PURE__*/ v.datetimeString(),
+
description: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
+
/*#__PURE__*/ v.stringLength(10, 50000),
+
/*#__PURE__*/ v.stringGraphemes(1, 5000),
+
]),
+
),
name: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
/*#__PURE__*/ v.stringLength(10, 640),
/*#__PURE__*/ v.stringGraphemes(1, 64),
+1 -1
lexicons/package.json
···
{
"type": "module",
"name": "@clipprjs/lexicons",
-
"version": "0.1.4",
+
"version": "1.0.0",
"description": "Clippr schema definitions",
"license": "AGPL-3.0-only",
"private": false,
+31
lexicons/CHANGELOG.md
···
+
# changelog for @clipprjs/lexicons
+
+
## v1.0.0
+
+
> this version should be considered as the starting point for a usable Lexicon API. previous versions should be ignored.
+
+
* added search queries for clips, tags and profiles
+
* added `social.clippr.actor.defs#preferences` with an accompanying query and procedure lexicon
+
* added more inline documentation to previously existing lexicons
+
* added query lexicons for having a clip and tag feed on a profile
+
* added general query lexicons for at:// URIs linking to clips and tags
+
+
## v0.1.4
+
+
* added length constraints to more strings in record lexicons
+
+
## v0.1.3
+
+
* made `displayName` required for profile records
+
+
## v0.1.2
+
+
* added npm tags.. i guess
+
+
## v0.1.1
+
+
* something(?)
+
+
## v0.1.0
+
+
* initial record and `social.clippr.actor.getProfile` query lexicons
+2 -2
lexicons/README.md
···
Lexicon package auto-generated with `@atcute/lex-cli`
-
> This package is *very* unstable. Lexicon attributes can be modified at any moment.
+
> This package is *somewhat* unstable. Lexicon attributes can be modified at any moment.
> Please do not use this package for anything until the [Clippr server](https://tangled.sh/@hexmani.ac/clippr) has been
-
> deployed for either public or developer consumption.
+
> deployed for either public or developer usage.
## Usage