arroact-umbraco-graphql-sdk 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Arroact
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,218 @@
1
+ # @arroact/umbraco-graphql-sdk
2
+
3
+ TypeScript SDK for Umbraco GraphQL headless CMS integration.
4
+
5
+ ## 🚀 Features
6
+
7
+ - ✅ **TypeScript First** - Full type safety and IntelliSense support
8
+ - ✅ **Environment Aware** - Different behaviors for dev/staging/production
9
+ - ✅ **Zero Configuration** - Works out of the box with sensible defaults
10
+ - ✅ **Extensible** - Easy to extend with custom queries and models
11
+ - ✅ **Production Ready** - Built with enterprise patterns
12
+ - ✅ **Tree Shakeable** - ESM and CJS builds included
13
+
14
+ ## 📦 Installation
15
+
16
+ ```bash
17
+ npm install @arroact/umbraco-graphql-sdk graphql
18
+ ```
19
+
20
+ ## 🔧 Usage
21
+
22
+ ### Basic Setup
23
+
24
+ ```typescript
25
+ import { HeadlessSDK } from '@arroact/umbraco-graphql-sdk';
26
+
27
+ const sdk = new HeadlessSDK({
28
+ environment: 'development',
29
+ graphqlUrl: 'https://your-umbraco-site.com/graphql',
30
+ apiKey: 'your-api-key', // optional
31
+ rootContentId: 'root-id', // optional
32
+ enableLogging: true, // optional
33
+ enableCache: false, // optional
34
+ });
35
+ ```
36
+
37
+ ### Fetching Pages
38
+
39
+ ```typescript
40
+ // Get a page by slug
41
+ const page = await sdk.getPageBySlug('about-us');
42
+
43
+ if (page) {
44
+ console.log(page.title);
45
+ console.log(page.content);
46
+ console.log(page.metaTitle);
47
+ console.log(page.metaDescription);
48
+ }
49
+ ```
50
+
51
+ ### Next.js Integration
52
+
53
+ ```typescript
54
+ // lib/sdk.ts
55
+ import { HeadlessSDK, Environment } from '@arroact/umbraco-graphql-sdk';
56
+
57
+ export const sdk = new HeadlessSDK({
58
+ environment: process.env.NEXT_PUBLIC_ENV as Environment,
59
+ graphqlUrl: process.env.GRAPHQL_URL!,
60
+ apiKey: process.env.GRAPHQL_API_KEY,
61
+ enableLogging: process.env.NEXT_PUBLIC_ENV === 'development',
62
+ });
63
+
64
+ // app/[slug]/page.tsx
65
+ import { sdk } from '@/lib/sdk';
66
+
67
+ export default async function Page({ params }: { params: { slug: string } }) {
68
+ const page = await sdk.getPageBySlug(params.slug);
69
+
70
+ return (
71
+ <div>
72
+ <h1>{page?.title}</h1>
73
+ <div dangerouslySetInnerHTML={{ __html: page?.content || '' }} />
74
+ </div>
75
+ );
76
+ }
77
+ ```
78
+
79
+ ## 📖 API Reference
80
+
81
+ ### `HeadlessSDK`
82
+
83
+ Main SDK class for interacting with Umbraco GraphQL.
84
+
85
+ #### Constructor Options
86
+
87
+ ```typescript
88
+ interface SdkConfig {
89
+ environment: 'development' | 'staging' | 'production';
90
+ graphqlUrl: string;
91
+ apiKey?: string;
92
+ rootContentId?: string;
93
+ enableLogging?: boolean;
94
+ enableCache?: boolean;
95
+ }
96
+ ```
97
+
98
+ #### Methods
99
+
100
+ ##### `getPageBySlug(slug: string): Promise<PageModel | null>`
101
+
102
+ Fetches a page by its URL slug.
103
+
104
+ **Returns:**
105
+
106
+ ```typescript
107
+ interface PageModel {
108
+ id: string;
109
+ slug: string;
110
+ title: string;
111
+ content: string;
112
+ metaTitle?: string;
113
+ metaDescription?: string;
114
+ publishedDate?: string;
115
+ updatedDate?: string;
116
+ }
117
+ ```
118
+
119
+ ## 🏗️ Architecture
120
+
121
+ The SDK is organized into clean, maintainable layers:
122
+
123
+ ```
124
+ src/
125
+ ├── client/ # GraphQL client factory
126
+ ├── types/ # TypeScript type definitions
127
+ ├── queries/ # GraphQL queries
128
+ ├── models/ # Data models
129
+ ├── mappers/ # Data transformation
130
+ ├── services/ # Business logic
131
+ ├── core/ # Main SDK class
132
+ └── index.ts # Public exports
133
+ ```
134
+
135
+ ## 🔒 Environment Behavior
136
+
137
+ ### Development
138
+ - Full logging enabled
139
+ - Detailed error messages
140
+ - Debug information
141
+
142
+ ### Staging
143
+ - Partial logging
144
+ - Error tracking
145
+ - Performance monitoring
146
+
147
+ ### Production
148
+ - Minimal logging (unless `enableLogging: true`)
149
+ - Error suppression
150
+ - Optimized performance
151
+
152
+ ## 🛠️ Development
153
+
154
+ ```bash
155
+ # Install dependencies
156
+ npm install
157
+
158
+ # Build the SDK
159
+ npm run build
160
+
161
+ # Watch mode
162
+ npm run dev
163
+
164
+ # Type checking
165
+ npm run lint
166
+ ```
167
+
168
+ ## 📦 Build Output
169
+
170
+ The SDK builds to multiple formats:
171
+
172
+ - `dist/index.js` - CommonJS
173
+ - `dist/index.mjs` - ES Modules
174
+ - `dist/index.d.ts` - TypeScript definitions
175
+
176
+ ## 🧩 Extending the SDK
177
+
178
+ ### Adding Custom Queries
179
+
180
+ ```typescript
181
+ // queries/custom.query.ts
182
+ import { gql } from 'graphql-request';
183
+
184
+ export const GET_CUSTOM_DATA = gql`
185
+ query GetCustomData($id: ID!) {
186
+ content(id: $id) {
187
+ # your fields
188
+ }
189
+ }
190
+ `;
191
+ ```
192
+
193
+ ### Adding Custom Services
194
+
195
+ ```typescript
196
+ // services/custom.service.ts
197
+ import { GraphQLClient } from 'graphql-request';
198
+
199
+ export class CustomService {
200
+ constructor(private client: GraphQLClient) {}
201
+
202
+ async getCustomData(id: string) {
203
+ // implementation
204
+ }
205
+ }
206
+ ```
207
+
208
+ ## 📄 License
209
+
210
+ MIT
211
+
212
+ ## 🤝 Contributing
213
+
214
+ Contributions are welcome! Please maintain the existing code structure and style.
215
+
216
+ ## 📞 Support
217
+
218
+ For issues and questions, please open a GitHub issue.
@@ -0,0 +1,181 @@
1
+ import { GraphQLClient } from 'graphql-request';
2
+
3
+ type Environment = 'development' | 'staging' | 'production';
4
+
5
+ interface SdkConfig {
6
+ environment: Environment;
7
+ graphqlUrl: string;
8
+ mediaUrl?: string;
9
+ apiKey?: string;
10
+ rootContentId?: string;
11
+ enableLogging?: boolean;
12
+ enableCache?: boolean;
13
+ }
14
+
15
+ interface PropertyMetadata {
16
+ key: string;
17
+ dataType: string;
18
+ value: any;
19
+ }
20
+ declare class PageModel {
21
+ id: string;
22
+ name: string;
23
+ slug: string;
24
+ title: string;
25
+ content: string;
26
+ contentType: string;
27
+ url: string;
28
+ parentId?: string;
29
+ metaTitle?: string;
30
+ metaDescription?: string;
31
+ publishedDate?: string;
32
+ updatedDate?: string;
33
+ properties: Record<string, PropertyMetadata>;
34
+ children: PageModel[];
35
+ [key: string]: any | undefined;
36
+ constructor(data: {
37
+ id: string;
38
+ name: string;
39
+ slug: string;
40
+ title: string;
41
+ content: string;
42
+ contentType: string;
43
+ url: string;
44
+ parentId?: string;
45
+ metaTitle?: string;
46
+ metaDescription?: string;
47
+ publishedDate?: string;
48
+ updatedDate?: string;
49
+ properties: Record<string, PropertyMetadata>;
50
+ children?: PageModel[];
51
+ });
52
+ Value(propertyAlias: string): any;
53
+ HasProperty(propertyAlias: string): boolean;
54
+ getMediaUrl(propertyAlias: string): string;
55
+ toJSON(): any;
56
+ static hydrate(data: any): PageModel | null;
57
+ }
58
+
59
+ interface WhereInput {
60
+ propertyKey?: string;
61
+ propertyValue?: string;
62
+ }
63
+ interface OrderByPropertyInput {
64
+ propertyKey?: string;
65
+ direction?: 'ASC' | 'DESC';
66
+ }
67
+ interface QueryOptions {
68
+ first?: number | null;
69
+ skip?: number | null;
70
+ where?: WhereInput | null;
71
+ orderBy?: 'ASC' | 'DESC' | null;
72
+ orderByProperty?: OrderByPropertyInput | null;
73
+ }
74
+
75
+ declare class HeadlessSDK {
76
+ private client;
77
+ private pageService;
78
+ private rootContentId?;
79
+ private static mediaBaseUrl;
80
+ constructor(config: SdkConfig);
81
+ static getMediaBaseUrl(): string;
82
+ getPageBySlug(slug: string): Promise<PageModel | null>;
83
+ getContentById(id: string): Promise<PageModel | null>;
84
+ getRoot(): Promise<PageModel | null>;
85
+ getRootChildren(options?: QueryOptions): Promise<PageModel[]>;
86
+ getChildrenById(id: string, options?: QueryOptions): Promise<PageModel[]>;
87
+ getPageBySlugWithOptions(slug: string, options?: QueryOptions): Promise<{
88
+ page: PageModel | null;
89
+ children: PageModel[];
90
+ }>;
91
+ getMediaUrl(path: string): string;
92
+ static hydrate(data: any): PageModel | null;
93
+ }
94
+
95
+ declare function createGraphQLClient(config: SdkConfig): GraphQLClient;
96
+
97
+ declare class PageService {
98
+ private client;
99
+ constructor(client: GraphQLClient);
100
+ getPageBySlug(slug: string): Promise<PageModel | null>;
101
+ getContentById(id: string): Promise<PageModel | null>;
102
+ getRootChildren(rootId: string, options?: QueryOptions): Promise<PageModel[]>;
103
+ getPageBySlugWithOptions(slug: string, options?: QueryOptions): Promise<{
104
+ page: PageModel | null;
105
+ children: PageModel[];
106
+ }>;
107
+ }
108
+
109
+ interface GraphQLProperty {
110
+ key: string;
111
+ value: string;
112
+ dataType: string;
113
+ }
114
+ interface GraphQLPageData {
115
+ id: string;
116
+ name: string;
117
+ contentType: string;
118
+ url: string;
119
+ properties: GraphQLProperty[];
120
+ createDate?: string;
121
+ updateDate?: string;
122
+ parentId?: string | null;
123
+ }
124
+ declare function mapGraphQLToPageModel(data: GraphQLPageData): PageModel;
125
+
126
+ declare const GET_PAGE_BY_SLUG: string;
127
+
128
+ declare const GET_CONTENT_BY_ID: string;
129
+
130
+ declare const GET_ROOT_CHILDREN: string;
131
+ declare const GET_PAGE_BY_SLUG_WITH_OPTIONS: string;
132
+
133
+ interface BlockGridArea {
134
+ alias: string;
135
+ rowSpan: number;
136
+ columnSpan: number;
137
+ items: BlockGridItem[];
138
+ }
139
+ interface BlockGridItem {
140
+ contentType: string;
141
+ content: any;
142
+ settings?: any;
143
+ areas?: BlockGridArea[];
144
+ rowSpan?: number;
145
+ columnSpan?: number;
146
+ areaGridColumns?: number;
147
+ }
148
+ interface BlockGridData {
149
+ items?: BlockGridItem[];
150
+ blocks?: BlockGridItem[];
151
+ }
152
+ declare class BlockGridUtils {
153
+ static extractBlocks(blockGridData: any): BlockGridItem[];
154
+ static getComponentName(contentType: string): string;
155
+ static validateBlock(block: any): block is BlockGridItem;
156
+ static parseBlockGridData(data: any): {
157
+ blocks: BlockGridItem[];
158
+ errors: string[];
159
+ };
160
+ }
161
+
162
+ declare class BlockModel {
163
+ private _content;
164
+ private _settings;
165
+ private _contentType;
166
+ private _properties;
167
+ constructor(content: any, settings?: any, contentType?: string);
168
+ private parseProperties;
169
+ get content(): any;
170
+ get settings(): any;
171
+ get contentType(): string;
172
+ get properties(): Record<string, any>;
173
+ Value(propertyAlias: string): any;
174
+ Setting(propertyAlias: string): any;
175
+ HasValue(propertyAlias: string): boolean;
176
+ HasSetting(propertyAlias: string): boolean;
177
+ getMediaUrl(propertyAlias: string): string;
178
+ }
179
+ declare function createBlockModel(content: any, settings?: any, contentType?: string): BlockModel & Record<string, any>;
180
+
181
+ export { type BlockGridArea, type BlockGridData, type BlockGridItem, BlockGridUtils, BlockModel, type Environment, GET_CONTENT_BY_ID, GET_PAGE_BY_SLUG, GET_PAGE_BY_SLUG_WITH_OPTIONS, GET_ROOT_CHILDREN, HeadlessSDK, type OrderByPropertyInput, PageModel, PageService, type PropertyMetadata, type QueryOptions, type SdkConfig, type WhereInput, createBlockModel, createGraphQLClient, mapGraphQLToPageModel };
@@ -0,0 +1,181 @@
1
+ import { GraphQLClient } from 'graphql-request';
2
+
3
+ type Environment = 'development' | 'staging' | 'production';
4
+
5
+ interface SdkConfig {
6
+ environment: Environment;
7
+ graphqlUrl: string;
8
+ mediaUrl?: string;
9
+ apiKey?: string;
10
+ rootContentId?: string;
11
+ enableLogging?: boolean;
12
+ enableCache?: boolean;
13
+ }
14
+
15
+ interface PropertyMetadata {
16
+ key: string;
17
+ dataType: string;
18
+ value: any;
19
+ }
20
+ declare class PageModel {
21
+ id: string;
22
+ name: string;
23
+ slug: string;
24
+ title: string;
25
+ content: string;
26
+ contentType: string;
27
+ url: string;
28
+ parentId?: string;
29
+ metaTitle?: string;
30
+ metaDescription?: string;
31
+ publishedDate?: string;
32
+ updatedDate?: string;
33
+ properties: Record<string, PropertyMetadata>;
34
+ children: PageModel[];
35
+ [key: string]: any | undefined;
36
+ constructor(data: {
37
+ id: string;
38
+ name: string;
39
+ slug: string;
40
+ title: string;
41
+ content: string;
42
+ contentType: string;
43
+ url: string;
44
+ parentId?: string;
45
+ metaTitle?: string;
46
+ metaDescription?: string;
47
+ publishedDate?: string;
48
+ updatedDate?: string;
49
+ properties: Record<string, PropertyMetadata>;
50
+ children?: PageModel[];
51
+ });
52
+ Value(propertyAlias: string): any;
53
+ HasProperty(propertyAlias: string): boolean;
54
+ getMediaUrl(propertyAlias: string): string;
55
+ toJSON(): any;
56
+ static hydrate(data: any): PageModel | null;
57
+ }
58
+
59
+ interface WhereInput {
60
+ propertyKey?: string;
61
+ propertyValue?: string;
62
+ }
63
+ interface OrderByPropertyInput {
64
+ propertyKey?: string;
65
+ direction?: 'ASC' | 'DESC';
66
+ }
67
+ interface QueryOptions {
68
+ first?: number | null;
69
+ skip?: number | null;
70
+ where?: WhereInput | null;
71
+ orderBy?: 'ASC' | 'DESC' | null;
72
+ orderByProperty?: OrderByPropertyInput | null;
73
+ }
74
+
75
+ declare class HeadlessSDK {
76
+ private client;
77
+ private pageService;
78
+ private rootContentId?;
79
+ private static mediaBaseUrl;
80
+ constructor(config: SdkConfig);
81
+ static getMediaBaseUrl(): string;
82
+ getPageBySlug(slug: string): Promise<PageModel | null>;
83
+ getContentById(id: string): Promise<PageModel | null>;
84
+ getRoot(): Promise<PageModel | null>;
85
+ getRootChildren(options?: QueryOptions): Promise<PageModel[]>;
86
+ getChildrenById(id: string, options?: QueryOptions): Promise<PageModel[]>;
87
+ getPageBySlugWithOptions(slug: string, options?: QueryOptions): Promise<{
88
+ page: PageModel | null;
89
+ children: PageModel[];
90
+ }>;
91
+ getMediaUrl(path: string): string;
92
+ static hydrate(data: any): PageModel | null;
93
+ }
94
+
95
+ declare function createGraphQLClient(config: SdkConfig): GraphQLClient;
96
+
97
+ declare class PageService {
98
+ private client;
99
+ constructor(client: GraphQLClient);
100
+ getPageBySlug(slug: string): Promise<PageModel | null>;
101
+ getContentById(id: string): Promise<PageModel | null>;
102
+ getRootChildren(rootId: string, options?: QueryOptions): Promise<PageModel[]>;
103
+ getPageBySlugWithOptions(slug: string, options?: QueryOptions): Promise<{
104
+ page: PageModel | null;
105
+ children: PageModel[];
106
+ }>;
107
+ }
108
+
109
+ interface GraphQLProperty {
110
+ key: string;
111
+ value: string;
112
+ dataType: string;
113
+ }
114
+ interface GraphQLPageData {
115
+ id: string;
116
+ name: string;
117
+ contentType: string;
118
+ url: string;
119
+ properties: GraphQLProperty[];
120
+ createDate?: string;
121
+ updateDate?: string;
122
+ parentId?: string | null;
123
+ }
124
+ declare function mapGraphQLToPageModel(data: GraphQLPageData): PageModel;
125
+
126
+ declare const GET_PAGE_BY_SLUG: string;
127
+
128
+ declare const GET_CONTENT_BY_ID: string;
129
+
130
+ declare const GET_ROOT_CHILDREN: string;
131
+ declare const GET_PAGE_BY_SLUG_WITH_OPTIONS: string;
132
+
133
+ interface BlockGridArea {
134
+ alias: string;
135
+ rowSpan: number;
136
+ columnSpan: number;
137
+ items: BlockGridItem[];
138
+ }
139
+ interface BlockGridItem {
140
+ contentType: string;
141
+ content: any;
142
+ settings?: any;
143
+ areas?: BlockGridArea[];
144
+ rowSpan?: number;
145
+ columnSpan?: number;
146
+ areaGridColumns?: number;
147
+ }
148
+ interface BlockGridData {
149
+ items?: BlockGridItem[];
150
+ blocks?: BlockGridItem[];
151
+ }
152
+ declare class BlockGridUtils {
153
+ static extractBlocks(blockGridData: any): BlockGridItem[];
154
+ static getComponentName(contentType: string): string;
155
+ static validateBlock(block: any): block is BlockGridItem;
156
+ static parseBlockGridData(data: any): {
157
+ blocks: BlockGridItem[];
158
+ errors: string[];
159
+ };
160
+ }
161
+
162
+ declare class BlockModel {
163
+ private _content;
164
+ private _settings;
165
+ private _contentType;
166
+ private _properties;
167
+ constructor(content: any, settings?: any, contentType?: string);
168
+ private parseProperties;
169
+ get content(): any;
170
+ get settings(): any;
171
+ get contentType(): string;
172
+ get properties(): Record<string, any>;
173
+ Value(propertyAlias: string): any;
174
+ Setting(propertyAlias: string): any;
175
+ HasValue(propertyAlias: string): boolean;
176
+ HasSetting(propertyAlias: string): boolean;
177
+ getMediaUrl(propertyAlias: string): string;
178
+ }
179
+ declare function createBlockModel(content: any, settings?: any, contentType?: string): BlockModel & Record<string, any>;
180
+
181
+ export { type BlockGridArea, type BlockGridData, type BlockGridItem, BlockGridUtils, BlockModel, type Environment, GET_CONTENT_BY_ID, GET_PAGE_BY_SLUG, GET_PAGE_BY_SLUG_WITH_OPTIONS, GET_ROOT_CHILDREN, HeadlessSDK, type OrderByPropertyInput, PageModel, PageService, type PropertyMetadata, type QueryOptions, type SdkConfig, type WhereInput, createBlockModel, createGraphQLClient, mapGraphQLToPageModel };