@offlinejs/devtools-ui 0.1.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.
@@ -0,0 +1,17 @@
1
+ import { OfflineEventName, OfflineDB } from '@offlinejs/types';
2
+
3
+ interface DevtoolsEventEntry {
4
+ event: OfflineEventName;
5
+ payload: unknown;
6
+ timestamp: number;
7
+ }
8
+ interface DevtoolsController {
9
+ destroy(): void;
10
+ events(): DevtoolsEventEntry[];
11
+ /** Alias for render — mounts a live-updating timeline into the target. */
12
+ mount(target: HTMLElement): void;
13
+ render(target: HTMLElement): void;
14
+ }
15
+ declare const createDevtoolsController: (db: OfflineDB) => DevtoolsController;
16
+
17
+ export { type DevtoolsController, type DevtoolsEventEntry, createDevtoolsController };
package/dist/index.js ADDED
@@ -0,0 +1,72 @@
1
+ // src/index.ts
2
+ var events = [
3
+ "sync:start",
4
+ "sync:end",
5
+ "offline",
6
+ "online",
7
+ "queue:add",
8
+ "queue:complete",
9
+ "conflict",
10
+ "error",
11
+ "worker:message",
12
+ "coordination:message"
13
+ ];
14
+ var createDevtoolsController = (db) => {
15
+ const entries = [];
16
+ let target = null;
17
+ const refresh = () => {
18
+ if (target) {
19
+ target.innerHTML = createMarkup(entries);
20
+ }
21
+ };
22
+ const disposers = events.map(
23
+ (event) => db.on(event, (payload) => {
24
+ entries.unshift({
25
+ event,
26
+ payload,
27
+ timestamp: Date.now()
28
+ });
29
+ entries.splice(100);
30
+ refresh();
31
+ })
32
+ );
33
+ const render = (nextTarget) => {
34
+ target = nextTarget;
35
+ refresh();
36
+ };
37
+ return {
38
+ destroy() {
39
+ for (const dispose of disposers) {
40
+ dispose();
41
+ }
42
+ target = null;
43
+ },
44
+ events: () => [...entries],
45
+ mount: render,
46
+ render
47
+ };
48
+ };
49
+ var createMarkup = (entries) => `
50
+ <section class="offlinejs-devtools" style="font-family: ui-sans-serif, system-ui, sans-serif; padding: 12px">
51
+ <div style="display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:8px">
52
+ <h2 style="margin:0;font-size:1.05rem">OfflineJS Devtools</h2>
53
+ <span style="opacity:.7;font-size:.85rem">${entries.length} event${entries.length === 1 ? "" : "s"}</span>
54
+ </div>
55
+ ${entries.length === 0 ? `<p style="margin:0;opacity:.7">Waiting for sync, queue, network, and conflict events\u2026</p>` : `<ol style="padding-left:20px;margin:0;display:grid;gap:10px">
56
+ ${entries.map(
57
+ (entry) => `
58
+ <li>
59
+ <strong>${escapeHtml(entry.event)}</strong>
60
+ <time style="margin-left:8px;opacity:.7;font-size:.85rem">${new Date(entry.timestamp).toLocaleTimeString()}</time>
61
+ <pre style="margin:6px 0 0;padding:8px;overflow:auto;border-radius:8px;background:rgba(0,0,0,.06);font-size:12px">${escapeHtml(JSON.stringify(entry.payload, null, 2))}</pre>
62
+ </li>
63
+ `
64
+ ).join("")}
65
+ </ol>`}
66
+ </section>
67
+ `;
68
+ var escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#039;");
69
+
70
+ export { createDevtoolsController };
71
+ //# sourceMappingURL=index.js.map
72
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";AAgBA,IAAM,MAAA,GAA6B;AAAA,EACjC,YAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,gBAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EACA,gBAAA;AAAA,EACA;AACF,CAAA;AAEO,IAAM,wBAAA,GAA2B,CAAC,EAAA,KAAsC;AAC7E,EAAA,MAAM,UAAgC,EAAC;AACvC,EAAA,IAAI,MAAA,GAA6B,IAAA;AAEjC,EAAA,MAAM,UAAU,MAAY;AAC1B,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,CAAO,SAAA,GAAY,aAAa,OAAO,CAAA;AAAA,IACzC;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,YAAY,MAAA,CAAO,GAAA;AAAA,IAAI,CAAC,KAAA,KAC5B,EAAA,CAAG,EAAA,CAAG,KAAA,EAAO,CAAC,OAAA,KAAyC;AACrD,MAAA,OAAA,CAAQ,OAAA,CAAQ;AAAA,QACd,KAAA;AAAA,QACA,OAAA;AAAA,QACA,SAAA,EAAW,KAAK,GAAA;AAAI,OACrB,CAAA;AACD,MAAA,OAAA,CAAQ,OAAO,GAAG,CAAA;AAClB,MAAA,OAAA,EAAQ;AAAA,IACV,CAAC;AAAA,GACH;AAEA,EAAA,MAAM,MAAA,GAAS,CAAC,UAAA,KAAkC;AAChD,IAAA,MAAA,GAAS,UAAA;AACT,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,OAAA,GAAU;AACR,MAAA,KAAA,MAAW,WAAW,SAAA,EAAW;AAC/B,QAAA,OAAA,EAAQ;AAAA,MACV;AACA,MAAA,MAAA,GAAS,IAAA;AAAA,IACX,CAAA;AAAA,IACA,MAAA,EAAQ,MAAM,CAAC,GAAG,OAAO,CAAA;AAAA,IACzB,KAAA,EAAO,MAAA;AAAA,IACP;AAAA,GACF;AACF;AAEA,IAAM,YAAA,GAAe,CAAC,OAAA,KAA0C;AAAA;AAAA;AAAA;AAAA,gDAAA,EAId,QAAQ,MAAM,CAAA,MAAA,EAAS,QAAQ,MAAA,KAAW,CAAA,GAAI,KAAK,GAAG,CAAA;AAAA;AAAA,IAAA,EAGlG,OAAA,CAAQ,MAAA,KAAW,CAAA,GACf,CAAA,8FAAA,CAAA,GACA,CAAA;AAAA,YAAA,EACI,OAAA,CACC,GAAA;AAAA,EACC,CAAC,KAAA,KAAU;AAAA;AAAA,4BAAA,EAEG,UAAA,CAAW,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,8EAAA,EAC2B,IAAI,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA,CAAE,oBAAoB,CAAA;AAAA,sIAAA,EACU,UAAA,CAAW,KAAK,SAAA,CAAU,KAAA,CAAM,SAAS,IAAA,EAAM,CAAC,CAAC,CAAC,CAAA;AAAA;AAAA,gBAAA;AAG5K,CAAA,CACC,IAAA,CAAK,EAAE,CAAC;AAAA,eAAA,CAEnB;AAAA;AAAA,CAAA;AAIJ,IAAM,UAAA,GAAa,CAAC,KAAA,KAClB,KAAA,CACG,WAAW,GAAA,EAAK,OAAO,CAAA,CACvB,UAAA,CAAW,GAAA,EAAK,MAAM,EACtB,UAAA,CAAW,GAAA,EAAK,MAAM,CAAA,CACtB,UAAA,CAAW,KAAK,QAAQ,CAAA,CACxB,UAAA,CAAW,GAAA,EAAK,QAAQ,CAAA","file":"index.js","sourcesContent":["import type { OfflineDB, OfflineEventName, OfflineEvents } from \"@offlinejs/types\";\n\nexport interface DevtoolsEventEntry {\n event: OfflineEventName;\n payload: unknown;\n timestamp: number;\n}\n\nexport interface DevtoolsController {\n destroy(): void;\n events(): DevtoolsEventEntry[];\n /** Alias for render — mounts a live-updating timeline into the target. */\n mount(target: HTMLElement): void;\n render(target: HTMLElement): void;\n}\n\nconst events: OfflineEventName[] = [\n \"sync:start\",\n \"sync:end\",\n \"offline\",\n \"online\",\n \"queue:add\",\n \"queue:complete\",\n \"conflict\",\n \"error\",\n \"worker:message\",\n \"coordination:message\"\n];\n\nexport const createDevtoolsController = (db: OfflineDB): DevtoolsController => {\n const entries: DevtoolsEventEntry[] = [];\n let target: HTMLElement | null = null;\n\n const refresh = (): void => {\n if (target) {\n target.innerHTML = createMarkup(entries);\n }\n };\n\n const disposers = events.map((event) =>\n db.on(event, (payload: OfflineEvents[typeof event]) => {\n entries.unshift({\n event,\n payload,\n timestamp: Date.now()\n });\n entries.splice(100);\n refresh();\n })\n );\n\n const render = (nextTarget: HTMLElement): void => {\n target = nextTarget;\n refresh();\n };\n\n return {\n destroy() {\n for (const dispose of disposers) {\n dispose();\n }\n target = null;\n },\n events: () => [...entries],\n mount: render,\n render\n };\n};\n\nconst createMarkup = (entries: DevtoolsEventEntry[]): string => `\n <section class=\"offlinejs-devtools\" style=\"font-family: ui-sans-serif, system-ui, sans-serif; padding: 12px\">\n <div style=\"display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:8px\">\n <h2 style=\"margin:0;font-size:1.05rem\">OfflineJS Devtools</h2>\n <span style=\"opacity:.7;font-size:.85rem\">${entries.length} event${entries.length === 1 ? \"\" : \"s\"}</span>\n </div>\n ${\n entries.length === 0\n ? `<p style=\"margin:0;opacity:.7\">Waiting for sync, queue, network, and conflict events…</p>`\n : `<ol style=\"padding-left:20px;margin:0;display:grid;gap:10px\">\n ${entries\n .map(\n (entry) => `\n <li>\n <strong>${escapeHtml(entry.event)}</strong>\n <time style=\"margin-left:8px;opacity:.7;font-size:.85rem\">${new Date(entry.timestamp).toLocaleTimeString()}</time>\n <pre style=\"margin:6px 0 0;padding:8px;overflow:auto;border-radius:8px;background:rgba(0,0,0,.06);font-size:12px\">${escapeHtml(JSON.stringify(entry.payload, null, 2))}</pre>\n </li>\n `\n )\n .join(\"\")}\n </ol>`\n }\n </section>\n`;\n\nconst escapeHtml = (value: string): string =>\n value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#039;\");\n"]}
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@offlinejs/devtools-ui",
3
+ "version": "0.1.0",
4
+ "description": "Framework-free Devtools UI for OfflineJS.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "dependencies": {
17
+ "@offlinejs/types": "0.1.0"
18
+ },
19
+ "devDependencies": {
20
+ "tsup": "latest",
21
+ "typescript": "latest"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public",
25
+ "registry": "https://registry.npmjs.org/"
26
+ },
27
+ "scripts": {
28
+ "build": "tsup",
29
+ "typecheck": "tsc --noEmit"
30
+ }
31
+ }