@seed-hypermedia/client 0.0.1 → 0.0.3

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.
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Auto-link child documents to their parent on first publish.
3
+ *
4
+ * When a document is created at a nested path (e.g. /docs/my-article), the
5
+ * parent document at /docs should contain an embed link pointing to the child.
6
+ * This module provides:
7
+ *
8
+ * - Pure decision logic: should a link be added?
9
+ * - Operation builder: what DocumentOperations to emit
10
+ * - Full I/O convenience: fetch parent, check, build ops, sign, publish
11
+ */
12
+ import type { HMDocument, HMSigner, UnpackedHypermediaId } from './hm-types';
13
+ import type { SeedClient } from './client';
14
+ import type { DocumentOperation } from './change';
15
+ /**
16
+ * Check if a document contains a link/embed to a specific child document.
17
+ * Compares URLs ignoring version and latest flags.
18
+ */
19
+ export declare function documentContainsLinkToChild(document: HMDocument, childId: UnpackedHypermediaId): boolean;
20
+ /**
21
+ * Check if a document has a self-referential Query block
22
+ * (a query to itself that would automatically include children).
23
+ */
24
+ export declare function documentHasSelfQuery(document: HMDocument, documentId: UnpackedHypermediaId): boolean;
25
+ /**
26
+ * Determine whether a parent auto-link should be added on first publish.
27
+ * Returns true when the parent document should receive an embed link to the child.
28
+ */
29
+ export declare function shouldAutoLinkParent(isPrivate: boolean, parentDocument: HMDocument | null, editableLocation: UnpackedHypermediaId, parentId: UnpackedHypermediaId): boolean;
30
+ /**
31
+ * Generate the DocumentOperations to append an Embed Card block to a parent document.
32
+ *
33
+ * The returned operations include a ReplaceBlock for the new embed block and a
34
+ * MoveBlocks that lists ALL root-level block IDs (existing + new) to ensure
35
+ * correct ordering. The CBOR MoveBlocks format with no `ref` positions blocks
36
+ * from the start, so we must re-specify the full ordering.
37
+ */
38
+ export declare function createAutoLinkOps(parentDocument: HMDocument, childHmUrl: string, newBlockId: string): DocumentOperation[];
39
+ /** Options for the auto-link convenience function. */
40
+ export type AutoLinkChildToParentOptions = {
41
+ /** Seed API client. */
42
+ client: SeedClient;
43
+ /** Account UID of the document owner. */
44
+ account: string;
45
+ /** Full path of the child document (e.g. "/tests/benefits-of-cli"). */
46
+ path: string;
47
+ /** hm:// URL of the published child document (with version). */
48
+ childHmUrl: string;
49
+ /** Signer for the parent document change. */
50
+ signer: HMSigner;
51
+ };
52
+ /**
53
+ * Auto-link a newly published child document to its parent.
54
+ *
55
+ * Computes the parent path, fetches the parent document, decides whether a link
56
+ * is needed (using `shouldAutoLinkParent`), and if so publishes an Embed Card
57
+ * block to the parent document.
58
+ *
59
+ * Returns true if a link was added, false otherwise. Throws on network errors.
60
+ */
61
+ export declare function autoLinkChildToParent(opts: AutoLinkChildToParentOptions): Promise<boolean>;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Block diffing utilities for document update.
3
+ *
4
+ * Computes minimal document operations by comparing existing document
5
+ * blocks with new blocks parsed from Markdown or JSON input.
6
+ *
7
+ * The primary flow trusts block IDs from the input: if an input block's
8
+ * ID exists in the old document, it's treated as an existing block and
9
+ * diffed for content changes. If the ID doesn't exist, the block is
10
+ * treated as new. Old blocks whose IDs don't appear in the new tree
11
+ * are deleted. This gives per-block granularity — a mix of known and
12
+ * unknown IDs is handled correctly.
13
+ */
14
+ import type { DocumentOperation } from './change';
15
+ import type { HMBlockNode } from './hm-types';
16
+ import type { BlockNode } from './markdown-to-blocks';
17
+ export type APIBlockNode = {
18
+ block: APIBlock;
19
+ children: APIBlockNode[];
20
+ };
21
+ export type APIBlock = {
22
+ id: string;
23
+ type: string;
24
+ text: string;
25
+ link: string;
26
+ annotations: unknown[];
27
+ attributes: Record<string, unknown>;
28
+ revision?: string;
29
+ };
30
+ type BlocksMapItem = {
31
+ parent: string;
32
+ left: string;
33
+ block: APIBlock;
34
+ };
35
+ type BlocksMap = Record<string, BlocksMapItem>;
36
+ export declare function createBlocksMap(nodes: APIBlockNode[], parentId?: string): BlocksMap;
37
+ /**
38
+ * Walk old and new block trees in parallel. When the new block at
39
+ * position N has the same type as the old block at position N, reuse
40
+ * the old block's ID. Otherwise assign the new block's generated ID.
41
+ *
42
+ * Returns a new tree with IDs reassigned (does not mutate inputs).
43
+ */
44
+ export declare function matchBlockIds(oldNodes: APIBlockNode[], newNodes: BlockNode[]): BlockNode[];
45
+ /**
46
+ * Compare the new block tree against the old blocks map and produce
47
+ * the minimal set of DocumentOperations:
48
+ *
49
+ * - ReplaceBlock for new or content-changed blocks
50
+ * - MoveBlocks for positioning (new blocks or position changes)
51
+ * - DeleteBlocks for blocks removed from the document
52
+ */
53
+ export declare function computeReplaceOps(oldMap: BlocksMap, matchedTree: BlockNode[], parentId?: string): DocumentOperation[];
54
+ /**
55
+ * Convert an HMBlockNode tree (from JSON input or API response) into
56
+ * a BlockNode tree compatible with the diff pipeline.
57
+ *
58
+ * HMBlockNode nests childrenType/language inside `attributes`, while
59
+ * SeedBlock/BlockNode has them at the top level.
60
+ */
61
+ export declare function hmBlockNodeToBlockNode(node: HMBlockNode): BlockNode;
62
+ export {};
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Seed block tree → Markdown formatter.
3
+ *
4
+ * Converts HMDocument/HMBlockNode trees to markdown with:
5
+ * - YAML frontmatter (always emitted, all HMMetadata fields)
6
+ * - Block IDs preserved as HTML comments (<!-- id:XXXXXXXX -->)
7
+ * - Inline annotations rendered as markdown formatting
8
+ *
9
+ * This module is purely synchronous and does NOT resolve embeds, mentions,
10
+ * or queries over the network. For resolved output, use the CLI's wrapper
11
+ * which adds a SeedClient-backed resolve layer on top.
12
+ *
13
+ * Round-trip compatible: output can be piped back through `parseMarkdown()`
14
+ * to recreate the same document with block IDs preserved.
15
+ */
16
+ import type { HMDocument, HMMetadata } from './hm-types';
17
+ export type BlocksToMarkdownOptions = {
18
+ /** Format ipfs:// URLs as https gateway URLs. Default: true. */
19
+ ipfsGateway?: boolean;
20
+ };
21
+ /**
22
+ * Emit YAML frontmatter from HMMetadata.
23
+ * Only includes fields that have defined, non-empty values.
24
+ * System fields (authors, version, genesis, account) are NOT emitted.
25
+ */
26
+ export declare function emitFrontmatter(metadata: HMMetadata): string;
27
+ /**
28
+ * Convert an HMDocument to markdown with frontmatter and block IDs.
29
+ *
30
+ * This is a synchronous, pure conversion. Embeds/queries are rendered
31
+ * as placeholder links (not resolved).
32
+ */
33
+ export declare function blocksToMarkdown(doc: HMDocument, options?: BlocksToMarkdownOptions): string;
package/dist/change.d.ts CHANGED
@@ -103,6 +103,11 @@ export declare function createDocumentChange(input: CreateDocumentChangeInput, s
103
103
  bytes: Uint8Array;
104
104
  cid: CID;
105
105
  }>;
