astro-loader-pocketbase 2.6.2 → 2.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-loader-pocketbase",
3
- "version": "2.6.2",
3
+ "version": "2.7.0-next.1",
4
4
  "description": "A content loader for Astro that uses the PocketBase API",
5
5
  "keywords": [
6
6
  "astro",
@@ -39,7 +39,8 @@
39
39
  "test:e2e:watch": "vitest watch $(find test -name '*.e2e-spec.ts')",
40
40
  "test:unit": "vitest run $(find test -name '*.spec.ts')",
41
41
  "test:unit:watch": "vitest watch $(find test -name '*.spec.ts')",
42
- "test:watch": "vitest watch"
42
+ "test:watch": "vitest watch",
43
+ "typecheck": "npx tsc --noEmit"
43
44
  },
44
45
  "devDependencies": {
45
46
  "@commitlint/cli": "^19.8.1",
@@ -56,9 +56,16 @@ export async function cleanupEntries(
56
56
  if (!collectionRequest.ok) {
57
57
  // If the collection is locked, an superuser token is required
58
58
  if (collectionRequest.status === 403) {
59
- context.logger.error(
60
- `The collection is not accessible without superuser rights. Please provide superuser credentials in the config.`
61
- );
59
+ if (
60
+ options.superuserCredentials &&
61
+ "impersonateToken" in options.superuserCredentials
62
+ ) {
63
+ context.logger.error("The given impersonate token is not valid.");
64
+ } else {
65
+ context.logger.error(
66
+ "The collection is not accessible without superuser rights. Please provide superuser credentials in the config."
67
+ );
68
+ }
62
69
  } else {
63
70
  const reason = await collectionRequest
64
71
  .json()
@@ -9,8 +9,6 @@ import { parseEntry } from "./parse-entry";
9
9
  * @param context Context of the loader.
10
10
  * @param superuserToken Superuser token to access all resources.
11
11
  * @param lastModified Date of the last fetch to only update changed entries.
12
- *
13
- * @returns `true` if the collection has an updated column, `false` otherwise.
14
12
  */
15
13
  export async function loadEntries(
16
14
  options: PocketBaseLoaderOptions,
@@ -78,9 +76,16 @@ export async function loadEntries(
78
76
  if (!collectionRequest.ok) {
79
77
  // If the collection is locked, an superuser token is required
80
78
  if (collectionRequest.status === 403) {
81
- throw new Error(
82
- `The collection is not accessible without superuser rights. Please provide superuser credentials in the config.`
83
- );
79
+ if (
80
+ options.superuserCredentials &&
81
+ "impersonateToken" in options.superuserCredentials
82
+ ) {
83
+ throw new Error("The given impersonate token is not valid.");
84
+ } else {
85
+ throw new Error(
86
+ "The collection is not accessible without superuser rights. Please provide superuser credentials in the config."
87
+ );
88
+ }
84
89
  }
85
90
 
86
91
  // Get the reason for the error
@@ -1,15 +1,18 @@
1
1
  import type { LoaderContext } from "astro/loaders";
2
2
  import packageJson from "../../package.json";
3
3
  import type { PocketBaseLoaderOptions } from "../types/pocketbase-loader-options.type";
4
- import { getSuperuserToken } from "../utils/get-superuser-token";
5
4
  import { shouldRefresh } from "../utils/should-refresh";
6
5
  import { cleanupEntries } from "./cleanup-entries";
7
6
  import { handleRealtimeUpdates } from "./handle-realtime-updates";
8
7
  import { loadEntries } from "./load-entries";
9
8
 
9
+ /**
10
+ * Load entries from a PocketBase collection.
11
+ */
10
12
  export async function loader(
11
13
  context: LoaderContext,
12
- options: PocketBaseLoaderOptions
14
+ options: PocketBaseLoaderOptions,
15
+ token: string | undefined
13
16
  ): Promise<void> {
14
17
  context.logger.label = `pocketbase-loader:${options.collectionName}`;
15
18
 
@@ -59,16 +62,6 @@ export async function loader(
59
62
  lastModified = undefined;
60
63
  }
61
64
 
62
- // Try to get a superuser token to access all resources.
63
- let token: string | undefined;
64
- if (options.superuserCredentials) {
65
- token = await getSuperuserToken(
66
- options.url,
67
- options.superuserCredentials,
68
- context.logger
69
- );
70
- }
71
-
72
65
  if (context.store.keys().length > 0) {
73
66
  // Cleanup entries that are no longer in the collection
74
67
  await cleanupEntries(options, context, token);
@@ -1,7 +1,9 @@
1
1
  import type { Loader } from "astro/loaders";
2
+ import type { ZodSchema } from "astro/zod";
2
3
  import { loader } from "./loader/loader";
3
4
  import { generateSchema } from "./schema/generate-schema";
4
5
  import type { PocketBaseLoaderOptions } from "./types/pocketbase-loader-options.type";
6
+ import { getSuperuserToken } from "./utils/get-superuser-token";
5
7
 
6
8
  /**
7
9
  * Loader for collections stored in PocketBase.
@@ -9,11 +11,38 @@ import type { PocketBaseLoaderOptions } from "./types/pocketbase-loader-options.
9
11
  * @param options Options for the loader. See {@link PocketBaseLoaderOptions} for more details.
10
12
  */
11
13
  export function pocketbaseLoader(options: PocketBaseLoaderOptions): Loader {
14
+ let tokenPromise: Promise<string | undefined>;
15
+ if (options.superuserCredentials) {
16
+ if ("impersonateToken" in options.superuserCredentials) {
17
+ // Impersonate token provided, so use it directly.
18
+ tokenPromise = Promise.resolve(
19
+ options.superuserCredentials.impersonateToken
20
+ );
21
+ } else {
22
+ // Email and password provided, so get a temporary superuser token.
23
+ tokenPromise = getSuperuserToken(
24
+ options.url,
25
+ options.superuserCredentials
26
+ );
27
+ }
28
+ } else {
29
+ // No credentials provided, so no token can be used.
30
+ tokenPromise = Promise.resolve(undefined);
31
+ }
32
+
12
33
  return {
13
34
  name: "pocketbase-loader",
14
- // Load the entries from the collection
15
- load: async (context) => loader(context, options),
16
- // Generate the schema for the collection according to the API
17
- schema: async () => await generateSchema(options)
35
+ load: async (context): Promise<void> => {
36
+ const token = await tokenPromise;
37
+
38
+ // Load the entries from the collection
39
+ await loader(context, options, token);
40
+ },
41
+ schema: async (): Promise<ZodSchema> => {
42
+ const token = await tokenPromise;
43
+
44
+ // Generate the schema for the collection according to the API
45
+ return await generateSchema(options, token);
46
+ }
18
47
  };
19
48
  }
@@ -28,14 +28,18 @@ const VALID_ID_TYPES = ["text", "number", "email", "url", "date"];
28
28
  * If a path to a local schema file is provided, the schema is read from the file.
29
29
  *
30
30
  * @param options Options for the loader. See {@link PocketBaseLoaderOptions} for more details.
31
+ * @param token The superuser token to authenticate the request.
31
32
  */
32
33
  export async function generateSchema(
33
- options: PocketBaseLoaderOptions
34
+ options: PocketBaseLoaderOptions,
35
+ token: string | undefined
34
36
  ): Promise<ZodSchema> {
35
37
  let collection: PocketBaseCollection | undefined;
36
38
 
37
- // Try to get the schema directly from the PocketBase instance
38
- collection = await getRemoteSchema(options);
39
+ if (token) {
40
+ // Try to get the schema directly from the PocketBase instance
41
+ collection = await getRemoteSchema(options, token);
42
+ }
39
43
 
40
44
  const hasSuperuserRights = !!collection || !!options.superuserCredentials;
41
45
 
@@ -1,30 +1,16 @@
1
1
  import type { PocketBaseLoaderOptions } from "../types/pocketbase-loader-options.type";
2
2
  import type { PocketBaseCollection } from "../types/pocketbase-schema.type";
3
- import { getSuperuserToken } from "../utils/get-superuser-token";
4
3
 
5
4
  /**
6
5
  * Fetches the schema for the specified collection from the PocketBase instance.
7
6
  *
8
7
  * @param options Options for the loader. See {@link PocketBaseLoaderOptions} for more details.
8
+ * @param token The superuser token to authenticate the request.
9
9
  */
10
10
  export async function getRemoteSchema(
11
- options: PocketBaseLoaderOptions
11
+ options: PocketBaseLoaderOptions,
12
+ token: string
12
13
  ): Promise<PocketBaseCollection | undefined> {
13
- if (!options.superuserCredentials) {
14
- return undefined;
15
- }
16
-
17
- // Get a superuser token
18
- const token = await getSuperuserToken(
19
- options.url,
20
- options.superuserCredentials
21
- );
22
-
23
- // If the token is invalid try another method
24
- if (!token) {
25
- return undefined;
26
- }
27
-
28
14
  // Build URL and headers for the schema request
29
15
  const schemaUrl = new URL(
30
16
  `api/collections/${options.collectionName}`,
@@ -58,16 +58,24 @@ export interface PocketBaseLoaderOptions {
58
58
  * Credentials of a superuser to get full access to the PocketBase instance.
59
59
  * This is required to get automatic type generation without a local schema, to access all resources even if they are not public and to fetch content of hidden fields.
60
60
  */
61
- superuserCredentials?: {
62
- /**
63
- * Email of the superuser.
64
- */
65
- email: string;
66
- /**
67
- * Password of the superuser.
68
- */
69
- password: string;
70
- };
61
+ superuserCredentials?:
62
+ | {
63
+ /**
64
+ * Email of the superuser.
65
+ */
66
+ email: string;
67
+ /**
68
+ * Password of the superuser.
69
+ */
70
+ password: string;
71
+ }
72
+ | {
73
+ /**
74
+ * Impersonate auth token of the superuser.
75
+ * This token will take precedence over the email and password.
76
+ */
77
+ impersonateToken: string;
78
+ };
71
79
  /**
72
80
  * File path to the local schema file.
73
81
  * This file will be used to generate the schema for the collection.