@laioutr/app-hygraph 1.7.2 → 1.8.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/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laioutr/app-hygraph",
3
- "version": "1.7.2",
3
+ "version": "1.8.0",
4
4
  "configKey": "@laioutr/app-hygraph",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.1",
package/dist/module.mjs CHANGED
@@ -3,7 +3,7 @@ import { defu } from 'defu';
3
3
  import { registerLaioutrApp } from '@laioutr-core/kit';
4
4
 
5
5
  const name = "@laioutr/app-hygraph";
6
- const version = "1.7.2";
6
+ const version = "1.8.0";
7
7
 
8
8
  const module = defineNuxtModule({
9
9
  meta: {
@@ -1,3 +1,8 @@
1
1
  export declare const blogCollectionToken: any;
2
- export declare const blogTopicToken: any;
3
2
  export declare const blogPostsToken: any;
3
+ /**
4
+ * Ids that the `blog/collection/posts` link should resolve via the topic
5
+ * relation (`topics_some`) instead of the blog-collection relation. Set by the
6
+ * "Blog Posts by Topic" query, which exposes a topic as a BlogCollection entity.
7
+ */
8
+ export declare const blogPostsTopicSourceToken: any;
@@ -1,4 +1,4 @@
1
1
  import { createPassthroughToken } from "#imports";
2
2
  export const blogCollectionToken = createPassthroughToken("hygraph/blog-collection");
3
- export const blogTopicToken = createPassthroughToken("hygraph/blog-topic");
4
3
  export const blogPostsToken = createPassthroughToken("hygraph/blog-posts");
4
+ export const blogPostsTopicSourceToken = createPassthroughToken("hygraph/blog-posts-topic-source");
@@ -1,20 +1,30 @@
1
1
  import { BlogCollectionPostsLink } from "@laioutr-core/canonical-types/blog";
2
- import { blogPostsToken } from "../../const/passthroughTokens.js";
2
+ import { blogPostsToken, blogPostsTopicSourceToken } from "../../const/passthroughTokens.js";
3
3
  import { resolveHygraphLocales } from "../../hygraph-utils/locale.js";
4
4
  import { defineHygraph } from "../../middleware/defineHygraph.js";
5
- import { BLOGS_QUERY } from "../../queries/blog.js";
5
+ import { BLOGS_BY_TOPIC_QUERY, BLOGS_QUERY } from "../../queries/blog.js";
6
6
  export default defineHygraph.linkHandler({
7
7
  implements: BlogCollectionPostsLink,
8
8
  run: async ({ context, entityIds, pagination, passthrough, clientEnv }) => {
9
9
  const locales = resolveHygraphLocales(clientEnv.locale);
10
+ const topicSourceIds = passthrough.get(blogPostsTopicSourceToken);
10
11
  const results = await Promise.all(
11
12
  entityIds.map(
12
- (id) => context.hygraph.request(BLOGS_QUERY, {
13
- skip: pagination.offset,
14
- first: pagination.limit,
15
- collectionId: id,
16
- locales
17
- })
13
+ (id) => (
14
+ // Ids exposed by the "Blog Posts by Topic" query are topic ids and must
15
+ // be filtered via the topic relation; all others are blog-collection ids.
16
+ topicSourceIds?.has(id) ? context.hygraph.request(BLOGS_BY_TOPIC_QUERY, {
17
+ skip: pagination.offset,
18
+ first: pagination.limit,
19
+ topicId: id,
20
+ locales
21
+ }) : context.hygraph.request(BLOGS_QUERY, {
22
+ skip: pagination.offset,
23
+ first: pagination.limit,
24
+ collectionId: id,
25
+ locales
26
+ })
27
+ )
18
28
  )
19
29
  );
20
30
  const allPosts = results.flatMap((r) => r.data.blogs);
@@ -1,10 +1,10 @@
1
- import { BlogTopicBySlug, BlogTopicBySlugNotFoundError } from "../../../shared/tokens/blog-topic.js";
2
- import { blogTopicToken } from "../../const/passthroughTokens.js";
1
+ import { BlogPostsByTopic } from "../../../shared/tokens/blog-topic.js";
2
+ import { blogCollectionToken, blogPostsTopicSourceToken } from "../../const/passthroughTokens.js";
3
3
  import { resolveHygraphLocales } from "../../hygraph-utils/locale.js";
4
4
  import { defineHygraph } from "../../middleware/defineHygraph.js";
5
5
  import { BLOG_TOPIC_BY_SLUG_QUERY } from "../../queries/blog.js";
6
6
  export default defineHygraph.queryHandler({
7
- implements: BlogTopicBySlug,
7
+ implements: BlogPostsByTopic,
8
8
  run: async ({ context, input, passthrough, clientEnv }) => {
9
9
  const result = await context.hygraph.request(BLOG_TOPIC_BY_SLUG_QUERY, {
10
10
  slug: input.slug,
@@ -12,9 +12,14 @@ export default defineHygraph.queryHandler({
12
12
  });
13
13
  const topic = result.data.topic;
14
14
  if (!topic) {
15
- throw new BlogTopicBySlugNotFoundError(input.slug);
15
+ return {};
16
16
  }
17
- passthrough.set(blogTopicToken, topic);
17
+ passthrough.set(blogCollectionToken, {
18
+ id: topic.id,
19
+ slug: topic.slug ?? input.slug,
20
+ title: topic.title ?? topic.slug ?? input.slug
21
+ });
22
+ passthrough.set(blogPostsTopicSourceToken, /* @__PURE__ */ new Set([topic.id]));
18
23
  return {
19
24
  id: topic.id
20
25
  };
@@ -1,14 +1,14 @@
1
- import { BlogTopicBySlug } from "../../../shared/tokens/blog-topic.js";
1
+ import { BlogPostsByTopic } from "../../../shared/tokens/blog-topic.js";
2
2
  import { resolveHygraphLocales } from "../../hygraph-utils/locale.js";
3
3
  import { defineHygraph } from "../../middleware/defineHygraph.js";
4
4
  import { BLOG_TOPICS_QUERY } from "../../queries/blog.js";
5
5
  export default defineHygraph.queryTemplateProvider({
6
- for: BlogTopicBySlug,
6
+ for: BlogPostsByTopic,
7
7
  run: async ({ context, clientEnv }) => {
8
8
  const result = await context.hygraph.request(BLOG_TOPICS_QUERY, {
9
9
  locales: resolveHygraphLocales(clientEnv.locale)
10
10
  });
11
- return result.data.topics.map((topic) => ({
11
+ return result.data.topics.filter((topic) => Boolean(topic.slug && topic.title)).map((topic) => ({
12
12
  input: { slug: topic.slug },
13
13
  label: topic.title
14
14
  }));
@@ -1,22 +1,16 @@
1
1
  import z from 'zod/v4';
2
2
  /**
3
- * Local stand-ins for the blog-topic tokens that do not exist in
4
- * `@laioutr-core/canonical-types` yet (neither `entity/blog-topic` nor the
5
- * topic tokens on `/blog`). These mirror the published blog-collection
6
- * equivalents one-to-one, so they can be lifted into the package unchanged
7
- * once it grows a topic surface.
3
+ * Exposes a blog topic AS a `BlogCollection` entity, so it appears in the
4
+ * existing BlogCollection-typed Studio query fields (e.g. "Blog Post Collection
5
+ * With Posts") and reuses the `blog/collection/posts` link no `BlogTopic`
6
+ * entity and no ui-app changes required.
7
+ *
8
+ * The handler resolves the topic by slug and fills the blog-collection
9
+ * passthrough with the topic; the shared posts link then filters by the topic
10
+ * relation for this id (see `blogPostsTopicSourceToken`).
8
11
  */
9
- export declare const BlogTopicBase: import("@laioutr-core/core-types/orchestr").EntityComponentToken<{
10
- name: "base";
11
- } & {
12
- readonly entityType: "BlogTopic";
13
- readonly schema: z.ZodObject<{
14
- slug: z.ZodString;
15
- title: z.ZodString;
16
- }, z.core.$strip>;
17
- }>;
18
- export declare const BlogTopicBySlug: import("@laioutr-core/core-types/orchestr").QueryToken<{
19
- name: "blog/topic/by-slug";
12
+ export declare const BlogPostsByTopic: import("@laioutr-core/core-types/orchestr").QueryToken<{
13
+ name: "blog/posts-by-topic";
20
14
  } & {
21
15
  entity: string;
22
16
  type: "single";
@@ -25,18 +19,3 @@ export declare const BlogTopicBySlug: import("@laioutr-core/core-types/orchestr"
25
19
  slug: z.ZodString;
26
20
  }, z.core.$strip>;
27
21
  }>;
28
- export declare class BlogTopicBySlugNotFoundError extends Error {
29
- static code: string;
30
- readonly code: string;
31
- readonly slug: string;
32
- constructor(slug: string);
33
- }
34
- export declare const BlogTopicPostsLink: import("@laioutr-core/core-types/orchestr").LinkToken<{
35
- name: "blog/topic/posts";
36
- } & {
37
- readonly label: "Blog topic posts";
38
- readonly source: "BlogTopic";
39
- readonly target: "BlogPost";
40
- readonly type: "multi";
41
- readonly defaultLimit: 12;
42
- }>;
@@ -1,32 +1,8 @@
1
1
  import z from "zod/v4";
2
- import { defineEntityComponentToken, defineLinkToken, defineQueryToken } from "@laioutr-core/core-types/orchestr";
3
- export const BlogTopicBase = defineEntityComponentToken("base", {
4
- entityType: "BlogTopic",
5
- schema: z.object({
6
- slug: z.string(),
7
- title: z.string()
8
- })
9
- });
10
- export const BlogTopicBySlug = defineQueryToken("blog/topic/by-slug", {
11
- entity: "BlogTopic",
2
+ import { defineQueryToken } from "@laioutr-core/core-types/orchestr";
3
+ export const BlogPostsByTopic = defineQueryToken("blog/posts-by-topic", {
4
+ entity: "BlogCollection",
12
5
  type: "single",
13
- label: "Blog topic by slug",
6
+ label: "Blog Posts by Topic",
14
7
  input: z.object({ slug: z.string() })
15
8
  });
16
- export class BlogTopicBySlugNotFoundError extends Error {
17
- static code = "BLOG_TOPIC_NOT_FOUND";
18
- code = BlogTopicBySlugNotFoundError.code;
19
- slug;
20
- constructor(slug) {
21
- super(`Blog Topic with slug ${slug} not found`);
22
- this.name = "BlogTopicBySlugNotFoundError";
23
- this.slug = slug;
24
- }
25
- }
26
- export const BlogTopicPostsLink = defineLinkToken("blog/topic/posts", {
27
- label: "Blog topic posts",
28
- source: "BlogTopic",
29
- target: "BlogPost",
30
- type: "multi",
31
- defaultLimit: 12
32
- });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laioutr/app-hygraph",
3
- "version": "1.7.2",
3
+ "version": "1.8.0",
4
4
  "description": "Laioutr Hygraph App",
5
5
  "repository": "your-org/@laioutr/app-hygraph",
6
6
  "license": "MIT",
@@ -43,6 +43,17 @@
43
43
  "files": [
44
44
  "dist"
45
45
  ],
46
+ "scripts": {
47
+ "dev": "npm run dev:prepare && nuxi dev playground",
48
+ "dev:build": "nuxi build playground",
49
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
50
+ "lint": "eslint .",
51
+ "prepack": "nuxt-module-build build",
52
+ "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish --access public && git push --follow-tags",
53
+ "test": "vitest run",
54
+ "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
55
+ "test:watch": "vitest watch"
56
+ },
46
57
  "dependencies": {
47
58
  "@nuxt/kit": "3.16.2",
48
59
  "zod": "3.25.61"
@@ -92,15 +103,5 @@
92
103
  "engines": {
93
104
  "node": ">=22.12.0",
94
105
  "pnpm": ">=10.15.0"
95
- },
96
- "scripts": {
97
- "dev": "npm run dev:prepare && nuxi dev playground",
98
- "dev:build": "nuxi build playground",
99
- "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
100
- "lint": "eslint .",
101
- "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish --access public && git push --follow-tags",
102
- "test": "vitest run",
103
- "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
104
- "test:watch": "vitest watch"
105
106
  }
106
- }
107
+ }
@@ -1,22 +0,0 @@
1
- import { BlogTopicBase } from "../../../shared/tokens/blog-topic.js";
2
- import { blogTopicToken } from "../../const/passthroughTokens.js";
3
- import { defineHygraph } from "../../middleware/defineHygraph.js";
4
- export default defineHygraph.componentResolver({
5
- entityType: "BlogTopic",
6
- label: "Blog Topic",
7
- provides: [BlogTopicBase],
8
- resolve: async ({ passthrough, $entity }) => {
9
- const topic = passthrough.require(blogTopicToken);
10
- return {
11
- entities: [
12
- $entity({
13
- id: topic.id,
14
- base: {
15
- slug: topic.slug,
16
- title: topic.title
17
- }
18
- })
19
- ]
20
- };
21
- }
22
- });
@@ -1,2 +0,0 @@
1
- declare const _default: import("nitropack").NitroAppPlugin;
2
- export default _default;
@@ -1,2 +0,0 @@
1
- declare const _default: import("nitropack").NitroAppPlugin;
2
- export default _default;
@@ -1,33 +0,0 @@
1
- import { BlogTopicPostsLink } from "../../../shared/tokens/blog-topic.js";
2
- import { blogPostsToken } from "../../const/passthroughTokens.js";
3
- import { resolveHygraphLocales } from "../../hygraph-utils/locale.js";
4
- import { defineHygraph } from "../../middleware/defineHygraph.js";
5
- import { BLOGS_BY_TOPIC_QUERY } from "../../queries/blog.js";
6
- export default defineHygraph.linkHandler({
7
- implements: BlogTopicPostsLink,
8
- run: async ({ context, entityIds, pagination, passthrough, clientEnv }) => {
9
- const locales = resolveHygraphLocales(clientEnv.locale);
10
- const results = await Promise.all(
11
- entityIds.map(
12
- (id) => context.hygraph.request(BLOGS_BY_TOPIC_QUERY, {
13
- skip: pagination.offset,
14
- first: pagination.limit,
15
- topicId: id,
16
- locales
17
- })
18
- )
19
- );
20
- const allPosts = results.flatMap((r) => r.data.blogs);
21
- passthrough.set(blogPostsToken, allPosts);
22
- return {
23
- links: entityIds.map((id, i) => {
24
- const data = results.at(i)?.data;
25
- return {
26
- sourceId: id,
27
- targetIds: data?.blogs.map((blog) => blog.id) ?? [],
28
- entityTotal: data?.blogsConnection.aggregate.count ?? data?.blogs.length ?? 0
29
- };
30
- })
31
- };
32
- }
33
- });