@seed-hypermedia/client 0.0.11 → 0.0.13

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.
@@ -1,7 +1,8 @@
1
1
  /**
2
- * Capability SDK — create capabilities (delegate access to other accounts).
2
+ * Capability SDK — create and resolve capabilities (delegate access to other accounts).
3
3
  */
4
4
  import type { HMPublishBlobsInput, HMSigner } from './hm-types';
5
+ import type { SeedClient } from './client';
5
6
  /** Role values for capability blobs. */
6
7
  export type CapabilityRole = 'WRITER' | 'AGENT';
7
8
  export type CreateCapabilityInput = {
@@ -19,3 +20,8 @@ export type CreateCapabilityInput = {
19
20
  * The signer is the issuer granting access to the delegate.
20
21
  */
21
22
  export declare function createCapability(input: CreateCapabilityInput, signer: HMSigner): Promise<HMPublishBlobsInput>;
23
+ /**
24
+ * Find a WRITER or AGENT capability for `signerAccount` on `targetAccount`.
25
+ * Returns the capability CID if found, undefined if not needed (same account) or not found.
26
+ */
27
+ export declare function resolveCapability(client: SeedClient, targetAccount: string, signerAccount: string): Promise<string | undefined>;
@@ -1148,6 +1148,87 @@ function isSurrogate(s, i) {
1148
1148
  const code = s.charCodeAt(i);
1149
1149
  return 55296 <= code && code <= 56319;
1150
1150
  }
1151
+ async function resolveHypermediaUrl(url) {
1152
+ let latest = false;
1153
+ let blockRef = null;
1154
+ let blockRange = null;
1155
+ let panel = null;
1156
+ try {
1157
+ const parsedUrl = new URL(url);
1158
+ const hasVersion = parsedUrl.searchParams.has("v");
1159
+ const hasLatest = parsedUrl.searchParams.has("l");
1160
+ panel = parsedUrl.searchParams.get("panel");
1161
+ if (parsedUrl.hash) {
1162
+ const fragment = parseFragment(parsedUrl.hash.slice(1));
1163
+ if (fragment) {
1164
+ blockRef = fragment.blockId;
1165
+ if ("start" in fragment && fragment.start !== void 0) {
1166
+ blockRange = { start: fragment.start, end: fragment.end };
1167
+ } else if ("expanded" in fragment && fragment.expanded) {
1168
+ blockRange = { expanded: fragment.expanded };
1169
+ }
1170
+ }
1171
+ }
1172
+ latest = blockRef ? false : hasLatest || !hasVersion;
1173
+ } catch {
1174
+ }
1175
+ const response = await fetch(url, {
1176
+ method: "OPTIONS"
1177
+ });
1178
+ if (response.status === 200) {
1179
+ const rawId = response.headers.get("x-hypermedia-id");
1180
+ const id = rawId ? decodeURIComponent(rawId) : null;
1181
+ const version = response.headers.get("x-hypermedia-version");
1182
+ const encodedTitle = response.headers.get("x-hypermedia-title");
1183
+ const title = encodedTitle ? decodeURIComponent(encodedTitle) : null;
1184
+ const rawTarget = response.headers.get("x-hypermedia-target");
1185
+ const target = rawTarget ? unpackHmId(decodeURIComponent(rawTarget)) : null;
1186
+ const rawAuthors = response.headers.get("x-hypermedia-authors");
1187
+ const authors = rawAuthors ? decodeURIComponent(rawAuthors).split(",").map((author) => unpackHmId(author)) : null;
1188
+ const type = response.headers.get("x-hypermedia-type");
1189
+ if (id) {
1190
+ const hmId = unpackHmId(id);
1191
+ const resolvedVersion = version ?? (hmId == null ? void 0 : hmId.version) ?? null;
1192
+ let siteHostname = null;
1193
+ try {
1194
+ const inputUrl = new URL(url);
1195
+ if (!inputUrl.pathname.startsWith("/hm/")) {
1196
+ siteHostname = inputUrl.origin;
1197
+ }
1198
+ } catch {
1199
+ }
1200
+ return {
1201
+ id,
1202
+ hmId: hmId ? {
1203
+ ...hmId,
1204
+ version: resolvedVersion,
1205
+ latest,
1206
+ blockRef,
1207
+ blockRange,
1208
+ hostname: siteHostname || hmId.hostname
1209
+ } : null,
1210
+ version,
1211
+ title,
1212
+ target,
1213
+ authors,
1214
+ type,
1215
+ panel
1216
+ };
1217
+ }
1218
+ return null;
1219
+ }
1220
+ return null;
1221
+ }
1222
+ async function resolveId(input) {
1223
+ const parsed = unpackHmId(input);
1224
+ if (parsed) return parsed;
1225
+ if (input.startsWith("http://") || input.startsWith("https://")) {
1226
+ const resolved = await resolveHypermediaUrl(input);
1227
+ if (resolved == null ? void 0 : resolved.hmId) return resolved.hmId;
1228
+ throw new Error(`URL does not appear to be a Seed Hypermedia resource: ${input}`);
1229
+ }
1230
+ throw new Error(`Invalid Hypermedia ID: ${input}`);
1231
+ }
1151
1232
 
1152
1233
  export {
1153
1234
  BlockRangeSchema,
@@ -1309,5 +1390,7 @@ export {
1309
1390
  parseFragment,
1310
1391
  unpackHmId,
1311
1392
  codePointLength,
1312
- isSurrogate
1393
+ isSurrogate,
1394
+ resolveHypermediaUrl,
1395
+ resolveId
1313
1396
  };
@@ -47033,4 +47033,70 @@ export declare function unpackHmId(hypermediaId?: string): UnpackedHypermediaId
47033
47033
  export declare function codePointLength(entry: string): number;
47034
47034
  /** Check if a UTF-16 code unit at index i is the start of a surrogate pair. */
47035
47035
  export declare function isSurrogate(s: string, i: number): boolean;
47036
+ /** Resolve a web URL to its Hypermedia metadata via an OPTIONS request. */
47037
+ export declare function resolveHypermediaUrl(url: string): Promise<{
47038
+ id: string;
47039
+ hmId: {
47040
+ version: string | null;
47041
+ latest: boolean;
47042
+ blockRef: string | null;
47043
+ blockRange: {
47044
+ start: number;
47045
+ end: number;
47046
+ } | {
47047
+ expanded: boolean;
47048
+ } | null;
47049
+ hostname: string | null;
47050
+ path: string[] | null;
47051
+ id: string;
47052
+ uid: string;
47053
+ scheme: string | null;
47054
+ targetDocUid?: string | null | undefined;
47055
+ targetDocPath?: string[] | null | undefined;
47056
+ } | null;
47057
+ version: string | null;
47058
+ title: string | null;
47059
+ target: {
47060
+ path: string[] | null;
47061
+ version: string | null;
47062
+ id: string;
47063
+ uid: string;
47064
+ blockRef: string | null;
47065
+ blockRange: {
47066
+ start?: number | undefined;
47067
+ end?: number | undefined;
47068
+ expanded?: boolean | undefined;
47069
+ } | null;
47070
+ hostname: string | null;
47071
+ scheme: string | null;
47072
+ latest?: boolean | null | undefined;
47073
+ targetDocUid?: string | null | undefined;
47074
+ targetDocPath?: string[] | null | undefined;
47075
+ } | null;
47076
+ authors: ({
47077
+ path: string[] | null;
47078
+ version: string | null;
47079
+ id: string;
47080
+ uid: string;
47081
+ blockRef: string | null;
47082
+ blockRange: {
47083
+ start?: number | undefined;
47084
+ end?: number | undefined;
47085
+ expanded?: boolean | undefined;
47086
+ } | null;
47087
+ hostname: string | null;
47088
+ scheme: string | null;
47089
+ latest?: boolean | null | undefined;
47090
+ targetDocUid?: string | null | undefined;
47091
+ targetDocPath?: string[] | null | undefined;
47092
+ } | null)[] | null;
47093
+ type: string | null;
47094
+ panel: string | null;
47095
+ } | null>;
47096
+ /**
47097
+ * Resolve a string that may be an hm:// ID, a gateway URL, or a site web URL
47098
+ * into an UnpackedHypermediaId. Tries synchronous parsing first, then falls
47099
+ * back to an OPTIONS request for web URLs.
47100
+ */
47101
+ export declare function resolveId(input: string): Promise<UnpackedHypermediaId>;
47036
47102
  export {};
package/dist/hm-types.mjs CHANGED
@@ -154,12 +154,14 @@ import {
154
154
  packHmId,
155
155
  parseCustomURL,
156
156
  parseFragment,
157
+ resolveHypermediaUrl,
158
+ resolveId,
157
159
  serializeBlockRange,
158
160
  siteDiscoverRequestSchema,
159
161
  toNumber,
160
162
  unpackHmId,
161
163
  unpackedHmIdSchema
162
- } from "./chunk-GMPLFPEM.mjs";
164
+ } from "./chunk-LCXR7GLM.mjs";
163
165
  export {
164
166
  BlockRangeSchema,
165
167
  BoldAnnotationSchema,
@@ -316,6 +318,8 @@ export {
316
318
  packHmId,
317
319
  parseCustomURL,
318
320
  parseFragment,
321
+ resolveHypermediaUrl,
322
+ resolveId,
319
323
  serializeBlockRange,
320
324
  siteDiscoverRequestSchema,
321
325
  toNumber,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { createCapability } from './capability';
1
+ export { createCapability, resolveCapability } from './capability';
2
2
  export type { CapabilityRole, CreateCapabilityInput } from './capability';
3
3
  export { createChange, createChangeOps, createDocumentChange, createDocumentChangeFromOps, createGenesisChange, signDocumentChange, signPreparedChange, } from './change';
4
4
  export type { CreateChangeOpsInput, CreateDocumentChangeFromOpsInput, CreateDocumentChangeInput, DocumentOperation, SignDocumentChangeInput, } from './change';
@@ -20,7 +20,7 @@ export type { GrobidOptions } from './grobid';
20
20
  export { embeddedPdfToBlocks } from './pdf-to-blocks-embedded';
21
21
  export type { EmbeddedPdfResult } from './pdf-to-blocks-embedded';
22
22
  export { trimTrailingEmptyBlocks } from './comment';
23
- export { codePointLength, entityQueryPathToHmIdPath, getHMQueryString, hmIdPathToEntityQueryPath, HYPERMEDIA_SCHEME, isSurrogate, packBaseId, packHmId, parseCustomURL, parseFragment, serializeBlockRange, unpackHmId, } from './hm-types';
23
+ export { codePointLength, entityQueryPathToHmIdPath, getHMQueryString, hmIdPathToEntityQueryPath, HYPERMEDIA_SCHEME, isSurrogate, packBaseId, packHmId, parseCustomURL, parseFragment, resolveHypermediaUrl, resolveId, serializeBlockRange, unpackHmId, } from './hm-types';
24
24
  export type { HMRequest, HMSigner, UnpackedHypermediaId } from './hm-types';
25
25
  export { fileToIpfsBlobs, filesToIpfsBlobs, resolveFileLinksInBlocks, hasFileLinks } from './file-to-ipfs';
26
26
  export type { CollectedBlob } from './file-to-ipfs';
package/dist/index.mjs CHANGED
@@ -13,10 +13,12 @@ import {
13
13
  packHmId,
14
14
  parseCustomURL,
15
15
  parseFragment,
16
+ resolveHypermediaUrl,
17
+ resolveId,
16
18
  serializeBlockRange,
17
19
  toNumber,
18
20
  unpackHmId
19
- } from "./chunk-GMPLFPEM.mjs";
21
+ } from "./chunk-LCXR7GLM.mjs";
20
22
 
21
23
  // src/capability.ts
22
24
  import { encode as cborEncode2 } from "@ipld/dag-cbor";
@@ -70,6 +72,16 @@ async function createCapability(input, signer) {
70
72
  unsigned.sig = await signObject(signer, unsigned);
71
73
  return toPublishInput(cborEncode2(unsigned));
72
74
  }
75
+ async function resolveCapability(client, targetAccount, signerAccount) {
76
+ if (targetAccount === signerAccount) return void 0;
77
+ const targetId = unpackHmId(`hm://${targetAccount}`);
78
+ if (!targetId) return void 0;
79
+ const caps = await client.request("ListCapabilities", { targetId });
80
+ const match = caps.capabilities.find(
81
+ (c) => c.delegate === signerAccount && (c.role === "WRITER" || c.role === "AGENT")
82
+ );
83
+ return match == null ? void 0 : match.id;
84
+ }
73
85
 
74
86
  // src/change.ts
75
87
  import { decode as cborDecode, encode as cborEncode4 } from "@ipld/dag-cbor";
@@ -3908,8 +3920,11 @@ export {
3908
3920
  pdfToBlocks,
3909
3921
  processFulltextDocument,
3910
3922
  pushSpanToAnnotation,
3923
+ resolveCapability,
3911
3924
  resolveDocumentState,
3912
3925
  resolveFileLinksInBlocks,
3926
+ resolveHypermediaUrl,
3927
+ resolveId,
3913
3928
  serializeBlockRange,
3914
3929
  shouldAutoLinkParent,
3915
3930
  signDocumentChange,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seed-hypermedia/client",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/seed-hypermedia/seed",
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export {createCapability} from './capability'
1
+ export {createCapability, resolveCapability} from './capability'
2
2
  export type {CapabilityRole, CreateCapabilityInput} from './capability'
3
3
  export {
4
4
  createChange,
@@ -46,6 +46,8 @@ export {
46
46
  packHmId,
47
47
  parseCustomURL,
48
48
  parseFragment,
49
+ resolveHypermediaUrl,
50
+ resolveId,
49
51
  serializeBlockRange,
50
52
  unpackHmId,
51
53
  } from './hm-types'