astro-loader-pocketbase 2.8.2-next.4 → 2.9.0-next.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 +11 -0
- package/package.json +1 -1
- package/src/index.ts +6 -1
- package/src/loader/fetch-collection.ts +21 -4
- package/src/loader/fetch-entry.ts +19 -4
- package/src/loader/live-collection-loader.ts +19 -2
- package/src/loader/live-entry-loader.ts +19 -2
- package/src/loader/parse-live-entry.ts +9 -10
- package/src/pocketbase-loader.ts +7 -3
- package/src/types/errors.ts +19 -0
package/README.md
CHANGED
|
@@ -309,6 +309,17 @@ const blogLive = defineLiveCollection({
|
|
|
309
309
|
});
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
+
### Error handling
|
|
313
|
+
|
|
314
|
+
The live content loader follows Astro's standard error handling conventions for live collections. For more information on how to handle errors in your components, see the [Astro documentation on error handling](https://docs.astro.build/en/reference/experimental-flags/live-content-collections/#error-handling).
|
|
315
|
+
|
|
316
|
+
| Error | When it's returned |
|
|
317
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
318
|
+
| `PocketBaseAuthenticationError` | Authentication or authorization fails (missing credentials or invalid token) |
|
|
319
|
+
| `LiveEntryNotFoundError` | The requested entry doesn't exist or doesn't match the applied filters |
|
|
320
|
+
| `LiveCollectionValidationError` | The data returned by PocketBase doesn't match the Zod schema or the `updatedField` doesn't contain valid data |
|
|
321
|
+
| `LiveCollectionError` | Any other error occurs (network errors, invalid filter syntax, PocketBase server errors, etc.) |
|
|
322
|
+
|
|
312
323
|
### Caveats
|
|
313
324
|
|
|
314
325
|
Live content loaders do not (yet 🤞🏼) support zod schemas and thus schema generation and entry transformation.
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
experimentalPocketbaseLiveLoader,
|
|
3
3
|
pocketbaseLoader
|
|
4
4
|
} from "./pocketbase-loader";
|
|
5
|
+
import { PocketBaseAuthenticationError } from "./types/errors";
|
|
5
6
|
import type {
|
|
6
7
|
ExperimentalPocketBaseLiveLoaderCollectionFilter,
|
|
7
8
|
ExperimentalPocketBaseLiveLoaderEntryFilter
|
|
@@ -11,7 +12,11 @@ import type {
|
|
|
11
12
|
PocketBaseLoaderOptions
|
|
12
13
|
} from "./types/pocketbase-loader-options.type";
|
|
13
14
|
|
|
14
|
-
export {
|
|
15
|
+
export {
|
|
16
|
+
experimentalPocketbaseLiveLoader,
|
|
17
|
+
PocketBaseAuthenticationError,
|
|
18
|
+
pocketbaseLoader
|
|
19
|
+
};
|
|
15
20
|
export type {
|
|
16
21
|
ExperimentalPocketBaseLiveLoaderCollectionFilter,
|
|
17
22
|
ExperimentalPocketBaseLiveLoaderEntryFilter,
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LiveCollectionError,
|
|
3
|
+
LiveEntryNotFoundError
|
|
4
|
+
} from "astro/content/runtime";
|
|
5
|
+
import { PocketBaseAuthenticationError } from "../types/errors";
|
|
1
6
|
import {
|
|
2
7
|
pocketBaseErrorResponse,
|
|
3
8
|
pocketBaseListResponse
|
|
@@ -72,20 +77,32 @@ export async function fetchCollection<TEntry extends PocketBaseEntry>(
|
|
|
72
77
|
options.superuserCredentials &&
|
|
73
78
|
"impersonateToken" in options.superuserCredentials
|
|
74
79
|
) {
|
|
75
|
-
throw new
|
|
80
|
+
throw new PocketBaseAuthenticationError(
|
|
81
|
+
options.collectionName,
|
|
82
|
+
"The given impersonate token is not valid."
|
|
83
|
+
);
|
|
76
84
|
} else {
|
|
77
|
-
throw new
|
|
85
|
+
throw new PocketBaseAuthenticationError(
|
|
86
|
+
options.collectionName,
|
|
78
87
|
"The collection is not accessible without superuser rights. Please provide superuser credentials in the config."
|
|
79
88
|
);
|
|
80
89
|
}
|
|
81
90
|
}
|
|
82
91
|
|
|
92
|
+
if (collectionRequest.status === 404) {
|
|
93
|
+
throw new LiveEntryNotFoundError(options.collectionName, {
|
|
94
|
+
...collectionFilter
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
83
98
|
// Get the reason for the error
|
|
84
99
|
const errorResponse = pocketBaseErrorResponse.parse(
|
|
85
100
|
await collectionRequest.json()
|
|
86
101
|
);
|
|
87
|
-
|
|
88
|
-
|
|
102
|
+
throw new LiveCollectionError(
|
|
103
|
+
options.collectionName,
|
|
104
|
+
errorResponse.message
|
|
105
|
+
);
|
|
89
106
|
}
|
|
90
107
|
|
|
91
108
|
// Get the data from the response
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LiveCollectionError,
|
|
3
|
+
LiveEntryNotFoundError
|
|
4
|
+
} from "astro/content/runtime";
|
|
5
|
+
import { PocketBaseAuthenticationError } from "../types/errors";
|
|
1
6
|
import { pocketBaseErrorResponse } from "../types/pocketbase-api-response.type";
|
|
2
7
|
import type { PocketBaseEntry } from "../types/pocketbase-entry.type";
|
|
3
8
|
import { pocketBaseEntry } from "../types/pocketbase-entry.type";
|
|
@@ -45,20 +50,30 @@ export async function fetchEntry<TEntry extends PocketBaseEntry>(
|
|
|
45
50
|
options.superuserCredentials &&
|
|
46
51
|
"impersonateToken" in options.superuserCredentials
|
|
47
52
|
) {
|
|
48
|
-
throw new
|
|
53
|
+
throw new PocketBaseAuthenticationError(
|
|
54
|
+
options.collectionName,
|
|
55
|
+
"The given impersonate token is not valid."
|
|
56
|
+
);
|
|
49
57
|
} else {
|
|
50
|
-
throw new
|
|
58
|
+
throw new PocketBaseAuthenticationError(
|
|
59
|
+
options.collectionName,
|
|
51
60
|
"The entry is not accessible without superuser rights. Please provide superuser credentials in the config."
|
|
52
61
|
);
|
|
53
62
|
}
|
|
54
63
|
}
|
|
55
64
|
|
|
65
|
+
if (entryRequest.status === 404) {
|
|
66
|
+
throw new LiveEntryNotFoundError(options.collectionName, id);
|
|
67
|
+
}
|
|
68
|
+
|
|
56
69
|
// Get the reason for the error
|
|
57
70
|
const errorResponse = pocketBaseErrorResponse.parse(
|
|
58
71
|
await entryRequest.json()
|
|
59
72
|
);
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
throw new LiveCollectionError(
|
|
74
|
+
options.collectionName,
|
|
75
|
+
errorResponse.message
|
|
76
|
+
);
|
|
62
77
|
}
|
|
63
78
|
|
|
64
79
|
// Get the data from the response
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LiveDataCollection, LiveDataEntry } from "astro";
|
|
2
|
+
import { LiveCollectionError } from "astro/content/runtime";
|
|
2
3
|
import type { PocketBaseEntry } from "../types/pocketbase-entry.type";
|
|
3
4
|
import type { ExperimentalPocketBaseLiveLoaderCollectionFilter } from "../types/pocketbase-live-loader-filter.type";
|
|
4
5
|
import type { ExperimentalPocketBaseLiveLoaderOptions } from "../types/pocketbase-loader-options.type";
|
|
@@ -14,7 +15,7 @@ export async function liveCollectionLoader<TEntry extends PocketBaseEntry>(
|
|
|
14
15
|
| undefined,
|
|
15
16
|
options: ExperimentalPocketBaseLiveLoaderOptions,
|
|
16
17
|
token: string | undefined
|
|
17
|
-
): Promise<LiveDataCollection<TEntry> | { error:
|
|
18
|
+
): Promise<LiveDataCollection<TEntry> | { error: LiveCollectionError }> {
|
|
18
19
|
const entries: Array<LiveDataEntry<TEntry>> = [];
|
|
19
20
|
|
|
20
21
|
try {
|
|
@@ -27,7 +28,23 @@ export async function liveCollectionLoader<TEntry extends PocketBaseEntry>(
|
|
|
27
28
|
collectionFilter
|
|
28
29
|
);
|
|
29
30
|
} catch (error) {
|
|
30
|
-
|
|
31
|
+
if (error instanceof LiveCollectionError) {
|
|
32
|
+
return { error };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (error instanceof Error) {
|
|
36
|
+
return {
|
|
37
|
+
error: new LiveCollectionError(
|
|
38
|
+
options.collectionName,
|
|
39
|
+
error.message,
|
|
40
|
+
error
|
|
41
|
+
)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
error: new LiveCollectionError(options.collectionName, String(error))
|
|
47
|
+
};
|
|
31
48
|
}
|
|
32
49
|
|
|
33
50
|
return {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LiveDataEntry } from "astro";
|
|
2
|
+
import { LiveCollectionError } from "astro/content/runtime";
|
|
2
3
|
import type { PocketBaseEntry } from "../types/pocketbase-entry.type";
|
|
3
4
|
import type { ExperimentalPocketBaseLiveLoaderOptions } from "../types/pocketbase-loader-options.type";
|
|
4
5
|
import { fetchEntry } from "./fetch-entry";
|
|
@@ -11,11 +12,27 @@ export async function liveEntryLoader<TEntry extends PocketBaseEntry>(
|
|
|
11
12
|
id: string,
|
|
12
13
|
options: ExperimentalPocketBaseLiveLoaderOptions,
|
|
13
14
|
token: string | undefined
|
|
14
|
-
): Promise<LiveDataEntry<TEntry> | { error:
|
|
15
|
+
): Promise<LiveDataEntry<TEntry> | { error: LiveCollectionError }> {
|
|
15
16
|
try {
|
|
16
17
|
const entry = await fetchEntry<TEntry>(id, options, token);
|
|
17
18
|
return parseLiveEntry(entry, options);
|
|
18
19
|
} catch (error) {
|
|
19
|
-
|
|
20
|
+
if (error instanceof LiveCollectionError) {
|
|
21
|
+
return { error };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (error instanceof Error) {
|
|
25
|
+
return {
|
|
26
|
+
error: new LiveCollectionError(
|
|
27
|
+
options.collectionName,
|
|
28
|
+
error.message,
|
|
29
|
+
error
|
|
30
|
+
)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
error: new LiveCollectionError(options.collectionName, String(error))
|
|
36
|
+
};
|
|
20
37
|
}
|
|
21
38
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { LiveDataEntry } from "astro";
|
|
2
|
+
import { LiveCollectionValidationError } from "astro/content/runtime";
|
|
3
|
+
import { z } from "astro/zod";
|
|
2
4
|
import type { PocketBaseEntry } from "../types/pocketbase-entry.type";
|
|
3
5
|
import type { ExperimentalPocketBaseLiveLoaderOptions } from "../types/pocketbase-loader-options.type";
|
|
4
6
|
|
|
@@ -17,18 +19,15 @@ export function parseLiveEntry<TEntry extends PocketBaseEntry>(
|
|
|
17
19
|
// use it as the last modified date cache hint
|
|
18
20
|
if (options.updatedField && entry[options.updatedField]) {
|
|
19
21
|
const value = `${entry[options.updatedField]}`;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
lastModified = date;
|
|
27
|
-
} catch {
|
|
28
|
-
console.warn(
|
|
29
|
-
`Entry ${entry.id} of collection ${options.collectionName} has an invalid date in ${options.updatedField}: ${value}`
|
|
22
|
+
const date = z.coerce.date().safeParse(value);
|
|
23
|
+
if (!date.success) {
|
|
24
|
+
throw new LiveCollectionValidationError(
|
|
25
|
+
options.collectionName,
|
|
26
|
+
entry.id,
|
|
27
|
+
date.error
|
|
30
28
|
);
|
|
31
29
|
}
|
|
30
|
+
lastModified = date.data;
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
if (!options.contentFields) {
|
package/src/pocketbase-loader.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LiveDataCollection, LiveDataEntry } from "astro";
|
|
2
|
+
import type { LiveCollectionError } from "astro/content/runtime";
|
|
2
3
|
import type { LiveLoader, Loader } from "astro/loaders";
|
|
3
4
|
import type { ZodSchema } from "astro/zod";
|
|
4
5
|
import { liveCollectionLoader } from "./loader/live-collection-loader";
|
|
@@ -65,7 +66,8 @@ export function experimentalPocketbaseLiveLoader<
|
|
|
65
66
|
): LiveLoader<
|
|
66
67
|
TEntry,
|
|
67
68
|
ExperimentalPocketBaseLiveLoaderEntryFilter,
|
|
68
|
-
ExperimentalPocketBaseLiveLoaderCollectionFilter
|
|
69
|
+
ExperimentalPocketBaseLiveLoaderCollectionFilter,
|
|
70
|
+
LiveCollectionError
|
|
69
71
|
> {
|
|
70
72
|
// Create shared promise for the superuser token, which can be reused
|
|
71
73
|
const tokenPromise = createTokenPromise(options);
|
|
@@ -74,7 +76,9 @@ export function experimentalPocketbaseLiveLoader<
|
|
|
74
76
|
name: "pocketbase-live-loader",
|
|
75
77
|
loadCollection: async ({
|
|
76
78
|
filter
|
|
77
|
-
}): Promise<
|
|
79
|
+
}): Promise<
|
|
80
|
+
LiveDataCollection<TEntry> | { error: LiveCollectionError }
|
|
81
|
+
> => {
|
|
78
82
|
const token = await tokenPromise;
|
|
79
83
|
|
|
80
84
|
// Load entries from the collection
|
|
@@ -82,7 +86,7 @@ export function experimentalPocketbaseLiveLoader<
|
|
|
82
86
|
},
|
|
83
87
|
loadEntry: async ({
|
|
84
88
|
filter
|
|
85
|
-
}): Promise<LiveDataEntry<TEntry> | { error:
|
|
89
|
+
}): Promise<LiveDataEntry<TEntry> | { error: LiveCollectionError }> => {
|
|
86
90
|
const token = await tokenPromise;
|
|
87
91
|
|
|
88
92
|
// Load a single entry from the collection
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { LiveCollectionError } from "astro/content/runtime";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error thrown when there is an authentication issue with PocketBase.
|
|
5
|
+
*/
|
|
6
|
+
export class PocketBaseAuthenticationError extends LiveCollectionError {
|
|
7
|
+
constructor(collection: string, message: string) {
|
|
8
|
+
super(collection, message);
|
|
9
|
+
this.name = "PocketBaseAuthenticationError";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static is(error: unknown): error is PocketBaseAuthenticationError {
|
|
13
|
+
// This is similar to the original implementation in Astro itself.
|
|
14
|
+
return (
|
|
15
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
16
|
+
!!error && (error as Error)?.name === "PocketBaseAuthenticationError"
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|