···2222import type { WebSocket } from "ws";
2323import { formatLabel, labelIsSigned, signLabel } from "./util/labels.js";
2424import type {
2525+ CreateLabelData,
2526 ProcedureHandler,
2627 QueryHandler,
2728 SavedLabel,
2829 SubscriptionHandler,
2930} from "./util/types.js";
3131+import { excludeUndefined } from "./util/util.js";
30323133/**
3234 * Options for the {@link LabelerServer} class.
···132134 }
133135134136 /**
135135- * Create and insert a label into the database, emitting it to subscribers.
136136- * @param label The label to create.
137137- * @returns The created label.
137137+ * Insert a label into the database, emitting it to subscribers.
138138+ * @param label The label to insert.
139139+ * @returns The inserted label.
138140 */
139139- async createLabel(label: ComAtprotoLabelDefs.Label): Promise<SavedLabel> {
141141+ private async saveLabel(label: ComAtprotoLabelDefs.Label): Promise<SavedLabel> {
140142 const signed = labelIsSigned(label) ? label : await signLabel(label, this.signingKey);
141143142144 const stmt = this.db.prepare(`
···155157 }
156158157159 /**
160160+ * Create and insert a label into the database, emitting it to subscribers.
161161+ * @param label The label to create.
162162+ * @returns The created label.
163163+ */
164164+ async createLabel(label: CreateLabelData): Promise<SavedLabel> {
165165+ return this.saveLabel(
166166+ excludeUndefined({
167167+ ...label,
168168+ src: label.src ?? this.did,
169169+ cts: label.cts ?? new Date().toISOString(),
170170+ }),
171171+ );
172172+ }
173173+174174+ /**
158175 * Create and insert labels into the database, emitting them to subscribers.
159176 * @param subject The subject of the labels.
160177 * @param labels The labels to create.
···170187 const createdLabels: Array<SavedLabel> = [];
171188 if (create) {
172189 for (const val of create) {
173173- const created = await this.createLabel({
174174- src: this.did,
175175- uri,
176176- ...(cid ? { cid } : {}),
177177- val,
178178- cts: new Date().toISOString(),
179179- });
190190+ const created = await this.createLabel({ uri, cid, val });
180191 createdLabels.push(created);
181192 }
182193 }
183194 if (negate) {
184195 for (const val of negate) {
185185- const negated = await this.createLabel({
186186- src: this.did,
187187- uri,
188188- ...(cid ? { cid } : {}),
189189- val,
190190- neg: true,
191191- cts: new Date().toISOString(),
192192- });
196196+ const negated = await this.createLabel({ uri, cid, val, neg: true });
193197 createdLabels.push(negated);
194198 }
195199 }
+1
src/index.ts
···11export { type LabelerOptions, LabelerServer } from "./LabelerServer.js";
22export { formatLabel, labelIsSigned, signLabel } from "./util/labels.js";
33export type {
44+ CreateLabelData,
45 ProcedureHandler,
56 QueryHandler,
67 SavedLabel,
+4-16
src/util/labels.ts
···11import { encode as cborEncode } from "@atcute/cbor";
22import type { ComAtprotoLabelDefs } from "@atproto/api";
33import type { Keypair } from "@atproto/crypto";
44-import type { SignedLabel, StrictPartial } from "./types.js";
44+import type { SignedLabel } from "./types.js";
55+import { excludeUndefined } from "./util.js";
5667const LABEL_VERSION = 1;
7888-export function formatLabel(
99- label: ComAtprotoLabelDefs.Label,
1010-): StrictPartial<ComAtprotoLabelDefs.Label> {
1111- const { src, uri, cid, val, neg, cts, exp, sig } = label;
1212- return {
1313- ver: LABEL_VERSION,
1414- src,
1515- uri,
1616- ...(cid ? { cid } : {}),
1717- val,
1818- neg: !!neg,
1919- cts,
2020- ...(exp ? { exp } : {}),
2121- ...(sig ? { sig } : {}),
2222- } as never;
99+export function formatLabel(label: ComAtprotoLabelDefs.Label): ComAtprotoLabelDefs.Label {
1010+ return excludeUndefined({ ...label, ver: LABEL_VERSION, neg: !!label.neg });
2311}
24122513export async function signLabel(
+23-2
src/util/types.ts
···99 RouteHandlerMethod,
1010} from "fastify";
11111212+type OptionalOrUndefinedKeys<T> = { [K in keyof T]: undefined extends T[K] ? K : never }[keyof T];
1313+type RequiredDefinedKeys<T> = Exclude<keyof T, OptionalOrUndefinedKeys<T>>;
1214export type StrictPartial<T> =
1313- & { [K in keyof T as undefined extends T[K] ? never : K]: T[K] }
1414- & { [K in keyof T as undefined extends T[K] ? K : never]?: T[K] };
1515+ & { [K in OptionalOrUndefinedKeys<T>]+?: Exclude<T[K], undefined> }
1616+ & { [K in RequiredDefinedKeys<T>]-?: T[K] };
15171818+/**
1919+ * Data required to create a label.
2020+ */
2121+export interface CreateLabelData {
2222+ /** The label value. */
2323+ val: string;
2424+ /** The subject of the label. If labeling an account, this should be a string beginning with `did:`. */
2525+ uri: string;
2626+ /** Optionally, a CID specifying the version of `uri` to label. */
2727+ cid?: string | undefined;
2828+ /** Whether this label is negating a previous instance of this label applied to the same subject. */
2929+ neg?: boolean | undefined;
3030+ /** The DID of the actor who created this label, if different from the labeler. */
3131+ src?: string | undefined;
3232+ /** The creation date of the label. Must be in ISO 8601 format. */
3333+ cts?: string | undefined;
3434+ /** The expiration date of the label, if any. Must be in ISO 8601 format. */
3535+ exp?: string | undefined;
3636+}
1637export type SignedLabel = ComAtprotoLabelDefs.Label & { sig: Uint8Array };
1738export type SavedLabel = SignedLabel & { id: number };
1839