@seed-hypermedia/client 0.0.1 → 0.0.2

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.
@@ -221,6 +221,7 @@ var HMDocumentMetadataSchema = z.object({
221
221
  siteUrl: z.string().optional(),
222
222
  layout: z.union([z.literal("Seed/Experimental/Newspaper"), z.literal("")]).optional(),
223
223
  displayPublishTime: z.string().optional(),
224
+ displayAuthor: z.string().optional(),
224
225
  seedExperimentalLogo: z.string().optional(),
225
226
  seedExperimentalHomeOrder: z.union([z.literal("UpdatedFirst"), z.literal("CreatedFirst")]).optional(),
226
227
  showOutline: z.boolean().optional(),
@@ -339,6 +340,10 @@ var HMAccountNotFoundSchema = z.object({
339
340
  uid: z.string()
340
341
  });
341
342
  var HMAccountResultSchema = z.discriminatedUnion("type", [HMAccountPayloadSchema, HMAccountNotFoundSchema]);
343
+ var HMSiteMemberSchema = z.object({
344
+ account: unpackedHmIdSchema,
345
+ role: z.enum(["owner", "writer", "member"])
346
+ });
342
347
  var HMAccountsMetadataSchema = z.record(
343
348
  z.string(),
344
349
  // account uid
@@ -356,7 +361,8 @@ var HMQuerySortSchema = z.object({
356
361
  z.literal("Title"),
357
362
  z.literal("CreateTime"),
358
363
  z.literal("UpdateTime"),
359
- z.literal("DisplayTime")
364
+ z.literal("DisplayTime"),
365
+ z.literal("ActivityTime")
360
366
  ])
361
367
  });
362
368
  var HMQuerySchema = z.object({
@@ -475,13 +481,19 @@ var HMResolvedResourceSchema = z.discriminatedUnion("type", [
475
481
  HMResourceCommentSchema,
476
482
  HMResourceTombstoneSchema
477
483
  ]);
484
+ var HMContactSubscribeSchema = z.object({
485
+ site: z.boolean().optional(),
486
+ profile: z.boolean().optional()
487
+ });
478
488
  var HMContactRecordSchema = z.object({
479
489
  id: z.string(),
480
490
  subject: z.string(),
481
491
  name: z.string(),
482
492
  account: z.string(),
493
+ signer: z.string(),
483
494
  createTime: HMTimestampSchema.optional(),
484
- updateTime: HMTimestampSchema.optional()
495
+ updateTime: HMTimestampSchema.optional(),
496
+ subscribe: HMContactSubscribeSchema.optional()
485
497
  });
486
498
  var HMAccountContactsRequestSchema = z.object({
487
499
  key: z.literal("AccountContacts"),
@@ -489,6 +501,122 @@ var HMAccountContactsRequestSchema = z.object({
489
501
  // account UID
490
502
  output: z.array(HMContactRecordSchema)
491
503
  });
504
+ var HMCommentDraftSchema = z.object({
505
+ blocks: z.array(HMBlockNodeSchema),
506
+ targetDocId: z.string().optional(),
507
+ replyCommentId: z.string().optional(),
508
+ quotingBlockId: z.string().optional(),
509
+ context: z.enum(["accessory", "feed", "document-content"]).optional(),
510
+ lastUpdateTime: z.number().optional()
511
+ });
512
+ var HMListedCommentDraftSchema = z.object({
513
+ id: z.string(),
514
+ targetDocId: z.string(),
515
+ replyCommentId: z.string().optional(),
516
+ quotingBlockId: z.string().optional(),
517
+ context: z.enum(["accessory", "feed", "document-content"]).optional(),
518
+ lastUpdateTime: z.number()
519
+ });
520
+ var HMHostConfigSchema = z.object({
521
+ peerId: z.string(),
522
+ registeredAccountUid: z.string(),
523
+ protocolId: z.string(),
524
+ addrs: z.array(z.string()),
525
+ hostname: z.string(),
526
+ isGateway: z.boolean()
527
+ });
528
+ var HMContactSchema = z.object({
529
+ metadata: HMDocumentMetadataSchema,
530
+ contacts: z.array(HMContactRecordSchema).optional(),
531
+ subjectContacts: z.array(HMContactRecordSchema).optional()
532
+ });
533
+ var HMContactItemSchema = z.object({
534
+ id: unpackedHmIdSchema,
535
+ metadata: HMDocumentMetadataSchema.optional()
536
+ });
537
+ var HMCapabilitySchema = z.object({
538
+ id: z.string(),
539
+ accountUid: z.string(),
540
+ role: HMRoleSchema,
541
+ capabilityId: z.string().optional(),
542
+ grantId: unpackedHmIdSchema,
543
+ label: z.string().optional(),
544
+ createTime: HMTimestampSchema
545
+ });
546
+ var siteDiscoverRequestSchema = z.object({
547
+ uid: z.string(),
548
+ path: z.array(z.string()),
549
+ version: z.string().optional(),
550
+ media: z.boolean().optional()
551
+ });
552
+ var HMPeerConnectionRequestSchema = z.object({
553
+ a: z.array(z.string()),
554
+ // addrs
555
+ d: z.string()
556
+ // peer/device ID
557
+ });
558
+ var ParsedFragmentSchema = BlockRangeSchema.extend({
559
+ blockId: z.string()
560
+ });
561
+ var HMCitationCommentSourceSchema = z.object({
562
+ type: z.literal("c"),
563
+ id: unpackedHmIdSchema,
564
+ author: z.string().optional(),
565
+ time: HMTimestampSchema.optional()
566
+ });
567
+ var HMCitationDocumentSourceSchema = z.object({
568
+ type: z.literal("d"),
569
+ id: unpackedHmIdSchema,
570
+ author: z.string().optional(),
571
+ time: HMTimestampSchema.optional()
572
+ });
573
+ var HMCitationSchema = z.object({
574
+ source: z.discriminatedUnion("type", [HMCitationCommentSourceSchema, HMCitationDocumentSourceSchema]),
575
+ isExactVersion: z.boolean(),
576
+ targetFragment: ParsedFragmentSchema.nullable(),
577
+ targetId: unpackedHmIdSchema
578
+ });
579
+ var DeviceLinkSessionSchema = z.object({
580
+ accountId: z.string(),
581
+ secretToken: z.string(),
582
+ addrInfo: z.object({
583
+ peerId: z.string(),
584
+ addrs: z.array(z.string())
585
+ })
586
+ });
587
+ var HMNavigationItemSchema = z.object({
588
+ type: z.literal("Link"),
589
+ id: z.string(),
590
+ text: z.string(),
591
+ link: z.string()
592
+ });
593
+ var HMDraftContentSchema = z.object({
594
+ content: z.array(z.any()),
595
+ // EditorBlock validation is handled elsewhere
596
+ deps: z.array(z.string().min(1)).default([]),
597
+ navigation: z.array(HMNavigationItemSchema).optional()
598
+ });
599
+ var HMDraftMetaBaseSchema = z.object({
600
+ id: z.string(),
601
+ locationUid: z.string().optional(),
602
+ locationPath: z.array(z.string()).optional(),
603
+ editUid: z.string().optional(),
604
+ editPath: z.array(z.string()).optional(),
605
+ metadata: HMDocumentMetadataSchema,
606
+ visibility: HMResourceVisibilitySchema.optional().default("PUBLIC")
607
+ });
608
+ var draftLocationRefinement = (data) => data.editUid || data.locationUid;
609
+ var HMDraftMetaSchema = HMDraftMetaBaseSchema.refine(draftLocationRefinement, {
610
+ message: "Either editUid or locationUid must be provided"
611
+ });
612
+ var HMListedDraftSchema = HMDraftMetaBaseSchema.extend({
613
+ lastUpdateTime: z.number()
614
+ }).refine(draftLocationRefinement, {
615
+ message: "Either editUid or locationUid must be provided"
616
+ });
617
+ var HMListedDraftReadSchema = HMDraftMetaBaseSchema.extend({
618
+ lastUpdateTime: z.number()
619
+ });
492
620
  var HMSubjectContactsRequestSchema = z.object({
493
621
  key: z.literal("SubjectContacts"),
494
622
  input: z.string(),
@@ -521,7 +649,8 @@ var HMSearchInputSchema = z.object({
521
649
  includeBody: z.boolean().optional(),
522
650
  contextSize: z.number().optional(),
523
651
  perspectiveAccountUid: z.string().optional(),
524
- searchType: z.number().optional()
652
+ searchType: z.number().optional(),
653
+ pageSize: z.number().optional()
525
654
  });
526
655
  var HMSearchResultItemSchema = z.object({
527
656
  id: unpackedHmIdSchema,
@@ -529,7 +658,7 @@ var HMSearchResultItemSchema = z.object({
529
658
  title: z.string(),
530
659
  icon: z.string(),
531
660
  parentNames: z.array(z.string()),
532
- versionTime: z.any().optional(),
661
+ versionTime: z.string().optional(),
533
662
  searchQuery: z.string(),
534
663
  type: z.enum(["document", "contact"])
535
664
  });
@@ -706,6 +835,7 @@ var HMInteractionSummaryOutputSchema = z.object({
706
835
  comments: z.number(),
707
836
  changes: z.number(),
708
837
  children: z.number(),
838
+ authorUids: z.array(z.string()).default([]),
709
839
  blocks: z.record(
710
840
  z.string(),
711
841
  z.object({
@@ -872,7 +1002,7 @@ function getHMQueryString({
872
1002
  if (version) {
873
1003
  query.v = version;
874
1004
  }
875
- if (latest) {
1005
+ if (latest && version) {
876
1006
  query.l = null;
877
1007
  }
878
1008
  if (panel) {
@@ -905,6 +1035,100 @@ function entityQueryPathToHmIdPath(path) {
905
1035
  if (path === "/") return [];
906
1036
  return path.split("/").filter(Boolean);
907
1037
  }
1038
+ function parseCustomURL(url) {
1039
+ if (!url) return null;
1040
+ const [scheme, rest] = url.split("://");
1041
+ if (!rest) return null;
1042
+ const [pathAndQuery, fragment = null] = rest.split("#");
1043
+ const [path, queryString] = (pathAndQuery == null ? void 0 : pathAndQuery.split("?")) || [];
1044
+ const query = new URLSearchParams(queryString);
1045
+ const queryObject = Object.fromEntries(query.entries());
1046
+ return {
1047
+ scheme: scheme || null,
1048
+ path: (path == null ? void 0 : path.split("/")) || [],
1049
+ query: queryObject,
1050
+ fragment
1051
+ };
1052
+ }
1053
+ function parseFragment(input) {
1054
+ if (!input) return null;
1055
+ const regex = /^([^\+\[]+)((\+)|\[(\d+)\:(\d+)\])?$/;
1056
+ const match = input.match(regex);
1057
+ if (match) {
1058
+ const blockId = match[1] || "";
1059
+ const expanded = match[3];
1060
+ const rangeStart = match[4];
1061
+ const rangeEnd = match[5];
1062
+ if (expanded === "+") {
1063
+ return { blockId, expanded: true };
1064
+ } else if (typeof rangeStart !== "undefined" && typeof rangeEnd !== "undefined") {
1065
+ return { blockId, start: parseInt(rangeStart), end: parseInt(rangeEnd) };
1066
+ } else {
1067
+ return { blockId, expanded: false };
1068
+ }
1069
+ } else {
1070
+ return { blockId: input, expanded: false };
1071
+ }
1072
+ }
1073
+ var STATIC_HM_PATHS = /* @__PURE__ */ new Set(["download", "connect", "register", "device-link", "profile", "contact"]);
1074
+ function unpackHmId(hypermediaId) {
1075
+ if (!hypermediaId) return null;
1076
+ const parsed = parseCustomURL(hypermediaId);
1077
+ if (!parsed) return null;
1078
+ let uid;
1079
+ let path;
1080
+ let hostname = null;
1081
+ if (parsed.scheme === "https" || parsed.scheme === "http") {
1082
+ if (parsed.path[1] !== "hm") return null;
1083
+ hostname = parsed.path[0];
1084
+ uid = parsed.path[2];
1085
+ if (uid && STATIC_HM_PATHS.has(uid)) return null;
1086
+ path = parsed.path.slice(3);
1087
+ } else if (parsed.scheme === HYPERMEDIA_SCHEME || parsed.scheme === "hm") {
1088
+ uid = parsed.path[0];
1089
+ path = parsed.path.slice(1);
1090
+ } else {
1091
+ return null;
1092
+ }
1093
+ const version = parsed.query.v || null;
1094
+ const fragment = parseFragment(parsed.fragment);
1095
+ const hasBlockRef = !!(fragment == null ? void 0 : fragment.blockId);
1096
+ const latest = hasBlockRef ? false : parsed.query.l === null || parsed.query.l === "" || !version;
1097
+ let blockRange = null;
1098
+ if (fragment) {
1099
+ if ("start" in fragment) {
1100
+ blockRange = { start: fragment.start, end: fragment.end };
1101
+ } else if ("expanded" in fragment) {
1102
+ blockRange = { expanded: fragment.expanded };
1103
+ }
1104
+ }
1105
+ return {
1106
+ id: packBaseId(uid || "", path),
1107
+ uid: uid || "",
1108
+ path: path || null,
1109
+ version,
1110
+ blockRef: fragment ? fragment.blockId : null,
1111
+ blockRange,
1112
+ hostname: hostname || null,
1113
+ latest,
1114
+ scheme: parsed.scheme
1115
+ };
1116
+ }
1117
+ function codePointLength(entry) {
1118
+ let count = 0;
1119
+ if (!entry) return 0;
1120
+ for (let i = 0; i < entry.length; i++) {
1121
+ count++;
1122
+ if (isSurrogate(entry, i)) {
1123
+ i++;
1124
+ }
1125
+ }
1126
+ return count;
1127
+ }
1128
+ function isSurrogate(s, i) {
1129
+ const code = s.charCodeAt(i);
1130
+ return 55296 <= code && code <= 56319;
1131
+ }
908
1132
 
909
1133
  export {
910
1134
  BlockRangeSchema,
@@ -954,6 +1178,7 @@ export {
954
1178
  HMAccountPayloadSchema,
955
1179
  HMAccountNotFoundSchema,
956
1180
  HMAccountResultSchema,
1181
+ HMSiteMemberSchema,
957
1182
  HMAccountsMetadataSchema,
958
1183
  HMQueryInclusionSchema,
959
1184
  HMQuerySortSchema,
@@ -975,8 +1200,25 @@ export {
975
1200
  HMResourceErrorSchema,
976
1201
  HMResourceSchema,
977
1202
  HMResolvedResourceSchema,
1203
+ HMContactSubscribeSchema,
978
1204
  HMContactRecordSchema,
979
1205
  HMAccountContactsRequestSchema,
1206
+ HMCommentDraftSchema,
1207
+ HMListedCommentDraftSchema,
1208
+ HMHostConfigSchema,
1209
+ HMContactSchema,
1210
+ HMContactItemSchema,
1211
+ HMCapabilitySchema,
1212
+ siteDiscoverRequestSchema,
1213
+ HMPeerConnectionRequestSchema,
1214
+ ParsedFragmentSchema,
1215
+ HMCitationSchema,
1216
+ DeviceLinkSessionSchema,
1217
+ HMNavigationItemSchema,
1218
+ HMDraftContentSchema,
1219
+ HMDraftMetaSchema,
1220
+ HMListedDraftSchema,
1221
+ HMListedDraftReadSchema,
980
1222
  HMSubjectContactsRequestSchema,
981
1223
  HMResourceRequestSchema,
982
1224
  HMResourceMetadataRequestSchema,
@@ -1040,5 +1282,10 @@ export {
1040
1282
  getHMQueryString,
1041
1283
  serializeBlockRange,
1042
1284
  hmIdPathToEntityQueryPath,
1043
- entityQueryPathToHmIdPath
1285
+ entityQueryPathToHmIdPath,
1286
+ parseCustomURL,
1287
+ parseFragment,
1288
+ unpackHmId,
1289
+ codePointLength,
1290
+ isSurrogate
1044
1291
  };
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;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * GROBID HTTP client — sends PDFs to a GROBID server for full-text extraction.
3
+ *
4
+ * Expects a running GROBID instance (e.g. via Docker):
5
+ * docker run --rm -p 8070:8070 grobid/grobid:0.8.2-full
6
+ */
7
+ export declare const DEFAULT_GROBID_URL = "http://localhost:8070";
8
+ export interface GrobidOptions {
9
+ /** Base URL of the GROBID server (default: http://localhost:8070) */
10
+ grobidUrl?: string;
11
+ /** Request TEI coordinates for specific element types */
12
+ teiCoordinates?: string[];
13
+ }
14
+ /**
15
+ * Check whether a GROBID server is reachable at the given URL.
16
+ * Returns true if the server responds within the timeout, false otherwise.
17
+ */
18
+ export declare function isGrobidAvailable(grobidUrl?: string, timeoutMs?: number): Promise<boolean>;
19
+ /**
20
+ * Send a PDF to GROBID's processFulltextDocument endpoint and return TEI XML.
21
+ */
22
+ export declare function processFulltextDocument(pdfBuffer: ArrayBuffer | Buffer, options?: GrobidOptions): Promise<string>;