@shard-for-obsidian/lib 0.2.3 → 0.3.0

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.
Files changed (47) hide show
  1. package/README.md +5 -7
  2. package/dist/adapters/index.d.ts +3 -0
  3. package/dist/adapters/index.d.ts.map +1 -0
  4. package/dist/adapters/index.js +2 -0
  5. package/dist/adapters/node.d.ts +9 -0
  6. package/dist/adapters/node.d.ts.map +1 -0
  7. package/dist/adapters/node.js +10 -0
  8. package/dist/adapters/obsidian.d.ts +13 -0
  9. package/dist/adapters/obsidian.d.ts.map +1 -0
  10. package/dist/adapters/obsidian.js +90 -0
  11. package/dist/client/OciRegistryClient.d.ts +23 -2
  12. package/dist/client/OciRegistryClient.d.ts.map +1 -1
  13. package/dist/client/OciRegistryClient.js +52 -3
  14. package/dist/index.d.ts +4 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +8 -0
  17. package/dist/index.js.map +2 -2
  18. package/dist/marketplace/client.d.ts +48 -0
  19. package/dist/marketplace/client.d.ts.map +1 -0
  20. package/dist/marketplace/client.js +104 -0
  21. package/dist/marketplace/index.d.ts +2 -0
  22. package/dist/marketplace/index.d.ts.map +1 -0
  23. package/dist/marketplace/index.js +1 -0
  24. package/dist/oci/index.d.ts +2 -0
  25. package/dist/oci/index.d.ts.map +1 -0
  26. package/dist/oci/index.js +1 -0
  27. package/dist/oci/tags.d.ts +26 -0
  28. package/dist/oci/tags.d.ts.map +1 -0
  29. package/dist/oci/tags.js +134 -0
  30. package/dist/schemas/annotations.d.ts +78 -0
  31. package/dist/schemas/annotations.d.ts.map +1 -0
  32. package/dist/schemas/annotations.js +39 -0
  33. package/dist/schemas/index.d.ts +5 -0
  34. package/dist/schemas/index.d.ts.map +1 -0
  35. package/dist/schemas/index.js +6 -0
  36. package/dist/schemas/manifest.d.ts +50 -0
  37. package/dist/schemas/manifest.d.ts.map +1 -0
  38. package/dist/schemas/manifest.js +25 -0
  39. package/dist/schemas/marketplace.d.ts +379 -0
  40. package/dist/schemas/marketplace.d.ts.map +1 -0
  41. package/dist/schemas/marketplace.js +67 -0
  42. package/dist/schemas/transforms.d.ts +60 -0
  43. package/dist/schemas/transforms.d.ts.map +1 -0
  44. package/dist/schemas/transforms.js +148 -0
  45. package/dist/types/ManifestTypes.d.ts +2 -23
  46. package/dist/types/ManifestTypes.d.ts.map +1 -1
  47. package/package.json +6 -2
