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 +35 -18
- package/bin/apostil.js +0 -0
- package/dist/adapters/localStorage.cjs +46 -0
- package/dist/adapters/localStorage.cjs.map +1 -0
- package/dist/adapters/localStorage.d.cts +5 -0
- package/dist/adapters/nextjs.cjs +112 -0
- package/dist/adapters/nextjs.cjs.map +1 -0
- package/dist/adapters/nextjs.d.cts +22 -0
- package/dist/adapters/rest.cjs +64 -0
- package/dist/adapters/rest.cjs.map +1 -0
- package/dist/adapters/rest.d.cts +9 -0
- package/dist/cli/index.cjs +293 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.js +59 -22
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +1467 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +64 -0
- package/dist/index.js +134 -64
- package/dist/index.js.map +1 -1
- package/dist/types-oQRt3lYH.d.cts +30 -0
- package/package.json +19 -7
package/README.md
CHANGED
|
@@ -1,45 +1,46 @@
|
|
|
1
1
|
# Apostil
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
##
|
|
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
|
-
- **
|
|
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
|
-
|
|
13
|
+
**1. Install** with npm, pnpm, or yarn
|
|
19
14
|
|
|
20
15
|
```bash
|
|
21
|
-
npm install apostil
|
|
16
|
+
npm install apostil
|
|
17
|
+
```
|
|
18
|
+
Or install globally
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g apostil
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
**2. Initialize**
|
|
25
24
|
|
|
26
25
|
```bash
|
|
27
|
-
npx 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
|
|
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
|
-
|
|
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.
|
|
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,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 };
|