apostil 0.1.1 → 0.1.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.
package/README.md CHANGED
@@ -1,45 +1,46 @@
1
1
  # Apostil
2
2
 
3
- Pin-and-comment feedback overlay for React & Next.js. Let your team leave contextual feedback directly on the UI.
3
+ Figma-like commenting tool for React & Next.js. Leave comments directly on the Web App UI, and never miss a feedback.
4
4
 
5
- ## Features
5
+ ## What can it do?
6
6
 
7
- - **Click to pin** — drop comment pins anywhere on the page
8
7
  - **Smart target detection** — auto-anchors to nearest meaningful element
9
- - **Thread-based** — replies, resolve/unresolve, delete
10
- - **Keyboard shortcuts** — `C` to toggle comment mode, `Esc` to cancel
11
- - **Popover-aware** — comments inside modals/popovers re-appear when reopened
12
- - **All Pages view** — see every comment across your project in one sidebar
13
- - **Auto z-index** — overlay detects highest z-index and sits above everything
8
+ - **Project level view** — see every comment across your project in one sidebar, like Figma.
14
9
  - **SSR-safe** — works with Next.js App Router
15
10
 
16
- ## Quick Start
11
+ ## Quick Start Guide
17
12
 
18
- ### 1. Install
13
+ **1. Install** with npm, pnpm, or yarn
19
14
 
20
15
  ```bash
21
- npm install apostil # or: pnpm add apostil / yarn add apostil
16
+ npm install apostil
17
+ ```
18
+ Or install globally
19
+ ```bash
20
+ npm install -g apostil
22
21
  ```
23
22
 
24
- ### 2. Initialize
23
+ **2. Initialize**
25
24
 
26
25
  ```bash
27
- npx apostil init # or: pnpm exec apostil init
26
+ npx apostil init # personal (default) local dev only
27
+ npx apostil init --dev # dev + staging environments
28
+ npx apostil init --public # all environments including production
28
29
  ```
29
30
 
30
31
  This will:
31
32
  - Create `app/api/apostil/route.ts` — API route for comment storage
32
- - Create `components/apostil-wrapper.tsx` — pre-configured wrapper component
33
+ - Create `components/apostil-wrapper.tsx` — pre-configured wrapper with env guard
33
34
  - Create `.apostil/` directory and add it to `.gitignore`
34
35
  - **Automatically wrap `{children}` in your root layout** with `<ApostilWrapper>`
35
36
 
36
- ### 3. Done
37
+ **3. Start your project and start commenting**
37
38
 
38
39
  ```bash
39
40
  npm run dev
40
41
  ```
41
42
 
42
- Press `C` on any page to start commenting. That's it.
43
+ Press `C` on any page to start commenting. On your first comment, you'll be prompted to enter your name — this is stored locally and used for all future comments. Click anywhere to place a pin, type your comment, and press `Enter` to save.
43
44
 
44
45
  ## How It Works
45
46
 
@@ -52,7 +53,23 @@ Comments are stored as JSON files in `.apostil/`:
52
53
  └── dashboard--settings.json
53
54
  ```
54
55
 
55
- The wrapper auto-detects the current page from `usePathname()` and loads the corresponding comments. Every page in your app gets commenting automatically.
56
+ The wrapper auto-detects the current page from `usePathname()` and loads the corresponding comments. Every page in your app gets commenting automatically. Comments persist across page refreshes and dev server restarts.
57
+
58
+ Click a pin to open its thread — you can reply to existing comments or resolve the thread. Resolved threads stay accessible but are visually distinguished.
59
+
60
+ ### Shareable Links
61
+
62
+ Apostil supports hash-based thread links. Append `#apostil-<threadId>` to any URL to deep-link directly to a comment thread. The sidebar's **All Pages** view uses this to navigate across pages and open the target thread automatically.
63
+
64
+ ## Modes
65
+
66
+ | Mode | Active in | Comments in git | Env override |
67
+ |------|-----------|----------------|--------------|
68
+ | `(default)` | Local dev only | No | — |
69
+ | `--dev` | Dev + staging | No | `NEXT_PUBLIC_APOSTIL=true` to force on |
70
+ | `--public` | All environments | Yes | `NEXT_PUBLIC_APOSTIL=false` to disable |
71
+
72
+ Re-run `npx apostil init --dev` (or `--public`) to switch modes — it will regenerate the wrapper component.
56
73
 
