@graffiti-garden/api 0.4.4 → 0.5.1

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/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var o=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var G=Object.prototype.hasOwnProperty;var d=(e,t)=>{for(var s in t)o(e,s,{get:t[s],enumerable:!0})},y=(e,t,s,l)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of b(t))!G.call(e,r)&&r!==s&&o(e,r,{get:()=>t[r],enumerable:!(l=O(t,r))||l.enumerable});return e};var x=e=>y(o({},"__esModule",{value:!0}),e);var g={};d(g,{Graffiti:()=>i,GraffitiErrorForbidden:()=>n,GraffitiErrorInvalidSchema:()=>f,GraffitiErrorInvalidUri:()=>S,GraffitiErrorNotFound:()=>c,GraffitiErrorPatchError:()=>h,GraffitiErrorPatchTestFailed:()=>m,GraffitiErrorSchemaMismatch:()=>p,GraffitiErrorUnauthorized:()=>a,GraffitiObjectJSONSchema:()=>u,GraffitiPutObjectJSONSchema:()=>j});module.exports=x(g);var i=class{objectToUri(t){return this.locationToUri(t)}};var u={type:"object",properties:{value:{type:"object"},channels:{type:"array",items:{type:"string"}},allowed:{type:"array",items:{type:"string"},nullable:!0},actor:{type:"string"},name:{type:"string"},source:{type:"string"},lastModified:{type:"number"},tombstone:{type:"boolean"}},additionalProperties:!1,required:["value","channels","actor","name","source","lastModified","tombstone"]},j={...u,required:["value","channels"]};var a=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorUnauthorized",Object.setPrototypeOf(this,e.prototype)}},n=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorForbidden",Object.setPrototypeOf(this,e.prototype)}},c=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorNotFound",Object.setPrototypeOf(this,e.prototype)}},f=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorInvalidSchema",Object.setPrototypeOf(this,e.prototype)}},p=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorSchemaMismatch",Object.setPrototypeOf(this,e.prototype)}},m=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorPatchTestFailed",Object.setPrototypeOf(this,e.prototype)}},h=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorPatchError",Object.setPrototypeOf(this,e.prototype)}},S=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorInvalidUri",Object.setPrototypeOf(this,e.prototype)}};
1
+ "use strict";var a=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var G=(e,t)=>{for(var s in t)a(e,s,{get:t[s],enumerable:!0})},j=(e,t,s,O)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of d(t))!y.call(e,r)&&r!==s&&a(e,r,{get:()=>t[r],enumerable:!(O=b(t,r))||O.enumerable});return e};var x=e=>j(a({},"__esModule",{value:!0}),e);var P={};G(P,{Graffiti:()=>i,GraffitiErrorForbidden:()=>n,GraffitiErrorInvalidSchema:()=>f,GraffitiErrorInvalidUri:()=>l,GraffitiErrorNotFound:()=>c,GraffitiErrorPatchError:()=>h,GraffitiErrorPatchTestFailed:()=>m,GraffitiErrorSchemaMismatch:()=>p,GraffitiErrorUnauthorized:()=>o,GraffitiErrorUnrecognizedUriScheme:()=>S,GraffitiObjectJSONSchema:()=>u,GraffitiPutObjectJSONSchema:()=>g});module.exports=x(P);var i=class{};var u={type:"object",properties:{value:{type:"object"},channels:{type:"array",items:{type:"string"}},allowed:{type:"array",items:{type:"string"},nullable:!0},url:{type:"string"},actor:{type:"string"},lastModified:{type:"number"},tombstone:{type:"boolean"}},additionalProperties:!1,required:["value","channels","actor","url","lastModified","tombstone"]},g={...u,required:["value","channels"]};var o=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorUnauthorized",Object.setPrototypeOf(this,e.prototype)}},n=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorForbidden",Object.setPrototypeOf(this,e.prototype)}},c=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorNotFound",Object.setPrototypeOf(this,e.prototype)}},f=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorInvalidSchema",Object.setPrototypeOf(this,e.prototype)}},p=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorSchemaMismatch",Object.setPrototypeOf(this,e.prototype)}},m=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorPatchTestFailed",Object.setPrototypeOf(this,e.prototype)}},h=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorPatchError",Object.setPrototypeOf(this,e.prototype)}},l=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorInvalidUri",Object.setPrototypeOf(this,e.prototype)}},S=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorUnrecognizedUriScheme",Object.setPrototypeOf(this,e.prototype)}};
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts", "../src/1-api.ts", "../src/2-types.ts", "../src/3-errors.ts"],
4
- "sourcesContent": ["export * from \"./1-api\";\nexport * from \"./2-types\";\nexport * from \"./3-errors\";\nexport type { JSONSchema } from \"json-schema-to-ts\";\n", "import type {\n GraffitiLocation,\n GraffitiObject,\n GraffitiObjectBase,\n GraffitiPatch,\n GraffitiSession,\n GraffitiPutObject,\n GraffitiStream,\n ChannelStats,\n} from \"./2-types\";\nimport type { JSONSchema } from \"json-schema-to-ts\";\n\n/**\n * This API describes a small but powerful set of methods that\n * can be used to create many different kinds of social media applications,\n * all of which can interoperate.\n * These methods should satisfy all of an application's needs for\n * the communication, storage, and access management of social data.\n * The rest of the application can be built with standard client-side\n * user interface tools to present and interact with the data \u2014\n * no server code necessary.\n * The Typescript source for this API is available at\n * [graffiti-garden/api](https://github.com/graffiti-garden/api).\n *\n * There are several different implementations of this Graffiti API available,\n * including a [federated implementation](https://github.com/graffiti-garden/implementation-federated),\n * that lets users choose where their data is stored,\n * and a [local implementation](https://github.com/graffiti-garden/implementation-local)\n * that can be used for testing and development. In our design of Graffiti, this API is our\n * primary focus as it is the layer that shapes the experience\n * of developing applications. While different implementations can provide tradeoffs between\n * other important properties (e.g. privacy, security, scalability), those properties\n * are useless if the system as a whole doesn't expose useful functionality to developers.\n *\n * On the other side of the stack, there is [Vue plugin](https://github.com/graffiti-garden/wrapper-vue/)\n * that wraps around this API to provide reactivity. Other high-level libraries\n * will be available in the future.\n *\n * ## Overview\n *\n * Graffiti provides applications with methods to create and store data\n * on behalf of their users using standard CRUD operations:\n * {@link put}, {@link get}, {@link patch}, and {@link delete}.\n * This data can represent both social artifacts (e.g. posts, profiles) and\n * activities (e.g. likes, follows) and is stored as JSON.\n *\n * The social aspect of Graffiti comes from the {@link discover} method\n * which allows applications to find objects that other users made.\n * It is a lot like a traditional query operation, but it only\n * returns objects that have been placed in particular\n * {@link GraffitiObjectBase.channels | `channels`}\n * specified by the discovering application.\n *\n * Graffiti builds on well known concepts and standards wherever possible.\n * JSON Objects can be typed with [JSON Schema](https://json-schema.org/) and patches\n * can be applied with [JSON Patch](https://jsonpatch.com).\n * For interoperability between Graffiti applications, we recommend that\n * objects use established properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/) when available,\n * however it is always possible to create additional properties, contributing\n * to the broader [folksonomy](https://en.wikipedia.org/wiki/Folksonomy).\n *\n * {@link GraffitiObjectBase.channels | `channels`} are one of the major concepts\n * unique to Graffiti along with *interaction relativity*, defined below.\n * Channels create boundaries between public spaces and work to prevent\n * [context collapse](https://en.wikipedia.org/wiki/Context_collapse)\n * even in a highly interoperable environment.\n * Interaction relativity means that all interactions between users are\n * actually atomic single-user operations that can be interpreted in different ways,\n * which also supports interoperability and pluralism.\n *\n * ### Channels\n *\n * {@link GraffitiObjectBase.channels | `channels`}\n * are a way for the creators of social data to express the intended audience of their\n * data. When a user creates data using the {@link put} method, they\n * can place their data in one or more channels.\n * Content consumers using the {@link discover} method will only see data\n * contained in one of the channels they specify.\n *\n * While many channels may be public, they partition\n * the public into different \"contexts\", mitigating the\n * phenomenon of [context collapse](https://en.wikipedia.org/wiki/Context_collapse) or the \"flattening of multiple audiences.\"\n * Any [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier) can be used as a channel, and so channels can represent people,\n * comment threads, topics, places (real or virtual), pieces of media, and more.\n *\n * For example, consider a comment on a post. If we place that comment in the channel\n * represented by the post's URI, then only people viewing the post will know to\n * look in that channel, giving it visibility akin to a comment on a blog post\n * or comment on Instagram ([since 2019](https://www.buzzfeednews.com/article/katienotopoulos/instagrams-following-activity-tab-is-going-away)).\n * If we also place the comment in the channel represented by the commenter's URI (their\n * {@link GraffitiObjectBase.actor | `actor` URI}), then people viewing the commenter's profile\n * will also see the comment, giving it more visibility, like a reply on Twitter.\n * If we *only* place the comment in the channel represented by the commenter's URI, then\n * it becomes like a quote tweet ([prior to 2020](https://x.com/Support/status/1300555325750292480)),\n * where the comment is only visible to the commenter's followers but not the audience\n * of the original post.\n *\n * The channel model differs from other models of communication such as the\n * [actor model](https://www.w3.org/TR/activitypub/#Overview) used by ActivityPub,\n * the protocol underlying Mastodon, or the [firehose model](https://bsky.social/about/blog/5-5-2023-federation-architecture)\n * used by the AT Protocol, the protocol underlying BlueSky.\n * The actor model is a fusion of direct messaging (like Email) and broadcasting\n * (like RSS) and works well for follow-based communication but struggles\n * to pass information via other rendez-vous.\n * In the actor model, even something as simple as comments can be\n * [very tricky and require server \"side effects\"](https://seb.jambor.dev/posts/understanding-activitypub-part-3-the-state-of-mastodon/).\n * The firehose model dumps all user data into one public database,\n * which doesn't allow for the carving out of different contexts that we did in our comment\n * example above. In the firehose model a comment will always be visible to *both* the original post's audience and\n * the commenter's followers.\n *\n * In some sense, channels provide a sort of \"social access control\" by forming\n * expectations about the audiences of different online spaces.\n * As a real world analogy, oftentimes support groups, such as alcoholics\n * anonymous, are open to the public but people in those spaces feel comfortable sharing intimate details\n * because they have expectations about the other people attending.\n * If someone malicious went to support groups just to spread people's secrets,\n * they would be shamed for violating these norms.\n * Similarly, in Graffiti, while you could spider public channels like a search engine\n * to find content about a person, revealing that you've done such a thing\n * would be shameful.\n *\n * Still, social access control is not perfect and so in situations where privacy is important,\n * objects can also be given\n * an {@link GraffitiObjectBase.allowed | `allowed`} list.\n * For example, to send someone a direct message you should put an object representing\n * that message in the channel that represents them (their {@link GraffitiObjectBase.actor | `actor` URI}),\n * so they can find it, *and* set the `allowed` field to only include the recipient,\n * so only they can read it.\n *\n * ### Interaction relativity\n *\n * Interaction relativity posits that \"interaction between two individuals only\n * exists relative to an observer,\" or equivalently, all interaction is [reified](https://en.wikipedia.org/wiki/Reification_(computer_science)).\n * For example, if one user creates a post and another user wants to \"like\" that post,\n * their like is not modifying the original post, it is simply another data object that points\n * to the post being liked, via its {@link locationToUri | URI}.\n *\n * ```json\n * {\n * activity: 'like',\n * target: 'uri-of-the-post-i-like',\n * actor: 'my-user-id'\n * }\n * ```\n *\n * In Graffiti, all interactions including *moderation* and *collaboration* are relative.\n * This means that applications can freely choose which interactions\n * they want to express to their users and how.\n * For example, one application could have a single fixed moderator,\n * another could allow users to choose which moderators they would like filter their content\n * like [Bluesky's stackable moderation](https://bsky.social/about/blog/03-12-2024-stackable-moderation),\n * and another could implement a fully democratic system like [PolicyKit](https://policykit.org/).\n * Each of these applications is one interpretation of the underlying refieid user interactions and\n * users can freely switch between them.\n *\n * Interaction relativy also allows applications to introduce new sorts of interactions\n * without having to coordinate with all the other existing applications,\n * keeping the ecosystem flexible and interoperable.\n * For example, an application could [add a \"Trust\" button to posts](https://social.cs.washington.edu/pub_details.html?id=trustnet)\n * and use it assess the truthfulness of posts made on applications across Graffiti.\n * New sorts of interactions like these can be smoothly absorbed by the broader ecosystem\n * as a [folksonomy](https://en.wikipedia.org/wiki/Folksonomy).\n *\n * Interactivy relativity is realized in Graffiti through two design decisions:\n * 1. The creators of objects can only modify their own objects. It is important for\n * users to be able to change and delete their own content to respect their\n * [right to be forgotten](https://en.wikipedia.org/wiki/Right_to_be_forgotten),\n * but beyond self-correction and self-censorship all other interaction is reified.\n * Many interactions can be reified via pointers, as in the \"like\" example above, and collaborative\n * edits can be refieid via [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type).\n * 2. No one owns channels. Unlike IRC/Slack channels or [Matrix rooms](https://matrix.org/docs/matrix-concepts/rooms_and_events/),\n * anyone can post to any channel, so long as they know the URI of that channel.\n * It is up to applications to hide content from channels either according to manual\n * filters or in response to user action.\n * For example, a user may create a post with the flag `disableReplies`.\n * Applications could then filter out any content from the replies channel\n * that the original poster has not specifically approved.\n *\n * @groupDescription CRUD Methods\n * Methods for {@link put | creating}, {@link get | reading}, {@link patch | updating},\n * and {@link delete | deleting} {@link GraffitiObjectBase | Graffiti objects}.\n * @groupDescription Query Methods\n * Methods that retrieve or accumulate information about multiple {@link GraffitiObjectBase | Graffiti objects} at a time.\n * @groupDescription Session Management\n * Methods and properties for logging in and out of a Graffiti implementation.\n * @groupDescription Utilities\n * Methods for for converting Graffiti objects to and from URIs.\n */\nexport abstract class Graffiti {\n /**\n * Converts a {@link GraffitiLocation} object containing a\n * {@link GraffitiObjectBase.name | `name`}, {@link GraffitiObjectBase.actor | `actor`},\n * and {@link GraffitiObjectBase.source | `source`} into a globally unique URI.\n * The form of this URI is implementation dependent.\n *\n * Its exact inverse is {@link uriToLocation}.\n *\n * @group Utilities\n */\n abstract locationToUri(location: GraffitiLocation): string;\n\n /**\n * Parses a globally unique Graffiti URI into a {@link GraffitiLocation}\n * object containing a {@link GraffitiObjectBase.name | `name`},\n * {@link GraffitiObjectBase.actor | `actor`}, and {@link GraffitiObjectBase.source | `source`}.\n *\n * Its exact inverse is {@link locationToUri}.\n *\n * @group Utilities\n */\n abstract uriToLocation(uri: string): GraffitiLocation;\n\n /**\n * An alias of {@link locationToUri}\n *\n * @group Utilities\n */\n objectToUri(object: GraffitiObjectBase) {\n return this.locationToUri(object);\n }\n\n /**\n * Creates a new {@link GraffitiObjectBase | object} or replaces an existing object.\n * An object can only be replaced by the same {@link GraffitiObjectBase.actor | `actor`}\n * that created it.\n *\n * Replacement occurs when the {@link GraffitiLocation} properties of the supplied object\n * ({@link GraffitiObjectBase.name | `name`}, {@link GraffitiObjectBase.actor | `actor`},\n * and {@link GraffitiObjectBase.source | `source`}) exactly match the location of an existing object.\n *\n * @returns The object that was replaced if one exists or an object with\n * with a `null` {@link GraffitiObjectBase.value | `value`} if this method\n * created a new object.\n * The object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of replacement/creation.\n *\n * @group CRUD Methods\n */\n abstract put<Schema extends JSONSchema>(\n /**\n * The object to be put. This object is statically type-checked against the [JSON schema](https://json-schema.org/) that can be optionally provided\n * as the generic type parameter. We highly recommend providing a schema to\n * ensure that the PUT object matches subsequent {@link get} or {@link discover}\n * methods.\n */\n object: GraffitiPutObject<Schema>,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Retrieves an object from a given location.\n *\n * The retrieved object is type-checked against the provided [JSON schema](https://json-schema.org/)\n * otherwise a {@link GraffitiErrorSchemaMismatch} is thrown.\n *\n * If the retreiving {@link GraffitiObjectBase.actor | `actor`} is not\n * the object's `actor`,\n * the object's {@link GraffitiObjectBase.allowed | `allowed`} and\n * {@link GraffitiObjectBase.channels | `channels`} properties are\n * not revealed.\n *\n * If the object existed but has since been deleted,\n * or the retrieving {@link GraffitiObjectBase.actor | `actor`}\n * was {@link GraffitiObjectBase.allowed | `allowed`} to access\n * the object but now isn't, this method may return the latest\n * version of the object that the {@link GraffitiObjectBase.actor | `actor`}\n * was allowed to access with its {@link GraffitiObjectBase.tombstone | `tombstone`}\n * set to `true`, if that object is stored in an implementation-side cache.\n *\n * Otherwise, if the object never existed, or the\n * retrieving {@link GraffitiObjectBase.actor | `actor`} was never\n * {@link GraffitiObjectBase.allowed | `allowed`} to access it, or if\n * the object was changed long enough ago that its history has been\n * purged from the cache, a {@link GraffitiErrorNotFound} is thrown.\n * The rate at which the cache is purged is implementation dependent.\n * See the `tombstoneRetention` property returned by {@link discover}.\n *\n * @group CRUD Methods\n */\n abstract get<Schema extends JSONSchema>(\n /**\n * The location of the object to get.\n */\n locationOrUri: GraffitiLocation | string,\n /**\n * The JSON schema to validate the retrieved object against.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}. If no `session` is provided,\n * the retrieved object's {@link GraffitiObjectBase.allowed | `allowed`}\n * property must be `undefined`.\n */\n session?: GraffitiSession | null,\n ): Promise<GraffitiObject<Schema>>;\n\n /**\n * Patches an existing object at a given location.\n * The patching {@link GraffitiObjectBase.actor | `actor`} must be the same as the\n * `actor` that created the object.\n *\n * @returns The object that was deleted if one exists or an object with\n * with a `null` {@link GraffitiObjectBase.value | `value`} otherwise.\n * The object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of deletion.\n *\n * @group CRUD Methods\n */\n abstract patch(\n /**\n * A collection of [JSON Patch](https://jsonpatch.com) operations\n * to apply to the object. See {@link GraffitiPatch} for more information.\n */\n patch: GraffitiPatch,\n /**\n * The location of the object to patch.\n */\n locationOrUri: GraffitiLocation | string,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Deletes an object from a given location.\n * The deleting {@link GraffitiObjectBase.actor | `actor`} must be the same as the\n * `actor` that created the object.\n *\n * If the object does not exist or has already been deleted,\n * {@link GraffitiErrorNotFound} is thrown.\n *\n * @returns The object that was deleted if one exists or an object with\n * with a `null` {@link GraffitiObjectBase.value | `value`} otherwise.\n * The object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of deletion.\n *\n * @group CRUD Methods\n */\n abstract delete(\n /**\n * The location of the object to delete.\n */\n locationOrUri: GraffitiLocation | string,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Discovers objects created by any user that are contained\n * in at least one of the given {@link GraffitiObjectBase.channels | `channels`}\n * and match the given [JSON Schema](https://json-schema.org).\n *\n * Objects are returned asynchronously as they are discovered but the stream\n * will end once all leads have been exhausted.\n * The method must be polled again for new objects.\n *\n * `discover` will not return objects that the {@link GraffitiObjectBase.actor | `actor`}\n * is not {@link GraffitiObjectBase.allowed | `allowed`} to access.\n * If the actor is not the creator of a discovered object,\n * the allowed list will be masked to only contain the querying actor if the\n * allowed list is not `undefined` (public). Additionally, if the actor is not the\n * creator of a discovered object, any {@link GraffitiObjectBase.channels | `channels`}\n * not specified by the `discover` method will not be revealed. This masking happens\n * before the supplied schema is applied.\n *\n * Since different implementations may fetch data from multiple sources there is\n * no guarentee on the order that objects are returned in. Additionally, the method\n * will return objects that have been deleted but with a\n * {@link GraffitiObjectBase.tombstone | `tombstone`} field set to `true` for\n * cache invalidation purposes.\n * The final `return()` value of the stream includes a `tombstoneRetention`\n * property that represents the minimum amount of time,\n * in milliseconds, that an application will retain and return tombstones for objects that\n * have been deleted.\n *\n * When repolling, the {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field can be queried via the schema to\n * only fetch objects that have been modified since the last poll.\n * Such queries should only be done if the time since the last poll\n * is less than the `tombstoneRetention` value of that poll, otherwise the tombstones\n * for objects that have been deleted may not be returned.\n *\n * ```json\n * {\n * \"properties\": {\n * \"lastModified\": {\n * \"minimum\": LAST_RETRIEVED_TIME\n * }\n * }\n * }\n * ```\n *\n * `discover` needs to be polled for new data because live updates to\n * an application can be visually distracting or lead to toxic engagement.\n * If and when an application wants real-time updates, such as in a chat\n * application, application authors must be intentional about their polling.\n *\n * Implementers should be aware that some users may applications may try to poll\n * {@link discover} repetitively. You can deal with this by rate limiting or\n * preemptively fetching data via a bidirectional channel, like a WebSocket.\n * Additionally, implementers should probably index the `lastModified` field\n * to speed up responses to schemas like the one above.\n *\n * @returns A stream of objects that match the given {@link GraffitiObjectBase.channels | `channels`}\n * and [JSON Schema](https://json-schema.org).\n *\n * @group Query Methods\n */\n abstract discover<Schema extends JSONSchema>(\n /**\n * The {@link GraffitiObjectBase.channels | `channels`} that objects must be associated with.\n */\n channels: string[],\n /**\n * A [JSON Schema](https://json-schema.org) that objects must satisfy.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}. If no `session` is provided,\n * only objects that have no {@link GraffitiObjectBase.allowed | `allowed`}\n * property will be returned.\n */\n session?: GraffitiSession | null,\n ): GraffitiStream<\n GraffitiObject<Schema>,\n {\n tombstoneRetention: number;\n }\n >;\n\n /**\n * Discovers objects **not** contained in any\n * {@link GraffitiObjectBase.channels | `channels`}\n * that were created by the querying {@link GraffitiObjectBase.actor | `actor`}\n * and match the given [JSON Schema](https://json-schema.org).\n * Unlike {@link discover}, this method will not return objects created by other users.\n *\n * This method is not useful for most applications, but necessary for\n * getting a global view of all a user's Graffiti data or debugging\n * channel usage.\n *\n * It's return value is the same as {@link discover}.\n *\n * @group Query Methods\n */\n abstract recoverOrphans<Schema extends JSONSchema>(\n /**\n * A [JSON Schema](https://json-schema.org) that orphaned objects must satisfy.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): GraffitiStream<\n GraffitiObject<Schema>,\n {\n tombstoneRetention: number;\n }\n >;\n\n /**\n * Returns statistics about all the {@link GraffitiObjectBase.channels | `channels`}\n * that an {@link GraffitiObjectBase.actor | `actor`} has posted to.\n * This is not very useful for most applications, but\n * necessary for certain applications where a user wants a\n * global view of all their Graffiti data or to debug\n * channel usage.\n *\n * @group Query Methods\n *\n * @returns A stream of statistics for each {@link GraffitiObjectBase.channels | `channel`}\n * that the {@link GraffitiObjectBase.actor | `actor`} has posted to.\n */\n abstract channelStats(\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): GraffitiStream<ChannelStats>;\n\n /**\n * Begins the login process. Depending on the implementation, this may\n * involve redirecting the user to a login page or opening a popup,\n * so it should always be called in response to a user action.\n *\n * The {@link GraffitiSession | session} object is returned\n * asynchronously via {@link Graffiti.sessionEvents | sessionEvents}\n * as a {@link GraffitiLoginEvent} with event type `login`.\n *\n * @group Session Management\n */\n abstract login(\n /**\n * Suggestions for the permissions that the\n * login process should grant. The login process may not\n * provide the exact proposed permissions.\n */\n proposal?: {\n /**\n * A suggested actor to login as. For example, if a user tries to\n * edit a post but are not logged in, the interface can infer that\n * they might want to log in as the actor who created the post\n * they are attempting to edit.\n *\n * Even if provided, the implementation should allow the user\n * to log in as a different actor if they choose.\n */\n actor?: string;\n /**\n * A yet to be defined permissions scope. An application may use\n * this to indicate the minimum necessary scope needed to\n * operate. For example, it may need to be able read private\n * messages from a certain set of channels, or write messages that\n * follow a particular schema.\n *\n * The login process should make it clear what scope an application\n * is requesting and allow the user to enhance or reduce that\n * scope as necessary.\n */\n scope?: {};\n },\n ): Promise<void>;\n\n /**\n * Begins the logout process. Depending on the implementation, this may\n * involve redirecting the user to a logout page or opening a popup,\n * so it should always be called in response to a user action.\n *\n * A confirmation will be returned asynchronously via\n * {@link Graffiti.sessionEvents | sessionEvents}\n * as a {@link GraffitiLogoutEvent} as event type `logout`.\n *\n * @group Session Management\n */\n abstract logout(\n /**\n * The {@link GraffitiSession | session} object to logout.\n */\n session: GraffitiSession,\n ): Promise<void>;\n\n /**\n * An event target that can be used to listen for the following\n * events and they're corresponding event types:\n * - `login` - {@link GraffitiLoginEvent}\n * - `logout` - {@link GraffitiLogoutEvent}\n * - `initialized` - {@link GraffitiSessionInitializedEvent}\n *\n * @group Session Management\n */\n abstract readonly sessionEvents: EventTarget;\n}\n", "import type { JSONSchema, FromSchema } from \"json-schema-to-ts\";\nimport type { Operation as JSONPatchOperation } from \"fast-json-patch\";\n\n/**\n * Objects are the atomic unit in Graffiti that can represent both data (*e.g.* a social media post or profile)\n * and activities (*e.g.* a like or follow).\n * Objects are created and modified by a single {@link actor | `actor`}.\n *\n * Most of an object's content is stored in its {@link value | `value`} property, which can be any JSON\n * object. However, we recommend using properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)\n * or properties that emerge in the Graffiti [folksonomy](https://en.wikipedia.org/wiki/Folksonomy)\n * to promote interoperability.\n *\n * The {@link name | `name`}, {@link actor | `actor`}, and {@link source | `source`}\n * properties together uniquely describe the {@link GraffitiLocation | object's location}\n * and can be {@link Graffiti.locationToUri | converted to a globally unique URI}.\n *\n * The {@link channels | `channels`} and {@link allowed | `allowed`} properties\n * enable the object's creator to shape the visibility of and access to their object.\n *\n * The {@link tombstone | `tombstone`} and {@link lastModified | `lastModified`} properties are for\n * caching and synchronization.\n */\nexport interface GraffitiObjectBase {\n /**\n * The object's content as freeform JSON. We recommend using properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)\n * or properties that emerge in the Graffiti [folksonomy](https://en.wikipedia.org/wiki/Folksonomy)\n * to promote interoperability.\n */\n value: {};\n\n /**\n * An array of URIs the creator associates with the object. Objects can only be found by querying\n * one of the object's channels using the\n * {@link Graffiti.discover} method. This allows creators to express the intended audience of their object\n * which helps to prevent [context collapse](https://en.wikipedia.org/wiki/Context_collapse) even\n * in the highly interoperable ecosystem that Graffiti envisions. For example, channel URIs may be:\n * - A user's own {@link actor | `actor`} URI. Putting an object in this channel is a way to broadcast\n * the object to the user's followers, like posting a tweet.\n * - The URI of a Graffiti post. Putting an object in this channel is a way to broadcast to anyone viewing\n * the post, like commenting on a tweet.\n * - A URI representing a topic. Putting an object in this channel is a way to broadcast to anyone interested\n * in that topic, like posting in a subreddit.\n */\n channels: string[];\n\n /**\n * An optional array of {@link actor | `actor`} URIs that the creator allows to access the object.\n * If no `allowed` array is provided, the object can be accessed by anyone (so long as they\n * also know the right {@link channels | `channel` } to look in). An object can always be accessed by its creator, even if\n * the `allowed` array is empty.\n *\n * The `allowed` array is not revealed to users other than the creator, like\n * a BCC email. A user may choose to add a `to` property to the object's {@link value | `value`} to indicate\n * other recipients, however this is not enforced by Graffiti and may not accurately reflect the actual `allowed` array.\n *\n * `allowed` can be combined with {@link channels | `channels`}. For example, to send someone a direct message\n * the sender should put their object in the channel of the recipient's {@link actor | `actor`} URI to notify them of the message and also add\n * the recipient's {@link actor | `actor`} URI to the `allowed` array to prevent others from seeing the message.\n */\n allowed?: string[] | null;\n\n /**\n * The URI of the `actor` that {@link Graffiti.put | created } the object. This `actor` also has the unique permission to\n * {@link Graffiti.patch | modify} or {@link Graffiti.delete | delete} the object.\n *\n * We borrow the term actor from the ActivityPub because\n * [like in ActivityPub](https://www.w3.org/TR/activitypub/#h-note-0)\n * there is not necessarily a one-to-one mapping between actors and people/users.\n * Multiple people can share the same actor or one person can have multiple actors.\n * Actors can also be bots.\n *\n * In Graffiti, actors are always globally unique URIs which\n * allows them to also function as {@link channels | `channels`}.\n */\n actor: string;\n\n /**\n * A name for the object. This name is not globally unique but it is unique when\n * combined with the {@link actor | `actor`} and {@link source | `source`}.\n * Often times it is not specified by the user and randomly generated during {@link Graffiti.put | creation}.\n * If an object is created with the same `name`, `actor`, and `source` as an existing object,\n * the existing object will be replaced with the new object.\n */\n name: string;\n\n /**\n * The URI of the source that stores the object. In some decentralized implementations,\n * it can represent the server or [pod](https://en.wikipedia.org/wiki/Solid_(web_decentralization_project)#Design)\n * that a user has delegated to store their objects. In others it may represent the distributed\n * storage network that the object is stored on.\n */\n source: string;\n\n /**\n * The time the object was last modified, measured in milliseconds since January 1, 1970.\n * This is used for caching and synchronization.\n * A number, rather than an ISO string or Date object, is used for easy comparison, sorting,\n * and JSON Schema [range queries](https://json-schema.org/understanding-json-schema/reference/numeric#range).\n *\n * It is possible to use this value to sort objects in a user's interface but in many cases it would be better to\n * use a `createdAt` property in the object's {@link value | `value`} to indicate when the object was created\n * rather than when it was modified.\n */\n lastModified: number;\n\n /**\n * A boolean indicating whether the object has been deleted.\n * Depending on implementation, objects stay available for some time after deletion to allow for synchronization.\n */\n tombstone: boolean;\n}\n\n/**\n * This type constrains the {@link GraffitiObjectBase} type to adhere to a\n * particular [JSON schema](https://json-schema.org/).\n * This allows for static type-checking of an object's {@link GraffitiObjectBase.value | `value`}\n * which is otherwise a freeform JSON object.\n *\n * Schema-aware objects are returned by {@link Graffiti.get} and {@link Graffiti.discover}.\n */\nexport type GraffitiObject<Schema extends JSONSchema> = GraffitiObjectBase &\n FromSchema<Schema & typeof GraffitiObjectJSONSchema>;\n\n/**\n * A JSON Schema equivalent to the {@link GraffitiObjectBase} type.\n * Needed internally for type inference of JSON Schemas, but can\n * be used by implementations to validate objects.\n */\nexport const GraffitiObjectJSONSchema = {\n type: \"object\",\n properties: {\n value: { type: \"object\" },\n channels: { type: \"array\", items: { type: \"string\" } },\n allowed: { type: \"array\", items: { type: \"string\" }, nullable: true },\n actor: { type: \"string\" },\n name: { type: \"string\" },\n source: { type: \"string\" },\n lastModified: { type: \"number\" },\n tombstone: { type: \"boolean\" },\n },\n additionalProperties: false,\n required: [\n \"value\",\n \"channels\",\n \"actor\",\n \"name\",\n \"source\",\n \"lastModified\",\n \"tombstone\",\n ],\n} as const satisfies JSONSchema;\n\n/**\n * This is a subset of properties from {@link GraffitiObjectBase} that uniquely\n * identify an object's location: {@link GraffitiObjectBase.actor | `actor`},\n * {@link GraffitiObjectBase.name | `name`}, and {@link GraffitiObjectBase.source | `source`}.\n * Attempts to create an object with the same `actor`, `name`, and `source`\n * as an existing object will replace the existing object (see {@link Graffiti.put}).\n *\n * This location can be converted to\n * a globally unique URI using {@link Graffiti.locationToUri}.\n */\nexport type GraffitiLocation = Pick<\n GraffitiObjectBase,\n \"actor\" | \"name\" | \"source\"\n>;\n\n/**\n * This object is a subset of {@link GraffitiObjectBase} that a user must construct locally before calling {@link Graffiti.put}.\n * This local copy does not require system-generated properties and may be statically typed with\n * a [JSON schema](https://json-schema.org/) to prevent the accidental creation of erroneous objects.\n *\n * This local object must have a {@link GraffitiObjectBase.value | `value`} and {@link GraffitiObjectBase.channels | `channels`}\n * and may optionally have an {@link GraffitiObjectBase.allowed | `allowed`} property.\n *\n * It may also contain any of the {@link GraffitiLocation } properties: {@link GraffitiObjectBase.actor | `actor`},\n * {@link GraffitiObjectBase.name | `name`}, and {@link GraffitiObjectBase.source | `source`}.\n * If the location provided exactly matches an existing object, the existing object will be replaced.\n * If no `name` is provided, one will be randomly generated.\n * If no `actor` is provided, the `actor` from the supplied {@link GraffitiSession | `session` } will be used.\n * If no `source` is provided, one may be inferred by the depending on implementation.\n *\n * This object does not need a {@link GraffitiObjectBase.lastModified | `lastModified`} or {@link GraffitiObjectBase.tombstone | `tombstone`}\n * property since these are automatically generated by the Graffiti system.\n */\nexport type GraffitiPutObject<Schema extends JSONSchema> = Pick<\n GraffitiObjectBase,\n \"value\" | \"channels\" | \"allowed\"\n> &\n Partial<GraffitiObjectBase> &\n FromSchema<Schema & typeof GraffitiPutObjectJSONSchema>;\n\n/**\n * A JSON Schema equivalent to the {@link GraffitiPutObject} type.\n * Needed internally for type inference of JSON Schemas, but can\n * be used by implementations to validate objects.\n */\nexport const GraffitiPutObjectJSONSchema = {\n ...GraffitiObjectJSONSchema,\n required: [\"value\", \"channels\"],\n} as const satisfies JSONSchema;\n\n/**\n * This object contains information that\n * {@link GraffitiObjectBase.source | `source`}s can\n * use to verify that a user has permission to operate a\n * particular {@link GraffitiObjectBase.actor | `actor`}.\n * This object is required of all {@link Graffiti} methods\n * that modify objects and is optional for methods that read objects.\n *\n * At a minimum the `session` object must contain the\n * {@link GraffitiSession.actor | `actor`} URI the user wants to authenticate with.\n * However it is likely that the `session` object must contain other\n * implementation-specific properties.\n * For example, a Solid implementation might include a\n * [`fetch`](https://docs.inrupt.com/developer-tools/api/javascript/solid-client-authn-browser/functions.html#fetch)\n * function. A distributed implementation may include\n * a cryptographic signature.\n *\n * As to why the `session` object is passed as an argument to every method\n * rather than being an internal property of the {@link Graffiti} instance,\n * this is primarily for type-checking to catch bugs related to login state.\n * Graffiti applications can expose some functionality to users who are not logged in\n * with {@link Graffiti.get} and {@link Graffiti.discover} but without type-checking\n * the `session` it can be easy to forget to hide buttons that trigger\n * other methods that require login.\n * In the future, `session` object may be updated to include scope information\n * and passing the `session` to each method can type-check whether the session provides the\n * necessary permissions.\n *\n * Passing the `session` object per-method also allows for multiple sessions\n * to be used within the same application, like an Email client fetching from\n * multiple accounts.\n */\nexport interface GraffitiSession {\n /**\n * The {@link GraffitiObjectBase.actor | `actor`} a user wants to authenticate with.\n */\n actor: string;\n /**\n * A yet undefined property detailing what operations the session\n * grants the user to perform. For example, to allow a user to\n * read private messages from a particular set of channels or\n * to allow the user to write object matching a particular schema.\n */\n scope?: {};\n}\n\n/**\n * This is the format for patches that modify {@link GraffitiObjectBase} objects\n * using the {@link Graffiti.patch} method. The patches must\n * be an array of [JSON Patch](https://jsonpatch.com) operations.\n * Patches can only be applied to the\n * {@link GraffitiObjectBase.value | `value`}, {@link GraffitiObjectBase.channels | `channels`},\n * and {@link GraffitiObjectBase.allowed | `allowed`} properties since the other\n * properties either describe the object's location or are automatically generated.\n * (See also {@link GraffitiPutObject}).\n */\nexport interface GraffitiPatch {\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.value | `value`}. The resulting\n * `value` must still be a JSON object.\n */\n value?: JSONPatchOperation[];\n\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.channels | `channels`}. The resulting\n * `channels` must still be an array of strings.\n */\n channels?: JSONPatchOperation[];\n\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.allowed | `allowed`} property. The resulting\n * `allowed` property must still be an array of strings or `undefined`.\n */\n allowed?: JSONPatchOperation[];\n}\n\n/**\n * This type represents a stream of data that are\n * returned by Graffiti's query-like operations such as\n * {@link Graffiti.discover} and {@link Graffiti.recoverOrphans}.\n *\n * Errors are returned within the stream rather than as\n * exceptions that would halt the entire stream. This is because\n * some implementations may pull data from multiple\n * {@link GraffitiObjectBase.source | `source`}s\n * including some that may be unreliable. In many cases,\n * these errors can be safely ignored.\n *\n * The stream is an [`AsyncGenerator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)\n * that can be iterated over using `for await` loops or calling `next` on the generator.\n * The stream can be terminated by breaking out of a loop calling `return` on the generator.\n */\nexport type GraffitiStream<TValue, TReturn = void> = AsyncGenerator<\n | {\n error?: undefined;\n value: TValue;\n }\n | {\n error: Error;\n source: string;\n },\n TReturn\n>;\n\n/**\n * Statistic about single channel returned by {@link Graffiti.channelStats}.\n * These statistics only account for contributions made by the\n * querying actor.\n */\nexport type ChannelStats = {\n /**\n * The URI of the channel.\n */\n channel: string;\n /**\n * The number of non-{@link GraffitiObjectBase.tombstone | `tombstone`}d objects\n * that the actor has posted to the channel.\n */\n count: number;\n /**\n * The time that the actor {@link GraffitiObjectBase.lastModified | last modified} an object in the channel,\n * measured in milliseconds since January 1, 1970.\n * {@link GraffitiObjectBase.tombstone | Tombstone}d objects do not effect this modification time.\n */\n lastModified: number;\n};\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * when a user logs in manually from {@link Graffiti.login}\n * or when their session is restored from a previous login.\n * The event name to listen for is `login`.\n */\nexport type GraffitiLoginEvent = CustomEvent<\n | {\n error: Error;\n session?: undefined;\n }\n | {\n error?: undefined;\n session: GraffitiSession;\n }\n>;\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * when a user logs out either manually with {@link Graffiti.logout}\n * or when their session times out or otherwise becomes invalid.\n * The event name to listen for is `logout`.\n */\nexport type GraffitiLogoutEvent = CustomEvent<\n | {\n error: Error;\n actor?: string;\n }\n | {\n error?: undefined;\n actor: string;\n }\n>;\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * after an application has attempted to complete any login redirects\n * and restore any previously active sessions.\n * Successful session restores will be returned in parallel as\n * their own {@link GraffitiLoginEvent} events.\n *\n * This event optionally returns an `href` property\n * representing the URL the user originated a login request\n * from, which may be useful for redirecting the user back to\n * the page they were on after login.\n * The event name to listen for is `initialized`.\n */\nexport type GraffitiSessionInitializedEvent = CustomEvent<\n | {\n error?: Error;\n href?: string;\n }\n | null\n | undefined\n>;\n", "export class GraffitiErrorUnauthorized extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorUnauthorized\";\n Object.setPrototypeOf(this, GraffitiErrorUnauthorized.prototype);\n }\n}\n\nexport class GraffitiErrorForbidden extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorForbidden\";\n Object.setPrototypeOf(this, GraffitiErrorForbidden.prototype);\n }\n}\n\nexport class GraffitiErrorNotFound extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorNotFound\";\n Object.setPrototypeOf(this, GraffitiErrorNotFound.prototype);\n }\n}\n\nexport class GraffitiErrorInvalidSchema extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorInvalidSchema\";\n Object.setPrototypeOf(this, GraffitiErrorInvalidSchema.prototype);\n }\n}\n\nexport class GraffitiErrorSchemaMismatch extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorSchemaMismatch\";\n Object.setPrototypeOf(this, GraffitiErrorSchemaMismatch.prototype);\n }\n}\n\nexport class GraffitiErrorPatchTestFailed extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorPatchTestFailed\";\n Object.setPrototypeOf(this, GraffitiErrorPatchTestFailed.prototype);\n }\n}\n\nexport class GraffitiErrorPatchError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorPatchError\";\n Object.setPrototypeOf(this, GraffitiErrorPatchError.prototype);\n }\n}\n\nexport class GraffitiErrorInvalidUri extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorInvalidUri\";\n Object.setPrototypeOf(this, GraffitiErrorInvalidUri.prototype);\n }\n}\n"],
5
- "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,cAAAE,EAAA,2BAAAC,EAAA,+BAAAC,EAAA,4BAAAC,EAAA,0BAAAC,EAAA,4BAAAC,EAAA,iCAAAC,EAAA,gCAAAC,EAAA,8BAAAC,EAAA,6BAAAC,EAAA,gCAAAC,IAAA,eAAAC,EAAAb,GC8LO,IAAec,EAAf,KAAwB,CA6B7B,YAAYC,EAA4B,CACtC,OAAO,KAAK,cAAcA,CAAM,CAClC,CA6VF,ECvbO,IAAMC,EAA2B,CACtC,KAAM,SACN,WAAY,CACV,MAAO,CAAE,KAAM,QAAS,EACxB,SAAU,CAAE,KAAM,QAAS,MAAO,CAAE,KAAM,QAAS,CAAE,EACrD,QAAS,CAAE,KAAM,QAAS,MAAO,CAAE,KAAM,QAAS,EAAG,SAAU,EAAK,EACpE,MAAO,CAAE,KAAM,QAAS,EACxB,KAAM,CAAE,KAAM,QAAS,EACvB,OAAQ,CAAE,KAAM,QAAS,EACzB,aAAc,CAAE,KAAM,QAAS,EAC/B,UAAW,CAAE,KAAM,SAAU,CAC/B,EACA,qBAAsB,GACtB,SAAU,CACR,QACA,WACA,QACA,OACA,SACA,eACA,WACF,CACF,EA+CaC,EAA8B,CACzC,GAAGD,EACH,SAAU,CAAC,QAAS,UAAU,CAChC,EC3MO,IAAME,EAAN,MAAMC,UAAkC,KAAM,CACnD,YAAYC,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,4BACZ,OAAO,eAAe,KAAMD,EAA0B,SAAS,CACjE,CACF,EAEaE,EAAN,MAAMC,UAA+B,KAAM,CAChD,YAAYF,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,yBACZ,OAAO,eAAe,KAAME,EAAuB,SAAS,CAC9D,CACF,EAEaC,EAAN,MAAMC,UAA8B,KAAM,CAC/C,YAAYJ,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,wBACZ,OAAO,eAAe,KAAMI,EAAsB,SAAS,CAC7D,CACF,EAEaC,EAAN,MAAMC,UAAmC,KAAM,CACpD,YAAYN,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,6BACZ,OAAO,eAAe,KAAMM,EAA2B,SAAS,CAClE,CACF,EAEaC,EAAN,MAAMC,UAAoC,KAAM,CACrD,YAAYR,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,8BACZ,OAAO,eAAe,KAAMQ,EAA4B,SAAS,CACnE,CACF,EAEaC,EAAN,MAAMC,UAAqC,KAAM,CACtD,YAAYV,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,+BACZ,OAAO,eAAe,KAAMU,EAA6B,SAAS,CACpE,CACF,EAEaC,EAAN,MAAMC,UAAgC,KAAM,CACjD,YAAYZ,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,0BACZ,OAAO,eAAe,KAAMY,EAAwB,SAAS,CAC/D,CACF,EAEaC,EAAN,MAAMC,UAAgC,KAAM,CACjD,YAAYd,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,0BACZ,OAAO,eAAe,KAAMc,EAAwB,SAAS,CAC/D,CACF",
6
- "names": ["index_exports", "__export", "Graffiti", "GraffitiErrorForbidden", "GraffitiErrorInvalidSchema", "GraffitiErrorInvalidUri", "GraffitiErrorNotFound", "GraffitiErrorPatchError", "GraffitiErrorPatchTestFailed", "GraffitiErrorSchemaMismatch", "GraffitiErrorUnauthorized", "GraffitiObjectJSONSchema", "GraffitiPutObjectJSONSchema", "__toCommonJS", "Graffiti", "object", "GraffitiObjectJSONSchema", "GraffitiPutObjectJSONSchema", "GraffitiErrorUnauthorized", "_GraffitiErrorUnauthorized", "message", "GraffitiErrorForbidden", "_GraffitiErrorForbidden", "GraffitiErrorNotFound", "_GraffitiErrorNotFound", "GraffitiErrorInvalidSchema", "_GraffitiErrorInvalidSchema", "GraffitiErrorSchemaMismatch", "_GraffitiErrorSchemaMismatch", "GraffitiErrorPatchTestFailed", "_GraffitiErrorPatchTestFailed", "GraffitiErrorPatchError", "_GraffitiErrorPatchError", "GraffitiErrorInvalidUri", "_GraffitiErrorInvalidUri"]
4
+ "sourcesContent": ["export * from \"./1-api\";\nexport * from \"./2-types\";\nexport * from \"./3-errors\";\nexport type { JSONSchema } from \"json-schema-to-ts\";\n", "import type {\n GraffitiObjectUrl,\n GraffitiObject,\n GraffitiObjectBase,\n GraffitiPatch,\n GraffitiSession,\n GraffitiPutObject,\n GraffitiStream,\n ChannelStats,\n} from \"./2-types\";\nimport type { JSONSchema } from \"json-schema-to-ts\";\n\n/**\n * This API describes a small but powerful set of methods that\n * can be used to create many different kinds of social media applications,\n * all of which can interoperate.\n * These methods should satisfy all of an application's needs for\n * the communication, storage, and access management of social data.\n * The rest of the application can be built with standard client-side\n * user interface tools to present and interact with the data \u2014\n * no server code necessary.\n * The Typescript source for this API is available at\n * [graffiti-garden/api](https://github.com/graffiti-garden/api).\n *\n * There are several different implementations of this Graffiti API available,\n * including a [federated implementation](https://github.com/graffiti-garden/implementation-federated),\n * that lets users choose where their data is stored,\n * and a [local implementation](https://github.com/graffiti-garden/implementation-local)\n * that can be used for testing and development. In our design of Graffiti, this API is our\n * primary focus as it is the layer that shapes the experience\n * of developing applications. While different implementations can provide tradeoffs between\n * other important properties (e.g. privacy, security, scalability), those properties\n * are useless if the system as a whole doesn't expose useful functionality to developers.\n *\n * On the other side of the stack, there is [Vue plugin](https://github.com/graffiti-garden/wrapper-vue/)\n * that wraps around this API to provide reactivity. Other high-level libraries\n * will be available in the future.\n *\n * ## Overview\n *\n * Graffiti provides applications with methods to create and store data\n * on behalf of their users using standard CRUD operations:\n * {@link put}, {@link get}, {@link patch}, and {@link delete}.\n * This data can represent both social artifacts (e.g. posts, profiles) and\n * activities (e.g. likes, follows) and is stored as JSON.\n *\n * The social aspect of Graffiti comes from the {@link discover} method\n * which allows applications to find objects that other users made.\n * It is a lot like a traditional query operation, but it only\n * returns objects that have been placed in particular\n * {@link GraffitiObjectBase.channels | `channels`}\n * specified by the discovering application.\n *\n * Graffiti builds on well known concepts and standards wherever possible.\n * JSON Objects can be typed with [JSON Schema](https://json-schema.org/) and patches\n * can be applied with [JSON Patch](https://jsonpatch.com).\n * For interoperability between Graffiti applications, we recommend that\n * objects use established properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/) when available,\n * however it is always possible to create additional properties, contributing\n * to the broader [folksonomy](https://en.wikipedia.org/wiki/Folksonomy).\n *\n * {@link GraffitiObjectBase.channels | `channels`} are one of the major concepts\n * unique to Graffiti along with *interaction relativity*, defined below.\n * Channels create boundaries between public spaces and work to prevent\n * [context collapse](https://en.wikipedia.org/wiki/Context_collapse)\n * even in a highly interoperable environment.\n * Interaction relativity means that all interactions between users are\n * actually atomic single-user operations that can be interpreted in different ways,\n * which also supports interoperability and pluralism.\n *\n * ### Channels\n *\n * {@link GraffitiObjectBase.channels | `channels`}\n * are a way for the creators of social data to express the intended audience of their\n * data. When a user creates data using the {@link put} method, they\n * can place their data in one or more channels.\n * Content consumers using the {@link discover} method will only see data\n * contained in one of the channels they specify.\n *\n * While many channels may be public, they partition\n * the public into different \"contexts\", mitigating the\n * phenomenon of [context collapse](https://en.wikipedia.org/wiki/Context_collapse) or the \"flattening of multiple audiences.\"\n * Any [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier) can be used as a channel, and so channels can represent people,\n * comment threads, topics, places (real or virtual), pieces of media, and more.\n *\n * For example, consider a comment on a post. If we place that comment in the channel\n * represented by the post's URL, then only people viewing the post will know to\n * look in that channel, giving it visibility akin to a comment on a blog post\n * or comment on Instagram ([since 2019](https://www.buzzfeednews.com/article/katienotopoulos/instagrams-following-activity-tab-is-going-away)).\n * If we also place the comment in the channel represented by the commenter's URI (their\n * {@link GraffitiObjectBase.actor | `actor` URI}), then people viewing the commenter's profile\n * will also see the comment, giving it more visibility, like a reply on Twitter.\n * If we *only* place the comment in the channel represented by the commenter's URI, then\n * it becomes like a quote tweet ([prior to 2020](https://x.com/Support/status/1300555325750292480)),\n * where the comment is only visible to the commenter's followers but not the audience\n * of the original post.\n *\n * The channel model differs from other models of communication such as the\n * [actor model](https://www.w3.org/TR/activitypub/#Overview) used by ActivityPub,\n * the protocol underlying Mastodon, or the [firehose model](https://bsky.social/about/blog/5-5-2023-federation-architecture)\n * used by the AT Protocol, the protocol underlying BlueSky.\n * The actor model is a fusion of direct messaging (like Email) and broadcasting\n * (like RSS) and works well for follow-based communication but struggles\n * to pass information via other rendez-vous.\n * In the actor model, even something as simple as comments can be\n * [very tricky and require server \"side effects\"](https://seb.jambor.dev/posts/understanding-activitypub-part-3-the-state-of-mastodon/).\n * The firehose model dumps all user data into one public database,\n * which doesn't allow for the carving out of different contexts that we did in our comment\n * example above. In the firehose model a comment will always be visible to *both* the original post's audience and\n * the commenter's followers.\n *\n * In some sense, channels provide a sort of \"social access control\" by forming\n * expectations about the audiences of different online spaces.\n * As a real world analogy, oftentimes support groups, such as alcoholics\n * anonymous, are open to the public but people in those spaces feel comfortable sharing intimate details\n * because they have expectations about the other people attending.\n * If someone malicious went to support groups just to spread people's secrets,\n * they would be shamed for violating these norms.\n * Similarly, in Graffiti, while you could spider public channels like a search engine\n * to find content about a person, revealing that you've done such a thing\n * would be shameful.\n *\n * Still, social access control is not perfect and so in situations where privacy is important,\n * objects can also be given\n * an {@link GraffitiObjectBase.allowed | `allowed`} list.\n * For example, to send someone a direct message you should put an object representing\n * that message in the channel that represents them (their {@link GraffitiObjectBase.actor | `actor` URI}),\n * so they can find it, *and* set the `allowed` field to only include the recipient,\n * so only they can read it.\n *\n * ### Interaction relativity\n *\n * Interaction relativity posits that \"interaction between two individuals only\n * exists relative to an observer,\" or equivalently, all interaction is [reified](https://en.wikipedia.org/wiki/Reification_(computer_science)).\n * For example, if one user creates a post and another user wants to \"like\" that post,\n * their like is not modifying the original post, it is simply another data object that points\n * to the post being liked, via its {@link GraffitiObjectBase.url | URL}.\n *\n * ```json\n * {\n * activity: 'like',\n * target: 'url-of-the-post-i-like',\n * actor: 'my-user-id'\n * }\n * ```\n *\n * In Graffiti, all interactions including *moderation* and *collaboration* are relative.\n * This means that applications can freely choose which interactions\n * they want to express to their users and how.\n * For example, one application could have a single fixed moderator,\n * another could allow users to choose which moderators they would like filter their content\n * like [Bluesky's stackable moderation](https://bsky.social/about/blog/03-12-2024-stackable-moderation),\n * and another could implement a fully democratic system like [PolicyKit](https://policykit.org/).\n * Each of these applications is one interpretation of the underlying refieid user interactions and\n * users can freely switch between them.\n *\n * Interaction relativy also allows applications to introduce new sorts of interactions\n * without having to coordinate with all the other existing applications,\n * keeping the ecosystem flexible and interoperable.\n * For example, an application could [add a \"Trust\" button to posts](https://social.cs.washington.edu/pub_details.html?id=trustnet)\n * and use it assess the truthfulness of posts made on applications across Graffiti.\n * New sorts of interactions like these can be smoothly absorbed by the broader ecosystem\n * as a [folksonomy](https://en.wikipedia.org/wiki/Folksonomy).\n *\n * Interactivy relativity is realized in Graffiti through two design decisions:\n * 1. The creators of objects can only modify their own objects. It is important for\n * users to be able to change and delete their own content to respect their\n * [right to be forgotten](https://en.wikipedia.org/wiki/Right_to_be_forgotten),\n * but beyond self-correction and self-censorship all other interaction is reified.\n * Many interactions can be reified via pointers, as in the \"like\" example above, and collaborative\n * edits can be refieid via [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type).\n * 2. No one owns channels. Unlike IRC/Slack channels or [Matrix rooms](https://matrix.org/docs/matrix-concepts/rooms_and_events/),\n * anyone can post to any channel, so long as they know the URI of that channel.\n * It is up to applications to hide content from channels either according to manual\n * filters or in response to user action.\n * For example, a user may create a post with the flag `disableReplies`.\n * Applications could then filter out any content from the replies channel\n * that the original poster has not specifically approved.\n *\n * @groupDescription CRUD Methods\n * Methods for {@link put | creating}, {@link get | reading}, {@link patch | updating},\n * and {@link delete | deleting} {@link GraffitiObjectBase | Graffiti objects}.\n * @groupDescription Query Methods\n * Methods that retrieve or accumulate information about multiple {@link GraffitiObjectBase | Graffiti objects} at a time.\n * @groupDescription Session Management\n * Methods and properties for logging in and out of a Graffiti implementation.\n */\nexport abstract class Graffiti {\n /**\n * Creates a new {@link GraffitiObjectBase | object} or replaces an existing object.\n * An object can only be replaced by the same {@link GraffitiObjectBase.actor | `actor`}\n * that created it.\n *\n * Replacement occurs when the {@link GraffitiObjectBase.url | `url`} of\n * the replaced object exactly matches an existing object's URL.\n *\n * @returns The object that was replaced if one exists or an object with\n * with an empty {@link GraffitiObjectBase.value | `value`},\n * {@link GraffitiObjectBase.channels | `channels`}, and {@link GraffitiObjectBase.allowed | `allowed`}\n * list if the method created a new object.\n * In either case, the object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of replacement/creation.\n *\n * @group CRUD Methods\n */\n abstract put<Schema extends JSONSchema>(\n /**\n * The object to be put. This object is statically type-checked against the [JSON schema](https://json-schema.org/) that can be optionally provided\n * as the generic type parameter. We highly recommend providing a schema to\n * ensure that the PUT object matches subsequent {@link get} or {@link discover}\n * methods.\n */\n object: GraffitiPutObject<Schema>,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Retrieves an object from a given location.\n *\n * The retrieved object is type-checked against the provided [JSON schema](https://json-schema.org/)\n * otherwise a {@link GraffitiErrorSchemaMismatch} is thrown.\n *\n * If the retreiving {@link GraffitiObjectBase.actor | `actor`} is not\n * the object's `actor`,\n * the object's {@link GraffitiObjectBase.allowed | `allowed`} and\n * {@link GraffitiObjectBase.channels | `channels`} properties are\n * not revealed, similar to a BCC.\n *\n * If the object existed but has since been deleted,\n * or the retrieving {@link GraffitiObjectBase.actor | `actor`}\n * was {@link GraffitiObjectBase.allowed | `allowed`} to access\n * the object but now isn't, this method may return the latest\n * version of the object that the {@link GraffitiObjectBase.actor | `actor`}\n * was allowed to access with its {@link GraffitiObjectBase.tombstone | `tombstone`}\n * set to `true`. This allows for the invalidation of the object\n * in a client-side cache.\n *\n * Otherwise, if the object never existed, or the\n * retrieving {@link GraffitiObjectBase.actor | `actor`} was never\n * {@link GraffitiObjectBase.allowed | `allowed`} to access it, or if\n * the object was changed long enough ago that it has been permanently deleted,\n * a {@link GraffitiErrorNotFound} is thrown.\n * The rate at which permanent deletions happen is implementation dependent.\n * See the `tombstoneRetention` property returned by {@link discover}.\n *\n * @group CRUD Methods\n */\n abstract get<Schema extends JSONSchema>(\n /**\n * The location of the object to get.\n */\n url: string | GraffitiObjectUrl,\n /**\n * The JSON schema to validate the retrieved object against.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}. If no `session` is provided,\n * the retrieved object's {@link GraffitiObjectBase.allowed | `allowed`}\n * property must be `undefined`.\n */\n session?: GraffitiSession | null,\n ): Promise<GraffitiObject<Schema>>;\n\n /**\n * Patches an existing object at a given location.\n * The patching {@link GraffitiObjectBase.actor | `actor`} must be the same as the\n * `actor` that created the object.\n *\n * @returns The original object prior to the patch\n * The object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of deletion.\n *\n * @throws {@link GraffitiErrorNotFound} if the object does not exist or has already been deleted.\n *\n * @group CRUD Methods\n */\n abstract patch(\n /**\n * A collection of [JSON Patch](https://jsonpatch.com) operations\n * to apply to the object. See {@link GraffitiPatch} for more information.\n */\n patch: GraffitiPatch,\n /**\n * The location of the object to patch.\n */\n url: string | GraffitiObjectUrl,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Deletes an object from a given location.\n * The deleting {@link GraffitiObjectBase.actor | `actor`} must be the same as the\n * `actor` that created the object.\n *\n * @returns The object that was deleted if one exists.\n * The object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of deletion.\n *\n * @throws {@link GraffitiErrorNotFound} if the object does not exist or has already been deleted.\n *\n * @group CRUD Methods\n */\n abstract delete(\n /**\n * The location of the object to delete.\n */\n url: string | GraffitiObjectUrl,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Discovers objects created by any user that are contained\n * in at least one of the given {@link GraffitiObjectBase.channels | `channels`}\n * and match the given [JSON Schema](https://json-schema.org).\n *\n * Objects are returned asynchronously as they are discovered but the stream\n * will end once all leads have been exhausted.\n * The method must be polled again for new objects.\n *\n * `discover` will not return objects that the {@link GraffitiObjectBase.actor | `actor`}\n * is not {@link GraffitiObjectBase.allowed | `allowed`} to access.\n * If the actor is not the creator of a discovered object,\n * the allowed list will be masked to only contain the querying actor if the\n * allowed list is not `undefined` (public). Additionally, if the actor is not the\n * creator of a discovered object, any {@link GraffitiObjectBase.channels | `channels`}\n * not specified by the `discover` method will not be revealed. This masking happens\n * before the supplied schema is applied.\n *\n * Since different implementations may fetch data from multiple sources there is\n * no guarentee on the order that objects are returned in. Additionally, the method\n * will return objects that have been deleted but with a\n * {@link GraffitiObjectBase.tombstone | `tombstone`} field set to `true` for\n * client-side cache invalidation purposes.\n * The final `return()` value of the stream includes a `tombstoneRetention`\n * property that represents the minimum amount of time,\n * in milliseconds, that an application will retain and return tombstones for objects that\n * have been deleted.\n *\n * When repolling, the {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field can be queried via the schema to\n * only fetch objects that have been modified since the last poll.\n * Such queries should only be done if the time since the last poll\n * is less than the `tombstoneRetention` value of that poll, otherwise the tombstones\n * for objects that have been deleted may not be returned.\n *\n * ```json\n * {\n * \"properties\": {\n * \"lastModified\": {\n * \"minimum\": LAST_RETRIEVED_TIME\n * }\n * }\n * }\n * ```\n *\n * `discover` needs to be polled for new data because live updates to\n * an application can be visually distracting or lead to toxic engagement.\n * If and when an application wants real-time updates, such as in a chat\n * application, application authors must be intentional about their polling.\n *\n * Implementers should be aware that some users may applications may try to poll\n * {@link discover} repetitively. They can deal with this by rate limiting or\n * preemptively fetching data via a bidirectional channel, like a WebSocket.\n * Additionally, implementers should probably index the `lastModified` field\n * to speed up responses to schemas like the one above.\n *\n * @returns A stream of objects that match the given {@link GraffitiObjectBase.channels | `channels`}\n * and [JSON Schema](https://json-schema.org).\n *\n * @group Query Methods\n */\n abstract discover<Schema extends JSONSchema>(\n /**\n * The {@link GraffitiObjectBase.channels | `channels`} that objects must be associated with.\n */\n channels: string[],\n /**\n * A [JSON Schema](https://json-schema.org) that objects must satisfy.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}. If no `session` is provided,\n * only objects that have no {@link GraffitiObjectBase.allowed | `allowed`}\n * property will be returned.\n */\n session?: GraffitiSession | null,\n ): GraffitiStream<\n GraffitiObject<Schema>,\n {\n tombstoneRetention: number;\n }\n >;\n\n /**\n * Discovers objects **not** contained in any\n * {@link GraffitiObjectBase.channels | `channels`}\n * that were created by the querying {@link GraffitiObjectBase.actor | `actor`}\n * and match the given [JSON Schema](https://json-schema.org).\n * Unlike {@link discover}, this method will not return objects created by other users.\n *\n * This method is not useful for most applications, but necessary for\n * getting a global view of all a user's Graffiti data or debugging\n * channel usage.\n *\n * It's return value is the same as {@link discover}.\n *\n * @group Query Methods\n */\n abstract recoverOrphans<Schema extends JSONSchema>(\n /**\n * A [JSON Schema](https://json-schema.org) that orphaned objects must satisfy.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): GraffitiStream<\n GraffitiObject<Schema>,\n {\n tombstoneRetention: number;\n }\n >;\n\n /**\n * Returns statistics about all the {@link GraffitiObjectBase.channels | `channels`}\n * that an {@link GraffitiObjectBase.actor | `actor`} has posted to.\n * This is not very useful for most applications, but\n * necessary for certain applications where a user wants a\n * global view of all their Graffiti data or to debug\n * channel usage.\n *\n * @group Query Methods\n *\n * @returns A stream of statistics for each {@link GraffitiObjectBase.channels | `channel`}\n * that the {@link GraffitiObjectBase.actor | `actor`} has posted to.\n */\n abstract channelStats(\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): GraffitiStream<ChannelStats>;\n\n /**\n * Begins the login process. Depending on the implementation, this may\n * involve redirecting the user to a login page or opening a popup,\n * so it should always be called in response to a user action.\n *\n * The {@link GraffitiSession | session} object is returned\n * asynchronously via {@link Graffiti.sessionEvents | sessionEvents}\n * as a {@link GraffitiLoginEvent} with event type `login`.\n *\n * @group Session Management\n */\n abstract login(\n /**\n * Suggestions for the permissions that the\n * login process should grant. The login process may not\n * provide the exact proposed permissions.\n */\n proposal?: {\n /**\n * A suggested actor to login as. For example, if a user tries to\n * edit a post but are not logged in, the interface can infer that\n * they might want to log in as the actor who created the post\n * they are attempting to edit.\n *\n * Even if provided, the implementation should allow the user\n * to log in as a different actor if they choose.\n */\n actor?: string;\n /**\n * A yet to be defined permissions scope. An application may use\n * this to indicate the minimum necessary scope needed to\n * operate. For example, it may need to be able read private\n * messages from a certain set of channels, or write messages that\n * follow a particular schema.\n *\n * The login process should make it clear what scope an application\n * is requesting and allow the user to enhance or reduce that\n * scope as necessary.\n */\n scope?: {};\n },\n ): Promise<void>;\n\n /**\n * Begins the logout process. Depending on the implementation, this may\n * involve redirecting the user to a logout page or opening a popup,\n * so it should always be called in response to a user action.\n *\n * A confirmation will be returned asynchronously via\n * {@link Graffiti.sessionEvents | sessionEvents}\n * as a {@link GraffitiLogoutEvent} as event type `logout`.\n *\n * @group Session Management\n */\n abstract logout(\n /**\n * The {@link GraffitiSession | session} object to logout.\n */\n session: GraffitiSession,\n ): Promise<void>;\n\n /**\n * An event target that can be used to listen for the following\n * events and they're corresponding event types:\n * - `login` - {@link GraffitiLoginEvent}\n * - `logout` - {@link GraffitiLogoutEvent}\n * - `initialized` - {@link GraffitiSessionInitializedEvent}\n *\n * @group Session Management\n */\n abstract readonly sessionEvents: EventTarget;\n}\n", "import type { JSONSchema, FromSchema } from \"json-schema-to-ts\";\nimport type { Operation as JSONPatchOperation } from \"fast-json-patch\";\n\n/**\n * Objects are the atomic unit in Graffiti that can represent both data (*e.g.* a social media post or profile)\n * and activities (*e.g.* a like or follow).\n * Objects are created and modified by a single {@link actor | `actor`}.\n *\n * Most of an object's content is stored in its {@link value | `value`} property, which can be any JSON\n * object. However, we recommend using properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)\n * or properties that emerge in the Graffiti [folksonomy](https://en.wikipedia.org/wiki/Folksonomy)\n * to promote interoperability.\n *\n * The object is globally addressable via its {@link url | `url`}.\n *\n * The {@link channels | `channels`} and {@link allowed | `allowed`} properties\n * enable the object's creator to shape the visibility of and access to their object.\n *\n * The {@link tombstone | `tombstone`} and {@link lastModified | `lastModified`} properties are for\n * caching and synchronization.\n */\nexport interface GraffitiObjectBase {\n /**\n * The object's content as freeform JSON. We recommend using properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)\n * or properties that emerge in the Graffiti [folksonomy](https://en.wikipedia.org/wiki/Folksonomy)\n * to promote interoperability.\n */\n value: {};\n\n /**\n * An array of URIs the creator associates with the object. Objects can only be found by querying\n * one of the object's channels using the\n * {@link Graffiti.discover} method. This allows creators to express the intended audience of their object\n * which helps to prevent [context collapse](https://en.wikipedia.org/wiki/Context_collapse) even\n * in the highly interoperable ecosystem that Graffiti envisions. For example, channel URIs may be:\n * - A user's own {@link actor | `actor`} URI. Putting an object in this channel is a way to broadcast\n * the object to the user's followers, like posting a tweet.\n * - The URL of a Graffiti post. Putting an object in this channel is a way to broadcast to anyone viewing\n * the post, like commenting on a tweet.\n * - A URI representing a topic. Putting an object in this channel is a way to broadcast to anyone interested\n * in that topic, like posting in a subreddit.\n */\n channels: string[];\n\n /**\n * An optional array of {@link actor | `actor`} URIs that the creator allows to access the object.\n * If no `allowed` array is provided, the object can be accessed by anyone (so long as they\n * also know the right {@link channels | `channel` } to look in). An object can always be accessed by its creator, even if\n * the `allowed` array is empty.\n *\n * The `allowed` array is not revealed to users other than the creator, like\n * a BCC email. A user may choose to add a `to` property to the object's {@link value | `value`} to indicate\n * other recipients, however this is not enforced by Graffiti and may not accurately reflect the actual `allowed` array.\n *\n * `allowed` can be combined with {@link channels | `channels`}. For example, to send someone a direct message\n * the sender should put their object in the channel of the recipient's {@link actor | `actor`} URI to notify them of the message and also add\n * the recipient's {@link actor | `actor`} URI to the `allowed` array to prevent others from seeing the message.\n */\n allowed?: string[] | null;\n\n /**\n * The URI of the `actor` that {@link Graffiti.put | created } the object. This `actor` also has the unique permission to\n * {@link Graffiti.patch | modify} or {@link Graffiti.delete | delete} the object.\n *\n * We borrow the term actor from the ActivityPub because\n * [like in ActivityPub](https://www.w3.org/TR/activitypub/#h-note-0)\n * there is not necessarily a one-to-one mapping between actors and people/users.\n * Multiple people can share the same actor or one person can have multiple actors.\n * Actors can also be bots.\n *\n * In Graffiti, actors are always globally unique URIs which\n * allows them to also function as {@link channels | `channels`}.\n */\n actor: string;\n\n /**\n * A globally unique identifier and locator for the object. It can be used to point to\n * an object or to retrieve the object directly with {@link Graffiti.get}.\n * If an object is {@link Graffiti.put | put} with the same URL\n * as an existing object, the existing object will be replaced with the new object.\n *\n * An object's URL is generated when the object is first creation and\n * should include sufficient randomness to prevent collisions\n * and guessing. The URL starts with a \"scheme\", just like web URLs start with `http` or `https`, to indicate\n * to indicate the particular Graffiti implementation. This allows for applications\n * to pull from multiple coexisting Graffiti implementations without collision.\n * Existing schemes include `graffiti:local:` for objects stored locally\n * (see the [local implementation](https://github.com/graffiti-garden/implementation-local))\n * and `graffiti:remote:` for objects stored on Graffiti-specific web servers (see the\n * [remote implementation](https://github.com/graffiti-garden/implementation-remote)).\n * Options available in the future might include `graffiti:solid:` for objects stored on Solid servers\n * or `graffiti:p2p:` for objects stored on a peer-to-peer network.\n */\n url: string;\n\n /**\n * The time the object was last modified, measured in milliseconds since January 1, 1970.\n * This is used for client-side caching and synchronization.\n * A number, rather than an ISO string or Date object, is used for easy comparison, sorting,\n * and JSON Schema [range queries](https://json-schema.org/understanding-json-schema/reference/numeric#range).\n *\n * It is possible to use this value to sort objects in a user's interface but in many cases it would be better to\n * use a [`published`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-published)\n * property in the object's {@link value | `value`} to indicate when the object was created\n * rather than when it was modified.\n */\n lastModified: number;\n\n /**\n * A boolean indicating whether the object has been deleted.\n * Depending on implementation, objects stay available for some time\n * after deletion to allow for synchronization and client-side caching\n */\n tombstone: boolean;\n}\n\n/**\n * This type constrains the {@link GraffitiObjectBase} type to adhere to a\n * particular [JSON schema](https://json-schema.org/).\n * This allows for static type-checking of an object's {@link GraffitiObjectBase.value | `value`}\n * which is otherwise a freeform JSON object.\n *\n * Schema-aware objects are returned by {@link Graffiti.get} and {@link Graffiti.discover}.\n */\nexport type GraffitiObject<Schema extends JSONSchema> = GraffitiObjectBase &\n FromSchema<Schema & typeof GraffitiObjectJSONSchema>;\n\n/**\n * A JSON Schema equivalent to the {@link GraffitiObjectBase} type.\n * Needed internally for type inference of JSON Schemas, but can\n * be used by implementations to validate objects.\n */\nexport const GraffitiObjectJSONSchema = {\n type: \"object\",\n properties: {\n value: { type: \"object\" },\n channels: { type: \"array\", items: { type: \"string\" } },\n allowed: { type: \"array\", items: { type: \"string\" }, nullable: true },\n url: { type: \"string\" },\n actor: { type: \"string\" },\n lastModified: { type: \"number\" },\n tombstone: { type: \"boolean\" },\n },\n additionalProperties: false,\n required: [\"value\", \"channels\", \"actor\", \"url\", \"lastModified\", \"tombstone\"],\n} as const satisfies JSONSchema;\n\n/**\n * This is an object containing only the {@link GraffitiObjectBase.url | `url`}\n * property of a {@link GraffitiObjectBase | GraffitiObject}.\n * It is used as a utility type so that users can call {@link Graffiti.get},\n * {@link Graffiti.patch}, or {@link Graffiti.delete} directly on an object\n * rather than on `object.url`.\n */\nexport type GraffitiObjectUrl = Pick<GraffitiObjectBase, \"url\">;\n\n/**\n * This object is a subset of {@link GraffitiObjectBase} that a user must construct locally before calling {@link Graffiti.put}.\n * This local copy does not require system-generated properties and may be statically typed with\n * a [JSON schema](https://json-schema.org/) to prevent the accidental creation of erroneous objects.\n *\n * This local object must have a {@link GraffitiObjectBase.value | `value`} and {@link GraffitiObjectBase.channels | `channels`}\n * and may optionally have an {@link GraffitiObjectBase.allowed | `allowed`} property.\n *\n * It may also include a {@link GraffitiObjectBase.url | `url`} property to specify the\n * URL of an existing object to replace. If no `url` is provided, one will be generated during object creation.\n *\n * This object does not need a {@link GraffitiObjectBase.lastModified | `lastModified`} or {@link GraffitiObjectBase.tombstone | `tombstone`}\n * property since these are automatically generated by the Graffiti system.\n */\nexport type GraffitiPutObject<Schema extends JSONSchema> = Pick<\n GraffitiObjectBase,\n \"value\" | \"channels\" | \"allowed\"\n> &\n Partial<GraffitiObjectBase> &\n FromSchema<Schema & typeof GraffitiPutObjectJSONSchema>;\n\n/**\n * A JSON Schema equivalent to the {@link GraffitiPutObject} type.\n * Needed internally for type inference of JSON Schemas, but can\n * be used by implementations to validate objects.\n */\nexport const GraffitiPutObjectJSONSchema = {\n ...GraffitiObjectJSONSchema,\n required: [\"value\", \"channels\"],\n} as const satisfies JSONSchema;\n\n/**\n * This object contains information that the underlying implementation can\n * use to verify that a user has permission to operate a\n * particular {@link GraffitiObjectBase.actor | `actor`}.\n * This object is required of all {@link Graffiti} methods\n * that modify objects and is optional for methods that read objects.\n *\n * At a minimum the `session` object must contain the\n * {@link GraffitiSession.actor | `actor`} URI the user wants to authenticate with.\n * However it is likely that the `session` object must contain other\n * implementation-specific properties.\n * For example, a Solid implementation might include a\n * [`fetch`](https://docs.inrupt.com/developer-tools/api/javascript/solid-client-authn-browser/functions.html#fetch)\n * function. A distributed implementation may include\n * a cryptographic signature.\n *\n * As to why the `session` object is passed as an argument to every method\n * rather than being an internal property of the {@link Graffiti} instance,\n * this is primarily for type-checking to catch bugs related to login state.\n * Graffiti applications can expose some functionality to users who are not logged in\n * with {@link Graffiti.get} and {@link Graffiti.discover} but without type-checking\n * the `session` it can be easy to forget to hide buttons that trigger\n * other methods that require login.\n * In the future, `session` object may be updated to include scope information\n * and passing the `session` to each method can type-check whether the session provides the\n * necessary permissions.\n *\n * Passing the `session` object per-method also allows for multiple sessions\n * to be used within the same application, like an Email client fetching from\n * multiple accounts.\n */\nexport interface GraffitiSession {\n /**\n * The {@link GraffitiObjectBase.actor | `actor`} a user wants to authenticate with.\n */\n actor: string;\n /**\n * A yet undefined property detailing what operations the session\n * grants the user to perform. For example, to allow a user to\n * read private messages from a particular set of channels or\n * to allow the user to write object matching a particular schema.\n */\n scope?: {};\n}\n\n/**\n * This is the format for patches that modify {@link GraffitiObjectBase} objects\n * using the {@link Graffiti.patch} method. The patches must\n * be an array of [JSON Patch](https://jsonpatch.com) operations.\n * Patches can only be applied to the\n * {@link GraffitiObjectBase.value | `value`}, {@link GraffitiObjectBase.channels | `channels`},\n * and {@link GraffitiObjectBase.allowed | `allowed`} properties since the other\n * properties either describe the object's location or are automatically generated.\n * (See also {@link GraffitiPutObject}).\n */\nexport interface GraffitiPatch {\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.value | `value`}. The resulting\n * `value` must still be a JSON object.\n */\n value?: JSONPatchOperation[];\n\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.channels | `channels`}. The resulting\n * `channels` must still be an array of strings.\n */\n channels?: JSONPatchOperation[];\n\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.allowed | `allowed`} property. The resulting\n * `allowed` property must still be an array of strings or `undefined`.\n */\n allowed?: JSONPatchOperation[];\n}\n\n/**\n * This type represents a stream of data that are\n * returned by Graffiti's query-like operations such as\n * {@link Graffiti.discover} and {@link Graffiti.recoverOrphans}.\n *\n * Errors are returned within the stream rather than as\n * exceptions that would halt the entire stream. This is because\n * some implementations may pull data from multiple sources\n * including some that may be unreliable. In many cases,\n * these errors can be safely ignored.\n * The `origin` property of the error object indicates the\n * source of the error including its scheme and other\n * implementation-specific details (e.g. domain name).\n *\n * The stream is an [`AsyncGenerator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)\n * that can be iterated over using `for await` loops or calling `next` on the generator.\n * The stream can be terminated by breaking out of a loop calling `return` on the generator.\n */\nexport type GraffitiStream<TValue, TReturn = void> = AsyncGenerator<\n | {\n error?: undefined;\n value: TValue;\n }\n | {\n error: Error;\n origin: string;\n },\n TReturn\n>;\n\n/**\n * Statistic about single channel returned by {@link Graffiti.channelStats}.\n * These statistics only account for contributions made by the\n * querying actor.\n */\nexport type ChannelStats = {\n /**\n * The URI of the channel.\n */\n channel: string;\n /**\n * The number of non-{@link GraffitiObjectBase.tombstone | `tombstone`}d objects\n * that the actor has posted to the channel.\n */\n count: number;\n /**\n * The time that the actor {@link GraffitiObjectBase.lastModified | last modified} an object in the channel,\n * measured in milliseconds since January 1, 1970.\n * {@link GraffitiObjectBase.tombstone | Tombstone}d objects do not effect this modification time.\n */\n lastModified: number;\n};\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * when a user logs in manually from {@link Graffiti.login}\n * or when their session is restored from a previous login.\n * The event name to listen for is `login`.\n */\nexport type GraffitiLoginEvent = CustomEvent<\n | {\n error: Error;\n session?: undefined;\n }\n | {\n error?: undefined;\n session: GraffitiSession;\n }\n>;\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * when a user logs out either manually with {@link Graffiti.logout}\n * or when their session times out or otherwise becomes invalid.\n * The event name to listen for is `logout`.\n */\nexport type GraffitiLogoutEvent = CustomEvent<\n | {\n error: Error;\n actor?: string;\n }\n | {\n error?: undefined;\n actor: string;\n }\n>;\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * after an application has attempted to complete any login redirects\n * and restore any previously active sessions.\n * Successful session restores will be returned in parallel as\n * their own {@link GraffitiLoginEvent} events.\n *\n * This event optionally returns an `href` property\n * representing the URL the user originated a login request\n * from, which may be useful for redirecting the user back to\n * the page they were on after login.\n * The event name to listen for is `initialized`.\n */\nexport type GraffitiSessionInitializedEvent = CustomEvent<\n | {\n error?: Error;\n href?: string;\n }\n | null\n | undefined\n>;\n", "export class GraffitiErrorUnauthorized extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorUnauthorized\";\n Object.setPrototypeOf(this, GraffitiErrorUnauthorized.prototype);\n }\n}\n\nexport class GraffitiErrorForbidden extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorForbidden\";\n Object.setPrototypeOf(this, GraffitiErrorForbidden.prototype);\n }\n}\n\nexport class GraffitiErrorNotFound extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorNotFound\";\n Object.setPrototypeOf(this, GraffitiErrorNotFound.prototype);\n }\n}\n\nexport class GraffitiErrorInvalidSchema extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorInvalidSchema\";\n Object.setPrototypeOf(this, GraffitiErrorInvalidSchema.prototype);\n }\n}\n\nexport class GraffitiErrorSchemaMismatch extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorSchemaMismatch\";\n Object.setPrototypeOf(this, GraffitiErrorSchemaMismatch.prototype);\n }\n}\n\nexport class GraffitiErrorPatchTestFailed extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorPatchTestFailed\";\n Object.setPrototypeOf(this, GraffitiErrorPatchTestFailed.prototype);\n }\n}\n\nexport class GraffitiErrorPatchError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorPatchError\";\n Object.setPrototypeOf(this, GraffitiErrorPatchError.prototype);\n }\n}\n\nexport class GraffitiErrorInvalidUri extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorInvalidUri\";\n Object.setPrototypeOf(this, GraffitiErrorInvalidUri.prototype);\n }\n}\n\nexport class GraffitiErrorUnrecognizedUriScheme extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorUnrecognizedUriScheme\";\n Object.setPrototypeOf(this, GraffitiErrorUnrecognizedUriScheme.prototype);\n }\n}\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,cAAAE,EAAA,2BAAAC,EAAA,+BAAAC,EAAA,4BAAAC,EAAA,0BAAAC,EAAA,4BAAAC,EAAA,iCAAAC,EAAA,gCAAAC,EAAA,8BAAAC,EAAA,uCAAAC,EAAA,6BAAAC,EAAA,gCAAAC,IAAA,eAAAC,EAAAd,GC4LO,IAAee,EAAf,KAAwB,CA4V/B,EClZO,IAAMC,EAA2B,CACtC,KAAM,SACN,WAAY,CACV,MAAO,CAAE,KAAM,QAAS,EACxB,SAAU,CAAE,KAAM,QAAS,MAAO,CAAE,KAAM,QAAS,CAAE,EACrD,QAAS,CAAE,KAAM,QAAS,MAAO,CAAE,KAAM,QAAS,EAAG,SAAU,EAAK,EACpE,IAAK,CAAE,KAAM,QAAS,EACtB,MAAO,CAAE,KAAM,QAAS,EACxB,aAAc,CAAE,KAAM,QAAS,EAC/B,UAAW,CAAE,KAAM,SAAU,CAC/B,EACA,qBAAsB,GACtB,SAAU,CAAC,QAAS,WAAY,QAAS,MAAO,eAAgB,WAAW,CAC7E,EAqCaC,EAA8B,CACzC,GAAGD,EACH,SAAU,CAAC,QAAS,UAAU,CAChC,EC3LO,IAAME,EAAN,MAAMC,UAAkC,KAAM,CACnD,YAAYC,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,4BACZ,OAAO,eAAe,KAAMD,EAA0B,SAAS,CACjE,CACF,EAEaE,EAAN,MAAMC,UAA+B,KAAM,CAChD,YAAYF,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,yBACZ,OAAO,eAAe,KAAME,EAAuB,SAAS,CAC9D,CACF,EAEaC,EAAN,MAAMC,UAA8B,KAAM,CAC/C,YAAYJ,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,wBACZ,OAAO,eAAe,KAAMI,EAAsB,SAAS,CAC7D,CACF,EAEaC,EAAN,MAAMC,UAAmC,KAAM,CACpD,YAAYN,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,6BACZ,OAAO,eAAe,KAAMM,EAA2B,SAAS,CAClE,CACF,EAEaC,EAAN,MAAMC,UAAoC,KAAM,CACrD,YAAYR,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,8BACZ,OAAO,eAAe,KAAMQ,EAA4B,SAAS,CACnE,CACF,EAEaC,EAAN,MAAMC,UAAqC,KAAM,CACtD,YAAYV,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,+BACZ,OAAO,eAAe,KAAMU,EAA6B,SAAS,CACpE,CACF,EAEaC,EAAN,MAAMC,UAAgC,KAAM,CACjD,YAAYZ,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,0BACZ,OAAO,eAAe,KAAMY,EAAwB,SAAS,CAC/D,CACF,EAEaC,EAAN,MAAMC,UAAgC,KAAM,CACjD,YAAYd,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,0BACZ,OAAO,eAAe,KAAMc,EAAwB,SAAS,CAC/D,CACF,EAEaC,EAAN,MAAMC,UAA2C,KAAM,CAC5D,YAAYhB,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,qCACZ,OAAO,eAAe,KAAMgB,EAAmC,SAAS,CAC1E,CACF",
6
+ "names": ["index_exports", "__export", "Graffiti", "GraffitiErrorForbidden", "GraffitiErrorInvalidSchema", "GraffitiErrorInvalidUri", "GraffitiErrorNotFound", "GraffitiErrorPatchError", "GraffitiErrorPatchTestFailed", "GraffitiErrorSchemaMismatch", "GraffitiErrorUnauthorized", "GraffitiErrorUnrecognizedUriScheme", "GraffitiObjectJSONSchema", "GraffitiPutObjectJSONSchema", "__toCommonJS", "Graffiti", "GraffitiObjectJSONSchema", "GraffitiPutObjectJSONSchema", "GraffitiErrorUnauthorized", "_GraffitiErrorUnauthorized", "message", "GraffitiErrorForbidden", "_GraffitiErrorForbidden", "GraffitiErrorNotFound", "_GraffitiErrorNotFound", "GraffitiErrorInvalidSchema", "_GraffitiErrorInvalidSchema", "GraffitiErrorSchemaMismatch", "_GraffitiErrorSchemaMismatch", "GraffitiErrorPatchTestFailed", "_GraffitiErrorPatchTestFailed", "GraffitiErrorPatchError", "_GraffitiErrorPatchError", "GraffitiErrorInvalidUri", "_GraffitiErrorInvalidUri", "GraffitiErrorUnrecognizedUriScheme", "_GraffitiErrorUnrecognizedUriScheme"]
7
7
  }
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var r=class{objectToUri(t){return this.locationToUri(t)}};var m={type:"object",properties:{value:{type:"object"},channels:{type:"array",items:{type:"string"}},allowed:{type:"array",items:{type:"string"},nullable:!0},actor:{type:"string"},name:{type:"string"},source:{type:"string"},lastModified:{type:"number"},tombstone:{type:"boolean"}},additionalProperties:!1,required:["value","channels","actor","name","source","lastModified","tombstone"]},S={...m,required:["value","channels"]};var s=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorUnauthorized",Object.setPrototypeOf(this,e.prototype)}},o=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorForbidden",Object.setPrototypeOf(this,e.prototype)}},i=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorNotFound",Object.setPrototypeOf(this,e.prototype)}},a=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorInvalidSchema",Object.setPrototypeOf(this,e.prototype)}},n=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorSchemaMismatch",Object.setPrototypeOf(this,e.prototype)}},c=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorPatchTestFailed",Object.setPrototypeOf(this,e.prototype)}},f=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorPatchError",Object.setPrototypeOf(this,e.prototype)}},p=class e extends Error{constructor(t){super(t),this.name="GraffitiErrorInvalidUri",Object.setPrototypeOf(this,e.prototype)}};export{r as Graffiti,o as GraffitiErrorForbidden,a as GraffitiErrorInvalidSchema,p as GraffitiErrorInvalidUri,i as GraffitiErrorNotFound,f as GraffitiErrorPatchError,c as GraffitiErrorPatchTestFailed,n as GraffitiErrorSchemaMismatch,s as GraffitiErrorUnauthorized,m as GraffitiObjectJSONSchema,S as GraffitiPutObjectJSONSchema};
1
+ var r=class{};var h={type:"object",properties:{value:{type:"object"},channels:{type:"array",items:{type:"string"}},allowed:{type:"array",items:{type:"string"},nullable:!0},url:{type:"string"},actor:{type:"string"},lastModified:{type:"number"},tombstone:{type:"boolean"}},additionalProperties:!1,required:["value","channels","actor","url","lastModified","tombstone"]},S={...h,required:["value","channels"]};var s=class t extends Error{constructor(e){super(e),this.name="GraffitiErrorUnauthorized",Object.setPrototypeOf(this,t.prototype)}},a=class t extends Error{constructor(e){super(e),this.name="GraffitiErrorForbidden",Object.setPrototypeOf(this,t.prototype)}},i=class t extends Error{constructor(e){super(e),this.name="GraffitiErrorNotFound",Object.setPrototypeOf(this,t.prototype)}},o=class t extends Error{constructor(e){super(e),this.name="GraffitiErrorInvalidSchema",Object.setPrototypeOf(this,t.prototype)}},n=class t extends Error{constructor(e){super(e),this.name="GraffitiErrorSchemaMismatch",Object.setPrototypeOf(this,t.prototype)}},c=class t extends Error{constructor(e){super(e),this.name="GraffitiErrorPatchTestFailed",Object.setPrototypeOf(this,t.prototype)}},f=class t extends Error{constructor(e){super(e),this.name="GraffitiErrorPatchError",Object.setPrototypeOf(this,t.prototype)}},p=class t extends Error{constructor(e){super(e),this.name="GraffitiErrorInvalidUri",Object.setPrototypeOf(this,t.prototype)}},m=class t extends Error{constructor(e){super(e),this.name="GraffitiErrorUnrecognizedUriScheme",Object.setPrototypeOf(this,t.prototype)}};export{r as Graffiti,a as GraffitiErrorForbidden,o as GraffitiErrorInvalidSchema,p as GraffitiErrorInvalidUri,i as GraffitiErrorNotFound,f as GraffitiErrorPatchError,c as GraffitiErrorPatchTestFailed,n as GraffitiErrorSchemaMismatch,s as GraffitiErrorUnauthorized,m as GraffitiErrorUnrecognizedUriScheme,h as GraffitiObjectJSONSchema,S as GraffitiPutObjectJSONSchema};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/1-api.ts", "../src/2-types.ts", "../src/3-errors.ts"],
4
- "sourcesContent": ["import type {\n GraffitiLocation,\n GraffitiObject,\n GraffitiObjectBase,\n GraffitiPatch,\n GraffitiSession,\n GraffitiPutObject,\n GraffitiStream,\n ChannelStats,\n} from \"./2-types\";\nimport type { JSONSchema } from \"json-schema-to-ts\";\n\n/**\n * This API describes a small but powerful set of methods that\n * can be used to create many different kinds of social media applications,\n * all of which can interoperate.\n * These methods should satisfy all of an application's needs for\n * the communication, storage, and access management of social data.\n * The rest of the application can be built with standard client-side\n * user interface tools to present and interact with the data \u2014\n * no server code necessary.\n * The Typescript source for this API is available at\n * [graffiti-garden/api](https://github.com/graffiti-garden/api).\n *\n * There are several different implementations of this Graffiti API available,\n * including a [federated implementation](https://github.com/graffiti-garden/implementation-federated),\n * that lets users choose where their data is stored,\n * and a [local implementation](https://github.com/graffiti-garden/implementation-local)\n * that can be used for testing and development. In our design of Graffiti, this API is our\n * primary focus as it is the layer that shapes the experience\n * of developing applications. While different implementations can provide tradeoffs between\n * other important properties (e.g. privacy, security, scalability), those properties\n * are useless if the system as a whole doesn't expose useful functionality to developers.\n *\n * On the other side of the stack, there is [Vue plugin](https://github.com/graffiti-garden/wrapper-vue/)\n * that wraps around this API to provide reactivity. Other high-level libraries\n * will be available in the future.\n *\n * ## Overview\n *\n * Graffiti provides applications with methods to create and store data\n * on behalf of their users using standard CRUD operations:\n * {@link put}, {@link get}, {@link patch}, and {@link delete}.\n * This data can represent both social artifacts (e.g. posts, profiles) and\n * activities (e.g. likes, follows) and is stored as JSON.\n *\n * The social aspect of Graffiti comes from the {@link discover} method\n * which allows applications to find objects that other users made.\n * It is a lot like a traditional query operation, but it only\n * returns objects that have been placed in particular\n * {@link GraffitiObjectBase.channels | `channels`}\n * specified by the discovering application.\n *\n * Graffiti builds on well known concepts and standards wherever possible.\n * JSON Objects can be typed with [JSON Schema](https://json-schema.org/) and patches\n * can be applied with [JSON Patch](https://jsonpatch.com).\n * For interoperability between Graffiti applications, we recommend that\n * objects use established properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/) when available,\n * however it is always possible to create additional properties, contributing\n * to the broader [folksonomy](https://en.wikipedia.org/wiki/Folksonomy).\n *\n * {@link GraffitiObjectBase.channels | `channels`} are one of the major concepts\n * unique to Graffiti along with *interaction relativity*, defined below.\n * Channels create boundaries between public spaces and work to prevent\n * [context collapse](https://en.wikipedia.org/wiki/Context_collapse)\n * even in a highly interoperable environment.\n * Interaction relativity means that all interactions between users are\n * actually atomic single-user operations that can be interpreted in different ways,\n * which also supports interoperability and pluralism.\n *\n * ### Channels\n *\n * {@link GraffitiObjectBase.channels | `channels`}\n * are a way for the creators of social data to express the intended audience of their\n * data. When a user creates data using the {@link put} method, they\n * can place their data in one or more channels.\n * Content consumers using the {@link discover} method will only see data\n * contained in one of the channels they specify.\n *\n * While many channels may be public, they partition\n * the public into different \"contexts\", mitigating the\n * phenomenon of [context collapse](https://en.wikipedia.org/wiki/Context_collapse) or the \"flattening of multiple audiences.\"\n * Any [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier) can be used as a channel, and so channels can represent people,\n * comment threads, topics, places (real or virtual), pieces of media, and more.\n *\n * For example, consider a comment on a post. If we place that comment in the channel\n * represented by the post's URI, then only people viewing the post will know to\n * look in that channel, giving it visibility akin to a comment on a blog post\n * or comment on Instagram ([since 2019](https://www.buzzfeednews.com/article/katienotopoulos/instagrams-following-activity-tab-is-going-away)).\n * If we also place the comment in the channel represented by the commenter's URI (their\n * {@link GraffitiObjectBase.actor | `actor` URI}), then people viewing the commenter's profile\n * will also see the comment, giving it more visibility, like a reply on Twitter.\n * If we *only* place the comment in the channel represented by the commenter's URI, then\n * it becomes like a quote tweet ([prior to 2020](https://x.com/Support/status/1300555325750292480)),\n * where the comment is only visible to the commenter's followers but not the audience\n * of the original post.\n *\n * The channel model differs from other models of communication such as the\n * [actor model](https://www.w3.org/TR/activitypub/#Overview) used by ActivityPub,\n * the protocol underlying Mastodon, or the [firehose model](https://bsky.social/about/blog/5-5-2023-federation-architecture)\n * used by the AT Protocol, the protocol underlying BlueSky.\n * The actor model is a fusion of direct messaging (like Email) and broadcasting\n * (like RSS) and works well for follow-based communication but struggles\n * to pass information via other rendez-vous.\n * In the actor model, even something as simple as comments can be\n * [very tricky and require server \"side effects\"](https://seb.jambor.dev/posts/understanding-activitypub-part-3-the-state-of-mastodon/).\n * The firehose model dumps all user data into one public database,\n * which doesn't allow for the carving out of different contexts that we did in our comment\n * example above. In the firehose model a comment will always be visible to *both* the original post's audience and\n * the commenter's followers.\n *\n * In some sense, channels provide a sort of \"social access control\" by forming\n * expectations about the audiences of different online spaces.\n * As a real world analogy, oftentimes support groups, such as alcoholics\n * anonymous, are open to the public but people in those spaces feel comfortable sharing intimate details\n * because they have expectations about the other people attending.\n * If someone malicious went to support groups just to spread people's secrets,\n * they would be shamed for violating these norms.\n * Similarly, in Graffiti, while you could spider public channels like a search engine\n * to find content about a person, revealing that you've done such a thing\n * would be shameful.\n *\n * Still, social access control is not perfect and so in situations where privacy is important,\n * objects can also be given\n * an {@link GraffitiObjectBase.allowed | `allowed`} list.\n * For example, to send someone a direct message you should put an object representing\n * that message in the channel that represents them (their {@link GraffitiObjectBase.actor | `actor` URI}),\n * so they can find it, *and* set the `allowed` field to only include the recipient,\n * so only they can read it.\n *\n * ### Interaction relativity\n *\n * Interaction relativity posits that \"interaction between two individuals only\n * exists relative to an observer,\" or equivalently, all interaction is [reified](https://en.wikipedia.org/wiki/Reification_(computer_science)).\n * For example, if one user creates a post and another user wants to \"like\" that post,\n * their like is not modifying the original post, it is simply another data object that points\n * to the post being liked, via its {@link locationToUri | URI}.\n *\n * ```json\n * {\n * activity: 'like',\n * target: 'uri-of-the-post-i-like',\n * actor: 'my-user-id'\n * }\n * ```\n *\n * In Graffiti, all interactions including *moderation* and *collaboration* are relative.\n * This means that applications can freely choose which interactions\n * they want to express to their users and how.\n * For example, one application could have a single fixed moderator,\n * another could allow users to choose which moderators they would like filter their content\n * like [Bluesky's stackable moderation](https://bsky.social/about/blog/03-12-2024-stackable-moderation),\n * and another could implement a fully democratic system like [PolicyKit](https://policykit.org/).\n * Each of these applications is one interpretation of the underlying refieid user interactions and\n * users can freely switch between them.\n *\n * Interaction relativy also allows applications to introduce new sorts of interactions\n * without having to coordinate with all the other existing applications,\n * keeping the ecosystem flexible and interoperable.\n * For example, an application could [add a \"Trust\" button to posts](https://social.cs.washington.edu/pub_details.html?id=trustnet)\n * and use it assess the truthfulness of posts made on applications across Graffiti.\n * New sorts of interactions like these can be smoothly absorbed by the broader ecosystem\n * as a [folksonomy](https://en.wikipedia.org/wiki/Folksonomy).\n *\n * Interactivy relativity is realized in Graffiti through two design decisions:\n * 1. The creators of objects can only modify their own objects. It is important for\n * users to be able to change and delete their own content to respect their\n * [right to be forgotten](https://en.wikipedia.org/wiki/Right_to_be_forgotten),\n * but beyond self-correction and self-censorship all other interaction is reified.\n * Many interactions can be reified via pointers, as in the \"like\" example above, and collaborative\n * edits can be refieid via [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type).\n * 2. No one owns channels. Unlike IRC/Slack channels or [Matrix rooms](https://matrix.org/docs/matrix-concepts/rooms_and_events/),\n * anyone can post to any channel, so long as they know the URI of that channel.\n * It is up to applications to hide content from channels either according to manual\n * filters or in response to user action.\n * For example, a user may create a post with the flag `disableReplies`.\n * Applications could then filter out any content from the replies channel\n * that the original poster has not specifically approved.\n *\n * @groupDescription CRUD Methods\n * Methods for {@link put | creating}, {@link get | reading}, {@link patch | updating},\n * and {@link delete | deleting} {@link GraffitiObjectBase | Graffiti objects}.\n * @groupDescription Query Methods\n * Methods that retrieve or accumulate information about multiple {@link GraffitiObjectBase | Graffiti objects} at a time.\n * @groupDescription Session Management\n * Methods and properties for logging in and out of a Graffiti implementation.\n * @groupDescription Utilities\n * Methods for for converting Graffiti objects to and from URIs.\n */\nexport abstract class Graffiti {\n /**\n * Converts a {@link GraffitiLocation} object containing a\n * {@link GraffitiObjectBase.name | `name`}, {@link GraffitiObjectBase.actor | `actor`},\n * and {@link GraffitiObjectBase.source | `source`} into a globally unique URI.\n * The form of this URI is implementation dependent.\n *\n * Its exact inverse is {@link uriToLocation}.\n *\n * @group Utilities\n */\n abstract locationToUri(location: GraffitiLocation): string;\n\n /**\n * Parses a globally unique Graffiti URI into a {@link GraffitiLocation}\n * object containing a {@link GraffitiObjectBase.name | `name`},\n * {@link GraffitiObjectBase.actor | `actor`}, and {@link GraffitiObjectBase.source | `source`}.\n *\n * Its exact inverse is {@link locationToUri}.\n *\n * @group Utilities\n */\n abstract uriToLocation(uri: string): GraffitiLocation;\n\n /**\n * An alias of {@link locationToUri}\n *\n * @group Utilities\n */\n objectToUri(object: GraffitiObjectBase) {\n return this.locationToUri(object);\n }\n\n /**\n * Creates a new {@link GraffitiObjectBase | object} or replaces an existing object.\n * An object can only be replaced by the same {@link GraffitiObjectBase.actor | `actor`}\n * that created it.\n *\n * Replacement occurs when the {@link GraffitiLocation} properties of the supplied object\n * ({@link GraffitiObjectBase.name | `name`}, {@link GraffitiObjectBase.actor | `actor`},\n * and {@link GraffitiObjectBase.source | `source`}) exactly match the location of an existing object.\n *\n * @returns The object that was replaced if one exists or an object with\n * with a `null` {@link GraffitiObjectBase.value | `value`} if this method\n * created a new object.\n * The object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of replacement/creation.\n *\n * @group CRUD Methods\n */\n abstract put<Schema extends JSONSchema>(\n /**\n * The object to be put. This object is statically type-checked against the [JSON schema](https://json-schema.org/) that can be optionally provided\n * as the generic type parameter. We highly recommend providing a schema to\n * ensure that the PUT object matches subsequent {@link get} or {@link discover}\n * methods.\n */\n object: GraffitiPutObject<Schema>,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Retrieves an object from a given location.\n *\n * The retrieved object is type-checked against the provided [JSON schema](https://json-schema.org/)\n * otherwise a {@link GraffitiErrorSchemaMismatch} is thrown.\n *\n * If the retreiving {@link GraffitiObjectBase.actor | `actor`} is not\n * the object's `actor`,\n * the object's {@link GraffitiObjectBase.allowed | `allowed`} and\n * {@link GraffitiObjectBase.channels | `channels`} properties are\n * not revealed.\n *\n * If the object existed but has since been deleted,\n * or the retrieving {@link GraffitiObjectBase.actor | `actor`}\n * was {@link GraffitiObjectBase.allowed | `allowed`} to access\n * the object but now isn't, this method may return the latest\n * version of the object that the {@link GraffitiObjectBase.actor | `actor`}\n * was allowed to access with its {@link GraffitiObjectBase.tombstone | `tombstone`}\n * set to `true`, if that object is stored in an implementation-side cache.\n *\n * Otherwise, if the object never existed, or the\n * retrieving {@link GraffitiObjectBase.actor | `actor`} was never\n * {@link GraffitiObjectBase.allowed | `allowed`} to access it, or if\n * the object was changed long enough ago that its history has been\n * purged from the cache, a {@link GraffitiErrorNotFound} is thrown.\n * The rate at which the cache is purged is implementation dependent.\n * See the `tombstoneRetention` property returned by {@link discover}.\n *\n * @group CRUD Methods\n */\n abstract get<Schema extends JSONSchema>(\n /**\n * The location of the object to get.\n */\n locationOrUri: GraffitiLocation | string,\n /**\n * The JSON schema to validate the retrieved object against.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}. If no `session` is provided,\n * the retrieved object's {@link GraffitiObjectBase.allowed | `allowed`}\n * property must be `undefined`.\n */\n session?: GraffitiSession | null,\n ): Promise<GraffitiObject<Schema>>;\n\n /**\n * Patches an existing object at a given location.\n * The patching {@link GraffitiObjectBase.actor | `actor`} must be the same as the\n * `actor` that created the object.\n *\n * @returns The object that was deleted if one exists or an object with\n * with a `null` {@link GraffitiObjectBase.value | `value`} otherwise.\n * The object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of deletion.\n *\n * @group CRUD Methods\n */\n abstract patch(\n /**\n * A collection of [JSON Patch](https://jsonpatch.com) operations\n * to apply to the object. See {@link GraffitiPatch} for more information.\n */\n patch: GraffitiPatch,\n /**\n * The location of the object to patch.\n */\n locationOrUri: GraffitiLocation | string,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Deletes an object from a given location.\n * The deleting {@link GraffitiObjectBase.actor | `actor`} must be the same as the\n * `actor` that created the object.\n *\n * If the object does not exist or has already been deleted,\n * {@link GraffitiErrorNotFound} is thrown.\n *\n * @returns The object that was deleted if one exists or an object with\n * with a `null` {@link GraffitiObjectBase.value | `value`} otherwise.\n * The object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of deletion.\n *\n * @group CRUD Methods\n */\n abstract delete(\n /**\n * The location of the object to delete.\n */\n locationOrUri: GraffitiLocation | string,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Discovers objects created by any user that are contained\n * in at least one of the given {@link GraffitiObjectBase.channels | `channels`}\n * and match the given [JSON Schema](https://json-schema.org).\n *\n * Objects are returned asynchronously as they are discovered but the stream\n * will end once all leads have been exhausted.\n * The method must be polled again for new objects.\n *\n * `discover` will not return objects that the {@link GraffitiObjectBase.actor | `actor`}\n * is not {@link GraffitiObjectBase.allowed | `allowed`} to access.\n * If the actor is not the creator of a discovered object,\n * the allowed list will be masked to only contain the querying actor if the\n * allowed list is not `undefined` (public). Additionally, if the actor is not the\n * creator of a discovered object, any {@link GraffitiObjectBase.channels | `channels`}\n * not specified by the `discover` method will not be revealed. This masking happens\n * before the supplied schema is applied.\n *\n * Since different implementations may fetch data from multiple sources there is\n * no guarentee on the order that objects are returned in. Additionally, the method\n * will return objects that have been deleted but with a\n * {@link GraffitiObjectBase.tombstone | `tombstone`} field set to `true` for\n * cache invalidation purposes.\n * The final `return()` value of the stream includes a `tombstoneRetention`\n * property that represents the minimum amount of time,\n * in milliseconds, that an application will retain and return tombstones for objects that\n * have been deleted.\n *\n * When repolling, the {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field can be queried via the schema to\n * only fetch objects that have been modified since the last poll.\n * Such queries should only be done if the time since the last poll\n * is less than the `tombstoneRetention` value of that poll, otherwise the tombstones\n * for objects that have been deleted may not be returned.\n *\n * ```json\n * {\n * \"properties\": {\n * \"lastModified\": {\n * \"minimum\": LAST_RETRIEVED_TIME\n * }\n * }\n * }\n * ```\n *\n * `discover` needs to be polled for new data because live updates to\n * an application can be visually distracting or lead to toxic engagement.\n * If and when an application wants real-time updates, such as in a chat\n * application, application authors must be intentional about their polling.\n *\n * Implementers should be aware that some users may applications may try to poll\n * {@link discover} repetitively. You can deal with this by rate limiting or\n * preemptively fetching data via a bidirectional channel, like a WebSocket.\n * Additionally, implementers should probably index the `lastModified` field\n * to speed up responses to schemas like the one above.\n *\n * @returns A stream of objects that match the given {@link GraffitiObjectBase.channels | `channels`}\n * and [JSON Schema](https://json-schema.org).\n *\n * @group Query Methods\n */\n abstract discover<Schema extends JSONSchema>(\n /**\n * The {@link GraffitiObjectBase.channels | `channels`} that objects must be associated with.\n */\n channels: string[],\n /**\n * A [JSON Schema](https://json-schema.org) that objects must satisfy.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}. If no `session` is provided,\n * only objects that have no {@link GraffitiObjectBase.allowed | `allowed`}\n * property will be returned.\n */\n session?: GraffitiSession | null,\n ): GraffitiStream<\n GraffitiObject<Schema>,\n {\n tombstoneRetention: number;\n }\n >;\n\n /**\n * Discovers objects **not** contained in any\n * {@link GraffitiObjectBase.channels | `channels`}\n * that were created by the querying {@link GraffitiObjectBase.actor | `actor`}\n * and match the given [JSON Schema](https://json-schema.org).\n * Unlike {@link discover}, this method will not return objects created by other users.\n *\n * This method is not useful for most applications, but necessary for\n * getting a global view of all a user's Graffiti data or debugging\n * channel usage.\n *\n * It's return value is the same as {@link discover}.\n *\n * @group Query Methods\n */\n abstract recoverOrphans<Schema extends JSONSchema>(\n /**\n * A [JSON Schema](https://json-schema.org) that orphaned objects must satisfy.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): GraffitiStream<\n GraffitiObject<Schema>,\n {\n tombstoneRetention: number;\n }\n >;\n\n /**\n * Returns statistics about all the {@link GraffitiObjectBase.channels | `channels`}\n * that an {@link GraffitiObjectBase.actor | `actor`} has posted to.\n * This is not very useful for most applications, but\n * necessary for certain applications where a user wants a\n * global view of all their Graffiti data or to debug\n * channel usage.\n *\n * @group Query Methods\n *\n * @returns A stream of statistics for each {@link GraffitiObjectBase.channels | `channel`}\n * that the {@link GraffitiObjectBase.actor | `actor`} has posted to.\n */\n abstract channelStats(\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): GraffitiStream<ChannelStats>;\n\n /**\n * Begins the login process. Depending on the implementation, this may\n * involve redirecting the user to a login page or opening a popup,\n * so it should always be called in response to a user action.\n *\n * The {@link GraffitiSession | session} object is returned\n * asynchronously via {@link Graffiti.sessionEvents | sessionEvents}\n * as a {@link GraffitiLoginEvent} with event type `login`.\n *\n * @group Session Management\n */\n abstract login(\n /**\n * Suggestions for the permissions that the\n * login process should grant. The login process may not\n * provide the exact proposed permissions.\n */\n proposal?: {\n /**\n * A suggested actor to login as. For example, if a user tries to\n * edit a post but are not logged in, the interface can infer that\n * they might want to log in as the actor who created the post\n * they are attempting to edit.\n *\n * Even if provided, the implementation should allow the user\n * to log in as a different actor if they choose.\n */\n actor?: string;\n /**\n * A yet to be defined permissions scope. An application may use\n * this to indicate the minimum necessary scope needed to\n * operate. For example, it may need to be able read private\n * messages from a certain set of channels, or write messages that\n * follow a particular schema.\n *\n * The login process should make it clear what scope an application\n * is requesting and allow the user to enhance or reduce that\n * scope as necessary.\n */\n scope?: {};\n },\n ): Promise<void>;\n\n /**\n * Begins the logout process. Depending on the implementation, this may\n * involve redirecting the user to a logout page or opening a popup,\n * so it should always be called in response to a user action.\n *\n * A confirmation will be returned asynchronously via\n * {@link Graffiti.sessionEvents | sessionEvents}\n * as a {@link GraffitiLogoutEvent} as event type `logout`.\n *\n * @group Session Management\n */\n abstract logout(\n /**\n * The {@link GraffitiSession | session} object to logout.\n */\n session: GraffitiSession,\n ): Promise<void>;\n\n /**\n * An event target that can be used to listen for the following\n * events and they're corresponding event types:\n * - `login` - {@link GraffitiLoginEvent}\n * - `logout` - {@link GraffitiLogoutEvent}\n * - `initialized` - {@link GraffitiSessionInitializedEvent}\n *\n * @group Session Management\n */\n abstract readonly sessionEvents: EventTarget;\n}\n", "import type { JSONSchema, FromSchema } from \"json-schema-to-ts\";\nimport type { Operation as JSONPatchOperation } from \"fast-json-patch\";\n\n/**\n * Objects are the atomic unit in Graffiti that can represent both data (*e.g.* a social media post or profile)\n * and activities (*e.g.* a like or follow).\n * Objects are created and modified by a single {@link actor | `actor`}.\n *\n * Most of an object's content is stored in its {@link value | `value`} property, which can be any JSON\n * object. However, we recommend using properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)\n * or properties that emerge in the Graffiti [folksonomy](https://en.wikipedia.org/wiki/Folksonomy)\n * to promote interoperability.\n *\n * The {@link name | `name`}, {@link actor | `actor`}, and {@link source | `source`}\n * properties together uniquely describe the {@link GraffitiLocation | object's location}\n * and can be {@link Graffiti.locationToUri | converted to a globally unique URI}.\n *\n * The {@link channels | `channels`} and {@link allowed | `allowed`} properties\n * enable the object's creator to shape the visibility of and access to their object.\n *\n * The {@link tombstone | `tombstone`} and {@link lastModified | `lastModified`} properties are for\n * caching and synchronization.\n */\nexport interface GraffitiObjectBase {\n /**\n * The object's content as freeform JSON. We recommend using properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)\n * or properties that emerge in the Graffiti [folksonomy](https://en.wikipedia.org/wiki/Folksonomy)\n * to promote interoperability.\n */\n value: {};\n\n /**\n * An array of URIs the creator associates with the object. Objects can only be found by querying\n * one of the object's channels using the\n * {@link Graffiti.discover} method. This allows creators to express the intended audience of their object\n * which helps to prevent [context collapse](https://en.wikipedia.org/wiki/Context_collapse) even\n * in the highly interoperable ecosystem that Graffiti envisions. For example, channel URIs may be:\n * - A user's own {@link actor | `actor`} URI. Putting an object in this channel is a way to broadcast\n * the object to the user's followers, like posting a tweet.\n * - The URI of a Graffiti post. Putting an object in this channel is a way to broadcast to anyone viewing\n * the post, like commenting on a tweet.\n * - A URI representing a topic. Putting an object in this channel is a way to broadcast to anyone interested\n * in that topic, like posting in a subreddit.\n */\n channels: string[];\n\n /**\n * An optional array of {@link actor | `actor`} URIs that the creator allows to access the object.\n * If no `allowed` array is provided, the object can be accessed by anyone (so long as they\n * also know the right {@link channels | `channel` } to look in). An object can always be accessed by its creator, even if\n * the `allowed` array is empty.\n *\n * The `allowed` array is not revealed to users other than the creator, like\n * a BCC email. A user may choose to add a `to` property to the object's {@link value | `value`} to indicate\n * other recipients, however this is not enforced by Graffiti and may not accurately reflect the actual `allowed` array.\n *\n * `allowed` can be combined with {@link channels | `channels`}. For example, to send someone a direct message\n * the sender should put their object in the channel of the recipient's {@link actor | `actor`} URI to notify them of the message and also add\n * the recipient's {@link actor | `actor`} URI to the `allowed` array to prevent others from seeing the message.\n */\n allowed?: string[] | null;\n\n /**\n * The URI of the `actor` that {@link Graffiti.put | created } the object. This `actor` also has the unique permission to\n * {@link Graffiti.patch | modify} or {@link Graffiti.delete | delete} the object.\n *\n * We borrow the term actor from the ActivityPub because\n * [like in ActivityPub](https://www.w3.org/TR/activitypub/#h-note-0)\n * there is not necessarily a one-to-one mapping between actors and people/users.\n * Multiple people can share the same actor or one person can have multiple actors.\n * Actors can also be bots.\n *\n * In Graffiti, actors are always globally unique URIs which\n * allows them to also function as {@link channels | `channels`}.\n */\n actor: string;\n\n /**\n * A name for the object. This name is not globally unique but it is unique when\n * combined with the {@link actor | `actor`} and {@link source | `source`}.\n * Often times it is not specified by the user and randomly generated during {@link Graffiti.put | creation}.\n * If an object is created with the same `name`, `actor`, and `source` as an existing object,\n * the existing object will be replaced with the new object.\n */\n name: string;\n\n /**\n * The URI of the source that stores the object. In some decentralized implementations,\n * it can represent the server or [pod](https://en.wikipedia.org/wiki/Solid_(web_decentralization_project)#Design)\n * that a user has delegated to store their objects. In others it may represent the distributed\n * storage network that the object is stored on.\n */\n source: string;\n\n /**\n * The time the object was last modified, measured in milliseconds since January 1, 1970.\n * This is used for caching and synchronization.\n * A number, rather than an ISO string or Date object, is used for easy comparison, sorting,\n * and JSON Schema [range queries](https://json-schema.org/understanding-json-schema/reference/numeric#range).\n *\n * It is possible to use this value to sort objects in a user's interface but in many cases it would be better to\n * use a `createdAt` property in the object's {@link value | `value`} to indicate when the object was created\n * rather than when it was modified.\n */\n lastModified: number;\n\n /**\n * A boolean indicating whether the object has been deleted.\n * Depending on implementation, objects stay available for some time after deletion to allow for synchronization.\n */\n tombstone: boolean;\n}\n\n/**\n * This type constrains the {@link GraffitiObjectBase} type to adhere to a\n * particular [JSON schema](https://json-schema.org/).\n * This allows for static type-checking of an object's {@link GraffitiObjectBase.value | `value`}\n * which is otherwise a freeform JSON object.\n *\n * Schema-aware objects are returned by {@link Graffiti.get} and {@link Graffiti.discover}.\n */\nexport type GraffitiObject<Schema extends JSONSchema> = GraffitiObjectBase &\n FromSchema<Schema & typeof GraffitiObjectJSONSchema>;\n\n/**\n * A JSON Schema equivalent to the {@link GraffitiObjectBase} type.\n * Needed internally for type inference of JSON Schemas, but can\n * be used by implementations to validate objects.\n */\nexport const GraffitiObjectJSONSchema = {\n type: \"object\",\n properties: {\n value: { type: \"object\" },\n channels: { type: \"array\", items: { type: \"string\" } },\n allowed: { type: \"array\", items: { type: \"string\" }, nullable: true },\n actor: { type: \"string\" },\n name: { type: \"string\" },\n source: { type: \"string\" },\n lastModified: { type: \"number\" },\n tombstone: { type: \"boolean\" },\n },\n additionalProperties: false,\n required: [\n \"value\",\n \"channels\",\n \"actor\",\n \"name\",\n \"source\",\n \"lastModified\",\n \"tombstone\",\n ],\n} as const satisfies JSONSchema;\n\n/**\n * This is a subset of properties from {@link GraffitiObjectBase} that uniquely\n * identify an object's location: {@link GraffitiObjectBase.actor | `actor`},\n * {@link GraffitiObjectBase.name | `name`}, and {@link GraffitiObjectBase.source | `source`}.\n * Attempts to create an object with the same `actor`, `name`, and `source`\n * as an existing object will replace the existing object (see {@link Graffiti.put}).\n *\n * This location can be converted to\n * a globally unique URI using {@link Graffiti.locationToUri}.\n */\nexport type GraffitiLocation = Pick<\n GraffitiObjectBase,\n \"actor\" | \"name\" | \"source\"\n>;\n\n/**\n * This object is a subset of {@link GraffitiObjectBase} that a user must construct locally before calling {@link Graffiti.put}.\n * This local copy does not require system-generated properties and may be statically typed with\n * a [JSON schema](https://json-schema.org/) to prevent the accidental creation of erroneous objects.\n *\n * This local object must have a {@link GraffitiObjectBase.value | `value`} and {@link GraffitiObjectBase.channels | `channels`}\n * and may optionally have an {@link GraffitiObjectBase.allowed | `allowed`} property.\n *\n * It may also contain any of the {@link GraffitiLocation } properties: {@link GraffitiObjectBase.actor | `actor`},\n * {@link GraffitiObjectBase.name | `name`}, and {@link GraffitiObjectBase.source | `source`}.\n * If the location provided exactly matches an existing object, the existing object will be replaced.\n * If no `name` is provided, one will be randomly generated.\n * If no `actor` is provided, the `actor` from the supplied {@link GraffitiSession | `session` } will be used.\n * If no `source` is provided, one may be inferred by the depending on implementation.\n *\n * This object does not need a {@link GraffitiObjectBase.lastModified | `lastModified`} or {@link GraffitiObjectBase.tombstone | `tombstone`}\n * property since these are automatically generated by the Graffiti system.\n */\nexport type GraffitiPutObject<Schema extends JSONSchema> = Pick<\n GraffitiObjectBase,\n \"value\" | \"channels\" | \"allowed\"\n> &\n Partial<GraffitiObjectBase> &\n FromSchema<Schema & typeof GraffitiPutObjectJSONSchema>;\n\n/**\n * A JSON Schema equivalent to the {@link GraffitiPutObject} type.\n * Needed internally for type inference of JSON Schemas, but can\n * be used by implementations to validate objects.\n */\nexport const GraffitiPutObjectJSONSchema = {\n ...GraffitiObjectJSONSchema,\n required: [\"value\", \"channels\"],\n} as const satisfies JSONSchema;\n\n/**\n * This object contains information that\n * {@link GraffitiObjectBase.source | `source`}s can\n * use to verify that a user has permission to operate a\n * particular {@link GraffitiObjectBase.actor | `actor`}.\n * This object is required of all {@link Graffiti} methods\n * that modify objects and is optional for methods that read objects.\n *\n * At a minimum the `session` object must contain the\n * {@link GraffitiSession.actor | `actor`} URI the user wants to authenticate with.\n * However it is likely that the `session` object must contain other\n * implementation-specific properties.\n * For example, a Solid implementation might include a\n * [`fetch`](https://docs.inrupt.com/developer-tools/api/javascript/solid-client-authn-browser/functions.html#fetch)\n * function. A distributed implementation may include\n * a cryptographic signature.\n *\n * As to why the `session` object is passed as an argument to every method\n * rather than being an internal property of the {@link Graffiti} instance,\n * this is primarily for type-checking to catch bugs related to login state.\n * Graffiti applications can expose some functionality to users who are not logged in\n * with {@link Graffiti.get} and {@link Graffiti.discover} but without type-checking\n * the `session` it can be easy to forget to hide buttons that trigger\n * other methods that require login.\n * In the future, `session` object may be updated to include scope information\n * and passing the `session` to each method can type-check whether the session provides the\n * necessary permissions.\n *\n * Passing the `session` object per-method also allows for multiple sessions\n * to be used within the same application, like an Email client fetching from\n * multiple accounts.\n */\nexport interface GraffitiSession {\n /**\n * The {@link GraffitiObjectBase.actor | `actor`} a user wants to authenticate with.\n */\n actor: string;\n /**\n * A yet undefined property detailing what operations the session\n * grants the user to perform. For example, to allow a user to\n * read private messages from a particular set of channels or\n * to allow the user to write object matching a particular schema.\n */\n scope?: {};\n}\n\n/**\n * This is the format for patches that modify {@link GraffitiObjectBase} objects\n * using the {@link Graffiti.patch} method. The patches must\n * be an array of [JSON Patch](https://jsonpatch.com) operations.\n * Patches can only be applied to the\n * {@link GraffitiObjectBase.value | `value`}, {@link GraffitiObjectBase.channels | `channels`},\n * and {@link GraffitiObjectBase.allowed | `allowed`} properties since the other\n * properties either describe the object's location or are automatically generated.\n * (See also {@link GraffitiPutObject}).\n */\nexport interface GraffitiPatch {\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.value | `value`}. The resulting\n * `value` must still be a JSON object.\n */\n value?: JSONPatchOperation[];\n\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.channels | `channels`}. The resulting\n * `channels` must still be an array of strings.\n */\n channels?: JSONPatchOperation[];\n\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.allowed | `allowed`} property. The resulting\n * `allowed` property must still be an array of strings or `undefined`.\n */\n allowed?: JSONPatchOperation[];\n}\n\n/**\n * This type represents a stream of data that are\n * returned by Graffiti's query-like operations such as\n * {@link Graffiti.discover} and {@link Graffiti.recoverOrphans}.\n *\n * Errors are returned within the stream rather than as\n * exceptions that would halt the entire stream. This is because\n * some implementations may pull data from multiple\n * {@link GraffitiObjectBase.source | `source`}s\n * including some that may be unreliable. In many cases,\n * these errors can be safely ignored.\n *\n * The stream is an [`AsyncGenerator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)\n * that can be iterated over using `for await` loops or calling `next` on the generator.\n * The stream can be terminated by breaking out of a loop calling `return` on the generator.\n */\nexport type GraffitiStream<TValue, TReturn = void> = AsyncGenerator<\n | {\n error?: undefined;\n value: TValue;\n }\n | {\n error: Error;\n source: string;\n },\n TReturn\n>;\n\n/**\n * Statistic about single channel returned by {@link Graffiti.channelStats}.\n * These statistics only account for contributions made by the\n * querying actor.\n */\nexport type ChannelStats = {\n /**\n * The URI of the channel.\n */\n channel: string;\n /**\n * The number of non-{@link GraffitiObjectBase.tombstone | `tombstone`}d objects\n * that the actor has posted to the channel.\n */\n count: number;\n /**\n * The time that the actor {@link GraffitiObjectBase.lastModified | last modified} an object in the channel,\n * measured in milliseconds since January 1, 1970.\n * {@link GraffitiObjectBase.tombstone | Tombstone}d objects do not effect this modification time.\n */\n lastModified: number;\n};\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * when a user logs in manually from {@link Graffiti.login}\n * or when their session is restored from a previous login.\n * The event name to listen for is `login`.\n */\nexport type GraffitiLoginEvent = CustomEvent<\n | {\n error: Error;\n session?: undefined;\n }\n | {\n error?: undefined;\n session: GraffitiSession;\n }\n>;\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * when a user logs out either manually with {@link Graffiti.logout}\n * or when their session times out or otherwise becomes invalid.\n * The event name to listen for is `logout`.\n */\nexport type GraffitiLogoutEvent = CustomEvent<\n | {\n error: Error;\n actor?: string;\n }\n | {\n error?: undefined;\n actor: string;\n }\n>;\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * after an application has attempted to complete any login redirects\n * and restore any previously active sessions.\n * Successful session restores will be returned in parallel as\n * their own {@link GraffitiLoginEvent} events.\n *\n * This event optionally returns an `href` property\n * representing the URL the user originated a login request\n * from, which may be useful for redirecting the user back to\n * the page they were on after login.\n * The event name to listen for is `initialized`.\n */\nexport type GraffitiSessionInitializedEvent = CustomEvent<\n | {\n error?: Error;\n href?: string;\n }\n | null\n | undefined\n>;\n", "export class GraffitiErrorUnauthorized extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorUnauthorized\";\n Object.setPrototypeOf(this, GraffitiErrorUnauthorized.prototype);\n }\n}\n\nexport class GraffitiErrorForbidden extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorForbidden\";\n Object.setPrototypeOf(this, GraffitiErrorForbidden.prototype);\n }\n}\n\nexport class GraffitiErrorNotFound extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorNotFound\";\n Object.setPrototypeOf(this, GraffitiErrorNotFound.prototype);\n }\n}\n\nexport class GraffitiErrorInvalidSchema extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorInvalidSchema\";\n Object.setPrototypeOf(this, GraffitiErrorInvalidSchema.prototype);\n }\n}\n\nexport class GraffitiErrorSchemaMismatch extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorSchemaMismatch\";\n Object.setPrototypeOf(this, GraffitiErrorSchemaMismatch.prototype);\n }\n}\n\nexport class GraffitiErrorPatchTestFailed extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorPatchTestFailed\";\n Object.setPrototypeOf(this, GraffitiErrorPatchTestFailed.prototype);\n }\n}\n\nexport class GraffitiErrorPatchError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorPatchError\";\n Object.setPrototypeOf(this, GraffitiErrorPatchError.prototype);\n }\n}\n\nexport class GraffitiErrorInvalidUri extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorInvalidUri\";\n Object.setPrototypeOf(this, GraffitiErrorInvalidUri.prototype);\n }\n}\n"],
5
- "mappings": "AA8LO,IAAeA,EAAf,KAAwB,CA6B7B,YAAYC,EAA4B,CACtC,OAAO,KAAK,cAAcA,CAAM,CAClC,CA6VF,ECvbO,IAAMC,EAA2B,CACtC,KAAM,SACN,WAAY,CACV,MAAO,CAAE,KAAM,QAAS,EACxB,SAAU,CAAE,KAAM,QAAS,MAAO,CAAE,KAAM,QAAS,CAAE,EACrD,QAAS,CAAE,KAAM,QAAS,MAAO,CAAE,KAAM,QAAS,EAAG,SAAU,EAAK,EACpE,MAAO,CAAE,KAAM,QAAS,EACxB,KAAM,CAAE,KAAM,QAAS,EACvB,OAAQ,CAAE,KAAM,QAAS,EACzB,aAAc,CAAE,KAAM,QAAS,EAC/B,UAAW,CAAE,KAAM,SAAU,CAC/B,EACA,qBAAsB,GACtB,SAAU,CACR,QACA,WACA,QACA,OACA,SACA,eACA,WACF,CACF,EA+CaC,EAA8B,CACzC,GAAGD,EACH,SAAU,CAAC,QAAS,UAAU,CAChC,EC3MO,IAAME,EAAN,MAAMC,UAAkC,KAAM,CACnD,YAAYC,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,4BACZ,OAAO,eAAe,KAAMD,EAA0B,SAAS,CACjE,CACF,EAEaE,EAAN,MAAMC,UAA+B,KAAM,CAChD,YAAYF,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,yBACZ,OAAO,eAAe,KAAME,EAAuB,SAAS,CAC9D,CACF,EAEaC,EAAN,MAAMC,UAA8B,KAAM,CAC/C,YAAYJ,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,wBACZ,OAAO,eAAe,KAAMI,EAAsB,SAAS,CAC7D,CACF,EAEaC,EAAN,MAAMC,UAAmC,KAAM,CACpD,YAAYN,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,6BACZ,OAAO,eAAe,KAAMM,EAA2B,SAAS,CAClE,CACF,EAEaC,EAAN,MAAMC,UAAoC,KAAM,CACrD,YAAYR,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,8BACZ,OAAO,eAAe,KAAMQ,EAA4B,SAAS,CACnE,CACF,EAEaC,EAAN,MAAMC,UAAqC,KAAM,CACtD,YAAYV,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,+BACZ,OAAO,eAAe,KAAMU,EAA6B,SAAS,CACpE,CACF,EAEaC,EAAN,MAAMC,UAAgC,KAAM,CACjD,YAAYZ,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,0BACZ,OAAO,eAAe,KAAMY,EAAwB,SAAS,CAC/D,CACF,EAEaC,EAAN,MAAMC,UAAgC,KAAM,CACjD,YAAYd,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,0BACZ,OAAO,eAAe,KAAMc,EAAwB,SAAS,CAC/D,CACF",
6
- "names": ["Graffiti", "object", "GraffitiObjectJSONSchema", "GraffitiPutObjectJSONSchema", "GraffitiErrorUnauthorized", "_GraffitiErrorUnauthorized", "message", "GraffitiErrorForbidden", "_GraffitiErrorForbidden", "GraffitiErrorNotFound", "_GraffitiErrorNotFound", "GraffitiErrorInvalidSchema", "_GraffitiErrorInvalidSchema", "GraffitiErrorSchemaMismatch", "_GraffitiErrorSchemaMismatch", "GraffitiErrorPatchTestFailed", "_GraffitiErrorPatchTestFailed", "GraffitiErrorPatchError", "_GraffitiErrorPatchError", "GraffitiErrorInvalidUri", "_GraffitiErrorInvalidUri"]
4
+ "sourcesContent": ["import type {\n GraffitiObjectUrl,\n GraffitiObject,\n GraffitiObjectBase,\n GraffitiPatch,\n GraffitiSession,\n GraffitiPutObject,\n GraffitiStream,\n ChannelStats,\n} from \"./2-types\";\nimport type { JSONSchema } from \"json-schema-to-ts\";\n\n/**\n * This API describes a small but powerful set of methods that\n * can be used to create many different kinds of social media applications,\n * all of which can interoperate.\n * These methods should satisfy all of an application's needs for\n * the communication, storage, and access management of social data.\n * The rest of the application can be built with standard client-side\n * user interface tools to present and interact with the data \u2014\n * no server code necessary.\n * The Typescript source for this API is available at\n * [graffiti-garden/api](https://github.com/graffiti-garden/api).\n *\n * There are several different implementations of this Graffiti API available,\n * including a [federated implementation](https://github.com/graffiti-garden/implementation-federated),\n * that lets users choose where their data is stored,\n * and a [local implementation](https://github.com/graffiti-garden/implementation-local)\n * that can be used for testing and development. In our design of Graffiti, this API is our\n * primary focus as it is the layer that shapes the experience\n * of developing applications. While different implementations can provide tradeoffs between\n * other important properties (e.g. privacy, security, scalability), those properties\n * are useless if the system as a whole doesn't expose useful functionality to developers.\n *\n * On the other side of the stack, there is [Vue plugin](https://github.com/graffiti-garden/wrapper-vue/)\n * that wraps around this API to provide reactivity. Other high-level libraries\n * will be available in the future.\n *\n * ## Overview\n *\n * Graffiti provides applications with methods to create and store data\n * on behalf of their users using standard CRUD operations:\n * {@link put}, {@link get}, {@link patch}, and {@link delete}.\n * This data can represent both social artifacts (e.g. posts, profiles) and\n * activities (e.g. likes, follows) and is stored as JSON.\n *\n * The social aspect of Graffiti comes from the {@link discover} method\n * which allows applications to find objects that other users made.\n * It is a lot like a traditional query operation, but it only\n * returns objects that have been placed in particular\n * {@link GraffitiObjectBase.channels | `channels`}\n * specified by the discovering application.\n *\n * Graffiti builds on well known concepts and standards wherever possible.\n * JSON Objects can be typed with [JSON Schema](https://json-schema.org/) and patches\n * can be applied with [JSON Patch](https://jsonpatch.com).\n * For interoperability between Graffiti applications, we recommend that\n * objects use established properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/) when available,\n * however it is always possible to create additional properties, contributing\n * to the broader [folksonomy](https://en.wikipedia.org/wiki/Folksonomy).\n *\n * {@link GraffitiObjectBase.channels | `channels`} are one of the major concepts\n * unique to Graffiti along with *interaction relativity*, defined below.\n * Channels create boundaries between public spaces and work to prevent\n * [context collapse](https://en.wikipedia.org/wiki/Context_collapse)\n * even in a highly interoperable environment.\n * Interaction relativity means that all interactions between users are\n * actually atomic single-user operations that can be interpreted in different ways,\n * which also supports interoperability and pluralism.\n *\n * ### Channels\n *\n * {@link GraffitiObjectBase.channels | `channels`}\n * are a way for the creators of social data to express the intended audience of their\n * data. When a user creates data using the {@link put} method, they\n * can place their data in one or more channels.\n * Content consumers using the {@link discover} method will only see data\n * contained in one of the channels they specify.\n *\n * While many channels may be public, they partition\n * the public into different \"contexts\", mitigating the\n * phenomenon of [context collapse](https://en.wikipedia.org/wiki/Context_collapse) or the \"flattening of multiple audiences.\"\n * Any [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier) can be used as a channel, and so channels can represent people,\n * comment threads, topics, places (real or virtual), pieces of media, and more.\n *\n * For example, consider a comment on a post. If we place that comment in the channel\n * represented by the post's URL, then only people viewing the post will know to\n * look in that channel, giving it visibility akin to a comment on a blog post\n * or comment on Instagram ([since 2019](https://www.buzzfeednews.com/article/katienotopoulos/instagrams-following-activity-tab-is-going-away)).\n * If we also place the comment in the channel represented by the commenter's URI (their\n * {@link GraffitiObjectBase.actor | `actor` URI}), then people viewing the commenter's profile\n * will also see the comment, giving it more visibility, like a reply on Twitter.\n * If we *only* place the comment in the channel represented by the commenter's URI, then\n * it becomes like a quote tweet ([prior to 2020](https://x.com/Support/status/1300555325750292480)),\n * where the comment is only visible to the commenter's followers but not the audience\n * of the original post.\n *\n * The channel model differs from other models of communication such as the\n * [actor model](https://www.w3.org/TR/activitypub/#Overview) used by ActivityPub,\n * the protocol underlying Mastodon, or the [firehose model](https://bsky.social/about/blog/5-5-2023-federation-architecture)\n * used by the AT Protocol, the protocol underlying BlueSky.\n * The actor model is a fusion of direct messaging (like Email) and broadcasting\n * (like RSS) and works well for follow-based communication but struggles\n * to pass information via other rendez-vous.\n * In the actor model, even something as simple as comments can be\n * [very tricky and require server \"side effects\"](https://seb.jambor.dev/posts/understanding-activitypub-part-3-the-state-of-mastodon/).\n * The firehose model dumps all user data into one public database,\n * which doesn't allow for the carving out of different contexts that we did in our comment\n * example above. In the firehose model a comment will always be visible to *both* the original post's audience and\n * the commenter's followers.\n *\n * In some sense, channels provide a sort of \"social access control\" by forming\n * expectations about the audiences of different online spaces.\n * As a real world analogy, oftentimes support groups, such as alcoholics\n * anonymous, are open to the public but people in those spaces feel comfortable sharing intimate details\n * because they have expectations about the other people attending.\n * If someone malicious went to support groups just to spread people's secrets,\n * they would be shamed for violating these norms.\n * Similarly, in Graffiti, while you could spider public channels like a search engine\n * to find content about a person, revealing that you've done such a thing\n * would be shameful.\n *\n * Still, social access control is not perfect and so in situations where privacy is important,\n * objects can also be given\n * an {@link GraffitiObjectBase.allowed | `allowed`} list.\n * For example, to send someone a direct message you should put an object representing\n * that message in the channel that represents them (their {@link GraffitiObjectBase.actor | `actor` URI}),\n * so they can find it, *and* set the `allowed` field to only include the recipient,\n * so only they can read it.\n *\n * ### Interaction relativity\n *\n * Interaction relativity posits that \"interaction between two individuals only\n * exists relative to an observer,\" or equivalently, all interaction is [reified](https://en.wikipedia.org/wiki/Reification_(computer_science)).\n * For example, if one user creates a post and another user wants to \"like\" that post,\n * their like is not modifying the original post, it is simply another data object that points\n * to the post being liked, via its {@link GraffitiObjectBase.url | URL}.\n *\n * ```json\n * {\n * activity: 'like',\n * target: 'url-of-the-post-i-like',\n * actor: 'my-user-id'\n * }\n * ```\n *\n * In Graffiti, all interactions including *moderation* and *collaboration* are relative.\n * This means that applications can freely choose which interactions\n * they want to express to their users and how.\n * For example, one application could have a single fixed moderator,\n * another could allow users to choose which moderators they would like filter their content\n * like [Bluesky's stackable moderation](https://bsky.social/about/blog/03-12-2024-stackable-moderation),\n * and another could implement a fully democratic system like [PolicyKit](https://policykit.org/).\n * Each of these applications is one interpretation of the underlying refieid user interactions and\n * users can freely switch between them.\n *\n * Interaction relativy also allows applications to introduce new sorts of interactions\n * without having to coordinate with all the other existing applications,\n * keeping the ecosystem flexible and interoperable.\n * For example, an application could [add a \"Trust\" button to posts](https://social.cs.washington.edu/pub_details.html?id=trustnet)\n * and use it assess the truthfulness of posts made on applications across Graffiti.\n * New sorts of interactions like these can be smoothly absorbed by the broader ecosystem\n * as a [folksonomy](https://en.wikipedia.org/wiki/Folksonomy).\n *\n * Interactivy relativity is realized in Graffiti through two design decisions:\n * 1. The creators of objects can only modify their own objects. It is important for\n * users to be able to change and delete their own content to respect their\n * [right to be forgotten](https://en.wikipedia.org/wiki/Right_to_be_forgotten),\n * but beyond self-correction and self-censorship all other interaction is reified.\n * Many interactions can be reified via pointers, as in the \"like\" example above, and collaborative\n * edits can be refieid via [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type).\n * 2. No one owns channels. Unlike IRC/Slack channels or [Matrix rooms](https://matrix.org/docs/matrix-concepts/rooms_and_events/),\n * anyone can post to any channel, so long as they know the URI of that channel.\n * It is up to applications to hide content from channels either according to manual\n * filters or in response to user action.\n * For example, a user may create a post with the flag `disableReplies`.\n * Applications could then filter out any content from the replies channel\n * that the original poster has not specifically approved.\n *\n * @groupDescription CRUD Methods\n * Methods for {@link put | creating}, {@link get | reading}, {@link patch | updating},\n * and {@link delete | deleting} {@link GraffitiObjectBase | Graffiti objects}.\n * @groupDescription Query Methods\n * Methods that retrieve or accumulate information about multiple {@link GraffitiObjectBase | Graffiti objects} at a time.\n * @groupDescription Session Management\n * Methods and properties for logging in and out of a Graffiti implementation.\n */\nexport abstract class Graffiti {\n /**\n * Creates a new {@link GraffitiObjectBase | object} or replaces an existing object.\n * An object can only be replaced by the same {@link GraffitiObjectBase.actor | `actor`}\n * that created it.\n *\n * Replacement occurs when the {@link GraffitiObjectBase.url | `url`} of\n * the replaced object exactly matches an existing object's URL.\n *\n * @returns The object that was replaced if one exists or an object with\n * with an empty {@link GraffitiObjectBase.value | `value`},\n * {@link GraffitiObjectBase.channels | `channels`}, and {@link GraffitiObjectBase.allowed | `allowed`}\n * list if the method created a new object.\n * In either case, the object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of replacement/creation.\n *\n * @group CRUD Methods\n */\n abstract put<Schema extends JSONSchema>(\n /**\n * The object to be put. This object is statically type-checked against the [JSON schema](https://json-schema.org/) that can be optionally provided\n * as the generic type parameter. We highly recommend providing a schema to\n * ensure that the PUT object matches subsequent {@link get} or {@link discover}\n * methods.\n */\n object: GraffitiPutObject<Schema>,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Retrieves an object from a given location.\n *\n * The retrieved object is type-checked against the provided [JSON schema](https://json-schema.org/)\n * otherwise a {@link GraffitiErrorSchemaMismatch} is thrown.\n *\n * If the retreiving {@link GraffitiObjectBase.actor | `actor`} is not\n * the object's `actor`,\n * the object's {@link GraffitiObjectBase.allowed | `allowed`} and\n * {@link GraffitiObjectBase.channels | `channels`} properties are\n * not revealed, similar to a BCC.\n *\n * If the object existed but has since been deleted,\n * or the retrieving {@link GraffitiObjectBase.actor | `actor`}\n * was {@link GraffitiObjectBase.allowed | `allowed`} to access\n * the object but now isn't, this method may return the latest\n * version of the object that the {@link GraffitiObjectBase.actor | `actor`}\n * was allowed to access with its {@link GraffitiObjectBase.tombstone | `tombstone`}\n * set to `true`. This allows for the invalidation of the object\n * in a client-side cache.\n *\n * Otherwise, if the object never existed, or the\n * retrieving {@link GraffitiObjectBase.actor | `actor`} was never\n * {@link GraffitiObjectBase.allowed | `allowed`} to access it, or if\n * the object was changed long enough ago that it has been permanently deleted,\n * a {@link GraffitiErrorNotFound} is thrown.\n * The rate at which permanent deletions happen is implementation dependent.\n * See the `tombstoneRetention` property returned by {@link discover}.\n *\n * @group CRUD Methods\n */\n abstract get<Schema extends JSONSchema>(\n /**\n * The location of the object to get.\n */\n url: string | GraffitiObjectUrl,\n /**\n * The JSON schema to validate the retrieved object against.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}. If no `session` is provided,\n * the retrieved object's {@link GraffitiObjectBase.allowed | `allowed`}\n * property must be `undefined`.\n */\n session?: GraffitiSession | null,\n ): Promise<GraffitiObject<Schema>>;\n\n /**\n * Patches an existing object at a given location.\n * The patching {@link GraffitiObjectBase.actor | `actor`} must be the same as the\n * `actor` that created the object.\n *\n * @returns The original object prior to the patch\n * The object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of deletion.\n *\n * @throws {@link GraffitiErrorNotFound} if the object does not exist or has already been deleted.\n *\n * @group CRUD Methods\n */\n abstract patch(\n /**\n * A collection of [JSON Patch](https://jsonpatch.com) operations\n * to apply to the object. See {@link GraffitiPatch} for more information.\n */\n patch: GraffitiPatch,\n /**\n * The location of the object to patch.\n */\n url: string | GraffitiObjectUrl,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Deletes an object from a given location.\n * The deleting {@link GraffitiObjectBase.actor | `actor`} must be the same as the\n * `actor` that created the object.\n *\n * @returns The object that was deleted if one exists.\n * The object will have a {@link GraffitiObjectBase.tombstone | `tombstone`}\n * field set to `true` and a {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field updated to the time of deletion.\n *\n * @throws {@link GraffitiErrorNotFound} if the object does not exist or has already been deleted.\n *\n * @group CRUD Methods\n */\n abstract delete(\n /**\n * The location of the object to delete.\n */\n url: string | GraffitiObjectUrl,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): Promise<GraffitiObjectBase>;\n\n /**\n * Discovers objects created by any user that are contained\n * in at least one of the given {@link GraffitiObjectBase.channels | `channels`}\n * and match the given [JSON Schema](https://json-schema.org).\n *\n * Objects are returned asynchronously as they are discovered but the stream\n * will end once all leads have been exhausted.\n * The method must be polled again for new objects.\n *\n * `discover` will not return objects that the {@link GraffitiObjectBase.actor | `actor`}\n * is not {@link GraffitiObjectBase.allowed | `allowed`} to access.\n * If the actor is not the creator of a discovered object,\n * the allowed list will be masked to only contain the querying actor if the\n * allowed list is not `undefined` (public). Additionally, if the actor is not the\n * creator of a discovered object, any {@link GraffitiObjectBase.channels | `channels`}\n * not specified by the `discover` method will not be revealed. This masking happens\n * before the supplied schema is applied.\n *\n * Since different implementations may fetch data from multiple sources there is\n * no guarentee on the order that objects are returned in. Additionally, the method\n * will return objects that have been deleted but with a\n * {@link GraffitiObjectBase.tombstone | `tombstone`} field set to `true` for\n * client-side cache invalidation purposes.\n * The final `return()` value of the stream includes a `tombstoneRetention`\n * property that represents the minimum amount of time,\n * in milliseconds, that an application will retain and return tombstones for objects that\n * have been deleted.\n *\n * When repolling, the {@link GraffitiObjectBase.lastModified | `lastModified`}\n * field can be queried via the schema to\n * only fetch objects that have been modified since the last poll.\n * Such queries should only be done if the time since the last poll\n * is less than the `tombstoneRetention` value of that poll, otherwise the tombstones\n * for objects that have been deleted may not be returned.\n *\n * ```json\n * {\n * \"properties\": {\n * \"lastModified\": {\n * \"minimum\": LAST_RETRIEVED_TIME\n * }\n * }\n * }\n * ```\n *\n * `discover` needs to be polled for new data because live updates to\n * an application can be visually distracting or lead to toxic engagement.\n * If and when an application wants real-time updates, such as in a chat\n * application, application authors must be intentional about their polling.\n *\n * Implementers should be aware that some users may applications may try to poll\n * {@link discover} repetitively. They can deal with this by rate limiting or\n * preemptively fetching data via a bidirectional channel, like a WebSocket.\n * Additionally, implementers should probably index the `lastModified` field\n * to speed up responses to schemas like the one above.\n *\n * @returns A stream of objects that match the given {@link GraffitiObjectBase.channels | `channels`}\n * and [JSON Schema](https://json-schema.org).\n *\n * @group Query Methods\n */\n abstract discover<Schema extends JSONSchema>(\n /**\n * The {@link GraffitiObjectBase.channels | `channels`} that objects must be associated with.\n */\n channels: string[],\n /**\n * A [JSON Schema](https://json-schema.org) that objects must satisfy.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}. If no `session` is provided,\n * only objects that have no {@link GraffitiObjectBase.allowed | `allowed`}\n * property will be returned.\n */\n session?: GraffitiSession | null,\n ): GraffitiStream<\n GraffitiObject<Schema>,\n {\n tombstoneRetention: number;\n }\n >;\n\n /**\n * Discovers objects **not** contained in any\n * {@link GraffitiObjectBase.channels | `channels`}\n * that were created by the querying {@link GraffitiObjectBase.actor | `actor`}\n * and match the given [JSON Schema](https://json-schema.org).\n * Unlike {@link discover}, this method will not return objects created by other users.\n *\n * This method is not useful for most applications, but necessary for\n * getting a global view of all a user's Graffiti data or debugging\n * channel usage.\n *\n * It's return value is the same as {@link discover}.\n *\n * @group Query Methods\n */\n abstract recoverOrphans<Schema extends JSONSchema>(\n /**\n * A [JSON Schema](https://json-schema.org) that orphaned objects must satisfy.\n */\n schema: Schema,\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): GraffitiStream<\n GraffitiObject<Schema>,\n {\n tombstoneRetention: number;\n }\n >;\n\n /**\n * Returns statistics about all the {@link GraffitiObjectBase.channels | `channels`}\n * that an {@link GraffitiObjectBase.actor | `actor`} has posted to.\n * This is not very useful for most applications, but\n * necessary for certain applications where a user wants a\n * global view of all their Graffiti data or to debug\n * channel usage.\n *\n * @group Query Methods\n *\n * @returns A stream of statistics for each {@link GraffitiObjectBase.channels | `channel`}\n * that the {@link GraffitiObjectBase.actor | `actor`} has posted to.\n */\n abstract channelStats(\n /**\n * An implementation-specific object with information to authenticate the\n * {@link GraffitiObjectBase.actor | `actor`}.\n */\n session: GraffitiSession,\n ): GraffitiStream<ChannelStats>;\n\n /**\n * Begins the login process. Depending on the implementation, this may\n * involve redirecting the user to a login page or opening a popup,\n * so it should always be called in response to a user action.\n *\n * The {@link GraffitiSession | session} object is returned\n * asynchronously via {@link Graffiti.sessionEvents | sessionEvents}\n * as a {@link GraffitiLoginEvent} with event type `login`.\n *\n * @group Session Management\n */\n abstract login(\n /**\n * Suggestions for the permissions that the\n * login process should grant. The login process may not\n * provide the exact proposed permissions.\n */\n proposal?: {\n /**\n * A suggested actor to login as. For example, if a user tries to\n * edit a post but are not logged in, the interface can infer that\n * they might want to log in as the actor who created the post\n * they are attempting to edit.\n *\n * Even if provided, the implementation should allow the user\n * to log in as a different actor if they choose.\n */\n actor?: string;\n /**\n * A yet to be defined permissions scope. An application may use\n * this to indicate the minimum necessary scope needed to\n * operate. For example, it may need to be able read private\n * messages from a certain set of channels, or write messages that\n * follow a particular schema.\n *\n * The login process should make it clear what scope an application\n * is requesting and allow the user to enhance or reduce that\n * scope as necessary.\n */\n scope?: {};\n },\n ): Promise<void>;\n\n /**\n * Begins the logout process. Depending on the implementation, this may\n * involve redirecting the user to a logout page or opening a popup,\n * so it should always be called in response to a user action.\n *\n * A confirmation will be returned asynchronously via\n * {@link Graffiti.sessionEvents | sessionEvents}\n * as a {@link GraffitiLogoutEvent} as event type `logout`.\n *\n * @group Session Management\n */\n abstract logout(\n /**\n * The {@link GraffitiSession | session} object to logout.\n */\n session: GraffitiSession,\n ): Promise<void>;\n\n /**\n * An event target that can be used to listen for the following\n * events and they're corresponding event types:\n * - `login` - {@link GraffitiLoginEvent}\n * - `logout` - {@link GraffitiLogoutEvent}\n * - `initialized` - {@link GraffitiSessionInitializedEvent}\n *\n * @group Session Management\n */\n abstract readonly sessionEvents: EventTarget;\n}\n", "import type { JSONSchema, FromSchema } from \"json-schema-to-ts\";\nimport type { Operation as JSONPatchOperation } from \"fast-json-patch\";\n\n/**\n * Objects are the atomic unit in Graffiti that can represent both data (*e.g.* a social media post or profile)\n * and activities (*e.g.* a like or follow).\n * Objects are created and modified by a single {@link actor | `actor`}.\n *\n * Most of an object's content is stored in its {@link value | `value`} property, which can be any JSON\n * object. However, we recommend using properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)\n * or properties that emerge in the Graffiti [folksonomy](https://en.wikipedia.org/wiki/Folksonomy)\n * to promote interoperability.\n *\n * The object is globally addressable via its {@link url | `url`}.\n *\n * The {@link channels | `channels`} and {@link allowed | `allowed`} properties\n * enable the object's creator to shape the visibility of and access to their object.\n *\n * The {@link tombstone | `tombstone`} and {@link lastModified | `lastModified`} properties are for\n * caching and synchronization.\n */\nexport interface GraffitiObjectBase {\n /**\n * The object's content as freeform JSON. We recommend using properties from the\n * [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)\n * or properties that emerge in the Graffiti [folksonomy](https://en.wikipedia.org/wiki/Folksonomy)\n * to promote interoperability.\n */\n value: {};\n\n /**\n * An array of URIs the creator associates with the object. Objects can only be found by querying\n * one of the object's channels using the\n * {@link Graffiti.discover} method. This allows creators to express the intended audience of their object\n * which helps to prevent [context collapse](https://en.wikipedia.org/wiki/Context_collapse) even\n * in the highly interoperable ecosystem that Graffiti envisions. For example, channel URIs may be:\n * - A user's own {@link actor | `actor`} URI. Putting an object in this channel is a way to broadcast\n * the object to the user's followers, like posting a tweet.\n * - The URL of a Graffiti post. Putting an object in this channel is a way to broadcast to anyone viewing\n * the post, like commenting on a tweet.\n * - A URI representing a topic. Putting an object in this channel is a way to broadcast to anyone interested\n * in that topic, like posting in a subreddit.\n */\n channels: string[];\n\n /**\n * An optional array of {@link actor | `actor`} URIs that the creator allows to access the object.\n * If no `allowed` array is provided, the object can be accessed by anyone (so long as they\n * also know the right {@link channels | `channel` } to look in). An object can always be accessed by its creator, even if\n * the `allowed` array is empty.\n *\n * The `allowed` array is not revealed to users other than the creator, like\n * a BCC email. A user may choose to add a `to` property to the object's {@link value | `value`} to indicate\n * other recipients, however this is not enforced by Graffiti and may not accurately reflect the actual `allowed` array.\n *\n * `allowed` can be combined with {@link channels | `channels`}. For example, to send someone a direct message\n * the sender should put their object in the channel of the recipient's {@link actor | `actor`} URI to notify them of the message and also add\n * the recipient's {@link actor | `actor`} URI to the `allowed` array to prevent others from seeing the message.\n */\n allowed?: string[] | null;\n\n /**\n * The URI of the `actor` that {@link Graffiti.put | created } the object. This `actor` also has the unique permission to\n * {@link Graffiti.patch | modify} or {@link Graffiti.delete | delete} the object.\n *\n * We borrow the term actor from the ActivityPub because\n * [like in ActivityPub](https://www.w3.org/TR/activitypub/#h-note-0)\n * there is not necessarily a one-to-one mapping between actors and people/users.\n * Multiple people can share the same actor or one person can have multiple actors.\n * Actors can also be bots.\n *\n * In Graffiti, actors are always globally unique URIs which\n * allows them to also function as {@link channels | `channels`}.\n */\n actor: string;\n\n /**\n * A globally unique identifier and locator for the object. It can be used to point to\n * an object or to retrieve the object directly with {@link Graffiti.get}.\n * If an object is {@link Graffiti.put | put} with the same URL\n * as an existing object, the existing object will be replaced with the new object.\n *\n * An object's URL is generated when the object is first creation and\n * should include sufficient randomness to prevent collisions\n * and guessing. The URL starts with a \"scheme\", just like web URLs start with `http` or `https`, to indicate\n * to indicate the particular Graffiti implementation. This allows for applications\n * to pull from multiple coexisting Graffiti implementations without collision.\n * Existing schemes include `graffiti:local:` for objects stored locally\n * (see the [local implementation](https://github.com/graffiti-garden/implementation-local))\n * and `graffiti:remote:` for objects stored on Graffiti-specific web servers (see the\n * [remote implementation](https://github.com/graffiti-garden/implementation-remote)).\n * Options available in the future might include `graffiti:solid:` for objects stored on Solid servers\n * or `graffiti:p2p:` for objects stored on a peer-to-peer network.\n */\n url: string;\n\n /**\n * The time the object was last modified, measured in milliseconds since January 1, 1970.\n * This is used for client-side caching and synchronization.\n * A number, rather than an ISO string or Date object, is used for easy comparison, sorting,\n * and JSON Schema [range queries](https://json-schema.org/understanding-json-schema/reference/numeric#range).\n *\n * It is possible to use this value to sort objects in a user's interface but in many cases it would be better to\n * use a [`published`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-published)\n * property in the object's {@link value | `value`} to indicate when the object was created\n * rather than when it was modified.\n */\n lastModified: number;\n\n /**\n * A boolean indicating whether the object has been deleted.\n * Depending on implementation, objects stay available for some time\n * after deletion to allow for synchronization and client-side caching\n */\n tombstone: boolean;\n}\n\n/**\n * This type constrains the {@link GraffitiObjectBase} type to adhere to a\n * particular [JSON schema](https://json-schema.org/).\n * This allows for static type-checking of an object's {@link GraffitiObjectBase.value | `value`}\n * which is otherwise a freeform JSON object.\n *\n * Schema-aware objects are returned by {@link Graffiti.get} and {@link Graffiti.discover}.\n */\nexport type GraffitiObject<Schema extends JSONSchema> = GraffitiObjectBase &\n FromSchema<Schema & typeof GraffitiObjectJSONSchema>;\n\n/**\n * A JSON Schema equivalent to the {@link GraffitiObjectBase} type.\n * Needed internally for type inference of JSON Schemas, but can\n * be used by implementations to validate objects.\n */\nexport const GraffitiObjectJSONSchema = {\n type: \"object\",\n properties: {\n value: { type: \"object\" },\n channels: { type: \"array\", items: { type: \"string\" } },\n allowed: { type: \"array\", items: { type: \"string\" }, nullable: true },\n url: { type: \"string\" },\n actor: { type: \"string\" },\n lastModified: { type: \"number\" },\n tombstone: { type: \"boolean\" },\n },\n additionalProperties: false,\n required: [\"value\", \"channels\", \"actor\", \"url\", \"lastModified\", \"tombstone\"],\n} as const satisfies JSONSchema;\n\n/**\n * This is an object containing only the {@link GraffitiObjectBase.url | `url`}\n * property of a {@link GraffitiObjectBase | GraffitiObject}.\n * It is used as a utility type so that users can call {@link Graffiti.get},\n * {@link Graffiti.patch}, or {@link Graffiti.delete} directly on an object\n * rather than on `object.url`.\n */\nexport type GraffitiObjectUrl = Pick<GraffitiObjectBase, \"url\">;\n\n/**\n * This object is a subset of {@link GraffitiObjectBase} that a user must construct locally before calling {@link Graffiti.put}.\n * This local copy does not require system-generated properties and may be statically typed with\n * a [JSON schema](https://json-schema.org/) to prevent the accidental creation of erroneous objects.\n *\n * This local object must have a {@link GraffitiObjectBase.value | `value`} and {@link GraffitiObjectBase.channels | `channels`}\n * and may optionally have an {@link GraffitiObjectBase.allowed | `allowed`} property.\n *\n * It may also include a {@link GraffitiObjectBase.url | `url`} property to specify the\n * URL of an existing object to replace. If no `url` is provided, one will be generated during object creation.\n *\n * This object does not need a {@link GraffitiObjectBase.lastModified | `lastModified`} or {@link GraffitiObjectBase.tombstone | `tombstone`}\n * property since these are automatically generated by the Graffiti system.\n */\nexport type GraffitiPutObject<Schema extends JSONSchema> = Pick<\n GraffitiObjectBase,\n \"value\" | \"channels\" | \"allowed\"\n> &\n Partial<GraffitiObjectBase> &\n FromSchema<Schema & typeof GraffitiPutObjectJSONSchema>;\n\n/**\n * A JSON Schema equivalent to the {@link GraffitiPutObject} type.\n * Needed internally for type inference of JSON Schemas, but can\n * be used by implementations to validate objects.\n */\nexport const GraffitiPutObjectJSONSchema = {\n ...GraffitiObjectJSONSchema,\n required: [\"value\", \"channels\"],\n} as const satisfies JSONSchema;\n\n/**\n * This object contains information that the underlying implementation can\n * use to verify that a user has permission to operate a\n * particular {@link GraffitiObjectBase.actor | `actor`}.\n * This object is required of all {@link Graffiti} methods\n * that modify objects and is optional for methods that read objects.\n *\n * At a minimum the `session` object must contain the\n * {@link GraffitiSession.actor | `actor`} URI the user wants to authenticate with.\n * However it is likely that the `session` object must contain other\n * implementation-specific properties.\n * For example, a Solid implementation might include a\n * [`fetch`](https://docs.inrupt.com/developer-tools/api/javascript/solid-client-authn-browser/functions.html#fetch)\n * function. A distributed implementation may include\n * a cryptographic signature.\n *\n * As to why the `session` object is passed as an argument to every method\n * rather than being an internal property of the {@link Graffiti} instance,\n * this is primarily for type-checking to catch bugs related to login state.\n * Graffiti applications can expose some functionality to users who are not logged in\n * with {@link Graffiti.get} and {@link Graffiti.discover} but without type-checking\n * the `session` it can be easy to forget to hide buttons that trigger\n * other methods that require login.\n * In the future, `session` object may be updated to include scope information\n * and passing the `session` to each method can type-check whether the session provides the\n * necessary permissions.\n *\n * Passing the `session` object per-method also allows for multiple sessions\n * to be used within the same application, like an Email client fetching from\n * multiple accounts.\n */\nexport interface GraffitiSession {\n /**\n * The {@link GraffitiObjectBase.actor | `actor`} a user wants to authenticate with.\n */\n actor: string;\n /**\n * A yet undefined property detailing what operations the session\n * grants the user to perform. For example, to allow a user to\n * read private messages from a particular set of channels or\n * to allow the user to write object matching a particular schema.\n */\n scope?: {};\n}\n\n/**\n * This is the format for patches that modify {@link GraffitiObjectBase} objects\n * using the {@link Graffiti.patch} method. The patches must\n * be an array of [JSON Patch](https://jsonpatch.com) operations.\n * Patches can only be applied to the\n * {@link GraffitiObjectBase.value | `value`}, {@link GraffitiObjectBase.channels | `channels`},\n * and {@link GraffitiObjectBase.allowed | `allowed`} properties since the other\n * properties either describe the object's location or are automatically generated.\n * (See also {@link GraffitiPutObject}).\n */\nexport interface GraffitiPatch {\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.value | `value`}. The resulting\n * `value` must still be a JSON object.\n */\n value?: JSONPatchOperation[];\n\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.channels | `channels`}. The resulting\n * `channels` must still be an array of strings.\n */\n channels?: JSONPatchOperation[];\n\n /**\n * An array of [JSON Patch](https://jsonpatch.com) operations to\n * modify the object's {@link GraffitiObjectBase.allowed | `allowed`} property. The resulting\n * `allowed` property must still be an array of strings or `undefined`.\n */\n allowed?: JSONPatchOperation[];\n}\n\n/**\n * This type represents a stream of data that are\n * returned by Graffiti's query-like operations such as\n * {@link Graffiti.discover} and {@link Graffiti.recoverOrphans}.\n *\n * Errors are returned within the stream rather than as\n * exceptions that would halt the entire stream. This is because\n * some implementations may pull data from multiple sources\n * including some that may be unreliable. In many cases,\n * these errors can be safely ignored.\n * The `origin` property of the error object indicates the\n * source of the error including its scheme and other\n * implementation-specific details (e.g. domain name).\n *\n * The stream is an [`AsyncGenerator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)\n * that can be iterated over using `for await` loops or calling `next` on the generator.\n * The stream can be terminated by breaking out of a loop calling `return` on the generator.\n */\nexport type GraffitiStream<TValue, TReturn = void> = AsyncGenerator<\n | {\n error?: undefined;\n value: TValue;\n }\n | {\n error: Error;\n origin: string;\n },\n TReturn\n>;\n\n/**\n * Statistic about single channel returned by {@link Graffiti.channelStats}.\n * These statistics only account for contributions made by the\n * querying actor.\n */\nexport type ChannelStats = {\n /**\n * The URI of the channel.\n */\n channel: string;\n /**\n * The number of non-{@link GraffitiObjectBase.tombstone | `tombstone`}d objects\n * that the actor has posted to the channel.\n */\n count: number;\n /**\n * The time that the actor {@link GraffitiObjectBase.lastModified | last modified} an object in the channel,\n * measured in milliseconds since January 1, 1970.\n * {@link GraffitiObjectBase.tombstone | Tombstone}d objects do not effect this modification time.\n */\n lastModified: number;\n};\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * when a user logs in manually from {@link Graffiti.login}\n * or when their session is restored from a previous login.\n * The event name to listen for is `login`.\n */\nexport type GraffitiLoginEvent = CustomEvent<\n | {\n error: Error;\n session?: undefined;\n }\n | {\n error?: undefined;\n session: GraffitiSession;\n }\n>;\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * when a user logs out either manually with {@link Graffiti.logout}\n * or when their session times out or otherwise becomes invalid.\n * The event name to listen for is `logout`.\n */\nexport type GraffitiLogoutEvent = CustomEvent<\n | {\n error: Error;\n actor?: string;\n }\n | {\n error?: undefined;\n actor: string;\n }\n>;\n\n/**\n * The event type produced in {@link Graffiti.sessionEvents}\n * after an application has attempted to complete any login redirects\n * and restore any previously active sessions.\n * Successful session restores will be returned in parallel as\n * their own {@link GraffitiLoginEvent} events.\n *\n * This event optionally returns an `href` property\n * representing the URL the user originated a login request\n * from, which may be useful for redirecting the user back to\n * the page they were on after login.\n * The event name to listen for is `initialized`.\n */\nexport type GraffitiSessionInitializedEvent = CustomEvent<\n | {\n error?: Error;\n href?: string;\n }\n | null\n | undefined\n>;\n", "export class GraffitiErrorUnauthorized extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorUnauthorized\";\n Object.setPrototypeOf(this, GraffitiErrorUnauthorized.prototype);\n }\n}\n\nexport class GraffitiErrorForbidden extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorForbidden\";\n Object.setPrototypeOf(this, GraffitiErrorForbidden.prototype);\n }\n}\n\nexport class GraffitiErrorNotFound extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorNotFound\";\n Object.setPrototypeOf(this, GraffitiErrorNotFound.prototype);\n }\n}\n\nexport class GraffitiErrorInvalidSchema extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorInvalidSchema\";\n Object.setPrototypeOf(this, GraffitiErrorInvalidSchema.prototype);\n }\n}\n\nexport class GraffitiErrorSchemaMismatch extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorSchemaMismatch\";\n Object.setPrototypeOf(this, GraffitiErrorSchemaMismatch.prototype);\n }\n}\n\nexport class GraffitiErrorPatchTestFailed extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorPatchTestFailed\";\n Object.setPrototypeOf(this, GraffitiErrorPatchTestFailed.prototype);\n }\n}\n\nexport class GraffitiErrorPatchError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorPatchError\";\n Object.setPrototypeOf(this, GraffitiErrorPatchError.prototype);\n }\n}\n\nexport class GraffitiErrorInvalidUri extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorInvalidUri\";\n Object.setPrototypeOf(this, GraffitiErrorInvalidUri.prototype);\n }\n}\n\nexport class GraffitiErrorUnrecognizedUriScheme extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"GraffitiErrorUnrecognizedUriScheme\";\n Object.setPrototypeOf(this, GraffitiErrorUnrecognizedUriScheme.prototype);\n }\n}\n"],
5
+ "mappings": "AA4LO,IAAeA,EAAf,KAAwB,CA4V/B,EClZO,IAAMC,EAA2B,CACtC,KAAM,SACN,WAAY,CACV,MAAO,CAAE,KAAM,QAAS,EACxB,SAAU,CAAE,KAAM,QAAS,MAAO,CAAE,KAAM,QAAS,CAAE,EACrD,QAAS,CAAE,KAAM,QAAS,MAAO,CAAE,KAAM,QAAS,EAAG,SAAU,EAAK,EACpE,IAAK,CAAE,KAAM,QAAS,EACtB,MAAO,CAAE,KAAM,QAAS,EACxB,aAAc,CAAE,KAAM,QAAS,EAC/B,UAAW,CAAE,KAAM,SAAU,CAC/B,EACA,qBAAsB,GACtB,SAAU,CAAC,QAAS,WAAY,QAAS,MAAO,eAAgB,WAAW,CAC7E,EAqCaC,EAA8B,CACzC,GAAGD,EACH,SAAU,CAAC,QAAS,UAAU,CAChC,EC3LO,IAAME,EAAN,MAAMC,UAAkC,KAAM,CACnD,YAAYC,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,4BACZ,OAAO,eAAe,KAAMD,EAA0B,SAAS,CACjE,CACF,EAEaE,EAAN,MAAMC,UAA+B,KAAM,CAChD,YAAYF,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,yBACZ,OAAO,eAAe,KAAME,EAAuB,SAAS,CAC9D,CACF,EAEaC,EAAN,MAAMC,UAA8B,KAAM,CAC/C,YAAYJ,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,wBACZ,OAAO,eAAe,KAAMI,EAAsB,SAAS,CAC7D,CACF,EAEaC,EAAN,MAAMC,UAAmC,KAAM,CACpD,YAAYN,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,6BACZ,OAAO,eAAe,KAAMM,EAA2B,SAAS,CAClE,CACF,EAEaC,EAAN,MAAMC,UAAoC,KAAM,CACrD,YAAYR,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,8BACZ,OAAO,eAAe,KAAMQ,EAA4B,SAAS,CACnE,CACF,EAEaC,EAAN,MAAMC,UAAqC,KAAM,CACtD,YAAYV,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,+BACZ,OAAO,eAAe,KAAMU,EAA6B,SAAS,CACpE,CACF,EAEaC,EAAN,MAAMC,UAAgC,KAAM,CACjD,YAAYZ,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,0BACZ,OAAO,eAAe,KAAMY,EAAwB,SAAS,CAC/D,CACF,EAEaC,EAAN,MAAMC,UAAgC,KAAM,CACjD,YAAYd,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,0BACZ,OAAO,eAAe,KAAMc,EAAwB,SAAS,CAC/D,CACF,EAEaC,EAAN,MAAMC,UAA2C,KAAM,CAC5D,YAAYhB,EAAkB,CAC5B,MAAMA,CAAO,EACb,KAAK,KAAO,qCACZ,OAAO,eAAe,KAAMgB,EAAmC,SAAS,CAC1E,CACF",
6
+ "names": ["Graffiti", "GraffitiObjectJSONSchema", "GraffitiPutObjectJSONSchema", "GraffitiErrorUnauthorized", "_GraffitiErrorUnauthorized", "message", "GraffitiErrorForbidden", "_GraffitiErrorForbidden", "GraffitiErrorNotFound", "_GraffitiErrorNotFound", "GraffitiErrorInvalidSchema", "_GraffitiErrorInvalidSchema", "GraffitiErrorSchemaMismatch", "_GraffitiErrorSchemaMismatch", "GraffitiErrorPatchTestFailed", "_GraffitiErrorPatchTestFailed", "GraffitiErrorPatchError", "_GraffitiErrorPatchError", "GraffitiErrorInvalidUri", "_GraffitiErrorInvalidUri", "GraffitiErrorUnrecognizedUriScheme", "_GraffitiErrorUnrecognizedUriScheme"]
7
7
  }