astro-integration-pocketbase 0.2.0 → 0.3.0-realtime-rc.1
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 +27 -3
- package/index.ts +2 -0
- package/package.json +13 -11
- package/src/core/index.ts +2 -0
- package/src/core/refresh-collections-realtime.ts +134 -0
- package/src/core/refresh-collections.ts +38 -0
- package/src/pocketbase-integration.ts +26 -33
- package/src/toolbar/dom/create-header.ts +54 -6
- package/src/toolbar/init-toolbar.ts +9 -3
- package/src/toolbar/types/options.ts +17 -0
- package/src/types/pocketbase-integration-options.type.ts +28 -0
- package/src/utils/get-superuser-token.ts +46 -0
package/README.md
CHANGED
|
@@ -40,6 +40,28 @@ If you click on the icon, you can see the PocketBase entity viewer.
|
|
|
40
40
|
|
|
41
41
|
If a loader is found, the viewer will show a refresh button to reload all entries from the loaders.
|
|
42
42
|
|
|
43
|
+
## Realtime updates
|
|
44
|
+
|
|
45
|
+
PocketBase allows you to subscribe to collection changes via its [Realtime API](https://pocketbase.io/docs/api-realtime/).
|
|
46
|
+
This integration allows you to subscribe to these changes and reload the entries / collections.
|
|
47
|
+
|
|
48
|
+
If you want realtime updates for collections with a [restricted list / search rule](https://pocketbase.io/docs/api-rules-and-filters/), you need to provide superuser credentials to the integration.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
pocketbaseIntegration({
|
|
52
|
+
...options,
|
|
53
|
+
// List of PocketBase collections to watch for changes
|
|
54
|
+
collectionsToWatch: ["posts", "comments"],
|
|
55
|
+
// Superuser credentials for restricted collections (optional)
|
|
56
|
+
superuserCredentials: {
|
|
57
|
+
email: "<superuser-email>",
|
|
58
|
+
password: "<superuser-password>"
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Tip:** You can disable the realtime updates temporarily via the toolbar.
|
|
64
|
+
|
|
43
65
|
## Entity viewer
|
|
44
66
|
|
|
45
67
|
To view the PocketBase entries inside the entity viewer, you need to use `Astro.props` to pass the entries to your page (and thus to the toolbar).
|
|
@@ -82,6 +104,8 @@ The integration will automatically detect PocketBase entries in the props and di
|
|
|
82
104
|
|
|
83
105
|
## All options
|
|
84
106
|
|
|
85
|
-
| Option
|
|
86
|
-
|
|
|
87
|
-
| `url`
|
|
107
|
+
| Option | Type | Required | Description |
|
|
108
|
+
| ---------------------- | ------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
109
|
+
| `url` | `string` | x | The URL of your PocketBase instance. |
|
|
110
|
+
| `collectionsToWatch` | `Array<string>` | | Collections to watch for changes. |
|
|
111
|
+
| `superuserCredentials` | `{ email: string, password: string }` | | The email and password of a superuser of the PocketBase instance. This is used for realtime updates of restricted collection. |
|
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro-integration-pocketbase",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-realtime-rc.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Luis Wolf <development@pawcode.de> (https://pawcode.de)",
|
|
6
6
|
"homepage": "https://github.com/pawcoding/astro-integration-pocketbase",
|
|
@@ -17,18 +17,20 @@
|
|
|
17
17
|
"prepare": "husky"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"astro": "^
|
|
20
|
+
"astro": "^5.0.0",
|
|
21
|
+
"eventsource": "^3.0.2"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
|
-
"@eslint/js": "^9.
|
|
24
|
-
"@stylistic/eslint-plugin": "^2.
|
|
25
|
-
"@types/node": "^22.
|
|
26
|
-
"astro": "^5.
|
|
27
|
-
"eslint": "^9.
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"typescript
|
|
24
|
+
"@eslint/js": "^9.17.0",
|
|
25
|
+
"@stylistic/eslint-plugin": "^2.12.1",
|
|
26
|
+
"@types/node": "^22.10.2",
|
|
27
|
+
"astro": "^5.1.1",
|
|
28
|
+
"eslint": "^9.17.0",
|
|
29
|
+
"eventsource": "^3.0.2",
|
|
30
|
+
"globals": "^15.14.0",
|
|
31
|
+
"husky": "^9.1.7",
|
|
32
|
+
"typescript": "^5.7.2",
|
|
33
|
+
"typescript-eslint": "^8.18.2"
|
|
32
34
|
},
|
|
33
35
|
"keywords": [
|
|
34
36
|
"astro",
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { 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
|
+
|
|
6
|
+
export function refreshCollectionsRealtime(
|
|
7
|
+
{
|
|
8
|
+
url,
|
|
9
|
+
superuserCredentials,
|
|
10
|
+
collectionsToWatch
|
|
11
|
+
}: PocketBaseIntegrationOptions,
|
|
12
|
+
{
|
|
13
|
+
logger,
|
|
14
|
+
refreshContent,
|
|
15
|
+
toolbar
|
|
16
|
+
}: Parameters<BaseIntegrationHooks["astro:server:setup"]>[0]
|
|
17
|
+
): EventSource | undefined {
|
|
18
|
+
// Check if collections should be watched
|
|
19
|
+
if (!collectionsToWatch || collectionsToWatch.length === 0) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Check if content loader is used
|
|
24
|
+
if (!refreshContent) {
|
|
25
|
+
logger.warn(
|
|
26
|
+
"No content loader available, skipping subscription to PocketBase realtime API."
|
|
27
|
+
);
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Check if EventSource is available
|
|
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 eventSource = new EventSource(`${url}/api/realtime`);
|
|
47
|
+
let wasConnectedOnce = false;
|
|
48
|
+
let isConnected = false;
|
|
49
|
+
|
|
50
|
+
// Log potential errors
|
|
51
|
+
eventSource.onerror = (error) => {
|
|
52
|
+
isConnected = false;
|
|
53
|
+
|
|
54
|
+
// Wait for 5 seconds in case of a connection error
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
if (isConnected) {
|
|
57
|
+
// Connection was automatically re-established, no need to log the error
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
logger.error(
|
|
62
|
+
`Error while connecting to PocketBase realtime API: ${error.type}`
|
|
63
|
+
);
|
|
64
|
+
}, 5000);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Add event listeners for all collections
|
|
68
|
+
for (const collection of collectionsToWatch) {
|
|
69
|
+
eventSource.addEventListener(`${collection}/*`, async () => {
|
|
70
|
+
// Do not refresh if the refresh is disabled
|
|
71
|
+
if (!refreshEnabled) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Refresh the content
|
|
76
|
+
logger.info(`Received update for ${collection}. Refreshing content...`);
|
|
77
|
+
await refreshContent({
|
|
78
|
+
loaders: ["pocketbase-loader"],
|
|
79
|
+
// TODO: add context to refresh one or all collections
|
|
80
|
+
context: {}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Add event listener for the connection event
|
|
86
|
+
eventSource.addEventListener("PB_CONNECT", async (event) => {
|
|
87
|
+
// Extract the clientId
|
|
88
|
+
const clientId = event.lastEventId;
|
|
89
|
+
|
|
90
|
+
// Get the superuser token if credentials are available
|
|
91
|
+
let superuserToken: string | undefined;
|
|
92
|
+
if (superuserCredentials) {
|
|
93
|
+
superuserToken = await getSuperuserToken(
|
|
94
|
+
url,
|
|
95
|
+
superuserCredentials,
|
|
96
|
+
logger
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Subscribe to the PocketBase realtime API
|
|
101
|
+
const result = await fetch(`${url}/api/realtime`, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
headers: {
|
|
104
|
+
"Content-Type": "application/json",
|
|
105
|
+
Authorization: superuserToken || ""
|
|
106
|
+
},
|
|
107
|
+
body: JSON.stringify({
|
|
108
|
+
clientId: clientId,
|
|
109
|
+
subscriptions: collectionsToWatch.map((collection) => `${collection}/*`)
|
|
110
|
+
})
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Log the connection status
|
|
114
|
+
if (!result.ok) {
|
|
115
|
+
logger.error(
|
|
116
|
+
`Error while subscribing to PocketBase realtime API: ${result.status}`
|
|
117
|
+
);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!wasConnectedOnce) {
|
|
122
|
+
wasConnectedOnce = true;
|
|
123
|
+
logger.info(
|
|
124
|
+
`Subscribed to PocketBase realtime API. Waiting for updates on ${collectionsToWatch.join(
|
|
125
|
+
", "
|
|
126
|
+
)}.`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
isConnected = true;
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return eventSource;
|
|
134
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
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("astro-integration-pocketbase:refresh", async () => {
|
|
20
|
+
// Send a loading state to the toolbar
|
|
21
|
+
toolbar.send("astro-integration-pocketbase:refresh", {
|
|
22
|
+
loading: true
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Refresh content loaded by the PocketBase loader
|
|
26
|
+
logger.info("Refreshing content loaded by PocketBase loader");
|
|
27
|
+
await refreshContent({
|
|
28
|
+
loaders: ["pocketbase-loader"],
|
|
29
|
+
// TODO: add context to refresh one or all collections
|
|
30
|
+
context: {}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Reset the loading state in the toolbar
|
|
34
|
+
toolbar.send("astro-integration-pocketbase:refresh", {
|
|
35
|
+
loading: false
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { AstroIntegration } from "astro";
|
|
2
|
+
import { EventSource } from "eventsource";
|
|
2
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { handleRefreshCollections, refreshCollectionsRealtime } from "./core";
|
|
5
|
+
import type { ToolbarOptions } from "./toolbar/types/options";
|
|
6
|
+
import type { PocketBaseIntegrationOptions } from "./types/pocketbase-integration-options.type";
|
|
7
|
+
|
|
8
|
+
export function pocketbaseIntegration(
|
|
9
|
+
options: PocketBaseIntegrationOptions
|
|
10
|
+
): AstroIntegration {
|
|
11
|
+
let eventSource: EventSource | undefined = undefined;
|
|
3
12
|
|
|
4
|
-
export function pocketbaseIntegration({
|
|
5
|
-
url
|
|
6
|
-
}: {
|
|
7
|
-
url: string;
|
|
8
|
-
}): AstroIntegration {
|
|
9
13
|
return {
|
|
10
14
|
name: "pocketbase-integration",
|
|
11
15
|
hooks: {
|
|
@@ -29,38 +33,27 @@ export function pocketbaseIntegration({
|
|
|
29
33
|
entrypoint: fileURLToPath(new URL("./middleware", import.meta.url))
|
|
30
34
|
});
|
|
31
35
|
},
|
|
32
|
-
"astro:server:setup": (
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
logger.info("Setting up refresh listener for PocketBase integration");
|
|
36
|
-
// Listen for the refresh event of the toolbar
|
|
37
|
-
toolbar.on("astro-integration-pocketbase:refresh", async () => {
|
|
38
|
-
// Send a loading state to the toolbar
|
|
39
|
-
toolbar.send("astro-integration-pocketbase:refresh", {
|
|
40
|
-
loading: true
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// Refresh content loaded by the PocketBase loader
|
|
44
|
-
await refreshContent({
|
|
45
|
-
loaders: ["pocketbase-loader"],
|
|
46
|
-
// TODO: add context to refresh one or all collections
|
|
47
|
-
context: {}
|
|
48
|
-
});
|
|
36
|
+
"astro:server:setup": (setupOptions) => {
|
|
37
|
+
// Listen for the refresh event of the toolbar
|
|
38
|
+
handleRefreshCollections(setupOptions);
|
|
49
39
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
loading: false
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
}
|
|
40
|
+
// Subscribe to PocketBase realtime API
|
|
41
|
+
eventSource = refreshCollectionsRealtime(options, setupOptions);
|
|
56
42
|
|
|
57
43
|
// Send settings to the toolbar on initialization
|
|
58
|
-
toolbar.onAppInitialized("pocketbase-entry", () => {
|
|
59
|
-
toolbar.send("astro-integration-pocketbase:settings", {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
44
|
+
setupOptions.toolbar.onAppInitialized("pocketbase-entry", () => {
|
|
45
|
+
setupOptions.toolbar.send("astro-integration-pocketbase:settings", {
|
|
46
|
+
hasContentLoader: !!setupOptions.refreshContent,
|
|
47
|
+
realtime: !!eventSource,
|
|
48
|
+
baseUrl: options.url
|
|
49
|
+
} satisfies ToolbarOptions);
|
|
63
50
|
});
|
|
51
|
+
},
|
|
52
|
+
"astro:server:done": () => {
|
|
53
|
+
// Close the EventSource connection when the server is done
|
|
54
|
+
if (eventSource) {
|
|
55
|
+
eventSource.close();
|
|
56
|
+
}
|
|
64
57
|
}
|
|
65
58
|
}
|
|
66
59
|
};
|
|
@@ -2,12 +2,16 @@ import type { ToolbarServerHelpers } from "astro";
|
|
|
2
2
|
import type { DevToolbarButton } from "astro/runtime/client/dev-toolbar/ui-library/button.js";
|
|
3
3
|
import { default as packageJson } from "../../../package.json";
|
|
4
4
|
|
|
5
|
+
export interface HeaderElements {
|
|
6
|
+
header: HTMLElement;
|
|
7
|
+
refresh: DevToolbarButton;
|
|
8
|
+
toggleContainer: HTMLDivElement;
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
/**
|
|
6
12
|
* Creates the header for the PocketBase toolbar.
|
|
7
13
|
*/
|
|
8
|
-
export function createHeader(
|
|
9
|
-
server: ToolbarServerHelpers
|
|
10
|
-
): [HTMLElement, DevToolbarButton] {
|
|
14
|
+
export function createHeader(server: ToolbarServerHelpers): HeaderElements {
|
|
11
15
|
// Create the header
|
|
12
16
|
const header = document.createElement("header");
|
|
13
17
|
header.style.display = "grid";
|
|
@@ -26,18 +30,62 @@ export function createHeader(
|
|
|
26
30
|
version.badgeStyle = "yellow";
|
|
27
31
|
header.appendChild(version);
|
|
28
32
|
|
|
33
|
+
// Create the actions container
|
|
34
|
+
const actions = document.createElement("div");
|
|
35
|
+
actions.style.display = "flex";
|
|
36
|
+
actions.style.alignItems = "start";
|
|
37
|
+
actions.style.justifyContent = "flex-end";
|
|
38
|
+
actions.style.gap = "0.25rem";
|
|
39
|
+
header.appendChild(actions);
|
|
40
|
+
|
|
41
|
+
// Create the real-time toggle
|
|
42
|
+
const toggleContainer = document.createElement("div");
|
|
43
|
+
toggleContainer.style.alignItems = "center";
|
|
44
|
+
// The toggle container is hidden by default
|
|
45
|
+
toggleContainer.style.display = "none";
|
|
46
|
+
actions.appendChild(toggleContainer);
|
|
47
|
+
|
|
48
|
+
const toggleLabel = document.createElement("label");
|
|
49
|
+
toggleLabel.textContent = "Real-time updates";
|
|
50
|
+
toggleLabel.htmlFor = "real-time-toggle";
|
|
51
|
+
toggleLabel.style.fontSize = "0.8rem";
|
|
52
|
+
toggleContainer.appendChild(toggleLabel);
|
|
53
|
+
|
|
54
|
+
const toggle = document.createElement("astro-dev-toolbar-toggle");
|
|
55
|
+
toggle.input.id = "real-time-toggle";
|
|
56
|
+
// Set the toggle state based on the local storage, default to true
|
|
57
|
+
toggle.input.checked = !(
|
|
58
|
+
localStorage.getItem("astro-integration-pocketbase:real-time") === "false"
|
|
59
|
+
);
|
|
60
|
+
toggle.input.addEventListener("change", () => {
|
|
61
|
+
// Store the toggle state in the local storage
|
|
62
|
+
localStorage.setItem(
|
|
63
|
+
"astro-integration-pocketbase:real-time",
|
|
64
|
+
toggle.input.checked.toString()
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// Send the toggle state to the server
|
|
68
|
+
server.send("astro-integration-pocketbase:real-time", toggle.input.checked);
|
|
69
|
+
});
|
|
70
|
+
// Send the initial toggle state to the server
|
|
71
|
+
server.send("astro-integration-pocketbase:real-time", toggle.input.checked);
|
|
72
|
+
toggleContainer.appendChild(toggle);
|
|
73
|
+
|
|
29
74
|
// Create the refresh button
|
|
30
75
|
const refresh = document.createElement("astro-dev-toolbar-button");
|
|
31
76
|
refresh.size = "small";
|
|
32
77
|
refresh.buttonStyle = "green";
|
|
33
|
-
refresh.style.marginLeft = "auto";
|
|
34
78
|
refresh.textContent = "Refresh content";
|
|
35
79
|
// The refresh button is hidden by default
|
|
36
80
|
refresh.style.display = "none";
|
|
37
81
|
refresh.addEventListener("click", () => {
|
|
38
82
|
server.send("astro-integration-pocketbase:refresh", true);
|
|
39
83
|
});
|
|
40
|
-
|
|
84
|
+
actions.appendChild(refresh);
|
|
41
85
|
|
|
42
|
-
return
|
|
86
|
+
return {
|
|
87
|
+
header,
|
|
88
|
+
refresh,
|
|
89
|
+
toggleContainer
|
|
90
|
+
};
|
|
43
91
|
}
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
import { createEntity, createHeader, createPlaceholder } from "./dom/";
|
|
6
6
|
import { listenToNavigation } from "./page-navigation-listener";
|
|
7
7
|
import type { Entity } from "./types/entity";
|
|
8
|
+
import type { ToolbarOptions } from "./types/options";
|
|
8
9
|
|
|
9
10
|
declare global {
|
|
10
11
|
interface Window {
|
|
@@ -25,7 +26,7 @@ export async function initToolbar(
|
|
|
25
26
|
|
|
26
27
|
const container = document.createElement("astro-dev-toolbar-window");
|
|
27
28
|
|
|
28
|
-
const
|
|
29
|
+
const { header, refresh, toggleContainer } = createHeader(server);
|
|
29
30
|
container.appendChild(header);
|
|
30
31
|
|
|
31
32
|
// Container for the main content
|
|
@@ -101,12 +102,17 @@ export async function initToolbar(
|
|
|
101
102
|
|
|
102
103
|
server.on(
|
|
103
104
|
"astro-integration-pocketbase:settings",
|
|
104
|
-
({
|
|
105
|
+
({ hasContentLoader, realtime, baseUrl }: ToolbarOptions) => {
|
|
105
106
|
// Show the refresh button if a loader is available
|
|
106
|
-
if (
|
|
107
|
+
if (hasContentLoader) {
|
|
107
108
|
refresh.style.display = "unset";
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
// Show the real-time toggle if real-time updates are available
|
|
112
|
+
if (realtime) {
|
|
113
|
+
toggleContainer.style.display = "flex";
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
// Store the base URL for later use
|
|
111
117
|
pbUrl = baseUrl;
|
|
112
118
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for the toolbar.
|
|
3
|
+
*/
|
|
4
|
+
export interface ToolbarOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Whether a content loader is active.
|
|
7
|
+
*/
|
|
8
|
+
hasContentLoader: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Whether a realtime connection to PocketBase is active.
|
|
11
|
+
*/
|
|
12
|
+
realtime: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Base URL of the PocketBase instance.
|
|
15
|
+
*/
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for the PocketBase integration.
|
|
3
|
+
*/
|
|
4
|
+
export interface PocketBaseIntegrationOptions {
|
|
5
|
+
/**
|
|
6
|
+
* URL of the PocketBase instance.
|
|
7
|
+
*/
|
|
8
|
+
url: string;
|
|
9
|
+
/**
|
|
10
|
+
* Credentials of a superuser to get full access to the PocketBase instance.
|
|
11
|
+
* This is required to access all resources even if they are not public.
|
|
12
|
+
*/
|
|
13
|
+
superuserCredentials?: {
|
|
14
|
+
/**
|
|
15
|
+
* Email of the superuser.
|
|
16
|
+
*/
|
|
17
|
+
email: string;
|
|
18
|
+
/**
|
|
19
|
+
* Password of the superuser.
|
|
20
|
+
*/
|
|
21
|
+
password: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* List of PocketBase collections to watch for changes.
|
|
25
|
+
* When an entry in one of these collections changes, the content will be reloaded.
|
|
26
|
+
*/
|
|
27
|
+
collectionsToWatch?: Array<string>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { AstroIntegrationLogger } from "astro";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This function will get a superuser token from the given PocketBase instance.
|
|
5
|
+
*
|
|
6
|
+
* @param url URL of the PocketBase instance
|
|
7
|
+
* @param superuserCredentials Credentials of the superuser
|
|
8
|
+
*
|
|
9
|
+
* @returns A superuser token to access all resources of the PocketBase instance.
|
|
10
|
+
*/
|
|
11
|
+
export async function getSuperuserToken(
|
|
12
|
+
url: string,
|
|
13
|
+
superuserCredentials: {
|
|
14
|
+
email: string;
|
|
15
|
+
password: string;
|
|
16
|
+
},
|
|
17
|
+
logger: AstroIntegrationLogger
|
|
18
|
+
): Promise<string | undefined> {
|
|
19
|
+
// Build the URL for the login endpoint
|
|
20
|
+
const loginUrl = new URL(
|
|
21
|
+
`api/collections/_superusers/auth-with-password`,
|
|
22
|
+
url
|
|
23
|
+
).href;
|
|
24
|
+
|
|
25
|
+
// Create a new FormData object to send the login data
|
|
26
|
+
const loginData = new FormData();
|
|
27
|
+
loginData.set("identity", superuserCredentials.email);
|
|
28
|
+
loginData.set("password", superuserCredentials.password);
|
|
29
|
+
|
|
30
|
+
// Send the login request to get a token
|
|
31
|
+
const loginRequest = await fetch(loginUrl, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
body: loginData
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// If the login request was not successful, print the error message and return undefined
|
|
37
|
+
if (!loginRequest.ok) {
|
|
38
|
+
const reason = await loginRequest.json().then((data) => data.message);
|
|
39
|
+
const errorMessage = `The given email / password for ${url} was not correct. Astro may not have access to all resources and permissions.\nReason: ${reason}`;
|
|
40
|
+
logger.error(errorMessage);
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Return the token
|
|
45
|
+
return await loginRequest.json().then((data) => data.token);
|
|
46
|
+
}
|