57
74
  ## Uninstall
58
75
 
@@ -67,7 +84,7 @@ npm uninstall apostil
67
84
 
68
85
  | Key | Action |
69
86
  |-----|--------|
70
- | `C` | Toggle comment mode |
87
+ | `C` | Toggle comment mode (modifier keys like `Cmd+C` / `Ctrl+C` are not intercepted) |
71
88
  | `Escape` | Cancel unsaved comment / exit comment mode |
72
89
  | `Enter` | Submit comment |
73
90
 
package/bin/apostil.js CHANGED
File without changes
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/adapters/localStorage.ts
21
+ var localStorage_exports = {};
22
+ __export(localStorage_exports, {
23
+ localStorageAdapter: () => localStorageAdapter
24
+ });
25
+ module.exports = __toCommonJS(localStorage_exports);
26
+ var STORAGE_PREFIX = "apostil-";
27
+ var localStorageAdapter = {
28
+ async load(pageId) {
29
+ if (typeof window === "undefined") return [];
30
+ try {
31
+ const raw = localStorage.getItem(`${STORAGE_PREFIX}${pageId}`);
32
+ return raw ? JSON.parse(raw) : [];
33
+ } catch {
34
+ return [];
35
+ }
36
+ },
37
+ async save(pageId, threads) {
38
+ if (typeof window === "undefined") return;
39
+ localStorage.setItem(`${STORAGE_PREFIX}${pageId}`, JSON.stringify(threads));
40
+ }
41
+ };
42
+ // Annotate the CommonJS export names for ESM import in node:
43
+ 0 && (module.exports = {
44
+ localStorageAdapter
45
+ });
46
+ //# sourceMappingURL=localStorage.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/localStorage.ts"],"sourcesContent":["import type { ApostilStorage, ApostilThread } from \"../types\";\n\nconst STORAGE_PREFIX = \"apostil-\";\n\nexport const localStorageAdapter: ApostilStorage = {\n async load(pageId: string): Promise<ApostilThread[]> {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = localStorage.getItem(`${STORAGE_PREFIX}${pageId}`);\n return raw ? JSON.parse(raw) : [];\n } catch {\n return [];\n }\n },\n\n async save(pageId: string, threads: ApostilThread[]): Promise<void> {\n if (typeof window === \"undefined\") return;\n localStorage.setItem(`${STORAGE_PREFIX}${pageId}`, JSON.stringify(threads));\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,IAAM,iBAAiB;AAEhB,IAAM,sBAAsC;AAAA,EACjD,MAAM,KAAK,QAA0C;AACnD,QAAI,OAAO,WAAW,YAAa,QAAO,CAAC;AAC3C,QAAI;AACF,YAAM,MAAM,aAAa,QAAQ,GAAG,cAAc,GAAG,MAAM,EAAE;AAC7D,aAAO,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AAAA,IAClC,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,QAAgB,SAAyC;AAClE,QAAI,OAAO,WAAW,YAAa;AACnC,iBAAa,QAAQ,GAAG,cAAc,GAAG,MAAM,IAAI,KAAK,UAAU,OAAO,CAAC;AAAA,EAC5E;AACF;","names":[]}
@@ -0,0 +1,5 @@
1
+ import { A as ApostilStorage } from '../types-oQRt3lYH.cjs';
2
+
3
+ declare const localStorageAdapter: ApostilStorage;
4
+
5
+ export { localStorageAdapter };
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/adapters/nextjs.ts
31
+ var nextjs_exports = {};
32
+ __export(nextjs_exports, {
33
+ GET: () => GET,
34
+ POST: () => POST,
35
+ createNextjsHandler: () => createNextjsHandler
36
+ });
37
+ module.exports = __toCommonJS(nextjs_exports);
38
+ function createNextjsHandler(directory = ".apostil") {
39
+ return {
40
+ async GET(request) {
41
+ const { promises: fs } = await import("fs");
42
+ const path = await import("path");
43
+ const url = new URL(request.url);
44
+ const pageId = url.searchParams.get("pageId");
45
+ const dir = path.join(process.cwd(), directory);
46
+ if (!pageId) {
47
+ try {
48
+ const files = await fs.readdir(dir);
49
+ const pages = [];
50
+ for (const file2 of files) {
51
+ if (!file2.endsWith(".json")) continue;
52
+ const id = file2.replace(".json", "");
53
+ try {
54
+ const data = await fs.readFile(path.join(dir, file2), "utf-8");
55
+ const threads = JSON.parse(data);
56
+ if (Array.isArray(threads) && threads.length > 0) {
57
+ pages.push({ pageId: id, threads });
58
+ }
59
+ } catch {
60
+ }
61
+ }
62
+ pages.sort((a, b) => {
63
+ const aLatest = Math.max(...a.threads.map((t) => new Date(t.createdAt).getTime()));
64
+ const bLatest = Math.max(...b.threads.map((t) => new Date(t.createdAt).getTime()));
65
+ return bLatest - aLatest;
66
+ });
67
+ return Response.json(pages);
68
+ } catch {
69
+ return Response.json([]);
70
+ }
71
+ }
72
+ const safeName = pageId.replace(/[^a-zA-Z0-9_-]/g, "");
73
+ const file = path.join(dir, `${safeName}.json`);
74
+ try {
75
+ const data = await fs.readFile(file, "utf-8");
76
+ return Response.json(JSON.parse(data));
77
+ } catch {
78
+ return Response.json([]);
79
+ }
80
+ },
81
+ async POST(request) {
82
+ const { promises: fs } = await import("fs");
83
+ const path = await import("path");
84
+ const url = new URL(request.url);
85
+ const pageId = url.searchParams.get("pageId");
86
+ if (!pageId) {
87
+ return Response.json({ error: "Missing pageId" }, { status: 400 });
88
+ }
89
+ const dir = path.join(process.cwd(), directory);
90
+ const safeName = pageId.replace(/[^a-zA-Z0-9_-]/g, "");
91
+ const file = path.join(dir, `${safeName}.json`);
92
+ try {
93
+ await fs.mkdir(dir, { recursive: true });
94
+ const threads = await request.json();
95
+ await fs.writeFile(file, JSON.stringify(threads, null, 2), "utf-8");
96
+ return Response.json({ ok: true });
97
+ } catch (e) {
98
+ return Response.json({ error: String(e) }, { status: 500 });
99
+ }
100
+ }
101
+ };
102
+ }
103
+ var defaultHandler = createNextjsHandler();
104
+ var GET = defaultHandler.GET;
105
+ var POST = defaultHandler.POST;
106
+ // Annotate the CommonJS export names for ESM import in node:
107
+ 0 && (module.exports = {
108
+ GET,
109
+ POST,
110
+ createNextjsHandler
111
+ });
112
+ //# sourceMappingURL=nextjs.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/nextjs.ts"],"sourcesContent":["/**\n * Next.js API route handler for apostil comment storage.\n * Stores comments as JSON files in the project's .apostil/ directory.\n *\n * Usage:\n *\n * // app/api/apostil/route.ts\n * export { GET, POST } from \"apostil/adapters/nextjs\";\n *\n * Or with custom directory:\n * import { createNextjsHandler } from \"apostil/adapters/nextjs\";\n * const { GET, POST } = createNextjsHandler(\".my-comments\");\n * export { GET, POST };\n */\n\nexport function createNextjsHandler(directory: string = \".apostil\") {\n return {\n async GET(request: Request) {\n const { promises: fs } = await import(\"fs\");\n const path = await import(\"path\");\n\n const url = new URL(request.url);\n const pageId = url.searchParams.get(\"pageId\");\n const dir = path.join(process.cwd(), directory);\n\n // If no pageId, return ALL comments across all pages\n if (!pageId) {\n try {\n const files = await fs.readdir(dir);\n const pages: { pageId: string; threads: unknown[] }[] = [];\n for (const file of files) {\n if (!file.endsWith(\".json\")) continue;\n const id = file.replace(\".json\", \"\");\n try {\n const data = await fs.readFile(path.join(dir, file), \"utf-8\");\n const threads = JSON.parse(data);\n if (Array.isArray(threads) && threads.length > 0) {\n pages.push({ pageId: id, threads });\n }\n } catch {}\n }\n pages.sort((a, b) => {\n const aLatest = Math.max(...(a.threads as Array<{ createdAt: string }>).map((t) => new Date(t.createdAt).getTime()));\n const bLatest = Math.max(...(b.threads as Array<{ createdAt: string }>).map((t) => new Date(t.createdAt).getTime()));\n return bLatest - aLatest;\n });\n return Response.json(pages);\n } catch {\n return Response.json([]);\n }\n }\n\n // Single page\n const safeName = pageId.replace(/[^a-zA-Z0-9_-]/g, \"\");\n const file = path.join(dir, `${safeName}.json`);\n try {\n const data = await fs.readFile(file, \"utf-8\");\n return Response.json(JSON.parse(data));\n } catch {\n return Response.json([]);\n }\n },\n\n async POST(request: Request) {\n const { promises: fs } = await import(\"fs\");\n const path = await import(\"path\");\n\n const url = new URL(request.url);\n const pageId = url.searchParams.get(\"pageId\");\n if (!pageId) {\n return Response.json({ error: \"Missing pageId\" }, { status: 400 });\n }\n\n const dir = path.join(process.cwd(), directory);\n const safeName = pageId.replace(/[^a-zA-Z0-9_-]/g, \"\");\n const file = path.join(dir, `${safeName}.json`);\n\n try {\n await fs.mkdir(dir, { recursive: true });\n const threads = await request.json();\n await fs.writeFile(file, JSON.stringify(threads, null, 2), \"utf-8\");\n return Response.json({ ok: true });\n } catch (e) {\n return Response.json({ error: String(e) }, { status: 500 });\n }\n },\n };\n}\n\n// Default handler with \".apostil\" directory\nconst defaultHandler = createNextjsHandler();\nexport const GET = defaultHandler.GET;\nexport const POST = defaultHandler.POST;\n"],"mappings":"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","names":["file"]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Next.js API route handler for apostil comment storage.
3
+ * Stores comments as JSON files in the project's .apostil/ directory.
4
+ *
5
+ * Usage:
6
+ *
7
+ * // app/api/apostil/route.ts
8
+ * export { GET, POST } from "apostil/adapters/nextjs";
9
+ *
10
+ * Or with custom directory:
11
+ * import { createNextjsHandler } from "apostil/adapters/nextjs";
12
+ * const { GET, POST } = createNextjsHandler(".my-comments");
13
+ * export { GET, POST };
14
+ */
15
+ declare function createNextjsHandler(directory?: string): {
16
+ GET(request: Request): Promise<Response>;
17
+ POST(request: Request): Promise<Response>;
18
+ };
19
+ declare const GET: (request: Request) => Promise<Response>;
20
+ declare const POST: (request: Request) => Promise<Response>;
21
+
22
+ export { GET, POST, createNextjsHandler };
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/adapters/rest.ts
21
+ var rest_exports = {};
22
+ __export(rest_exports, {
23
+ createRestAdapter: () => createRestAdapter
24
+ });
25
+ module.exports = __toCommonJS(rest_exports);
26
+ function createRestAdapter(baseUrl) {
27
+ return {
28
+ async load(pageId) {
29
+ const url = `${baseUrl}?pageId=${encodeURIComponent(pageId)}`;
30
+ try {
31
+ const res = await fetch(url);
32
+ if (!res.ok) {
33
+ console.warn(`[apostil] load failed: ${res.status} ${res.statusText} \u2014 ${url}`);
34
+ return [];
35
+ }
36
+ const data = await res.json();
37
+ return data;
38
+ } catch (e) {
39
+ console.warn(`[apostil] load error:`, e, `\u2014 ${url}`);
40
+ return [];
41
+ }
42
+ },
43
+ async save(pageId, threads) {
44
+ const url = `${baseUrl}?pageId=${encodeURIComponent(pageId)}`;
45
+ try {
46
+ const res = await fetch(url, {
47
+ method: "POST",
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify(threads)
50
+ });
51
+ if (!res.ok) {
52
+ console.warn(`[apostil] save failed: ${res.status} ${res.statusText} \u2014 ${url}`);
53
+ }
54
+ } catch (e) {
55
+ console.warn(`[apostil] save error:`, e, `\u2014 ${url}`);
56
+ }
57
+ }
58
+ };
59
+ }
60
+ // Annotate the CommonJS export names for ESM import in node:
61
+ 0 && (module.exports = {
62
+ createRestAdapter
63
+ });
64
+ //# sourceMappingURL=rest.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/rest.ts"],"sourcesContent":["import type { ApostilStorage, ApostilThread } from \"../types\";\n\n/**\n * REST API storage adapter.\n * Works with any backend that implements GET/POST for threads.\n */\nexport function createRestAdapter(baseUrl: string): ApostilStorage {\n return {\n async load(pageId: string): Promise<ApostilThread[]> {\n const url = `${baseUrl}?pageId=${encodeURIComponent(pageId)}`;\n try {\n const res = await fetch(url);\n if (!res.ok) {\n console.warn(`[apostil] load failed: ${res.status} ${res.statusText} — ${url}`);\n return [];\n }\n const data = await res.json();\n return data;\n } catch (e) {\n console.warn(`[apostil] load error:`, e, `— ${url}`);\n return [];\n }\n },\n\n async save(pageId: string, threads: ApostilThread[]): Promise<void> {\n const url = `${baseUrl}?pageId=${encodeURIComponent(pageId)}`;\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(threads),\n });\n if (!res.ok) {\n console.warn(`[apostil] save failed: ${res.status} ${res.statusText} — ${url}`);\n }\n } catch (e) {\n console.warn(`[apostil] save error:`, e, `— ${url}`);\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMO,SAAS,kBAAkB,SAAiC;AACjE,SAAO;AAAA,IACL,MAAM,KAAK,QAA0C;AACnD,YAAM,MAAM,GAAG,OAAO,WAAW,mBAAmB,MAAM,CAAC;AAC3D,UAAI;AACF,cAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,YAAI,CAAC,IAAI,IAAI;AACX,kBAAQ,KAAK,0BAA0B,IAAI,MAAM,IAAI,IAAI,UAAU,WAAM,GAAG,EAAE;AAC9E,iBAAO,CAAC;AAAA,QACV;AACA,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,eAAO;AAAA,MACT,SAAS,GAAG;AACV,gBAAQ,KAAK,yBAAyB,GAAG,UAAK,GAAG,EAAE;AACnD,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AAAA,IAEA,MAAM,KAAK,QAAgB,SAAyC;AAClE,YAAM,MAAM,GAAG,OAAO,WAAW,mBAAmB,MAAM,CAAC;AAC3D,UAAI;AACF,cAAM,MAAM,MAAM,MAAM,KAAK;AAAA,UAC3B,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,QAC9B,CAAC;AACD,YAAI,CAAC,IAAI,IAAI;AACX,kBAAQ,KAAK,0BAA0B,IAAI,MAAM,IAAI,IAAI,UAAU,WAAM,GAAG,EAAE;AAAA,QAChF;AAAA,MACF,SAAS,GAAG;AACV,gBAAQ,KAAK,yBAAyB,GAAG,UAAK,GAAG,EAAE;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,9 @@
1
+ import { A as ApostilStorage } from '../types-oQRt3lYH.cjs';
2
+
3
+ /**
4
+ * REST API storage adapter.
5
+ * Works with any backend that implements GET/POST for threads.
6
+ */
7
+ declare function createRestAdapter(baseUrl: string): ApostilStorage;
8
+
9
+ export { createRestAdapter };