astro-integration-pocketbase 3.1.1 → 3.1.2-next.2
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/{src/types/pocketbase-integration-options.type.ts → dist/index.d.mts} +26 -19
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +237 -0
- package/dist/index.mjs.map +1 -0
- package/dist/middleware.d.mts +5 -0
- package/dist/middleware.d.mts.map +1 -0
- package/dist/middleware.mjs +53 -0
- package/dist/middleware.mjs.map +1 -0
- package/dist/toolbar.d.mts +5 -0
- package/dist/toolbar.d.mts.map +1 -0
- package/dist/toolbar.mjs +254 -0
- package/dist/toolbar.mjs.map +1 -0
- package/package.json +23 -13
- package/index.ts +0 -5
- package/src/core/index.ts +0 -2
- package/src/core/refresh-collections-realtime.ts +0 -169
- package/src/core/refresh-collections.ts +0 -46
- package/src/middleware/index.ts +0 -50
- package/src/middleware/is-pocketbase-entry.ts +0 -33
- package/src/pocketbase-integration.ts +0 -75
- package/src/toolbar/dom/create-entity.ts +0 -69
- package/src/toolbar/dom/create-header.ts +0 -153
- package/src/toolbar/dom/create-placeholder.ts +0 -20
- package/src/toolbar/dom/index.ts +0 -3
- package/src/toolbar/index.ts +0 -6
- package/src/toolbar/init-toolbar.ts +0 -98
- package/src/toolbar/types/entity.ts +0 -8
- package/src/toolbar/types/options.ts +0 -17
- package/src/tsconfig.json +0 -7
- package/src/types/pocketbase-api-response.type.ts +0 -21
- package/src/utils/get-superuser-token.ts +0 -68
- package/src/utils/map-collections-to-watch.ts +0 -56
- package/src/utils/push-to-map-array.ts +0 -16
package/dist/toolbar.mjs
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { defineToolbarApp } from "astro/toolbar";
|
|
2
|
+
import { closeOnOutsideClick, createWindowElement, synchronizePlacementOnUpdate } from "astro/runtime/client/dev-toolbar/apps/utils/window.js";
|
|
3
|
+
//#region src/toolbar/dom/create-entity.ts
|
|
4
|
+
/**
|
|
5
|
+
* Creates cards for the entities.
|
|
6
|
+
*/
|
|
7
|
+
function createEntities(data, baseUrl) {
|
|
8
|
+
const groupedData = Object.groupBy(data, (data) => data.collectionName);
|
|
9
|
+
return `
|
|
10
|
+
<style>
|
|
11
|
+
.collectionName {
|
|
12
|
+
text-transform: capitalize;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.entity {
|
|
16
|
+
position: relative;
|
|
17
|
+
|
|
18
|
+
pre {
|
|
19
|
+
margin: 0;
|
|
20
|
+
overflow: auto;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
astro-dev-toolbar-button {
|
|
24
|
+
position: absolute;
|
|
25
|
+
top: 0;
|
|
26
|
+
right: 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
</style>
|
|
30
|
+
|
|
31
|
+
${Object.keys(groupedData).map((collection) => `
|
|
32
|
+
<b class=".collectionName">${collection}</b>
|
|
33
|
+
${groupedData[collection]?.map((entity) => createEntity(entity, baseUrl)).join("")}
|
|
34
|
+
`).join("")}
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Creates a card for a single entity
|
|
39
|
+
*/
|
|
40
|
+
function createEntity(data, baseUrl) {
|
|
41
|
+
return `
|
|
42
|
+
<astro-dev-toolbar-card>
|
|
43
|
+
<div class="entity">
|
|
44
|
+
<pre>${JSON.stringify(data, void 0, 2).replaceAll("<", "<")}</pre>
|
|
45
|
+
|
|
46
|
+
${baseUrl ? `
|
|
47
|
+
<astro-dev-toolbar-button
|
|
48
|
+
size="small"
|
|
49
|
+
button-style="purple"
|
|
50
|
+
title="View in PocketBase"
|
|
51
|
+
onclick="window.open('${baseUrl}/_/#/collections?collection=${data.collectionId}&recordId=${data.id}&record=${data.id}', '_blank')"
|
|
52
|
+
>
|
|
53
|
+
View in PocketBase
|
|
54
|
+
</astro-dev-toolbar-button>
|
|
55
|
+
` : ""}
|
|
56
|
+
</div>
|
|
57
|
+
</astro-dev-toolbar-card>
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region package.json
|
|
62
|
+
var version = "3.1.2-next.2";
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/toolbar/dom/create-header.ts
|
|
65
|
+
/**
|
|
66
|
+
* Creates the header for the PocketBase toolbar.
|
|
67
|
+
*/
|
|
68
|
+
function createHeader(windowElement, server, { hasContentLoader, realtime }) {
|
|
69
|
+
const header = windowElement.querySelector("header");
|
|
70
|
+
if (!header) throw new Error("The header element is missing");
|
|
71
|
+
header.innerHTML = `
|
|
72
|
+
<style>
|
|
73
|
+
header {
|
|
74
|
+
display: grid;
|
|
75
|
+
grid-template-columns: auto auto 1fr;
|
|
76
|
+
gap: 0.5rem;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
h1 {
|
|
80
|
+
display: flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
gap: 8px;
|
|
83
|
+
font-weight: 600;
|
|
84
|
+
color: #fff;
|
|
85
|
+
margin: 0;
|
|
86
|
+
font-size: 22px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.actions {
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: start;
|
|
92
|
+
justify-content: flex-end;
|
|
93
|
+
gap: 0.25rem;
|
|
94
|
+
|
|
95
|
+
.toggle-container {
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
|
|
99
|
+
label {
|
|
100
|
+
font-size: 0.8rem;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
</style>
|
|
105
|
+
|
|
106
|
+
<h1>PocketBase</h1>
|
|
107
|
+
<astro-dev-toolbar-badge badge-style="yellow">
|
|
108
|
+
${version}
|
|
109
|
+
</astro-dev-toolbar-badge>
|
|
110
|
+
|
|
111
|
+
<div class="actions">
|
|
112
|
+
${realtime ? `
|
|
113
|
+
<div class="toggle-container">
|
|
114
|
+
<label
|
|
115
|
+
for="real-time"
|
|
116
|
+
title="Enable or disable real-time updates temporarily"
|
|
117
|
+
>
|
|
118
|
+
Real-time updates
|
|
119
|
+
</label>
|
|
120
|
+
<!-- real-time-toggle -->
|
|
121
|
+
</div>
|
|
122
|
+
` : ""}
|
|
123
|
+
${hasContentLoader ? `
|
|
124
|
+
<astro-dev-toolbar-button
|
|
125
|
+
id="refresh-content"
|
|
126
|
+
size="small"
|
|
127
|
+
button-style="green"
|
|
128
|
+
title="Right click to force refresh every collection"
|
|
129
|
+
>
|
|
130
|
+
Refresh content
|
|
131
|
+
</astro-dev-toolbar-button>
|
|
132
|
+
` : ""}
|
|
133
|
+
</div>
|
|
134
|
+
`;
|
|
135
|
+
if (realtime) {
|
|
136
|
+
const realTimeToggle = document.createElement("astro-dev-toolbar-toggle");
|
|
137
|
+
realTimeToggle.input.id = "real-time-toggle";
|
|
138
|
+
realTimeToggle.input.title = "Enable or disable real-time updates temporarily";
|
|
139
|
+
realTimeToggle.input.checked = !(localStorage.getItem("astro-integration-pocketbase:real-time") === "false");
|
|
140
|
+
realTimeToggle.input.addEventListener("change", () => {
|
|
141
|
+
localStorage.setItem("astro-integration-pocketbase:real-time", realTimeToggle.input.checked.toString());
|
|
142
|
+
server.send("astro-integration-pocketbase:real-time", realTimeToggle.input.checked);
|
|
143
|
+
});
|
|
144
|
+
server.send("astro-integration-pocketbase:real-time", realTimeToggle.input.checked);
|
|
145
|
+
windowElement.querySelector(".toggle-container")?.append(realTimeToggle);
|
|
146
|
+
}
|
|
147
|
+
if (hasContentLoader) {
|
|
148
|
+
const refresh = windowElement.querySelector("#refresh-content");
|
|
149
|
+
if (!refresh) throw new Error("The refresh button is missing");
|
|
150
|
+
refresh.addEventListener("click", () => {
|
|
151
|
+
server.send("astro-integration-pocketbase:refresh", { force: false });
|
|
152
|
+
});
|
|
153
|
+
refresh.addEventListener("contextmenu", (event) => {
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
server.send("astro-integration-pocketbase:refresh", { force: true });
|
|
156
|
+
});
|
|
157
|
+
server.on("astro-integration-pocketbase:refresh", ({ loading }) => {
|
|
158
|
+
if (loading) {
|
|
159
|
+
refresh.textContent = "Refreshing content...";
|
|
160
|
+
refresh.buttonStyle = "gray";
|
|
161
|
+
refresh.style.pointerEvents = "none";
|
|
162
|
+
} else {
|
|
163
|
+
refresh.textContent = "Refresh content";
|
|
164
|
+
refresh.buttonStyle = "green";
|
|
165
|
+
refresh.style.pointerEvents = "unset";
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region src/toolbar/dom/create-placeholder.ts
|
|
172
|
+
/**
|
|
173
|
+
* Creates a placeholder card.
|
|
174
|
+
*/
|
|
175
|
+
function createPlaceholder() {
|
|
176
|
+
return `
|
|
177
|
+
<style>
|
|
178
|
+
#placeholder div {
|
|
179
|
+
display: flex;
|
|
180
|
+
align-items: center;
|
|
181
|
+
justify-content: center;
|
|
182
|
+
}
|
|
183
|
+
</style>
|
|
184
|
+
|
|
185
|
+
<astro-dev-toolbar-card id="placeholder">
|
|
186
|
+
<div>
|
|
187
|
+
<span> Here you will see the raw content of an entity </span>
|
|
188
|
+
</div>
|
|
189
|
+
</astro-dev-toolbar-card>
|
|
190
|
+
`;
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/toolbar/init-toolbar.ts
|
|
194
|
+
/**
|
|
195
|
+
* Initializes the PocketBase toolbar.
|
|
196
|
+
*/
|
|
197
|
+
function initToolbar(canvas, app, server) {
|
|
198
|
+
let options = {
|
|
199
|
+
realtime: false,
|
|
200
|
+
hasContentLoader: false,
|
|
201
|
+
baseUrl: ""
|
|
202
|
+
};
|
|
203
|
+
server.on("astro-integration-pocketbase:settings", (updatedOptions) => {
|
|
204
|
+
options = updatedOptions;
|
|
205
|
+
createPocketBaseWindow();
|
|
206
|
+
});
|
|
207
|
+
createPocketBaseWindow();
|
|
208
|
+
document.addEventListener("astro:after-swap", createPocketBaseWindow);
|
|
209
|
+
closeOnOutsideClick(app);
|
|
210
|
+
synchronizePlacementOnUpdate(app, canvas);
|
|
211
|
+
function createPocketBaseWindow() {
|
|
212
|
+
canvas.innerHTML = "";
|
|
213
|
+
const entities = window.__astro_entities__ || [];
|
|
214
|
+
const windowElement = createWindowElement(`
|
|
215
|
+
<style>
|
|
216
|
+
:host astro-dev-toolbar-window {
|
|
217
|
+
max-height: 480px;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
main {
|
|
221
|
+
display: flex;
|
|
222
|
+
flex-direction: column;
|
|
223
|
+
gap: 1rem;
|
|
224
|
+
overflow-y: auto;
|
|
225
|
+
}
|
|
226
|
+
</style>
|
|
227
|
+
|
|
228
|
+
<header></header>
|
|
229
|
+
|
|
230
|
+
<hr />
|
|
231
|
+
|
|
232
|
+
<main>
|
|
233
|
+
${entities.length > 0 ? createEntities(entities, options.baseUrl) : createPlaceholder()}
|
|
234
|
+
</main>
|
|
235
|
+
`);
|
|
236
|
+
createHeader(windowElement, server, options);
|
|
237
|
+
canvas.append(windowElement);
|
|
238
|
+
if (entities.length > 0) app.toggleNotification({
|
|
239
|
+
state: true,
|
|
240
|
+
level: "info"
|
|
241
|
+
});
|
|
242
|
+
else {
|
|
243
|
+
app.toggleNotification({ state: false });
|
|
244
|
+
app.toggleState({ state: false });
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region src/toolbar/index.ts
|
|
250
|
+
var toolbar_default = defineToolbarApp({ init: initToolbar });
|
|
251
|
+
//#endregion
|
|
252
|
+
export { toolbar_default as default };
|
|
253
|
+
|
|
254
|
+
//# sourceMappingURL=toolbar.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolbar.mjs","names":["packageJson.version"],"sources":["../src/toolbar/dom/create-entity.ts","../package.json","../src/toolbar/dom/create-header.ts","../src/toolbar/dom/create-placeholder.ts","../src/toolbar/init-toolbar.ts","../src/toolbar/index.ts"],"sourcesContent":["import type { Entity } from \"../types/entity\";\n\n/**\n * Creates cards for the entities.\n */\nexport function createEntities(data: Array<Entity>, baseUrl: string): string {\n const groupedData = Object.groupBy(data, (data) => data.collectionName);\n const collections = Object.keys(groupedData);\n\n return /* HTML */ `\n <style>\n .collectionName {\n text-transform: capitalize;\n }\n\n .entity {\n position: relative;\n\n pre {\n margin: 0;\n overflow: auto;\n }\n\n astro-dev-toolbar-button {\n position: absolute;\n top: 0;\n right: 0;\n }\n }\n </style>\n\n ${collections\n .map(\n (collection) => /* HTML */ `\n <b class=\".collectionName\">${collection}</b>\n ${groupedData[collection]\n ?.map((entity) => createEntity(entity, baseUrl))\n .join(\"\")}\n `\n )\n .join(\"\")}\n `;\n}\n\n/**\n * Creates a card for a single entity\n */\nfunction createEntity(data: Entity, baseUrl: string): string {\n return /* HTML */ `\n <astro-dev-toolbar-card>\n <div class=\"entity\">\n <pre>${JSON.stringify(data, undefined, 2).replaceAll(\"<\", \"<\")}</pre>\n\n ${baseUrl\n ? /* HTML */ `\n <astro-dev-toolbar-button\n size=\"small\"\n button-style=\"purple\"\n title=\"View in PocketBase\"\n onclick=\"window.open('${baseUrl}/_/#/collections?collection=${data.collectionId}&recordId=${data.id}&record=${data.id}', '_blank')\"\n >\n View in PocketBase\n </astro-dev-toolbar-button>\n `\n : \"\"}\n </div>\n </astro-dev-toolbar-card>\n `;\n}\n","","import type { ToolbarServerHelpers } from \"astro\";\nimport type { DevToolbarButton } from \"astro/runtime/client/dev-toolbar/ui-library/button.js\";\nimport type { DevToolbarWindow } from \"astro/runtime/client/dev-toolbar/ui-library/window.js\";\nimport { default as packageJson } from \"../../../package.json\";\nimport type { ToolbarOptions } from \"../types/options\";\n\n/**\n * Creates the header for the PocketBase toolbar.\n */\n// oxlint-disable-next-line max-lines-per-function\nexport function createHeader(\n windowElement: DevToolbarWindow,\n server: ToolbarServerHelpers,\n { hasContentLoader, realtime }: ToolbarOptions\n): void {\n const header = windowElement.querySelector(\"header\");\n if (!header) {\n throw new Error(\"The header element is missing\");\n }\n\n header.innerHTML = /* HTML */ `\n <style>\n header {\n display: grid;\n grid-template-columns: auto auto 1fr;\n gap: 0.5rem;\n }\n\n h1 {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n color: #fff;\n margin: 0;\n font-size: 22px;\n }\n\n .actions {\n display: flex;\n align-items: start;\n justify-content: flex-end;\n gap: 0.25rem;\n\n .toggle-container {\n display: flex;\n align-items: center;\n\n label {\n font-size: 0.8rem;\n }\n }\n }\n </style>\n\n <h1>PocketBase</h1>\n <astro-dev-toolbar-badge badge-style=\"yellow\">\n ${packageJson.version}\n </astro-dev-toolbar-badge>\n\n <div class=\"actions\">\n ${realtime\n ? /* HTML */ `\n <div class=\"toggle-container\">\n <label\n for=\"real-time\"\n title=\"Enable or disable real-time updates temporarily\"\n >\n Real-time updates\n </label>\n <!-- real-time-toggle -->\n </div>\n `\n : \"\"}\n ${hasContentLoader\n ? /* HTML */ `\n <astro-dev-toolbar-button\n id=\"refresh-content\"\n size=\"small\"\n button-style=\"green\"\n title=\"Right click to force refresh every collection\"\n >\n Refresh content\n </astro-dev-toolbar-button>\n `\n : \"\"}\n </div>\n `;\n\n if (realtime) {\n // Create the toggle for real-time updates\n const realTimeToggle = document.createElement(\"astro-dev-toolbar-toggle\");\n realTimeToggle.input.id = \"real-time-toggle\";\n realTimeToggle.input.title =\n \"Enable or disable real-time updates temporarily\";\n // Set the toggle state based on the local storage, default to true\n realTimeToggle.input.checked = !(\n localStorage.getItem(\"astro-integration-pocketbase:real-time\") === \"false\"\n );\n realTimeToggle.input.addEventListener(\"change\", () => {\n // Store the toggle state in the local storage\n localStorage.setItem(\n \"astro-integration-pocketbase:real-time\",\n realTimeToggle.input.checked.toString()\n );\n\n // Send the toggle state to the server\n server.send(\n \"astro-integration-pocketbase:real-time\",\n realTimeToggle.input.checked\n );\n });\n // Send the initial toggle state to the server\n server.send(\n \"astro-integration-pocketbase:real-time\",\n realTimeToggle.input.checked\n );\n windowElement.querySelector(\".toggle-container\")?.append(realTimeToggle);\n }\n\n if (hasContentLoader) {\n // Add click listeners to the refresh button\n const refresh =\n windowElement.querySelector<DevToolbarButton>(\"#refresh-content\");\n if (!refresh) {\n throw new Error(\"The refresh button is missing\");\n }\n\n refresh.addEventListener(\"click\", () => {\n server.send(\"astro-integration-pocketbase:refresh\", { force: false });\n });\n refresh.addEventListener(\"contextmenu\", (event) => {\n event.preventDefault();\n server.send(\"astro-integration-pocketbase:refresh\", { force: true });\n });\n\n server.on(\n \"astro-integration-pocketbase:refresh\",\n ({ loading }: { loading?: boolean }) => {\n // Show loading state while refreshing content\n if (loading) {\n refresh.textContent = \"Refreshing content...\";\n refresh.buttonStyle = \"gray\";\n refresh.style.pointerEvents = \"none\";\n } else {\n refresh.textContent = \"Refresh content\";\n refresh.buttonStyle = \"green\";\n refresh.style.pointerEvents = \"unset\";\n }\n }\n );\n }\n}\n","/**\n * Creates a placeholder card.\n */\nexport function createPlaceholder(): string {\n return /* HTML */ `\n <style>\n #placeholder div {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n </style>\n\n <astro-dev-toolbar-card id=\"placeholder\">\n <div>\n <span> Here you will see the raw content of an entity </span>\n </div>\n </astro-dev-toolbar-card>\n `;\n}\n","import {\n closeOnOutsideClick,\n createWindowElement,\n synchronizePlacementOnUpdate\n} from \"astro/runtime/client/dev-toolbar/apps/utils/window.js\";\nimport type {\n ToolbarAppEventTarget,\n ToolbarServerHelpers\n} from \"astro/runtime/client/dev-toolbar/helpers.js\";\nimport { createEntities, createHeader, createPlaceholder } from \"./dom\";\nimport type { Entity } from \"./types/entity\";\nimport type { ToolbarOptions } from \"./types/options\";\n\ndeclare global {\n interface Window {\n __astro_entities__?: Array<Entity>;\n }\n}\n\n/**\n * Initializes the PocketBase toolbar.\n */\nexport function initToolbar(\n canvas: ShadowRoot,\n app: ToolbarAppEventTarget,\n server: ToolbarServerHelpers\n): void {\n // Options for the toolbar\n let options: ToolbarOptions = {\n realtime: false,\n hasContentLoader: false,\n baseUrl: \"\"\n };\n\n // Update the options and refresh the toolbar\n server.on(\n \"astro-integration-pocketbase:settings\",\n (updatedOptions: ToolbarOptions) => {\n options = updatedOptions;\n createPocketBaseWindow();\n }\n );\n\n // Create the window (for every page navigation)\n createPocketBaseWindow();\n document.addEventListener(\"astro:after-swap\", createPocketBaseWindow);\n\n // Setup the window\n closeOnOutsideClick(app);\n synchronizePlacementOnUpdate(app, canvas);\n\n function createPocketBaseWindow(): void {\n // Clear any existing content\n canvas.innerHTML = \"\";\n\n const entities = window.__astro_entities__ || [];\n\n // Create the main window element\n const windowElement = createWindowElement(/* HTML */ `\n <style>\n :host astro-dev-toolbar-window {\n max-height: 480px;\n }\n\n main {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n overflow-y: auto;\n }\n </style>\n\n <header></header>\n\n <hr />\n\n <main>\n ${entities.length > 0\n ? createEntities(entities, options.baseUrl)\n : createPlaceholder()}\n </main>\n `);\n\n // Create and insert the header\n createHeader(windowElement, server, options);\n\n // Add the window to the canvas\n canvas.append(windowElement);\n\n // Update the toolbar depending on the current state\n if (entities.length > 0) {\n app.toggleNotification({ state: true, level: \"info\" });\n } else {\n app.toggleNotification({ state: false });\n app.toggleState({ state: false });\n }\n }\n}\n","import { defineToolbarApp } from \"astro/toolbar\";\nimport { initToolbar } from \"./init-toolbar\";\n\nexport default defineToolbarApp({\n init: initToolbar\n});\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro-integration-pocketbase",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.2-next.2",
|
|
4
4
|
"description": "An Astro integration to support developers working with astro-loader-pocketbase.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro",
|
|
@@ -23,41 +23,51 @@
|
|
|
23
23
|
"url": "git+https://github.com/pawcoding/astro-integration-pocketbase.git"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
|
-
"
|
|
27
|
-
"index.ts"
|
|
26
|
+
"dist"
|
|
28
27
|
],
|
|
29
28
|
"type": "module",
|
|
29
|
+
"types": "./dist/index.d.mts",
|
|
30
30
|
"exports": {
|
|
31
|
-
".": "./index.
|
|
31
|
+
".": "./dist/index.mjs",
|
|
32
|
+
"./middleware": "./dist/middleware.mjs",
|
|
33
|
+
"./toolbar": "./dist/toolbar.mjs",
|
|
34
|
+
"./package.json": "./package.json"
|
|
32
35
|
},
|
|
33
36
|
"publishConfig": {
|
|
34
37
|
"access": "public",
|
|
35
38
|
"provenance": true
|
|
36
39
|
},
|
|
37
40
|
"scripts": {
|
|
41
|
+
"build": "tsdown",
|
|
38
42
|
"format": "oxfmt",
|
|
39
43
|
"format:check": "oxfmt --check",
|
|
40
44
|
"lint": "oxlint --type-aware --type-check",
|
|
41
45
|
"lint:fix": "oxlint --type-aware --type-check --fix",
|
|
42
46
|
"prepare": "husky",
|
|
47
|
+
"prepublishOnly": "npm run build",
|
|
43
48
|
"typecheck": "npx @typescript/native-preview --noEmit -p src/tsconfig.json"
|
|
44
49
|
},
|
|
45
50
|
"devDependencies": {
|
|
46
|
-
"@commitlint/cli": "
|
|
47
|
-
"@commitlint/config-conventional": "
|
|
48
|
-
"@types/node": "24.12.
|
|
49
|
-
"astro": "6.2
|
|
51
|
+
"@commitlint/cli": "21.0.2",
|
|
52
|
+
"@commitlint/config-conventional": "21.0.2",
|
|
53
|
+
"@types/node": "24.12.4",
|
|
54
|
+
"astro": "6.4.2",
|
|
50
55
|
"eventsource": "4.1.0",
|
|
51
56
|
"globals": "17.6.0",
|
|
52
57
|
"husky": "9.1.7",
|
|
53
|
-
"lint-staged": "
|
|
54
|
-
"oxfmt": "0.
|
|
55
|
-
"oxlint": "1.
|
|
56
|
-
"oxlint-tsgolint": "0.
|
|
58
|
+
"lint-staged": "17.0.6",
|
|
59
|
+
"oxfmt": "0.52.0",
|
|
60
|
+
"oxlint": "1.67.0",
|
|
61
|
+
"oxlint-tsgolint": "0.23.0",
|
|
62
|
+
"publint": "0.3.21",
|
|
63
|
+
"tsdown": "0.22.1"
|
|
57
64
|
},
|
|
58
65
|
"peerDependencies": {
|
|
59
66
|
"astro": "^6.0.0",
|
|
60
67
|
"eventsource": "^4.0.0"
|
|
61
68
|
},
|
|
62
|
-
"
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=22.12.0"
|
|
71
|
+
},
|
|
72
|
+
"packageManager": "npm@11.16.0"
|
|
63
73
|
}
|
package/index.ts
DELETED
package/src/core/index.ts
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import type { AstroIntegrationLogger, BaseIntegrationHooks } from "astro";
|
|
2
|
-
import { EventSource } from "eventsource";
|
|
3
|
-
import type { PocketBaseIntegrationOptions } from "../types/pocketbase-integration-options.type";
|
|
4
|
-
import { getSuperuserToken } from "../utils/get-superuser-token";
|
|
5
|
-
import { mapCollectionsToWatch } from "../utils/map-collections-to-watch";
|
|
6
|
-
|
|
7
|
-
export function refreshCollectionsRealtime(
|
|
8
|
-
options: PocketBaseIntegrationOptions,
|
|
9
|
-
{
|
|
10
|
-
logger,
|
|
11
|
-
refreshContent,
|
|
12
|
-
toolbar
|
|
13
|
-
}: Parameters<BaseIntegrationHooks["astro:server:setup"]>[0]
|
|
14
|
-
): EventSource | undefined {
|
|
15
|
-
// Check if collections should be watched
|
|
16
|
-
const collectionsMap = mapCollectionsToWatch(options.collectionsToWatch);
|
|
17
|
-
if (!collectionsMap) {
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
const remoteCollections = [...collectionsMap.keys()];
|
|
21
|
-
|
|
22
|
-
// Check if content loader is used
|
|
23
|
-
if (!refreshContent) {
|
|
24
|
-
logger.warn(
|
|
25
|
-
"No content loader available, skipping subscription to PocketBase realtime API."
|
|
26
|
-
);
|
|
27
|
-
return undefined;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Check if EventSource is available
|
|
31
|
-
// oxlint-disable-next-line no-unnecessary-condition
|
|
32
|
-
if (!EventSource) {
|
|
33
|
-
logger.warn(
|
|
34
|
-
"EventSource is not available, skipping subscription to PocketBase realtime API.\n" +
|
|
35
|
-
"Please install the 'eventsource' package."
|
|
36
|
-
);
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
let refreshEnabled = true;
|
|
41
|
-
// Enable or disable real-time updates via the toolbar
|
|
42
|
-
toolbar.on("astro-integration-pocketbase:real-time", (enabled: boolean) => {
|
|
43
|
-
refreshEnabled = enabled;
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const eventSourceUrl = new URL("api/realtime", options.url).href;
|
|
47
|
-
const eventSource = new EventSource(eventSourceUrl);
|
|
48
|
-
let wasConnectedOnce = false;
|
|
49
|
-
let isConnected = false;
|
|
50
|
-
|
|
51
|
-
// Log potential errors
|
|
52
|
-
// oxlint-disable-next-line prefer-await-to-callbacks
|
|
53
|
-
eventSource.addEventListener("error", (error) => {
|
|
54
|
-
isConnected = false;
|
|
55
|
-
|
|
56
|
-
// Wait for 5 seconds in case of a connection error
|
|
57
|
-
setTimeout(() => {
|
|
58
|
-
if (isConnected) {
|
|
59
|
-
// Connection was automatically re-established, no need to log the error
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
logger.error(
|
|
64
|
-
`Error while connecting to PocketBase realtime API: ${error.type}`
|
|
65
|
-
);
|
|
66
|
-
}, 5000);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// Add event listeners for all collections
|
|
70
|
-
for (const collection of remoteCollections) {
|
|
71
|
-
eventSource.addEventListener(
|
|
72
|
-
`${collection}/*`,
|
|
73
|
-
async (event: MessageEvent<string>) => {
|
|
74
|
-
// Do not refresh if the refresh is disabled
|
|
75
|
-
if (!refreshEnabled) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Refresh the content
|
|
80
|
-
logger.info(`Received update for ${collection}. Refreshing content...`);
|
|
81
|
-
await refreshContent({
|
|
82
|
-
loaders: ["pocketbase-loader"],
|
|
83
|
-
context: {
|
|
84
|
-
source: "astro-integration-pocketbase",
|
|
85
|
-
collection: collectionsMap.get(collection),
|
|
86
|
-
// oxlint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
87
|
-
data: JSON.parse(event.data)
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Add event listener for the connection event
|
|
95
|
-
eventSource.addEventListener(
|
|
96
|
-
"PB_CONNECT",
|
|
97
|
-
async (event: MessageEvent<void>) => {
|
|
98
|
-
isConnected = await handleConnectEvent(
|
|
99
|
-
event,
|
|
100
|
-
remoteCollections,
|
|
101
|
-
wasConnectedOnce,
|
|
102
|
-
options,
|
|
103
|
-
logger
|
|
104
|
-
);
|
|
105
|
-
if (isConnected) {
|
|
106
|
-
wasConnectedOnce = true;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
return eventSource;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async function handleConnectEvent(
|
|
115
|
-
event: MessageEvent<void>,
|
|
116
|
-
remoteCollections: Array<string>,
|
|
117
|
-
wasConnectedOnce: boolean,
|
|
118
|
-
options: PocketBaseIntegrationOptions,
|
|
119
|
-
logger: AstroIntegrationLogger
|
|
120
|
-
): Promise<boolean> {
|
|
121
|
-
// Extract the clientId
|
|
122
|
-
const clientId = event.lastEventId;
|
|
123
|
-
|
|
124
|
-
// Get the superuser token if credentials are available
|
|
125
|
-
let superuserToken: string | undefined;
|
|
126
|
-
if (options.superuserCredentials) {
|
|
127
|
-
if ("impersonateToken" in options.superuserCredentials) {
|
|
128
|
-
superuserToken = options.superuserCredentials.impersonateToken;
|
|
129
|
-
} else {
|
|
130
|
-
superuserToken = await getSuperuserToken(
|
|
131
|
-
options.url,
|
|
132
|
-
options.superuserCredentials,
|
|
133
|
-
logger
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Subscribe to the PocketBase realtime API
|
|
139
|
-
const subscriptionUrl = new URL("api/realtime", options.url).href;
|
|
140
|
-
const result = await fetch(subscriptionUrl, {
|
|
141
|
-
method: "POST",
|
|
142
|
-
headers: {
|
|
143
|
-
"Content-Type": "application/json",
|
|
144
|
-
Authorization: superuserToken || ""
|
|
145
|
-
},
|
|
146
|
-
body: JSON.stringify({
|
|
147
|
-
clientId,
|
|
148
|
-
subscriptions: remoteCollections.map((collection) => `${collection}/*`)
|
|
149
|
-
})
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// Log the connection status
|
|
153
|
-
if (!result.ok) {
|
|
154
|
-
logger.error(
|
|
155
|
-
`Error while subscribing to PocketBase realtime API: ${result.status}`
|
|
156
|
-
);
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (!wasConnectedOnce) {
|
|
161
|
-
logger.info(
|
|
162
|
-
`Subscribed to PocketBase realtime API. Waiting for updates on ${remoteCollections.join(
|
|
163
|
-
", "
|
|
164
|
-
)}.`
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { BaseIntegrationHooks } from "astro";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Listen for the refresh event of the toolbar.
|
|
5
|
-
* When the event is triggered in the toolbar, refresh the content loaded by the PocketBase loader.
|
|
6
|
-
*/
|
|
7
|
-
export function handleRefreshCollections({
|
|
8
|
-
toolbar,
|
|
9
|
-
refreshContent,
|
|
10
|
-
logger
|
|
11
|
-
}: Parameters<BaseIntegrationHooks["astro:server:setup"]>[0]): void {
|
|
12
|
-
if (!refreshContent) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
logger.info("Setting up refresh listener for PocketBase integration");
|
|
17
|
-
|
|
18
|
-
// Listen for the refresh event of the toolbar
|
|
19
|
-
toolbar.on(
|
|
20
|
-
"astro-integration-pocketbase:refresh",
|
|
21
|
-
// oxlint-disable-next-line strict-void-return
|
|
22
|
-
async ({ force }: { force: boolean }) => {
|
|
23
|
-
// Send a loading state to the toolbar
|
|
24
|
-
toolbar.send("astro-integration-pocketbase:refresh", {
|
|
25
|
-
loading: true
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Refresh content loaded by the PocketBase loader
|
|
29
|
-
logger.info(
|
|
30
|
-
`Refreshing ${force ? "all " : ""}content loaded by PocketBase loader`
|
|
31
|
-
);
|
|
32
|
-
await refreshContent({
|
|
33
|
-
loaders: ["pocketbase-loader"],
|
|
34
|
-
context: {
|
|
35
|
-
source: "astro-integration-pocketbase",
|
|
36
|
-
force
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// Reset the loading state in the toolbar
|
|
41
|
-
toolbar.send("astro-integration-pocketbase:refresh", {
|
|
42
|
-
loading: false
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
);
|
|
46
|
-
}
|
package/src/middleware/index.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { defineMiddleware } from "astro/middleware";
|
|
2
|
-
import type { PocketBaseEntry } from "./is-pocketbase-entry";
|
|
3
|
-
import { isPocketbaseEntry } from "./is-pocketbase-entry";
|
|
4
|
-
|
|
5
|
-
export const onRequest = defineMiddleware(async (context, next) => {
|
|
6
|
-
// Look for entities given as props to the page
|
|
7
|
-
const props = Object.values(context.props);
|
|
8
|
-
const entities = findEntitiesRecursive(props).map((entity) => entity.data);
|
|
9
|
-
|
|
10
|
-
const response = await next();
|
|
11
|
-
const contentType = response.headers.get("content-type");
|
|
12
|
-
if (!contentType?.includes("text/html")) {
|
|
13
|
-
// Pass through non-HTML responses unchanged
|
|
14
|
-
return response;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const body = await response.text();
|
|
18
|
-
|
|
19
|
-
// Append the entities to the <head>
|
|
20
|
-
const entitiesJson = JSON.stringify(entities);
|
|
21
|
-
const newBody = body.replace(
|
|
22
|
-
"</head>",
|
|
23
|
-
`<script>window.__astro_entities__ = ${entitiesJson}</script></head>`
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
return new Response(newBody, response);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Find PocketBase entities in the given data.
|
|
31
|
-
*/
|
|
32
|
-
function findEntitiesRecursive(data: unknown): Array<PocketBaseEntry> {
|
|
33
|
-
// Check if the data is an array and search for entities in each element
|
|
34
|
-
if (Array.isArray(data)) {
|
|
35
|
-
return data.flatMap((item) => findEntitiesRecursive(item));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (typeof data === "object" && data !== null) {
|
|
39
|
-
// Check if the data is an object and a PocketBase entry
|
|
40
|
-
if (isPocketbaseEntry(data)) {
|
|
41
|
-
return [data];
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Search for entities in all values
|
|
45
|
-
return findEntitiesRecursive(Object.values(data));
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// No entities found
|
|
49
|
-
return [];
|
|
50
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { z } from "astro/zod";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Schema for a PocketBase entry created with [astro-loader-pocketbase](https://github.com/pawcoding/astro-loader-pocketbase)
|
|
5
|
-
*/
|
|
6
|
-
const pocketbaseEntrySchema = z.object({
|
|
7
|
-
id: z.string(),
|
|
8
|
-
data: z.object({
|
|
9
|
-
id: z.string(),
|
|
10
|
-
collectionId: z.string(),
|
|
11
|
-
collectionName: z.string()
|
|
12
|
-
}),
|
|
13
|
-
digest: z.string().length(16),
|
|
14
|
-
collection: z.string()
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Type for a PocketBase entry created with [astro-loader-pocketbase](https://github.com/pawcoding/astro-loader-pocketbase)
|
|
19
|
-
*/
|
|
20
|
-
export type PocketBaseEntry = z.infer<typeof pocketbaseEntrySchema>;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Checks if the given data is a PocketBase entry.
|
|
24
|
-
*/
|
|
25
|
-
export function isPocketbaseEntry(data: unknown): data is PocketBaseEntry {
|
|
26
|
-
try {
|
|
27
|
-
// Try to parse the data with the PocketBase entry schema
|
|
28
|
-
pocketbaseEntrySchema.parse(data);
|
|
29
|
-
return true;
|
|
30
|
-
} catch {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
}
|