@@ -0,0 +1,134 @@
1
+ import { parseRepoAndRef } from "../parsing/RepoParser.js";
2
+ /**
3
+ * Platform-agnostic base64 encoding for Basic Auth.
4
+ */
5
+ function encodeBasicAuth(username, password) {
6
+ const credentials = `${username}:${password}`;
7
+ // Use TextEncoder + btoa for browser compatibility
8
+ if (typeof Buffer !== "undefined") {
9
+ // Node.js environment
10
+ return Buffer.from(credentials).toString("base64");
11
+ }
12
+ else {
13
+ // Browser environment
14
+ return btoa(credentials);
15
+ }
16
+ }
17
+ /**
18
+ * Parse WWW-Authenticate header to extract auth challenge.
19
+ */
20
+ function parseAuthChallenge(header) {
21
+ // Format: Bearer realm="...",service="...",scope="..."
22
+ const realmMatch = /realm="([^"]+)"/.exec(header);
23
+ const serviceMatch = /service="([^"]+)"/.exec(header);
24
+ const scopeMatch = /scope="([^"]+)"/.exec(header);
25
+ if (!realmMatch || !serviceMatch || !scopeMatch) {
26
+ return null;
27
+ }
28
+ return {
29
+ realm: realmMatch[1],
30
+ service: serviceMatch[1],
31
+ scope: scopeMatch[1],
32
+ };
33
+ }
34
+ /**
35
+ * Exchange GitHub token for OCI registry token.
36
+ */
37
+ async function getRegistryToken(challenge, adapter, githubToken) {
38
+ const url = `${challenge.realm}?service=${challenge.service}&scope=${challenge.scope}`;
39
+ const headers = {
40
+ Accept: "application/json",
41
+ };
42
+ // For GHCR, we need to use Basic auth with the GitHub token
43
+ // Username can be anything, password is the token
44
+ if (githubToken) {
45
+ const basicAuth = encodeBasicAuth("token", githubToken);
46
+ headers.Authorization = `Basic ${basicAuth}`;
47
+ }
48
+ try {
49
+ const response = await adapter.fetch(url, { headers });
50
+ if (!response.ok) {
51
+ return null;
52
+ }
53
+ const data = (await response.json());
54
+ return data.token || null;
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ }
60
+ /**
61
+ * Query all available tags from an OCI registry.
62
+ */
63
+ export async function queryOciTags(opts) {
64
+ const { registryUrl, adapter, token } = opts;
65
+ const ref = parseRepoAndRef(registryUrl);
66
+ // OCI Distribution API: GET /v2/<name>/tags/list
67
+ const url = `https://${ref.index.name}/v2/${ref.remoteName}/tags/list`;
68
+ const headers = {
69
+ Accept: "application/json",
70
+ };
71
+ // Try initial request
72
+ let response = await adapter.fetch(url, { headers });
73
+ // If 401, try to exchange token and retry
74
+ if (response.status === 401 && token) {
75
+ const wwwAuth = response.headers.get("www-authenticate");
76
+ if (wwwAuth) {
77
+ const challenge = parseAuthChallenge(wwwAuth);
78
+ if (challenge) {
79
+ const registryToken = await getRegistryToken(challenge, adapter, token);
80
+ if (registryToken) {
81
+ headers.Authorization = `Bearer ${registryToken}`;
82
+ response = await adapter.fetch(url, { headers });
83
+ }
84
+ }
85
+ }
86
+ }
87
+ if (!response.ok) {
88
+ throw new Error(`Failed to query OCI tags: ${response.status} ${response.statusText}`);
89
+ }
90
+ const data = (await response.json());
91
+ return data.tags || [];
92
+ }
93
+ /**
94
+ * Query metadata for a specific tag.
95
+ */
96
+ export async function queryTagMetadata(opts) {
97
+ const { registryUrl, tag, adapter, token } = opts;
98
+ const ref = parseRepoAndRef(registryUrl);
99
+ // OCI Distribution API: GET /v2/<name>/manifests/<tag>
100
+ const url = `https://${ref.index.name}/v2/${ref.remoteName}/manifests/${tag}`;
101
+ const headers = {
102
+ Accept: "application/vnd.oci.image.manifest.v1+json",
103
+ };
104
+ // Try initial request
105
+ let response = await adapter.fetch(url, { headers });
106
+ // If 401, try to exchange token and retry
107
+ if (response.status === 401 && token) {
108
+ const wwwAuth = response.headers.get("www-authenticate");
109
+ if (wwwAuth) {
110
+ const challenge = parseAuthChallenge(wwwAuth);
111
+ if (challenge) {
112
+ const registryToken = await getRegistryToken(challenge, adapter, token);
113
+ if (registryToken) {
114
+ headers.Authorization = `Bearer ${registryToken}`;
115
+ response = await adapter.fetch(url, { headers });
116
+ }
117
+ }
118
+ }
119
+ }
120
+ if (!response.ok) {
121
+ throw new Error(`Failed to query tag metadata: ${response.status} ${response.statusText}`);
122
+ }
123
+ const manifest = (await response.json());
124
+ // Extract metadata
125
+ const publishedAt = manifest.created || new Date().toISOString();
126
+ const layerSizes = manifest.layers?.map((l) => l.size) || [];
127
+ const size = layerSizes.reduce((sum, s) => sum + s, 0);
128
+ const annotations = manifest.annotations || {};
129
+ return {
130
+ publishedAt,
131
+ size,
132
+ annotations,
133
+ };
134
+ }
@@ -0,0 +1,78 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * OCI manifest annotations for Obsidian plugins
4
+ * Uses full annotation keys as they appear in OCI manifests
5
+ */
6
+ export declare const PluginAnnotationsSchema: z.ZodObject<{
7
+ /** Plugin ID */
8
+ "vnd.obsidianmd.plugin.id": z.ZodString;
9
+ /** Display name */
10
+ "vnd.obsidianmd.plugin.name": z.ZodString;
11
+ /** Plugin version */
12
+ "vnd.obsidianmd.plugin.version": z.ZodString;
13
+ /** Plugin description */
14
+ "vnd.obsidianmd.plugin.description": z.ZodString;
15
+ /** Plugin author */
16
+ "vnd.obsidianmd.plugin.author": z.ZodString;
17
+ /** VCS source URL (e.g., git+https://github.com/owner/repo.git) */
18
+ "vnd.obsidianmd.plugin.source": z.ZodString;
19
+ /** Publication timestamp (ISO 8601) */
20
+ "vnd.obsidianmd.plugin.published-at": z.ZodString;
21
+ /** Plugin introduction from community-plugins.json (required) */
22
+ "vnd.obsidianmd.plugin.introduction": z.ZodString;
23
+ /** Funding URL - string or JSON-serialized object (optional) */
24
+ "vnd.obsidianmd.plugin.funding-url": z.ZodOptional<z.ZodString>;
25
+ /** Is desktop only - string representation of boolean (required) */
26
+ "vnd.obsidianmd.plugin.is-desktop-only": z.ZodString;
27
+ /** Indicates plugin was converted from legacy format */
28
+ "vnd.obsidianmd.plugin.converted": z.ZodOptional<z.ZodString>;
29
+ /** Author URL */
30
+ "vnd.obsidianmd.plugin.author-url": z.ZodOptional<z.ZodString>;
31
+ /** Minimum Obsidian version required (required) */
32
+ "vnd.obsidianmd.plugin.min-app-version": z.ZodString;
33
+ /** OCI image source repository URL */
34
+ "org.opencontainers.image.source": z.ZodString;
35
+ /** OCI standard: Plugin title */
36
+ "org.opencontainers.image.title": z.ZodString;
37
+ /** OCI standard: Creation timestamp (RFC 3339) */
38
+ "org.opencontainers.image.created": z.ZodString;
39
+ }, "strip", z.ZodTypeAny, {
40
+ "org.opencontainers.image.title": string;
41
+ "vnd.obsidianmd.plugin.id": string;
42
+ "vnd.obsidianmd.plugin.name": string;
43
+ "vnd.obsidianmd.plugin.version": string;
44
+ "vnd.obsidianmd.plugin.description": string;
45
+ "vnd.obsidianmd.plugin.author": string;
46
+ "vnd.obsidianmd.plugin.source": string;
47
+ "vnd.obsidianmd.plugin.published-at": string;
48
+ "vnd.obsidianmd.plugin.introduction": string;
49
+ "vnd.obsidianmd.plugin.is-desktop-only": string;
50
+ "vnd.obsidianmd.plugin.min-app-version": string;
51
+ "org.opencontainers.image.source": string;
52
+ "org.opencontainers.image.created": string;
53
+ "vnd.obsidianmd.plugin.funding-url"?: string | undefined;
54
+ "vnd.obsidianmd.plugin.converted"?: string | undefined;
55
+ "vnd.obsidianmd.plugin.author-url"?: string | undefined;
56
+ }, {
57
+ "org.opencontainers.image.title": string;
58
+ "vnd.obsidianmd.plugin.id": string;
59
+ "vnd.obsidianmd.plugin.name": string;
60
+ "vnd.obsidianmd.plugin.version": string;
61
+ "vnd.obsidianmd.plugin.description": string;
62
+ "vnd.obsidianmd.plugin.author": string;
63
+ "vnd.obsidianmd.plugin.source": string;
64
+ "vnd.obsidianmd.plugin.published-at": string;
65
+ "vnd.obsidianmd.plugin.introduction": string;
66
+ "vnd.obsidianmd.plugin.is-desktop-only": string;
67
+ "vnd.obsidianmd.plugin.min-app-version": string;
68
+ "org.opencontainers.image.source": string;
69
+ "org.opencontainers.image.created": string;
70
+ "vnd.obsidianmd.plugin.funding-url"?: string | undefined;
71
+ "vnd.obsidianmd.plugin.converted"?: string | undefined;
72
+ "vnd.obsidianmd.plugin.author-url"?: string | undefined;
73
+ }>;
74
+ /**
75
+ * Inferred TypeScript type from schema
76
+ */
77
+ export type PluginAnnotations = z.infer<typeof PluginAnnotationsSchema>;
78
+ //# sourceMappingURL=annotations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotations.d.ts","sourceRoot":"","sources":["../../src/schemas/annotations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,uBAAuB;IAClC,gBAAgB;;IAEhB,mBAAmB;;IAEnB,qBAAqB;;IAErB,yBAAyB;;IAEzB,oBAAoB;;IAEpB,mEAAmE;;IAEnE,uCAAuC;;IAEvC,iEAAiE;;IAEjE,gEAAgE;;IAEhE,oEAAoE;;IAEpE,wDAAwD;;IAExD,iBAAiB;;IAEjB,mDAAmD;;IAEnD,sCAAsC;;IAEtC,iCAAiC;;IAEjC,kDAAkD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAElD,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * OCI manifest annotations for Obsidian plugins
4
+ * Uses full annotation keys as they appear in OCI manifests
5
+ */
6
+ export const PluginAnnotationsSchema = z.object({
7
+ /** Plugin ID */
8
+ "vnd.obsidianmd.plugin.id": z.string(),
9
+ /** Display name */
10
+ "vnd.obsidianmd.plugin.name": z.string(),
11
+ /** Plugin version */
12
+ "vnd.obsidianmd.plugin.version": z.string(),
13
+ /** Plugin description */
14
+ "vnd.obsidianmd.plugin.description": z.string(),
15
+ /** Plugin author */
16
+ "vnd.obsidianmd.plugin.author": z.string(),
17
+ /** VCS source URL (e.g., git+https://github.com/owner/repo.git) */
18
+ "vnd.obsidianmd.plugin.source": z.string().regex(/^git\+https:\/\//),
19
+ /** Publication timestamp (ISO 8601) */
20
+ "vnd.obsidianmd.plugin.published-at": z.string().datetime(),
21
+ /** Plugin introduction from community-plugins.json (required) */
22
+ "vnd.obsidianmd.plugin.introduction": z.string(),
23
+ /** Funding URL - string or JSON-serialized object (optional) */
24
+ "vnd.obsidianmd.plugin.funding-url": z.string().optional(),
25
+ /** Is desktop only - string representation of boolean (required) */
26
+ "vnd.obsidianmd.plugin.is-desktop-only": z.string(),
27
+ /** Indicates plugin was converted from legacy format */
28
+ "vnd.obsidianmd.plugin.converted": z.string().optional(),
29
+ /** Author URL */
30
+ "vnd.obsidianmd.plugin.author-url": z.string().url().optional(),
31
+ /** Minimum Obsidian version required (required) */
32
+ "vnd.obsidianmd.plugin.min-app-version": z.string(),
33
+ /** OCI image source repository URL */
34
+ "org.opencontainers.image.source": z.string().url(),
35
+ /** OCI standard: Plugin title */
36
+ "org.opencontainers.image.title": z.string(),
37
+ /** OCI standard: Creation timestamp (RFC 3339) */
38
+ "org.opencontainers.image.created": z.string().datetime(),
39
+ });
@@ -0,0 +1,5 @@
1
+ export { ObsidianManifestSchema, type ObsidianManifest } from "./manifest.js";
2
+ export { PluginAnnotationsSchema, type PluginAnnotations, } from "./annotations.js";
3
+ export { PluginVersionSchema, MarketplacePluginSchema, MarketplaceIndexSchema, CachedMarketplaceDataSchema, type PluginVersion, type MarketplacePlugin, type MarketplaceIndex, type CachedMarketplaceData, } from "./marketplace.js";
4
+ export { repoToVcsUrl, vcsUrlToGitHubUrl, manifestToAnnotations, manifestToAnnotationsLegacy, annotationsToMarketplacePlugin, type CommunityPluginMetadata, } from "./transforms.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE9E,OAAO,EACL,uBAAuB,EACvB,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,2BAA2B,EAC3B,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,GAC3B,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,2BAA2B,EAC3B,8BAA8B,EAC9B,KAAK,uBAAuB,GAC7B,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,6 @@
1
+ // Schemas
2
+ export { ObsidianManifestSchema } from "./manifest.js";
3
+ export { PluginAnnotationsSchema, } from "./annotations.js";
4
+ export { PluginVersionSchema, MarketplacePluginSchema, MarketplaceIndexSchema, CachedMarketplaceDataSchema, } from "./marketplace.js";
5
+ // Transform utilities
6
+ export { repoToVcsUrl, vcsUrlToGitHubUrl, manifestToAnnotations, manifestToAnnotationsLegacy, annotationsToMarketplacePlugin, } from "./transforms.js";
@@ -0,0 +1,50 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Obsidian plugin manifest schema
4
+ * Based on official Obsidian manifest.json structure
5
+ */
6
+ export declare const ObsidianManifestSchema: z.ZodObject<{
7
+ /** Plugin ID */
8
+ id: z.ZodString;
9
+ /** Display name */
10
+ name: z.ZodString;
11
+ /** Plugin version */
12
+ version: z.ZodString;
13
+ /** Minimum Obsidian version required (required) */
14
+ minAppVersion: z.ZodString;
15
+ /** Plugin description */
16
+ description: z.ZodString;
17
+ /** Plugin author */
18
+ author: z.ZodString;
19
+ /** Author URL (optional) */
20
+ authorUrl: z.ZodOptional<z.ZodString>;
21
+ /** Is desktop only? (optional) */
22
+ isDesktopOnly: z.ZodOptional<z.ZodBoolean>;
23
+ /** Funding URLs (optional) */
24
+ fundingUrl: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
25
+ }, "strip", z.ZodTypeAny, {
26
+ id: string;
27
+ name: string;
28
+ version: string;
29
+ minAppVersion: string;
30
+ description: string;
31
+ author: string;
32
+ authorUrl?: string | undefined;
33
+ isDesktopOnly?: boolean | undefined;
34
+ fundingUrl?: string | Record<string, string> | undefined;
35
+ }, {
36
+ id: string;
37
+ name: string;
38
+ version: string;
39
+ minAppVersion: string;
40
+ description: string;
41
+ author: string;
42
+ authorUrl?: string | undefined;
43
+ isDesktopOnly?: boolean | undefined;
44
+ fundingUrl?: string | Record<string, string> | undefined;
45
+ }>;
46
+ /**
47
+ * Inferred TypeScript type from schema
48
+ */
49
+ export type ObsidianManifest = z.infer<typeof ObsidianManifestSchema>;
50
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/schemas/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,sBAAsB;IACjC,gBAAgB;;IAEhB,mBAAmB;;IAEnB,qBAAqB;;IAErB,mDAAmD;;IAEnD,yBAAyB;;IAEzB,oBAAoB;;IAEpB,4BAA4B;;IAE5B,kCAAkC;;IAElC,8BAA8B;;;;;;;;;;;;;;;;;;;;;;EAE9B,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Obsidian plugin manifest schema
4
+ * Based on official Obsidian manifest.json structure
5
+ */
6
+ export const ObsidianManifestSchema = z.object({
7
+ /** Plugin ID */
8
+ id: z.string(),
9
+ /** Display name */
10
+ name: z.string(),
11
+ /** Plugin version */
12
+ version: z.string(),
13
+ /** Minimum Obsidian version required (required) */
14
+ minAppVersion: z.string(),
15
+ /** Plugin description */
16
+ description: z.string(),
17
+ /** Plugin author */
18
+ author: z.string(),
19
+ /** Author URL (optional) */
20
+ authorUrl: z.string().url().optional(),
21
+ /** Is desktop only? (optional) */
22
+ isDesktopOnly: z.boolean().optional(),
23
+ /** Funding URLs (optional) */
24
+ fundingUrl: z.union([z.string().url(), z.record(z.string())]).optional(),
25
+ });