@cedgetec-utils/astro-components 1.2.0 → 1.4.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.
- package/package.json +11 -5
- package/src/components/index.ts +7 -0
- package/src/libs/directus.ts +184 -0
- package/src/libs/index.ts +4 -0
- package/index.ts +0 -7
- /package/src/{DirectusImage.astro → components/DirectusImage.astro} +0 -0
- /package/src/{Head.astro → components/Head.astro} +0 -0
- /package/src/{Matomo.astro → components/Matomo.astro} +0 -0
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cedgetec-utils/astro-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
|
-
".": "./index.ts"
|
|
6
|
+
".": "./src/components/index.ts",
|
|
7
|
+
"./libs": "./src/libs/index.ts"
|
|
7
8
|
},
|
|
8
9
|
"files": [
|
|
9
10
|
"src",
|
|
@@ -13,10 +14,15 @@
|
|
|
13
14
|
"astro-component"
|
|
14
15
|
],
|
|
15
16
|
"scripts": {},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"astro": "^5.17.1"
|
|
19
|
+
},
|
|
16
20
|
"devDependencies": {
|
|
17
|
-
"
|
|
21
|
+
"oxfmt": "^0.28.0",
|
|
22
|
+
"oxlint": "^1.43.0",
|
|
23
|
+
"typescript": "^5.9.3"
|
|
18
24
|
},
|
|
19
25
|
"peerDependencies": {
|
|
20
|
-
"astro": "^5.
|
|
26
|
+
"astro": "^5.17.1"
|
|
21
27
|
}
|
|
22
|
-
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Do not write code directly here, instead use the `src` folder!
|
|
2
|
+
// Then, use this file to export everything you want your user to access.
|
|
3
|
+
|
|
4
|
+
export { default as DirectusImage } from "./DirectusImage.astro";
|
|
5
|
+
export type { DirectusImageData } from "./DirectusImage.astro";
|
|
6
|
+
export { default as Head } from "./Head.astro";
|
|
7
|
+
export { default as Matomo } from "./Matomo.astro";
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import type { ZodObject, ZodRawShape, ZodSchema } from "astro/zod"
|
|
2
|
+
import { defineCollection } from "astro:content"
|
|
3
|
+
import { z } from "astro/zod"
|
|
4
|
+
|
|
5
|
+
async function fetchWithRetry(
|
|
6
|
+
url: string,
|
|
7
|
+
options: RequestInit = {},
|
|
8
|
+
retries = 10,
|
|
9
|
+
delay = 200,
|
|
10
|
+
): Promise<Response> {
|
|
11
|
+
try {
|
|
12
|
+
const controller = new AbortController()
|
|
13
|
+
const timeout = setTimeout(() => controller.abort(), 10_000)
|
|
14
|
+
|
|
15
|
+
const res = await fetch(url, {
|
|
16
|
+
...options,
|
|
17
|
+
signal: controller.signal,
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
clearTimeout(timeout)
|
|
21
|
+
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
throw new Error(`HTTP ${res.status}`)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return res
|
|
27
|
+
} catch (err) {
|
|
28
|
+
if (retries <= 0) throw err
|
|
29
|
+
console.warn(`Fetch failed, retrying (${retries})…`)
|
|
30
|
+
await new Promise((r) => setTimeout(r, delay))
|
|
31
|
+
return fetchWithRetry(url, options, retries - 1, delay * 1.5)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getZodSchemaPaths(schema: ZodSchema, prefix = ""): string[] {
|
|
36
|
+
const paths: string[] = []
|
|
37
|
+
|
|
38
|
+
// Unwrap optional, nullable, and effects (transforms, refinements, etc.)
|
|
39
|
+
let unwrapped = schema
|
|
40
|
+
while (
|
|
41
|
+
unwrapped instanceof z.ZodOptional ||
|
|
42
|
+
unwrapped instanceof z.ZodNullable ||
|
|
43
|
+
unwrapped instanceof z.ZodEffects
|
|
44
|
+
) {
|
|
45
|
+
if (unwrapped instanceof z.ZodEffects) {
|
|
46
|
+
unwrapped = unwrapped._def.schema
|
|
47
|
+
} else {
|
|
48
|
+
unwrapped = unwrapped._def.innerType
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Handle ZodObject
|
|
53
|
+
if (unwrapped instanceof z.ZodObject) {
|
|
54
|
+
const shape = unwrapped.shape
|
|
55
|
+
for (const key in shape) {
|
|
56
|
+
const fieldPath = prefix ? `${prefix}.${key}` : key
|
|
57
|
+
const fieldSchema = shape[key]
|
|
58
|
+
|
|
59
|
+
// Recursively get paths for nested schemas
|
|
60
|
+
const nestedPaths = getZodSchemaPaths(fieldSchema, fieldPath)
|
|
61
|
+
|
|
62
|
+
if (nestedPaths.length > 0) {
|
|
63
|
+
paths.push(...nestedPaths)
|
|
64
|
+
} else {
|
|
65
|
+
paths.push(fieldPath)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} // Handle ZodArray
|
|
69
|
+
else if (unwrapped instanceof z.ZodArray) {
|
|
70
|
+
const elementSchema = unwrapped._def.type
|
|
71
|
+
// Get paths from the array element schema without adding array indices
|
|
72
|
+
const nestedPaths = getZodSchemaPaths(elementSchema, prefix)
|
|
73
|
+
paths.push(...nestedPaths)
|
|
74
|
+
} // Handle ZodDiscriminatedUnion (for Directus M2A relationships)
|
|
75
|
+
else if (unwrapped instanceof z.ZodDiscriminatedUnion) {
|
|
76
|
+
const discriminator = unwrapped._def.discriminator as string
|
|
77
|
+
const options = unwrapped._def.options as z.ZodObject<any>[]
|
|
78
|
+
|
|
79
|
+
// Always include the discriminator field
|
|
80
|
+
paths.push(prefix ? `${prefix}.${discriminator}` : discriminator)
|
|
81
|
+
|
|
82
|
+
for (const option of options) {
|
|
83
|
+
const shape = option.shape
|
|
84
|
+
// Get the literal value of the discriminator (e.g., "pages_content_heading")
|
|
85
|
+
let discriminatorValue: string | undefined
|
|
86
|
+
const discriminatorSchema = shape[discriminator]
|
|
87
|
+
if (discriminatorSchema instanceof z.ZodLiteral) {
|
|
88
|
+
discriminatorValue = discriminatorSchema._def.value as string
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Process other fields in this variant
|
|
92
|
+
for (const key in shape) {
|
|
93
|
+
if (key === discriminator) continue
|
|
94
|
+
|
|
95
|
+
const fieldPath = prefix ? `${prefix}.${key}` : key
|
|
96
|
+
const fieldSchema = shape[key]
|
|
97
|
+
|
|
98
|
+
// For M2A "item" fields, use Directus collection-specific syntax
|
|
99
|
+
if (key === "item" && discriminatorValue) {
|
|
100
|
+
const itemPaths = getZodSchemaPaths(fieldSchema, "")
|
|
101
|
+
for (const itemPath of itemPaths) {
|
|
102
|
+
// Use syntax: item:collection_name.field
|
|
103
|
+
paths.push(`${fieldPath}:${discriminatorValue}.${itemPath}`)
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
const nestedPaths = getZodSchemaPaths(fieldSchema, fieldPath)
|
|
107
|
+
paths.push(...nestedPaths)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} // Base case: primitive types
|
|
112
|
+
else {
|
|
113
|
+
if (prefix) {
|
|
114
|
+
paths.push(prefix)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return paths
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export class Directus {
|
|
122
|
+
#apiDomain: string
|
|
123
|
+
|
|
124
|
+
constructor(apiDomain: string) {
|
|
125
|
+
this.#apiDomain = apiDomain
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async #query(collection: string, fields?: string[]) {
|
|
129
|
+
const response = await fetchWithRetry(
|
|
130
|
+
`https://${this.#apiDomain}/items/${collection}${
|
|
131
|
+
fields && `?fields=${fields.join(",")}`
|
|
132
|
+
}`,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
const data = await response.json()
|
|
136
|
+
|
|
137
|
+
return data.data
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
collection<T extends ZodRawShape>(name: string, schema: ZodObject<T>) {
|
|
141
|
+
const schemaWithId = schema.extend({ id: z.coerce.string() })
|
|
142
|
+
return defineCollection({
|
|
143
|
+
schema: schemaWithId,
|
|
144
|
+
loader: async () => {
|
|
145
|
+
const result = await this.#query(name, getZodSchemaPaths(schemaWithId))
|
|
146
|
+
if (Array.isArray(result)) {
|
|
147
|
+
return result
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return [result]
|
|
151
|
+
},
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
imageSchema() {
|
|
156
|
+
return z
|
|
157
|
+
.object({
|
|
158
|
+
id: z.string(),
|
|
159
|
+
type: z.string(),
|
|
160
|
+
title: z.string(),
|
|
161
|
+
modified_on: z.string(),
|
|
162
|
+
width: z.number().nullish(),
|
|
163
|
+
height: z.number().nullish(),
|
|
164
|
+
})
|
|
165
|
+
.transform((image) => ({
|
|
166
|
+
...image,
|
|
167
|
+
url: `https://${this.#apiDomain}/assets/${image.id}`,
|
|
168
|
+
}))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
fileSchema() {
|
|
172
|
+
return z
|
|
173
|
+
.object({
|
|
174
|
+
id: z.string(),
|
|
175
|
+
type: z.string(),
|
|
176
|
+
title: z.string(),
|
|
177
|
+
modified_on: z.string(),
|
|
178
|
+
})
|
|
179
|
+
.transform((file) => ({
|
|
180
|
+
...file,
|
|
181
|
+
url: `https://${this.#apiDomain}/assets/${file.id}`,
|
|
182
|
+
}))
|
|
183
|
+
}
|
|
184
|
+
}
|
package/index.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
// Do not write code directly here, instead use the `src` folder!
|
|
2
|
-
// Then, use this file to export everything you want your user to access.
|
|
3
|
-
|
|
4
|
-
export { default as DirectusImage } from "./src/DirectusImage.astro";
|
|
5
|
-
export type { DirectusImageData } from "./src/DirectusImage.astro";
|
|
6
|
-
export { default as Head } from "./src/Head.astro";
|
|
7
|
-
export { default as Matomo } from "./src/Matomo.astro";
|
|
File without changes
|
|
File without changes
|
|
File without changes
|