106
+ /**
107
+ * Map a proto ResourceVisibility enum value to the CBOR string used in Ref blobs.
108
+ * Returns "Private" for private documents, undefined otherwise (omitted from CBOR = public).
109
+ */
110
+ export declare function visibilityToCbor(protoVisibility?: number): string | undefined;
106
111
  export type SignDocumentChangeInput = {
107
112
  /** Account UID (base58btc-encoded principal) */
108
113
  account: string;
@@ -116,6 +121,8 @@ export type SignDocumentChangeInput = {
116
121
  generation?: number | bigint;
117
122
  /** Optional capability CID string */
118
123
  capability?: string;
124
+ /** Proto ResourceVisibility enum value (0=unspecified, 1=public, 2=private) */
125
+ visibility?: number;
119
126
  };
120
127
  /**
121
128
  * Sign a prepared change and create a version ref, returning blobs ready for publishing.
@@ -21,7 +21,7 @@ var unpackedHmIdSchema = z.object({
21
21
  targetDocUid: z.string().nullable().optional(),
22
22
  targetDocPath: z.array(z.string()).nullable().optional()
23
23
  });
24
- var HMBlockChildrenTypeSchema = z.union([z.literal("Group"), z.literal("Ordered"), z.literal("Unordered"), z.literal("Blockquote")]).nullable();
24
+ var HMBlockChildrenTypeSchema = z.union([z.literal("Group"), z.literal("Ordered"), z.literal("Unordered"), z.literal("Blockquote"), z.literal("Grid")]).nullable();
25
25
  var HMEmbedViewSchema = z.union([z.literal("Content"), z.literal("Card"), z.literal("Comments")]);
26
26
  var HMQueryStyleSchema = z.union([z.literal("Card"), z.literal("List")]);
27
27
  var baseAnnotationProperties = {
@@ -93,7 +93,8 @@ var textBlockProperties = {
93
93
  annotations: HMAnnotationsSchema
94
94
  };
95
95
  var parentBlockAttributes = {
96
- childrenType: HMBlockChildrenTypeSchema.optional()
96
+ childrenType: HMBlockChildrenTypeSchema.optional(),
97
+ columnCount: z.number().optional()
97
98
  };
98
99
  var HMBlockParagraphSchema = z.object({
99
100
  type: z.literal("Paragraph"),
@@ -221,6 +222,7 @@ var HMDocumentMetadataSchema = z.object({
221
222
  siteUrl: z.string().optional(),
222
223
  layout: z.union([z.literal("Seed/Experimental/Newspaper"), z.literal("")]).optional(),
223
224
  displayPublishTime: z.string().optional(),
225
+ displayAuthor: z.string().optional(),
224
226
  seedExperimentalLogo: z.string().optional(),
225
227
  seedExperimentalHomeOrder: z.union([z.literal("UpdatedFirst"), z.literal("CreatedFirst")]).optional(),
226
228
  showOutline: z.boolean().optional(),
@@ -339,6 +341,10 @@ var HMAccountNotFoundSchema = z.object({
339
341
  uid: z.string()
340
342
  });
341
343
  var HMAccountResultSchema = z.discriminatedUnion("type", [HMAccountPayloadSchema, HMAccountNotFoundSchema]);
344
+ var HMSiteMemberSchema = z.object({
345
+ account: unpackedHmIdSchema,
346
+ role: z.enum(["owner", "writer", "member"])
347
+ });
342
348
  var HMAccountsMetadataSchema = z.record(
343
349
  z.string(),
344
350
  // account uid
@@ -356,7 +362,8 @@ var HMQuerySortSchema = z.object({
356
362
  z.literal("Title"),
357
363
  z.literal("CreateTime"),
358
364
  z.literal("UpdateTime"),
359
- z.literal("DisplayTime")
365
+ z.literal("DisplayTime"),
366
+ z.literal("ActivityTime")
360
367
  ])
361
368
  });
362
369
  var HMQuerySchema = z.object({
@@ -475,13 +482,19 @@ var HMResolvedResourceSchema = z.discriminatedUnion("type", [
475
482
  HMResourceCommentSchema,
476
483
  HMResourceTombstoneSchema
477
484
  ]);
485
+ var HMContactSubscribeSchema = z.object({
486
+ site: z.boolean().optional(),
487
+ profile: z.boolean().optional()
488
+ });
478
489
  var HMContactRecordSchema = z.object({
479
490
  id: z.string(),
480
491
  subject: z.string(),
481
492
  name: z.string(),
482
493
  account: z.string(),
494
+ signer: z.string(),
483
495
  createTime: HMTimestampSchema.optional(),
484
- updateTime: HMTimestampSchema.optional()
496
+ updateTime: HMTimestampSchema.optional(),
497
+ subscribe: HMContactSubscribeSchema.optional()
485
498
  });
486
499
  var HMAccountContactsRequestSchema = z.object({
487
500
  key: z.literal("AccountContacts"),
@@ -489,6 +502,122 @@ var HMAccountContactsRequestSchema = z.object({
489
502
  // account UID
490
503
  output: z.array(HMContactRecordSchema)
491
504
  });
505
+ var HMCommentDraftSchema = z.object({
506
+ blocks: z.array(HMBlockNodeSchema),
507
+ targetDocId: z.string().optional(),
508
+ replyCommentId: z.string().optional(),
509
+ quotingBlockId: z.string().optional(),
510
+ context: z.enum(["accessory", "feed", "document-content"]).optional(),
511
+ lastUpdateTime: z.number().optional()
512
+ });
513
+ var HMListedCommentDraftSchema = z.object({
514
+ id: z.string(),
515
+ targetDocId: z.string(),
516
+ replyCommentId: z.string().optional(),
517
+ quotingBlockId: z.string().optional(),
518
+ context: z.enum(["accessory", "feed", "document-content"]).optional(),
519
+ lastUpdateTime: z.number()
520
+ });
521
+ var HMHostConfigSchema = z.object({
522
+ peerId: z.string(),
523
+ registeredAccountUid: z.string(),
524
+ protocolId: z.string(),
525
+ addrs: z.array(z.string()),
526
+ hostname: z.string(),
527
+ isGateway: z.boolean()
528
+ });
529
+ var HMContactSchema = z.object({
530
+ metadata: HMDocumentMetadataSchema,
531
+ contacts: z.array(HMContactRecordSchema).optional(),
532
+ subjectContacts: z.array(HMContactRecordSchema).optional()
533
+ });
534
+ var HMContactItemSchema = z.object({
535
+ id: unpackedHmIdSchema,
536
+ metadata: HMDocumentMetadataSchema.optional()
537
+ });
538
+ var HMCapabilitySchema = z.object({
539
+ id: z.string(),
540
+ accountUid: z.string(),
541
+ role: HMRoleSchema,
542
+ capabilityId: z.string().optional(),
543
+ grantId: unpackedHmIdSchema,
544
+ label: z.string().optional(),
545
+ createTime: HMTimestampSchema
546
+ });
547
+ var siteDiscoverRequestSchema = z.object({
548
+ uid: z.string(),
549
+ path: z.array(z.string()),
550
+ version: z.string().optional(),
551
+ media: z.boolean().optional()
552
+ });
553
+ var HMPeerConnectionRequestSchema = z.object({
554
+ a: z.array(z.string()),
555
+ // addrs
556
+ d: z.string()
557
+ // peer/device ID
558
+ });
559
+ var ParsedFragmentSchema = BlockRangeSchema.extend({
560
+ blockId: z.string()
561
+ });
562
+ var HMCitationCommentSourceSchema = z.object({
563
+ type: z.literal("c"),
564
+ id: unpackedHmIdSchema,
565
+ author: z.string().optional(),
566
+ time: HMTimestampSchema.optional()
567
+ });
568
+ var HMCitationDocumentSourceSchema = z.object({
569
+ type: z.literal("d"),
570
+ id: unpackedHmIdSchema,
571
+ author: z.string().optional(),
572
+ time: HMTimestampSchema.optional()
573
+ });
574
+ var HMCitationSchema = z.object({
575
+ source: z.discriminatedUnion("type", [HMCitationCommentSourceSchema, HMCitationDocumentSourceSchema]),
576
+ isExactVersion: z.boolean(),
577
+ targetFragment: ParsedFragmentSchema.nullable(),
578
+ targetId: unpackedHmIdSchema
579
+ });
580
+ var DeviceLinkSessionSchema = z.object({
581
+ accountId: z.string(),
582
+ secretToken: z.string(),
583
+ addrInfo: z.object({
584
+ peerId: z.string(),
585
+ addrs: z.array(z.string())
586
+ })
587
+ });
588
+ var HMNavigationItemSchema = z.object({
589
+ type: z.literal("Link"),
590
+ id: z.string(),
591
+ text: z.string(),
592
+ link: z.string()
593
+ });
594
+ var HMDraftContentSchema = z.object({
595
+ content: z.array(z.any()),
596
+ // EditorBlock validation is handled elsewhere
597
+ deps: z.array(z.string().min(1)).default([]),
598
+ navigation: z.array(HMNavigationItemSchema).optional()
599
+ });
600
+ var HMDraftMetaBaseSchema = z.object({
601
+ id: z.string(),
602
+ locationUid: z.string().optional(),
603
+ locationPath: z.array(z.string()).optional(),
604
+ editUid: z.string().optional(),
605
+ editPath: z.array(z.string()).optional(),
606
+ metadata: HMDocumentMetadataSchema,
607
+ visibility: HMResourceVisibilitySchema.optional().default("PUBLIC")
608
+ });
609
+ var draftLocationRefinement = (data) => data.editUid || data.locationUid;
610
+ var HMDraftMetaSchema = HMDraftMetaBaseSchema.refine(draftLocationRefinement, {
611
+ message: "Either editUid or locationUid must be provided"
612
+ });
613
+ var HMListedDraftSchema = HMDraftMetaBaseSchema.extend({
614
+ lastUpdateTime: z.number()
615
+ }).refine(draftLocationRefinement, {
616
+ message: "Either editUid or locationUid must be provided"
617
+ });
618
+ var HMListedDraftReadSchema = HMDraftMetaBaseSchema.extend({
619
+ lastUpdateTime: z.number()
620
+ });
492
621
  var HMSubjectContactsRequestSchema = z.object({
493
622
  key: z.literal("SubjectContacts"),
494
623
  input: z.string(),
@@ -521,7 +650,8 @@ var HMSearchInputSchema = z.object({
521
650
  includeBody: z.boolean().optional(),
522
651
  contextSize: z.number().optional(),
523
652
  perspectiveAccountUid: z.string().optional(),
524
- searchType: z.number().optional()
653
+ searchType: z.number().optional(),
654
+ pageSize: z.number().optional()
525
655
  });
526
656
  var HMSearchResultItemSchema = z.object({
527
657
  id: unpackedHmIdSchema,
@@ -529,7 +659,7 @@ var HMSearchResultItemSchema = z.object({
529
659
  title: z.string(),
530
660
  icon: z.string(),
531
661
  parentNames: z.array(z.string()),
532
- versionTime: z.any().optional(),
662
+ versionTime: z.string().optional(),
533
663
  searchQuery: z.string(),
534
664
  type: z.enum(["document", "contact"])
535
665
  });
@@ -706,6 +836,7 @@ var HMInteractionSummaryOutputSchema = z.object({
706
836
  comments: z.number(),
707
837
  changes: z.number(),
708
838
  children: z.number(),
839
+ authorUids: z.array(z.string()).default([]),
709
840
  blocks: z.record(
710
841
  z.string(),
711
842
  z.object({
@@ -872,7 +1003,7 @@ function getHMQueryString({
872
1003
  if (version) {
873
1004
  query.v = version;
874
1005
  }
875
- if (latest) {
1006
+ if (latest && version) {
876
1007
  query.l = null;
877
1008
  }
878
1009
  if (panel) {
@@ -905,6 +1036,100 @@ function entityQueryPathToHmIdPath(path) {
905
1036
  if (path === "/") return [];
906
1037
  return path.split("/").filter(Boolean);
907
1038
  }
1039
+ function parseCustomURL(url) {
1040
+ if (!url) return null;
1041
+ const [scheme, rest] = url.split("://");
1042
+ if (!rest) return null;
1043
+ const [pathAndQuery, fragment = null] = rest.split("#");
1044
+ const [path, queryString] = (pathAndQuery == null ? void 0 : pathAndQuery.split("?")) || [];
1045
+ const query = new URLSearchParams(queryString);
1046
+ const queryObject = Object.fromEntries(query.entries());
1047
+ return {
1048
+ scheme: scheme || null,
1049
+ path: (path == null ? void 0 : path.split("/")) || [],
1050
+ query: queryObject,
1051
+ fragment
1052
+ };
1053
+ }
1054
+ function parseFragment(input) {
1055
+ if (!input) return null;
1056
+ const regex = /^([^\+\[]+)((\+)|\[(\d+)\:(\d+)\])?$/;
1057
+ const match = input.match(regex);
1058
+ if (match) {
1059
+ const blockId = match[1] || "";
1060
+ const expanded = match[3];
1061
+ const rangeStart = match[4];
1062
+ const rangeEnd = match[5];
1063
+ if (expanded === "+") {
1064
+ return { blockId, expanded: true };
1065
+ } else if (typeof rangeStart !== "undefined" && typeof rangeEnd !== "undefined") {
1066
+ return { blockId, start: parseInt(rangeStart), end: parseInt(rangeEnd) };
1067
+ } else {
1068
+ return { blockId, expanded: false };
1069
+ }
1070
+ } else {
1071
+ return { blockId: input, expanded: false };
1072
+ }
1073
+ }
1074
+ var STATIC_HM_PATHS = /* @__PURE__ */ new Set(["download", "connect", "register", "device-link", "profile", "contact"]);
1075
+ function unpackHmId(hypermediaId) {
1076
+ if (!hypermediaId) return null;
1077
+ const parsed = parseCustomURL(hypermediaId);
1078
+ if (!parsed) return null;
1079
+ let uid;
1080
+ let path;
1081
+ let hostname = null;
1082
+ if (parsed.scheme === "https" || parsed.scheme === "http") {
1083
+ if (parsed.path[1] !== "hm") return null;
1084
+ hostname = parsed.path[0];
1085
+ uid = parsed.path[2];
1086
+ if (uid && STATIC_HM_PATHS.has(uid)) return null;
1087
+ path = parsed.path.slice(3);
1088
+ } else if (parsed.scheme === HYPERMEDIA_SCHEME || parsed.scheme === "hm") {
1089
+ uid = parsed.path[0];
1090
+ path = parsed.path.slice(1);
1091
+ } else {
1092
+ return null;
1093
+ }
1094
+ const version = parsed.query.v || null;
1095
+ const fragment = parseFragment(parsed.fragment);
1096
+ const hasBlockRef = !!(fragment == null ? void 0 : fragment.blockId);
1097
+ const latest = hasBlockRef ? false : parsed.query.l === null || parsed.query.l === "" || !version;
1098
+ let blockRange = null;
1099
+ if (fragment) {
1100
+ if ("start" in fragment) {
1101
+ blockRange = { start: fragment.start, end: fragment.end };
1102
+ } else if ("expanded" in fragment) {
1103
+ blockRange = { expanded: fragment.expanded };
1104
+ }
1105
+ }
1106
+ return {
1107
+ id: packBaseId(uid || "", path),
1108
+ uid: uid || "",
1109
+ path: path || null,
1110
+ version,
1111
+ blockRef: fragment ? fragment.blockId : null,
1112
+ blockRange,
1113
+ hostname: hostname || null,
1114
+ latest,
1115
+ scheme: parsed.scheme
1116
+ };
1117
+ }
1118
+ function codePointLength(entry) {
1119
+ let count = 0;
1120
+ if (!entry) return 0;
1121
+ for (let i = 0; i < entry.length; i++) {
1122
+ count++;
1123
+ if (isSurrogate(entry, i)) {
1124
+ i++;
1125
+ }
1126
+ }
1127
+ return count;
1128
+ }
1129
+ function isSurrogate(s, i) {
1130
+ const code = s.charCodeAt(i);
1131
+ return 55296 <= code && code <= 56319;
1132
+ }
908
1133
 
909
1134
  export {
910
1135
  BlockRangeSchema,
@@ -954,6 +1179,7 @@ export {
954
1179
  HMAccountPayloadSchema,
955
1180
  HMAccountNotFoundSchema,
956
1181
  HMAccountResultSchema,
1182
+ HMSiteMemberSchema,
957
1183
  HMAccountsMetadataSchema,
958
1184
  HMQueryInclusionSchema,
959
1185
  HMQuerySortSchema,
@@ -975,8 +1201,25 @@ export {
975
1201
  HMResourceErrorSchema,
976
1202
  HMResourceSchema,
977
1203
  HMResolvedResourceSchema,
1204
+ HMContactSubscribeSchema,
978
1205
  HMContactRecordSchema,
979
1206
  HMAccountContactsRequestSchema,
1207
+ HMCommentDraftSchema,
1208
+ HMListedCommentDraftSchema,
1209
+ HMHostConfigSchema,
1210
+ HMContactSchema,
1211
+ HMContactItemSchema,
1212
+ HMCapabilitySchema,
1213
+ siteDiscoverRequestSchema,
1214
+ HMPeerConnectionRequestSchema,
1215
+ ParsedFragmentSchema,
1216
+ HMCitationSchema,
1217
+ DeviceLinkSessionSchema,
1218
+ HMNavigationItemSchema,
1219
+ HMDraftContentSchema,
1220
+ HMDraftMetaSchema,
1221
+ HMListedDraftSchema,
1222
+ HMListedDraftReadSchema,
980
1223
  HMSubjectContactsRequestSchema,
981
1224
  HMResourceRequestSchema,
982
1225
  HMResourceMetadataRequestSchema,
@@ -1040,5 +1283,10 @@ export {
1040
1283
  getHMQueryString,
1041
1284
  serializeBlockRange,
1042
1285
  hmIdPathToEntityQueryPath,
1043
- entityQueryPathToHmIdPath
1286
+ entityQueryPathToHmIdPath,
1287
+ parseCustomURL,
1288
+ parseFragment,
1289
+ unpackHmId,
1290
+ codePointLength,
1291
+ isSurrogate
1044
1292
  };
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import type { HMPrepareDocumentChangeInput, HMRequest, HMSigner } from './hm-types';
2
+ import { type HMPrepareDocumentChangeInput, type HMRequest, type HMSigner } from './hm-types';
3
3
  /**
4
4
  * Deserializes a URL query string using a Zod schema.
5
5
  * If the query contains only a __value key, returns the primitive value directly.
package/dist/comment.d.ts CHANGED
@@ -40,4 +40,9 @@ export type DeleteCommentInput = {
40
40
  visibility?: 'Private' | '';
41
41
  };
42
42
  export declare function deleteComment(input: DeleteCommentInput, signer: HMSigner): Promise<HMPublishBlobsInput>;
43
+ /**
44
+ * Compute the record ID ("authority/tsid") from raw CBOR-encoded comment blob bytes.
45
+ * The TSID is a 10-byte base58btc value: 6 bytes ms timestamp + 4 bytes SHA256 prefix.
46
+ */
47
+ export declare function commentRecordIdFromBlob(blobData: Uint8Array): Promise<string>;
43
48
  export {};
package/dist/contact.d.ts CHANGED
@@ -1,21 +1,35 @@
1
1
  import type { HMPublishBlobsInput, HMSigner } from './hm-types';
2
+ export type ContactSubscribe = {
3
+ site?: boolean;
4
+ profile?: boolean;
5
+ };
2
6
  export type CreateContactInput = {
3
7
  /** The subject account UID (base58btc-encoded principal) */
4
8
  subjectUid: string;
9
+ /** The account UID (base58btc-encoded principal) */
10
+ accountUid?: string;
5
11
  /** The display name for the contact */
6
- name: string;
12
+ name?: string;
13
+ /** The subscribe information for the contact */
14
+ subscribe?: ContactSubscribe;
7
15
  };
8
16
  export type UpdateContactInput = {
9
17
  /** The contact record ID in format "authority/tsid" */
10
18
  contactId: string;
11
19
  /** The subject account UID */
12
20
  subjectUid: string;
21
+ /** The account UID (base58btc-encoded principal) */
22
+ accountUid?: string;
13
23
  /** The updated display name */
14
- name: string;
24
+ name?: string;
25
+ /** The subscribe information for the contact */
26
+ subscribe?: ContactSubscribe;
15
27
  };
16
28
  export type DeleteContactInput = {
17
29
  /** The contact record ID in format "authority/tsid" */
18
30
  contactId: string;
31
+ /** The account UID (base58btc-encoded principal) */
32
+ accountUid?: string;
19
33
  };
20
34
  export type CreateContactResult = HMPublishBlobsInput & {
21
35
  /** The record ID in format "authority/tsid" */
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Resolves document state (genesis, heads, depth) from the ListChanges API.
3
+ *
4
+ * Depth is needed to construct valid Change blobs but is not directly
5
+ * exposed by the read API. We compute it by walking the change DAG:
6
+ * genesis has depth 0, each subsequent change has depth = max(dep depths) + 1.
7
+ */
8
+ import type { SeedClient } from './client';
9
+ /** The resolved state of a document's change DAG. */
10
+ export type DocumentState = {
11
+ /** CID of the genesis change blob. */
12
+ genesis: string;
13
+ /** CIDs of the current head changes (not depended on by any other change). */
14
+ heads: string[];
15
+ /** Maximum depth among head changes. */
16
+ headDepth: number;
17
+ /** Dot-separated head CIDs (version string). */
18
+ version: string;
19
+ };
20
+ /**
21
+ * Resolves the current document state including head depth.
22
+ */
23
+ export declare function resolveDocumentState(client: SeedClient, targetId: string): Promise<DocumentState>;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Shared IPFS file chunking utilities.
3
+ *
4
+ * Chunks binary data into UnixFS IPFS blocks using a MemoryBlockstore.
5
+ * Used by both the CLI (file:// link resolution) and the web app
6
+ * (comment attachment uploads) so the logic is not duplicated.
7
+ */
8
+ import type { HMBlockNode } from './hm-types';
9
+ export type CollectedBlob = {
10
+ cid: string;
11
+ data: Uint8Array;
12
+ };
13
+ /**
14
+ * Chunk a single piece of binary data into UnixFS IPFS blocks.
15
+ *
16
+ * Returns the root CID and all constituent IPFS blobs (DAG blocks)
17
+ * that should be published alongside the document/comment.
18
+ */
19
+ export declare function fileToIpfsBlobs(data: Uint8Array): Promise<{
20
+ cid: string;
21
+ blobs: CollectedBlob[];
22
+ }>;
23
+ /**
24
+ * Chunk multiple binary attachments into IPFS blocks using a shared blockstore.
25
+ *
26
+ * Returns the root CIDs (one per input) and all collected IPFS blobs.
27
+ * This is the multi-file equivalent of `fileToIpfsBlobs`, suitable for
28
+ * comment editors that upload several images at once.
29
+ */
30
+ export declare function filesToIpfsBlobs(binaries: Uint8Array[]): Promise<{
31
+ resultCIDs: string[];
32
+ blobs: CollectedBlob[];
33
+ }>;
34
+ /**
35
+ * Resolve all file:// links in a block tree.
36
+ *
37
+ * Walks the tree, finds blocks whose `link` field starts with `file://`,
38
+ * reads the data via the provided `readFile` callback, chunks with UnixFS,
39
+ * and replaces the link with `ipfs://ROOT_CID`.
40
+ *
41
+ * The `readFile` callback allows this to work in both Node.js (fs.readFileSync)
42
+ * and browser environments without importing `fs` directly.
43
+ *
44
+ * @returns The modified block tree and all collected IPFS blobs.
45
+ */
46
+ export declare function resolveFileLinksInBlocks(nodes: HMBlockNode[], readFile: (path: string) => Uint8Array | Promise<Uint8Array>): Promise<{
47
+ nodes: HMBlockNode[];
48
+ blobs: CollectedBlob[];
49
+ }>;
50
+ /**
51
+ * Check whether any block in the tree has a file:// link.
52
+ */
53
+ export declare function hasFileLinks(nodes: HMBlockNode[]): boolean;