forked from
tokono.ma/diffuse
A music player that connects to your cloud/distributed storage.
1import * as TID from "@atcute/tid";
2
3import { loadURI } from "../loader.js";
4import * as CID from "../cid.js";
5
6/**
7 * @import {Facet} from "~/definitions/types.d.ts"
8 */
9
10/**
11 * @param {{ description?: string; kind: string | undefined; name: string; tags?: string[]; uri: string }} _args
12 * @param {{ fetchHTML: boolean }} options
13 *
14 * @example Creates a facet with correct $type, name, uri, id, and timestamps
15 * ```js
16 * import { facetFromURI } from "~/common/facets/utils.js";
17 *
18 * const facet = await facetFromURI({ name: "My Facet", uri: "facets/test/index.html", kind: undefined, description: undefined }, { fetchHTML: false });
19 *
20 * if (facet.$type !== "sh.diffuse.output.facet") throw new Error("$type should be sh.diffuse.output.facet");
21 * if (facet.name !== "My Facet") throw new Error("name should be preserved");
22 * if (facet.uri !== "facets/test/index.html") throw new Error("uri should be preserved");
23 * if (typeof facet.id !== "string" || facet.id.length === 0) throw new Error("id should be a non-empty string");
24 * if (!facet.createdAt) throw new Error("createdAt should be set");
25 * if (facet.createdAt !== facet.updatedAt) throw new Error("createdAt and updatedAt should match");
26 * if (new Date(facet.createdAt).toISOString() !== facet.createdAt) throw new Error("createdAt should be a valid ISO string");
27 * ```
28 *
29 * @example fetchHTML false leaves html and cid undefined; kind is validated
30 * ```js
31 * import { facetFromURI } from "~/common/facets/utils.js";
32 *
33 * const base = { name: "Test", uri: "test.html", description: undefined };
34 *
35 * const noHtml = await facetFromURI({ ...base, kind: undefined }, { fetchHTML: false });
36 * if (noHtml.html !== undefined) throw new Error("html should be undefined when fetchHTML is false");
37 * if (noHtml.cid !== undefined) throw new Error("cid should be undefined when fetchHTML is false");
38 *
39 * const prelude = await facetFromURI({ ...base, kind: "prelude" }, { fetchHTML: false });
40 * if (prelude.kind !== "prelude") throw new Error("prelude kind should be preserved");
41 *
42 * const interactive = await facetFromURI({ ...base, kind: "interactive" }, { fetchHTML: false });
43 * if (interactive.kind !== "interactive") throw new Error("interactive kind should be preserved");
44 *
45 * const unknown = await facetFromURI({ ...base, kind: "unknown" }, { fetchHTML: false });
46 * if (unknown.kind !== undefined) throw new Error("unrecognised kind should be set to undefined");
47 * ```
48 *
49 * @example Generates unique ids across calls
50 * ```js
51 * import { facetFromURI } from "~/common/facets/utils.js";
52 *
53 * const a = await facetFromURI({ name: "A", uri: "a.html", kind: undefined, description: undefined }, { fetchHTML: false });
54 * const b = await facetFromURI({ name: "B", uri: "b.html", kind: undefined, description: undefined }, { fetchHTML: false });
55 * if (a.id === b.id) throw new Error("ids should be unique across calls");
56 * ```
57 */
58export async function facetFromURI(
59 { description, kind, name, tags, uri },
60 { fetchHTML },
61) {
62 const html = fetchHTML ? await loadURI(uri) : undefined;
63 const cid = html
64 ? await CID.create(0x55, new TextEncoder().encode(html))
65 : undefined;
66 const timestamp = new Date().toISOString();
67
68 /** @type {Facet} */
69 const facet = {
70 $type: "sh.diffuse.output.facet",
71 createdAt: timestamp,
72 id: TID.now(),
73 cid,
74 description,
75 html,
76 name,
77 kind: kind === "interactive" || kind === "prelude" ? kind : undefined,
78 tags: tags?.length ? tags : undefined,
79 updatedAt: timestamp,
80 uri,
81 };
82
83 return facet;
84}