@23blocks/jsonapi-codec 1.0.3 → 2.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.
@@ -0,0 +1 @@
1
+ export * from "./src/index";
@@ -0,0 +1,182 @@
1
+ import { _ } from '@swc/helpers/_/_extends';
2
+ import { BlockErrorException } from '@23blocks/contracts';
3
+
4
+ /**
5
+ * Type guard for single resource document
6
+ */ function isSingleResourceDocument(doc) {
7
+ return doc.data !== null && doc.data !== undefined && !Array.isArray(doc.data);
8
+ }
9
+ /**
10
+ * Type guard for collection resource document
11
+ */ function isCollectionDocument(doc) {
12
+ return Array.isArray(doc.data);
13
+ }
14
+ /**
15
+ * Type guard for error document
16
+ */ function isErrorDocument(doc) {
17
+ return Array.isArray(doc.errors) && doc.errors.length > 0;
18
+ }
19
+
20
+ /**
21
+ * Create a key for the included map
22
+ */ function resourceKey(type, id) {
23
+ return `${type}:${id}`;
24
+ }
25
+ /**
26
+ * Build an included map from an array of resources
27
+ */ function buildIncludedMap(included = []) {
28
+ const map = new Map();
29
+ for (const resource of included){
30
+ map.set(resourceKey(resource.type, resource.id), resource);
31
+ }
32
+ return map;
33
+ }
34
+ /**
35
+ * Get a resource from the included map
36
+ */ function getIncluded(included, type, id) {
37
+ return included.get(resourceKey(type, id));
38
+ }
39
+ /**
40
+ * Resolve a relationship from included resources
41
+ */ function resolveRelationship(resource, relationshipName, included, mapper) {
42
+ var _resource_relationships;
43
+ const relationship = (_resource_relationships = resource.relationships) == null ? void 0 : _resource_relationships[relationshipName];
44
+ if (!(relationship == null ? void 0 : relationship.data)) {
45
+ return null;
46
+ }
47
+ const data = relationship.data;
48
+ if (Array.isArray(data)) {
49
+ throw new Error(`Expected single relationship for '${relationshipName}', got array. Use resolveRelationshipMany instead.`);
50
+ }
51
+ const related = getIncluded(included, data.type, data.id);
52
+ if (!related) {
53
+ return null;
54
+ }
55
+ return mapper.map(related, included);
56
+ }
57
+ /**
58
+ * Resolve a has-many relationship from included resources
59
+ */ function resolveRelationshipMany(resource, relationshipName, included, mapper) {
60
+ var _resource_relationships;
61
+ const relationship = (_resource_relationships = resource.relationships) == null ? void 0 : _resource_relationships[relationshipName];
62
+ if (!(relationship == null ? void 0 : relationship.data)) {
63
+ return [];
64
+ }
65
+ const data = relationship.data;
66
+ if (!Array.isArray(data)) {
67
+ throw new Error(`Expected array relationship for '${relationshipName}', got single. Use resolveRelationship instead.`);
68
+ }
69
+ return data.map((identifier)=>{
70
+ const related = getIncluded(included, identifier.type, identifier.id);
71
+ if (!related) {
72
+ return null;
73
+ }
74
+ return mapper.map(related, included);
75
+ }).filter((item)=>item !== null);
76
+ }
77
+
78
+ /**
79
+ * Decode a single resource from a JSON:API document
80
+ */ function decodeOne(document, mapper) {
81
+ if (!isSingleResourceDocument(document)) {
82
+ throw new Error('Expected single resource document');
83
+ }
84
+ const included = buildIncludedMap(document.included);
85
+ return mapper.map(document.data, included);
86
+ }
87
+ /**
88
+ * Decode a single resource from a JSON:API document, returning null if not found
89
+ */ function decodeOneOrNull(document, mapper) {
90
+ if (!document.data || Array.isArray(document.data)) {
91
+ return null;
92
+ }
93
+ const included = buildIncludedMap(document.included);
94
+ return mapper.map(document.data, included);
95
+ }
96
+ /**
97
+ * Decode multiple resources from a JSON:API document
98
+ */ function decodeMany(document, mapper) {
99
+ if (!isCollectionDocument(document)) {
100
+ throw new Error('Expected collection document');
101
+ }
102
+ const included = buildIncludedMap(document.included);
103
+ return document.data.map((resource)=>mapper.map(resource, included));
104
+ }
105
+ /**
106
+ * Extract pagination metadata from JSON:API meta
107
+ */ function extractPageMeta(meta) {
108
+ var _meta_current_page, _meta_total_pages, _meta_total_count, _meta_per_page;
109
+ return {
110
+ currentPage: (_meta_current_page = meta == null ? void 0 : meta.current_page) != null ? _meta_current_page : 1,
111
+ totalPages: (_meta_total_pages = meta == null ? void 0 : meta.total_pages) != null ? _meta_total_pages : 1,
112
+ totalCount: (_meta_total_count = meta == null ? void 0 : meta.total_count) != null ? _meta_total_count : 0,
113
+ perPage: (_meta_per_page = meta == null ? void 0 : meta.per_page) != null ? _meta_per_page : 0
114
+ };
115
+ }
116
+ /**
117
+ * Decode a paginated collection from a JSON:API document
118
+ */ function decodePageResult(document, mapper) {
119
+ const data = isCollectionDocument(document) ? decodeMany(document, mapper) : [];
120
+ return {
121
+ data,
122
+ meta: extractPageMeta(document.meta)
123
+ };
124
+ }
125
+ /**
126
+ * Decode with a custom decoder function
127
+ */ function decodeWith(document, decoder) {
128
+ const included = buildIncludedMap(document.included);
129
+ return decoder(document, included);
130
+ }
131
+
132
+ /**
133
+ * Convert a JSON:API error to a BlockError
134
+ */ function jsonApiErrorToBlockError(error) {
135
+ var _error_source, _error_source1;
136
+ var _error_code, _error_detail, _ref, _error_source_pointer;
137
+ return {
138
+ code: (_error_code = error.code) != null ? _error_code : 'unknown_error',
139
+ message: (_ref = (_error_detail = error.detail) != null ? _error_detail : error.title) != null ? _ref : 'An unknown error occurred',
140
+ status: error.status ? parseInt(error.status, 10) : 500,
141
+ source: (_error_source_pointer = (_error_source = error.source) == null ? void 0 : _error_source.pointer) != null ? _error_source_pointer : (_error_source1 = error.source) == null ? void 0 : _error_source1.parameter,
142
+ meta: error.meta
143
+ };
144
+ }
145
+ /**
146
+ * Convert multiple JSON:API errors to a single BlockError
147
+ * Uses the first error as the primary error, includes others in meta
148
+ */ function jsonApiErrorsToBlockError(errors) {
149
+ if (errors.length === 0) {
150
+ return {
151
+ code: 'unknown_error',
152
+ message: 'An unknown error occurred',
153
+ status: 500
154
+ };
155
+ }
156
+ const primary = jsonApiErrorToBlockError(errors[0]);
157
+ if (errors.length > 1) {
158
+ primary.meta = _({}, primary.meta, {
159
+ additionalErrors: errors.slice(1).map(jsonApiErrorToBlockError)
160
+ });
161
+ }
162
+ return primary;
163
+ }
164
+ /**
165
+ * Create a BlockErrorException from JSON:API errors
166
+ */ function blockErrorFromJsonApi(errors) {
167
+ return new BlockErrorException(jsonApiErrorsToBlockError(errors));
168
+ }
169
+ /**
170
+ * Check if a document is an error document and throw if so
171
+ */ function throwIfError(document) {
172
+ if (isErrorDocument(document)) {
173
+ throw blockErrorFromJsonApi(document.errors);
174
+ }
175
+ }
176
+ /**
177
+ * Assert that a document is not an error document
178
+ */ function assertNotError(document) {
179
+ throwIfError(document);
180
+ }
181
+
182
+ export { assertNotError, blockErrorFromJsonApi, buildIncludedMap, decodeMany, decodeOne, decodeOneOrNull, decodePageResult, decodeWith, extractPageMeta, getIncluded, isCollectionDocument, isErrorDocument, isSingleResourceDocument, jsonApiErrorToBlockError, jsonApiErrorsToBlockError, resolveRelationship, resolveRelationshipMany, resourceKey, throwIfError };
@@ -0,0 +1,5 @@
1
+ export { type JsonApiResource, type JsonApiRelationship, type JsonApiResourceIdentifier, type JsonApiLinks, type JsonApiLink, type JsonApiError, type JsonApiDocument, type JsonApiMeta, isSingleResourceDocument, isCollectionDocument, isErrorDocument, } from './lib/types.js';
2
+ export { type IncludedMap, type ResourceMapper, resourceKey, buildIncludedMap, getIncluded, resolveRelationship, resolveRelationshipMany, } from './lib/mapper.js';
3
+ export { decodeOne, decodeOneOrNull, decodeMany, extractPageMeta, decodePageResult, decodeWith, } from './lib/decode.js';
4
+ export { jsonApiErrorToBlockError, jsonApiErrorsToBlockError, blockErrorFromJsonApi, throwIfError, assertNotError, } from './lib/errors.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,SAAS,EACT,eAAe,EACf,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,UAAU,GACX,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,YAAY,EACZ,cAAc,GACf,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { PageResult, PageMeta } from '@23blocks/contracts';
2
+ import type { JsonApiDocument, JsonApiMeta } from './types.js';
3
+ import type { ResourceMapper, IncludedMap } from './mapper.js';
4
+ /**
5
+ * Decode a single resource from a JSON:API document
6
+ */
7
+ export declare function decodeOne<T>(document: JsonApiDocument, mapper: ResourceMapper<T>): T;
8
+ /**
9
+ * Decode a single resource from a JSON:API document, returning null if not found
10
+ */
11
+ export declare function decodeOneOrNull<T>(document: JsonApiDocument, mapper: ResourceMapper<T>): T | null;
12
+ /**
13
+ * Decode multiple resources from a JSON:API document
14
+ */
15
+ export declare function decodeMany<T>(document: JsonApiDocument, mapper: ResourceMapper<T>): T[];
16
+ /**
17
+ * Extract pagination metadata from JSON:API meta
18
+ */
19
+ export declare function extractPageMeta(meta?: JsonApiMeta): PageMeta;
20
+ /**
21
+ * Decode a paginated collection from a JSON:API document
22
+ */
23
+ export declare function decodePageResult<T>(document: JsonApiDocument, mapper: ResourceMapper<T>): PageResult<T>;
24
+ /**
25
+ * Decode with a custom decoder function
26
+ */
27
+ export declare function decodeWith<T>(document: JsonApiDocument, decoder: (doc: JsonApiDocument, included: IncludedMap) => T): T;
28
+ //# sourceMappingURL=decode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode.d.ts","sourceRoot":"","sources":["../../../src/lib/decode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/D;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EACzB,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GACxB,CAAC,CAOH;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GACxB,CAAC,GAAG,IAAI,CAOV;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAC1B,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GACxB,CAAC,EAAE,CAOL;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,QAAQ,CAO5D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GACxB,UAAU,CAAC,CAAC,CAAC,CASf;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAC1B,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,KAAK,CAAC,GAC1D,CAAC,CAGH"}
@@ -0,0 +1,24 @@
1
+ import { BlockErrorException, type BlockError } from '@23blocks/contracts';
2
+ import type { JsonApiDocument, JsonApiError } from './types.js';
3
+ /**
4
+ * Convert a JSON:API error to a BlockError
5
+ */
6
+ export declare function jsonApiErrorToBlockError(error: JsonApiError): BlockError;
7
+ /**
8
+ * Convert multiple JSON:API errors to a single BlockError
9
+ * Uses the first error as the primary error, includes others in meta
10
+ */
11
+ export declare function jsonApiErrorsToBlockError(errors: JsonApiError[]): BlockError;
12
+ /**
13
+ * Create a BlockErrorException from JSON:API errors
14
+ */
15
+ export declare function blockErrorFromJsonApi(errors: JsonApiError[]): BlockErrorException;
16
+ /**
17
+ * Check if a document is an error document and throw if so
18
+ */
19
+ export declare function throwIfError(document: JsonApiDocument): void;
20
+ /**
21
+ * Assert that a document is not an error document
22
+ */
23
+ export declare function assertNotError<T extends JsonApiDocument>(document: T): asserts document is T;
24
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGhE;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,YAAY,GAAG,UAAU,CAQxE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,UAAU,CAmB5E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,mBAAmB,CAEjF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAI5D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,eAAe,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,CAE5F"}
@@ -0,0 +1,40 @@
1
+ import type { JsonApiResource } from './types.js';
2
+ /**
3
+ * Included resources map for efficient relationship resolution
4
+ */
5
+ export type IncludedMap = Map<string, JsonApiResource>;
6
+ /**
7
+ * Resource mapper interface
8
+ * Each block provides mappers for its resource types
9
+ */
10
+ export interface ResourceMapper<T> {
11
+ /** JSON:API resource type this mapper handles */
12
+ type: string;
13
+ /**
14
+ * Map a JSON:API resource to a domain object
15
+ * @param resource - The JSON:API resource to map
16
+ * @param included - Map of included resources for relationship resolution
17
+ */
18
+ map(resource: JsonApiResource, included: IncludedMap): T;
19
+ }
20
+ /**
21
+ * Create a key for the included map
22
+ */
23
+ export declare function resourceKey(type: string, id: string): string;
24
+ /**
25
+ * Build an included map from an array of resources
26
+ */
27
+ export declare function buildIncludedMap(included?: JsonApiResource[]): IncludedMap;
28
+ /**
29
+ * Get a resource from the included map
30
+ */
31
+ export declare function getIncluded(included: IncludedMap, type: string, id: string): JsonApiResource | undefined;
32
+ /**
33
+ * Resolve a relationship from included resources
34
+ */
35
+ export declare function resolveRelationship<T>(resource: JsonApiResource, relationshipName: string, included: IncludedMap, mapper: ResourceMapper<T>): T | null;
36
+ /**
37
+ * Resolve a has-many relationship from included resources
38
+ */
39
+ export declare function resolveRelationshipMany<T>(resource: JsonApiResource, relationshipName: string, included: IncludedMap, mapper: ResourceMapper<T>): T[];
40
+ //# sourceMappingURL=mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../../../src/lib/mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEvD;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IAEb;;;;OAIG;IACH,GAAG,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,GAAG,CAAC,CAAC;CAC1D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,GAAE,eAAe,EAAO,GAAG,WAAW,CAM9E;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,eAAe,GAAG,SAAS,CAE7B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,QAAQ,EAAE,eAAe,EACzB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GACxB,CAAC,GAAG,IAAI,CAmBV;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,QAAQ,EAAE,eAAe,EACzB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GACxB,CAAC,EAAE,CAsBL"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * JSON:API Resource Object
3
+ * @see https://jsonapi.org/format/#document-resource-objects
4
+ */
5
+ export interface JsonApiResource<TAttributes = Record<string, unknown>> {
6
+ /** Resource type */
7
+ type: string;
8
+ /** Resource ID */
9
+ id: string;
10
+ /** Resource attributes */
11
+ attributes?: TAttributes;
12
+ /** Resource relationships */
13
+ relationships?: Record<string, JsonApiRelationship>;
14
+ /** Resource links */
15
+ links?: JsonApiLinks;
16
+ /** Resource meta */
17
+ meta?: Record<string, unknown>;
18
+ }
19
+ /**
20
+ * JSON:API Relationship Object
21
+ * @see https://jsonapi.org/format/#document-resource-object-relationships
22
+ */
23
+ export interface JsonApiRelationship {
24
+ /** Relationship data */
25
+ data: JsonApiResourceIdentifier | JsonApiResourceIdentifier[] | null;
26
+ /** Relationship links */
27
+ links?: JsonApiLinks;
28
+ /** Relationship meta */
29
+ meta?: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * JSON:API Resource Identifier Object
33
+ * @see https://jsonapi.org/format/#document-resource-identifier-objects
34
+ */
35
+ export interface JsonApiResourceIdentifier {
36
+ /** Resource type */
37
+ type: string;
38
+ /** Resource ID */
39
+ id: string;
40
+ /** Identifier meta */
41
+ meta?: Record<string, unknown>;
42
+ }
43
+ /**
44
+ * JSON:API Links Object
45
+ * @see https://jsonapi.org/format/#document-links
46
+ */
47
+ export interface JsonApiLinks {
48
+ self?: string | JsonApiLink;
49
+ related?: string | JsonApiLink;
50
+ first?: string | JsonApiLink | null;
51
+ last?: string | JsonApiLink | null;
52
+ prev?: string | JsonApiLink | null;
53
+ next?: string | JsonApiLink | null;
54
+ [key: string]: string | JsonApiLink | null | undefined;
55
+ }
56
+ /**
57
+ * JSON:API Link Object
58
+ * @see https://jsonapi.org/format/#document-links
59
+ */
60
+ export interface JsonApiLink {
61
+ href: string;
62
+ rel?: string;
63
+ describedby?: string;
64
+ title?: string;
65
+ type?: string;
66
+ hreflang?: string | string[];
67
+ meta?: Record<string, unknown>;
68
+ }
69
+ /**
70
+ * JSON:API Error Object
71
+ * @see https://jsonapi.org/format/#error-objects
72
+ */
73
+ export interface JsonApiError {
74
+ /** Unique identifier for this error */
75
+ id?: string;
76
+ /** Links related to the error */
77
+ links?: {
78
+ about?: string | JsonApiLink;
79
+ type?: string | JsonApiLink;
80
+ };
81
+ /** HTTP status code */
82
+ status?: string;
83
+ /** Application-specific error code */
84
+ code?: string;
85
+ /** Short summary of the error */
86
+ title?: string;
87
+ /** Detailed explanation of the error */
88
+ detail?: string;
89
+ /** Source of the error */
90
+ source?: {
91
+ pointer?: string;
92
+ parameter?: string;
93
+ header?: string;
94
+ };
95
+ /** Error meta */
96
+ meta?: Record<string, unknown>;
97
+ }
98
+ /**
99
+ * JSON:API Document
100
+ * @see https://jsonapi.org/format/#document-structure
101
+ */
102
+ export interface JsonApiDocument<TAttributes = Record<string, unknown>> {
103
+ /** Primary data */
104
+ data?: JsonApiResource<TAttributes> | JsonApiResource<TAttributes>[] | null;
105
+ /** Included resources */
106
+ included?: JsonApiResource[];
107
+ /** Errors */
108
+ errors?: JsonApiError[];
109
+ /** Top-level meta */
110
+ meta?: JsonApiMeta;
111
+ /** Top-level links */
112
+ links?: JsonApiLinks;
113
+ /** JSON:API version info */
114
+ jsonapi?: {
115
+ version?: string;
116
+ ext?: string[];
117
+ profile?: string[];
118
+ meta?: Record<string, unknown>;
119
+ };
120
+ }
121
+ /**
122
+ * JSON:API Meta Object (commonly used for pagination)
123
+ */
124
+ export interface JsonApiMeta {
125
+ /** Current page number */
126
+ current_page?: number;
127
+ /** Total number of pages */
128
+ total_pages?: number;
129
+ /** Total count of items */
130
+ total_count?: number;
131
+ /** Items per page */
132
+ per_page?: number;
133
+ /** Any additional meta fields */
134
+ [key: string]: unknown;
135
+ }
136
+ /**
137
+ * Type guard for single resource document
138
+ */
139
+ export declare function isSingleResourceDocument<T>(doc: JsonApiDocument<T>): doc is JsonApiDocument<T> & {
140
+ data: JsonApiResource<T>;
141
+ };
142
+ /**
143
+ * Type guard for collection resource document
144
+ */
145
+ export declare function isCollectionDocument<T>(doc: JsonApiDocument<T>): doc is JsonApiDocument<T> & {
146
+ data: JsonApiResource<T>[];
147
+ };
148
+ /**
149
+ * Type guard for error document
150
+ */
151
+ export declare function isErrorDocument(doc: JsonApiDocument): doc is JsonApiDocument & {
152
+ errors: JsonApiError[];
153
+ };
154
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@23blocks/jsonapi-codec",
3
- "version": "1.0.3",
3
+ "version": "2.0.0",
4
4
  "description": "JSON:API v1.0 codec for encoding/decoding API responses",
5
5
  "license": "MIT",
6
6
  "author": "23blocks <hello@23blocks.com>",
@@ -22,15 +22,15 @@
22
22
  "parser"
23
23
  ],
24
24
  "type": "module",
25
- "main": "./dist/index.js",
26
- "module": "./dist/index.js",
25
+ "main": "./dist/index.esm.js",
26
+ "module": "./dist/index.esm.js",
27
27
  "types": "./dist/index.d.ts",
28
28
  "exports": {
29
29
  "./package.json": "./package.json",
30
30
  ".": {
31
31
  "types": "./dist/index.d.ts",
32
- "import": "./dist/index.js",
33
- "default": "./dist/index.js"
32
+ "import": "./dist/index.esm.js",
33
+ "default": "./dist/index.esm.js"
34
34
  }
35
35
  },
36
36
  "files": [
@@ -41,7 +41,7 @@
41
41
  "sourceRoot": "packages/jsonapi-codec/src",
42
42
  "targets": {
43
43
  "build": {
44
- "executor": "@nx/js:swc",
44
+ "executor": "@nx/rollup:rollup",
45
45
  "outputs": [
46
46
  "{options.outputPath}"
47
47
  ],
@@ -49,8 +49,10 @@
49
49
  "outputPath": "packages/jsonapi-codec/dist",
50
50
  "main": "packages/jsonapi-codec/src/index.ts",
51
51
  "tsConfig": "packages/jsonapi-codec/tsconfig.lib.json",
52
- "skipTypeCheck": true,
53
- "stripLeadingPaths": true
52
+ "compiler": "swc",
53
+ "format": [
54
+ "esm"
55
+ ]
54
56
  }
55
57
  }
56
58
  }
package/dist/index.js DELETED
@@ -1,10 +0,0 @@
1
- // JSON:API Types
2
- export { isSingleResourceDocument, isCollectionDocument, isErrorDocument } from './lib/types.js';
3
- // Resource Mapper
4
- export { resourceKey, buildIncludedMap, getIncluded, resolveRelationship, resolveRelationshipMany } from './lib/mapper.js';
5
- // Decoding
6
- export { decodeOne, decodeOneOrNull, decodeMany, extractPageMeta, decodePageResult, decodeWith } from './lib/decode.js';
7
- // Error Handling
8
- export { jsonApiErrorToBlockError, jsonApiErrorsToBlockError, blockErrorFromJsonApi, throwIfError, assertNotError } from './lib/errors.js';
9
-
10
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// JSON:API Types\nexport {\n type JsonApiResource,\n type JsonApiRelationship,\n type JsonApiResourceIdentifier,\n type JsonApiLinks,\n type JsonApiLink,\n type JsonApiError,\n type JsonApiDocument,\n type JsonApiMeta,\n isSingleResourceDocument,\n isCollectionDocument,\n isErrorDocument,\n} from './lib/types.js';\n\n// Resource Mapper\nexport {\n type IncludedMap,\n type ResourceMapper,\n resourceKey,\n buildIncludedMap,\n getIncluded,\n resolveRelationship,\n resolveRelationshipMany,\n} from './lib/mapper.js';\n\n// Decoding\nexport {\n decodeOne,\n decodeOneOrNull,\n decodeMany,\n extractPageMeta,\n decodePageResult,\n decodeWith,\n} from './lib/decode.js';\n\n// Error Handling\nexport {\n jsonApiErrorToBlockError,\n jsonApiErrorsToBlockError,\n blockErrorFromJsonApi,\n throwIfError,\n assertNotError,\n} from './lib/errors.js';\n"],"names":["isSingleResourceDocument","isCollectionDocument","isErrorDocument","resourceKey","buildIncludedMap","getIncluded","resolveRelationship","resolveRelationshipMany","decodeOne","decodeOneOrNull","decodeMany","extractPageMeta","decodePageResult","decodeWith","jsonApiErrorToBlockError","jsonApiErrorsToBlockError","blockErrorFromJsonApi","throwIfError","assertNotError"],"rangeMappings":";;;;;;;","mappings":"AAAA,iBAAiB;AACjB,SASEA,wBAAwB,EACxBC,oBAAoB,EACpBC,eAAe,QACV,iBAAiB;AAExB,kBAAkB;AAClB,SAGEC,WAAW,EACXC,gBAAgB,EAChBC,WAAW,EACXC,mBAAmB,EACnBC,uBAAuB,QAClB,kBAAkB;AAEzB,WAAW;AACX,SACEC,SAAS,EACTC,eAAe,EACfC,UAAU,EACVC,eAAe,EACfC,gBAAgB,EAChBC,UAAU,QACL,kBAAkB;AAEzB,iBAAiB;AACjB,SACEC,wBAAwB,EACxBC,yBAAyB,EACzBC,qBAAqB,EACrBC,YAAY,EACZC,cAAc,QACT,kBAAkB"}
@@ -1,57 +0,0 @@
1
- import { isSingleResourceDocument, isCollectionDocument } from './types.js';
2
- import { buildIncludedMap } from './mapper.js';
3
- /**
4
- * Decode a single resource from a JSON:API document
5
- */ export function decodeOne(document, mapper) {
6
- if (!isSingleResourceDocument(document)) {
7
- throw new Error('Expected single resource document');
8
- }
9
- const included = buildIncludedMap(document.included);
10
- return mapper.map(document.data, included);
11
- }
12
- /**
13
- * Decode a single resource from a JSON:API document, returning null if not found
14
- */ export function decodeOneOrNull(document, mapper) {
15
- if (!document.data || Array.isArray(document.data)) {
16
- return null;
17
- }
18
- const included = buildIncludedMap(document.included);
19
- return mapper.map(document.data, included);
20
- }
21
- /**
22
- * Decode multiple resources from a JSON:API document
23
- */ export function decodeMany(document, mapper) {
24
- if (!isCollectionDocument(document)) {
25
- throw new Error('Expected collection document');
26
- }
27
- const included = buildIncludedMap(document.included);
28
- return document.data.map((resource)=>mapper.map(resource, included));
29
- }
30
- /**
31
- * Extract pagination metadata from JSON:API meta
32
- */ export function extractPageMeta(meta) {
33
- var _meta_current_page, _meta_total_pages, _meta_total_count, _meta_per_page;
34
- return {
35
- currentPage: (_meta_current_page = meta == null ? void 0 : meta.current_page) != null ? _meta_current_page : 1,
36
- totalPages: (_meta_total_pages = meta == null ? void 0 : meta.total_pages) != null ? _meta_total_pages : 1,
37
- totalCount: (_meta_total_count = meta == null ? void 0 : meta.total_count) != null ? _meta_total_count : 0,
38
- perPage: (_meta_per_page = meta == null ? void 0 : meta.per_page) != null ? _meta_per_page : 0
39
- };
40
- }
41
- /**
42
- * Decode a paginated collection from a JSON:API document
43
- */ export function decodePageResult(document, mapper) {
44
- const data = isCollectionDocument(document) ? decodeMany(document, mapper) : [];
45
- return {
46
- data,
47
- meta: extractPageMeta(document.meta)
48
- };
49
- }
50
- /**
51
- * Decode with a custom decoder function
52
- */ export function decodeWith(document, decoder) {
53
- const included = buildIncludedMap(document.included);
54
- return decoder(document, included);
55
- }
56
-
57
- //# sourceMappingURL=decode.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/lib/decode.ts"],"sourcesContent":["import type { PageResult, PageMeta } from '@23blocks/contracts';\nimport type { JsonApiDocument, JsonApiMeta } from './types.js';\nimport { isSingleResourceDocument, isCollectionDocument } from './types.js';\nimport type { ResourceMapper, IncludedMap } from './mapper.js';\nimport { buildIncludedMap } from './mapper.js';\n\n/**\n * Decode a single resource from a JSON:API document\n */\nexport function decodeOne<T>(\n document: JsonApiDocument,\n mapper: ResourceMapper<T>\n): T {\n if (!isSingleResourceDocument(document)) {\n throw new Error('Expected single resource document');\n }\n\n const included = buildIncludedMap(document.included);\n return mapper.map(document.data, included);\n}\n\n/**\n * Decode a single resource from a JSON:API document, returning null if not found\n */\nexport function decodeOneOrNull<T>(\n document: JsonApiDocument,\n mapper: ResourceMapper<T>\n): T | null {\n if (!document.data || Array.isArray(document.data)) {\n return null;\n }\n\n const included = buildIncludedMap(document.included);\n return mapper.map(document.data, included);\n}\n\n/**\n * Decode multiple resources from a JSON:API document\n */\nexport function decodeMany<T>(\n document: JsonApiDocument,\n mapper: ResourceMapper<T>\n): T[] {\n if (!isCollectionDocument(document)) {\n throw new Error('Expected collection document');\n }\n\n const included = buildIncludedMap(document.included);\n return document.data.map((resource) => mapper.map(resource, included));\n}\n\n/**\n * Extract pagination metadata from JSON:API meta\n */\nexport function extractPageMeta(meta?: JsonApiMeta): PageMeta {\n return {\n currentPage: meta?.current_page ?? 1,\n totalPages: meta?.total_pages ?? 1,\n totalCount: meta?.total_count ?? 0,\n perPage: meta?.per_page ?? 0,\n };\n}\n\n/**\n * Decode a paginated collection from a JSON:API document\n */\nexport function decodePageResult<T>(\n document: JsonApiDocument,\n mapper: ResourceMapper<T>\n): PageResult<T> {\n const data = isCollectionDocument(document)\n ? decodeMany(document, mapper)\n : [];\n\n return {\n data,\n meta: extractPageMeta(document.meta),\n };\n}\n\n/**\n * Decode with a custom decoder function\n */\nexport function decodeWith<T>(\n document: JsonApiDocument,\n decoder: (doc: JsonApiDocument, included: IncludedMap) => T\n): T {\n const included = buildIncludedMap(document.included);\n return decoder(document, included);\n}\n"],"names":["isSingleResourceDocument","isCollectionDocument","buildIncludedMap","decodeOne","document","mapper","Error","included","map","data","decodeOneOrNull","Array","isArray","decodeMany","resource","extractPageMeta","meta","currentPage","current_page","totalPages","total_pages","totalCount","total_count","perPage","per_page","decodePageResult","decodeWith","decoder"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAEA,SAASA,wBAAwB,EAAEC,oBAAoB,QAAQ,aAAa;AAE5E,SAASC,gBAAgB,QAAQ,cAAc;AAE/C;;CAEC,GACD,OAAO,SAASC,UACdC,QAAyB,EACzBC,MAAyB;IAEzB,IAAI,CAACL,yBAAyBI,WAAW;QACvC,MAAM,IAAIE,MAAM;IAClB;IAEA,MAAMC,WAAWL,iBAAiBE,SAASG,QAAQ;IACnD,OAAOF,OAAOG,GAAG,CAACJ,SAASK,IAAI,EAAEF;AACnC;AAEA;;CAEC,GACD,OAAO,SAASG,gBACdN,QAAyB,EACzBC,MAAyB;IAEzB,IAAI,CAACD,SAASK,IAAI,IAAIE,MAAMC,OAAO,CAACR,SAASK,IAAI,GAAG;QAClD,OAAO;IACT;IAEA,MAAMF,WAAWL,iBAAiBE,SAASG,QAAQ;IACnD,OAAOF,OAAOG,GAAG,CAACJ,SAASK,IAAI,EAAEF;AACnC;AAEA;;CAEC,GACD,OAAO,SAASM,WACdT,QAAyB,EACzBC,MAAyB;IAEzB,IAAI,CAACJ,qBAAqBG,WAAW;QACnC,MAAM,IAAIE,MAAM;IAClB;IAEA,MAAMC,WAAWL,iBAAiBE,SAASG,QAAQ;IACnD,OAAOH,SAASK,IAAI,CAACD,GAAG,CAAC,CAACM,WAAaT,OAAOG,GAAG,CAACM,UAAUP;AAC9D;AAEA;;CAEC,GACD,OAAO,SAASQ,gBAAgBC,IAAkB;QAEjCA,oBACDA,mBACAA,mBACHA;IAJX,OAAO;QACLC,aAAaD,CAAAA,qBAAAA,wBAAAA,KAAME,YAAY,YAAlBF,qBAAsB;QACnCG,YAAYH,CAAAA,oBAAAA,wBAAAA,KAAMI,WAAW,YAAjBJ,oBAAqB;QACjCK,YAAYL,CAAAA,oBAAAA,wBAAAA,KAAMM,WAAW,YAAjBN,oBAAqB;QACjCO,SAASP,CAAAA,iBAAAA,wBAAAA,KAAMQ,QAAQ,YAAdR,iBAAkB;IAC7B;AACF;AAEA;;CAEC,GACD,OAAO,SAASS,iBACdrB,QAAyB,EACzBC,MAAyB;IAEzB,MAAMI,OAAOR,qBAAqBG,YAC9BS,WAAWT,UAAUC,UACrB,EAAE;IAEN,OAAO;QACLI;QACAO,MAAMD,gBAAgBX,SAASY,IAAI;IACrC;AACF;AAEA;;CAEC,GACD,OAAO,SAASU,WACdtB,QAAyB,EACzBuB,OAA2D;IAE3D,MAAMpB,WAAWL,iBAAiBE,SAASG,QAAQ;IACnD,OAAOoB,QAAQvB,UAAUG;AAC3B"}
@@ -1,54 +0,0 @@
1
- import { _ as _extends } from "@swc/helpers/_/_extends";
2
- import { BlockErrorException } from '@23blocks/contracts';
3
- import { isErrorDocument } from './types.js';
4
- /**
5
- * Convert a JSON:API error to a BlockError
6
- */ export function jsonApiErrorToBlockError(error) {
7
- var _error_source, _error_source1;
8
- var _error_code, _error_detail, _ref, _error_source_pointer;
9
- return {
10
- code: (_error_code = error.code) != null ? _error_code : 'unknown_error',
11
- message: (_ref = (_error_detail = error.detail) != null ? _error_detail : error.title) != null ? _ref : 'An unknown error occurred',
12
- status: error.status ? parseInt(error.status, 10) : 500,
13
- source: (_error_source_pointer = (_error_source = error.source) == null ? void 0 : _error_source.pointer) != null ? _error_source_pointer : (_error_source1 = error.source) == null ? void 0 : _error_source1.parameter,
14
- meta: error.meta
15
- };
16
- }
17
- /**
18
- * Convert multiple JSON:API errors to a single BlockError
19
- * Uses the first error as the primary error, includes others in meta
20
- */ export function jsonApiErrorsToBlockError(errors) {
21
- if (errors.length === 0) {
22
- return {
23
- code: 'unknown_error',
24
- message: 'An unknown error occurred',
25
- status: 500
26
- };
27
- }
28
- const primary = jsonApiErrorToBlockError(errors[0]);
29
- if (errors.length > 1) {
30
- primary.meta = _extends({}, primary.meta, {
31
- additionalErrors: errors.slice(1).map(jsonApiErrorToBlockError)
32
- });
33
- }
34
- return primary;
35
- }
36
- /**
37
- * Create a BlockErrorException from JSON:API errors
38
- */ export function blockErrorFromJsonApi(errors) {
39
- return new BlockErrorException(jsonApiErrorsToBlockError(errors));
40
- }
41
- /**
42
- * Check if a document is an error document and throw if so
43
- */ export function throwIfError(document) {
44
- if (isErrorDocument(document)) {
45
- throw blockErrorFromJsonApi(document.errors);
46
- }
47
- }
48
- /**
49
- * Assert that a document is not an error document
50
- */ export function assertNotError(document) {
51
- throwIfError(document);
52
- }
53
-
54
- //# sourceMappingURL=errors.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/lib/errors.ts"],"sourcesContent":["import { BlockErrorException, type BlockError } from '@23blocks/contracts';\nimport type { JsonApiDocument, JsonApiError } from './types.js';\nimport { isErrorDocument } from './types.js';\n\n/**\n * Convert a JSON:API error to a BlockError\n */\nexport function jsonApiErrorToBlockError(error: JsonApiError): BlockError {\n return {\n code: error.code ?? 'unknown_error',\n message: error.detail ?? error.title ?? 'An unknown error occurred',\n status: error.status ? parseInt(error.status, 10) : 500,\n source: error.source?.pointer ?? error.source?.parameter,\n meta: error.meta,\n };\n}\n\n/**\n * Convert multiple JSON:API errors to a single BlockError\n * Uses the first error as the primary error, includes others in meta\n */\nexport function jsonApiErrorsToBlockError(errors: JsonApiError[]): BlockError {\n if (errors.length === 0) {\n return {\n code: 'unknown_error',\n message: 'An unknown error occurred',\n status: 500,\n };\n }\n\n const primary = jsonApiErrorToBlockError(errors[0]);\n\n if (errors.length > 1) {\n primary.meta = {\n ...primary.meta,\n additionalErrors: errors.slice(1).map(jsonApiErrorToBlockError),\n };\n }\n\n return primary;\n}\n\n/**\n * Create a BlockErrorException from JSON:API errors\n */\nexport function blockErrorFromJsonApi(errors: JsonApiError[]): BlockErrorException {\n return new BlockErrorException(jsonApiErrorsToBlockError(errors));\n}\n\n/**\n * Check if a document is an error document and throw if so\n */\nexport function throwIfError(document: JsonApiDocument): void {\n if (isErrorDocument(document)) {\n throw blockErrorFromJsonApi(document.errors);\n }\n}\n\n/**\n * Assert that a document is not an error document\n */\nexport function assertNotError<T extends JsonApiDocument>(document: T): asserts document is T {\n throwIfError(document);\n}\n"],"names":["BlockErrorException","isErrorDocument","jsonApiErrorToBlockError","error","code","message","detail","title","status","parseInt","source","pointer","parameter","meta","jsonApiErrorsToBlockError","errors","length","primary","additionalErrors","slice","map","blockErrorFromJsonApi","throwIfError","document","assertNotError"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";AAAA,SAASA,mBAAmB,QAAyB,sBAAsB;AAE3E,SAASC,eAAe,QAAQ,aAAa;AAE7C;;CAEC,GACD,OAAO,SAASC,yBAAyBC,KAAmB;QAKhDA,eAAyBA;QAH3BA,aACGA,eAAAA,MAEDA;IAJV,OAAO;QACLC,MAAMD,CAAAA,cAAAA,MAAMC,IAAI,YAAVD,cAAc;QACpBE,SAASF,CAAAA,OAAAA,CAAAA,gBAAAA,MAAMG,MAAM,YAAZH,gBAAgBA,MAAMI,KAAK,YAA3BJ,OAA+B;QACxCK,QAAQL,MAAMK,MAAM,GAAGC,SAASN,MAAMK,MAAM,EAAE,MAAM;QACpDE,QAAQP,CAAAA,yBAAAA,gBAAAA,MAAMO,MAAM,qBAAZP,cAAcQ,OAAO,YAArBR,yBAAyBA,iBAAAA,MAAMO,MAAM,qBAAZP,eAAcS,SAAS;QACxDC,MAAMV,MAAMU,IAAI;IAClB;AACF;AAEA;;;CAGC,GACD,OAAO,SAASC,0BAA0BC,MAAsB;IAC9D,IAAIA,OAAOC,MAAM,KAAK,GAAG;QACvB,OAAO;YACLZ,MAAM;YACNC,SAAS;YACTG,QAAQ;QACV;IACF;IAEA,MAAMS,UAAUf,yBAAyBa,MAAM,CAAC,EAAE;IAElD,IAAIA,OAAOC,MAAM,GAAG,GAAG;QACrBC,QAAQJ,IAAI,GAAG,aACVI,QAAQJ,IAAI;YACfK,kBAAkBH,OAAOI,KAAK,CAAC,GAAGC,GAAG,CAAClB;;IAE1C;IAEA,OAAOe;AACT;AAEA;;CAEC,GACD,OAAO,SAASI,sBAAsBN,MAAsB;IAC1D,OAAO,IAAIf,oBAAoBc,0BAA0BC;AAC3D;AAEA;;CAEC,GACD,OAAO,SAASO,aAAaC,QAAyB;IACpD,IAAItB,gBAAgBsB,WAAW;QAC7B,MAAMF,sBAAsBE,SAASR,MAAM;IAC7C;AACF;AAEA;;CAEC,GACD,OAAO,SAASS,eAA0CD,QAAW;IACnED,aAAaC;AACf"}
@@ -1,59 +0,0 @@
1
- /**
2
- * Create a key for the included map
3
- */ export function resourceKey(type, id) {
4
- return `${type}:${id}`;
5
- }
6
- /**
7
- * Build an included map from an array of resources
8
- */ export function buildIncludedMap(included = []) {
9
- const map = new Map();
10
- for (const resource of included){
11
- map.set(resourceKey(resource.type, resource.id), resource);
12
- }
13
- return map;
14
- }
15
- /**
16
- * Get a resource from the included map
17
- */ export function getIncluded(included, type, id) {
18
- return included.get(resourceKey(type, id));
19
- }
20
- /**
21
- * Resolve a relationship from included resources
22
- */ export function resolveRelationship(resource, relationshipName, included, mapper) {
23
- var _resource_relationships;
24
- const relationship = (_resource_relationships = resource.relationships) == null ? void 0 : _resource_relationships[relationshipName];
25
- if (!(relationship == null ? void 0 : relationship.data)) {
26
- return null;
27
- }
28
- const data = relationship.data;
29
- if (Array.isArray(data)) {
30
- throw new Error(`Expected single relationship for '${relationshipName}', got array. Use resolveRelationshipMany instead.`);
31
- }
32
- const related = getIncluded(included, data.type, data.id);
33
- if (!related) {
34
- return null;
35
- }
36
- return mapper.map(related, included);
37
- }
38
- /**
39
- * Resolve a has-many relationship from included resources
40
- */ export function resolveRelationshipMany(resource, relationshipName, included, mapper) {
41
- var _resource_relationships;
42
- const relationship = (_resource_relationships = resource.relationships) == null ? void 0 : _resource_relationships[relationshipName];
43
- if (!(relationship == null ? void 0 : relationship.data)) {
44
- return [];
45
- }
46
- const data = relationship.data;
47
- if (!Array.isArray(data)) {
48
- throw new Error(`Expected array relationship for '${relationshipName}', got single. Use resolveRelationship instead.`);
49
- }
50
- return data.map((identifier)=>{
51
- const related = getIncluded(included, identifier.type, identifier.id);
52
- if (!related) {
53
- return null;
54
- }
55
- return mapper.map(related, included);
56
- }).filter((item)=>item !== null);
57
- }
58
-
59
- //# sourceMappingURL=mapper.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/lib/mapper.ts"],"sourcesContent":["import type { JsonApiResource } from './types.js';\n\n/**\n * Included resources map for efficient relationship resolution\n */\nexport type IncludedMap = Map<string, JsonApiResource>;\n\n/**\n * Resource mapper interface\n * Each block provides mappers for its resource types\n */\nexport interface ResourceMapper<T> {\n /** JSON:API resource type this mapper handles */\n type: string;\n\n /**\n * Map a JSON:API resource to a domain object\n * @param resource - The JSON:API resource to map\n * @param included - Map of included resources for relationship resolution\n */\n map(resource: JsonApiResource, included: IncludedMap): T;\n}\n\n/**\n * Create a key for the included map\n */\nexport function resourceKey(type: string, id: string): string {\n return `${type}:${id}`;\n}\n\n/**\n * Build an included map from an array of resources\n */\nexport function buildIncludedMap(included: JsonApiResource[] = []): IncludedMap {\n const map = new Map<string, JsonApiResource>();\n for (const resource of included) {\n map.set(resourceKey(resource.type, resource.id), resource);\n }\n return map;\n}\n\n/**\n * Get a resource from the included map\n */\nexport function getIncluded(\n included: IncludedMap,\n type: string,\n id: string\n): JsonApiResource | undefined {\n return included.get(resourceKey(type, id));\n}\n\n/**\n * Resolve a relationship from included resources\n */\nexport function resolveRelationship<T>(\n resource: JsonApiResource,\n relationshipName: string,\n included: IncludedMap,\n mapper: ResourceMapper<T>\n): T | null {\n const relationship = resource.relationships?.[relationshipName];\n if (!relationship?.data) {\n return null;\n }\n\n const data = relationship.data;\n if (Array.isArray(data)) {\n throw new Error(\n `Expected single relationship for '${relationshipName}', got array. Use resolveRelationshipMany instead.`\n );\n }\n\n const related = getIncluded(included, data.type, data.id);\n if (!related) {\n return null;\n }\n\n return mapper.map(related, included);\n}\n\n/**\n * Resolve a has-many relationship from included resources\n */\nexport function resolveRelationshipMany<T>(\n resource: JsonApiResource,\n relationshipName: string,\n included: IncludedMap,\n mapper: ResourceMapper<T>\n): T[] {\n const relationship = resource.relationships?.[relationshipName];\n if (!relationship?.data) {\n return [];\n }\n\n const data = relationship.data;\n if (!Array.isArray(data)) {\n throw new Error(\n `Expected array relationship for '${relationshipName}', got single. Use resolveRelationship instead.`\n );\n }\n\n return data\n .map((identifier) => {\n const related = getIncluded(included, identifier.type, identifier.id);\n if (!related) {\n return null;\n }\n return mapper.map(related, included);\n })\n .filter((item): item is T => item !== null);\n}\n"],"names":["resourceKey","type","id","buildIncludedMap","included","map","Map","resource","set","getIncluded","get","resolveRelationship","relationshipName","mapper","relationship","relationships","data","Array","isArray","Error","related","resolveRelationshipMany","identifier","filter","item"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAuBA;;CAEC,GACD,OAAO,SAASA,YAAYC,IAAY,EAAEC,EAAU;IAClD,OAAO,CAAC,EAAED,KAAK,CAAC,EAAEC,GAAG,CAAC;AACxB;AAEA;;CAEC,GACD,OAAO,SAASC,iBAAiBC,WAA8B,EAAE;IAC/D,MAAMC,MAAM,IAAIC;IAChB,KAAK,MAAMC,YAAYH,SAAU;QAC/BC,IAAIG,GAAG,CAACR,YAAYO,SAASN,IAAI,EAAEM,SAASL,EAAE,GAAGK;IACnD;IACA,OAAOF;AACT;AAEA;;CAEC,GACD,OAAO,SAASI,YACdL,QAAqB,EACrBH,IAAY,EACZC,EAAU;IAEV,OAAOE,SAASM,GAAG,CAACV,YAAYC,MAAMC;AACxC;AAEA;;CAEC,GACD,OAAO,SAASS,oBACdJ,QAAyB,EACzBK,gBAAwB,EACxBR,QAAqB,EACrBS,MAAyB;QAEJN;IAArB,MAAMO,gBAAeP,0BAAAA,SAASQ,aAAa,qBAAtBR,uBAAwB,CAACK,iBAAiB;IAC/D,IAAI,EAACE,gCAAAA,aAAcE,IAAI,GAAE;QACvB,OAAO;IACT;IAEA,MAAMA,OAAOF,aAAaE,IAAI;IAC9B,IAAIC,MAAMC,OAAO,CAACF,OAAO;QACvB,MAAM,IAAIG,MACR,CAAC,kCAAkC,EAAEP,iBAAiB,kDAAkD,CAAC;IAE7G;IAEA,MAAMQ,UAAUX,YAAYL,UAAUY,KAAKf,IAAI,EAAEe,KAAKd,EAAE;IACxD,IAAI,CAACkB,SAAS;QACZ,OAAO;IACT;IAEA,OAAOP,OAAOR,GAAG,CAACe,SAAShB;AAC7B;AAEA;;CAEC,GACD,OAAO,SAASiB,wBACdd,QAAyB,EACzBK,gBAAwB,EACxBR,QAAqB,EACrBS,MAAyB;QAEJN;IAArB,MAAMO,gBAAeP,0BAAAA,SAASQ,aAAa,qBAAtBR,uBAAwB,CAACK,iBAAiB;IAC/D,IAAI,EAACE,gCAAAA,aAAcE,IAAI,GAAE;QACvB,OAAO,EAAE;IACX;IAEA,MAAMA,OAAOF,aAAaE,IAAI;IAC9B,IAAI,CAACC,MAAMC,OAAO,CAACF,OAAO;QACxB,MAAM,IAAIG,MACR,CAAC,iCAAiC,EAAEP,iBAAiB,+CAA+C,CAAC;IAEzG;IAEA,OAAOI,KACJX,GAAG,CAAC,CAACiB;QACJ,MAAMF,UAAUX,YAAYL,UAAUkB,WAAWrB,IAAI,EAAEqB,WAAWpB,EAAE;QACpE,IAAI,CAACkB,SAAS;YACZ,OAAO;QACT;QACA,OAAOP,OAAOR,GAAG,CAACe,SAAShB;IAC7B,GACCmB,MAAM,CAAC,CAACC,OAAoBA,SAAS;AAC1C"}
package/dist/lib/types.js DELETED
@@ -1,20 +0,0 @@
1
- /**
2
- * JSON:API Resource Object
3
- * @see https://jsonapi.org/format/#document-resource-objects
4
- */ /**
5
- * Type guard for single resource document
6
- */ export function isSingleResourceDocument(doc) {
7
- return doc.data !== null && doc.data !== undefined && !Array.isArray(doc.data);
8
- }
9
- /**
10
- * Type guard for collection resource document
11
- */ export function isCollectionDocument(doc) {
12
- return Array.isArray(doc.data);
13
- }
14
- /**
15
- * Type guard for error document
16
- */ export function isErrorDocument(doc) {
17
- return Array.isArray(doc.errors) && doc.errors.length > 0;
18
- }
19
-
20
- //# sourceMappingURL=types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/lib/types.ts"],"sourcesContent":["/**\n * JSON:API Resource Object\n * @see https://jsonapi.org/format/#document-resource-objects\n */\nexport interface JsonApiResource<TAttributes = Record<string, unknown>> {\n /** Resource type */\n type: string;\n /** Resource ID */\n id: string;\n /** Resource attributes */\n attributes?: TAttributes;\n /** Resource relationships */\n relationships?: Record<string, JsonApiRelationship>;\n /** Resource links */\n links?: JsonApiLinks;\n /** Resource meta */\n meta?: Record<string, unknown>;\n}\n\n/**\n * JSON:API Relationship Object\n * @see https://jsonapi.org/format/#document-resource-object-relationships\n */\nexport interface JsonApiRelationship {\n /** Relationship data */\n data: JsonApiResourceIdentifier | JsonApiResourceIdentifier[] | null;\n /** Relationship links */\n links?: JsonApiLinks;\n /** Relationship meta */\n meta?: Record<string, unknown>;\n}\n\n/**\n * JSON:API Resource Identifier Object\n * @see https://jsonapi.org/format/#document-resource-identifier-objects\n */\nexport interface JsonApiResourceIdentifier {\n /** Resource type */\n type: string;\n /** Resource ID */\n id: string;\n /** Identifier meta */\n meta?: Record<string, unknown>;\n}\n\n/**\n * JSON:API Links Object\n * @see https://jsonapi.org/format/#document-links\n */\nexport interface JsonApiLinks {\n self?: string | JsonApiLink;\n related?: string | JsonApiLink;\n first?: string | JsonApiLink | null;\n last?: string | JsonApiLink | null;\n prev?: string | JsonApiLink | null;\n next?: string | JsonApiLink | null;\n [key: string]: string | JsonApiLink | null | undefined;\n}\n\n/**\n * JSON:API Link Object\n * @see https://jsonapi.org/format/#document-links\n */\nexport interface JsonApiLink {\n href: string;\n rel?: string;\n describedby?: string;\n title?: string;\n type?: string;\n hreflang?: string | string[];\n meta?: Record<string, unknown>;\n}\n\n/**\n * JSON:API Error Object\n * @see https://jsonapi.org/format/#error-objects\n */\nexport interface JsonApiError {\n /** Unique identifier for this error */\n id?: string;\n /** Links related to the error */\n links?: {\n about?: string | JsonApiLink;\n type?: string | JsonApiLink;\n };\n /** HTTP status code */\n status?: string;\n /** Application-specific error code */\n code?: string;\n /** Short summary of the error */\n title?: string;\n /** Detailed explanation of the error */\n detail?: string;\n /** Source of the error */\n source?: {\n pointer?: string;\n parameter?: string;\n header?: string;\n };\n /** Error meta */\n meta?: Record<string, unknown>;\n}\n\n/**\n * JSON:API Document\n * @see https://jsonapi.org/format/#document-structure\n */\nexport interface JsonApiDocument<TAttributes = Record<string, unknown>> {\n /** Primary data */\n data?: JsonApiResource<TAttributes> | JsonApiResource<TAttributes>[] | null;\n /** Included resources */\n included?: JsonApiResource[];\n /** Errors */\n errors?: JsonApiError[];\n /** Top-level meta */\n meta?: JsonApiMeta;\n /** Top-level links */\n links?: JsonApiLinks;\n /** JSON:API version info */\n jsonapi?: {\n version?: string;\n ext?: string[];\n profile?: string[];\n meta?: Record<string, unknown>;\n };\n}\n\n/**\n * JSON:API Meta Object (commonly used for pagination)\n */\nexport interface JsonApiMeta {\n /** Current page number */\n current_page?: number;\n /** Total number of pages */\n total_pages?: number;\n /** Total count of items */\n total_count?: number;\n /** Items per page */\n per_page?: number;\n /** Any additional meta fields */\n [key: string]: unknown;\n}\n\n/**\n * Type guard for single resource document\n */\nexport function isSingleResourceDocument<T>(\n doc: JsonApiDocument<T>\n): doc is JsonApiDocument<T> & { data: JsonApiResource<T> } {\n return doc.data !== null && doc.data !== undefined && !Array.isArray(doc.data);\n}\n\n/**\n * Type guard for collection resource document\n */\nexport function isCollectionDocument<T>(\n doc: JsonApiDocument<T>\n): doc is JsonApiDocument<T> & { data: JsonApiResource<T>[] } {\n return Array.isArray(doc.data);\n}\n\n/**\n * Type guard for error document\n */\nexport function isErrorDocument(\n doc: JsonApiDocument\n): doc is JsonApiDocument & { errors: JsonApiError[] } {\n return Array.isArray(doc.errors) && doc.errors.length > 0;\n}\n"],"names":["isSingleResourceDocument","doc","data","undefined","Array","isArray","isCollectionDocument","isErrorDocument","errors","length"],"rangeMappings":";;;;;;;;;;;;;;;;;","mappings":"AAAA;;;CAGC,GA4ID;;CAEC,GACD,OAAO,SAASA,yBACdC,GAAuB;IAEvB,OAAOA,IAAIC,IAAI,KAAK,QAAQD,IAAIC,IAAI,KAAKC,aAAa,CAACC,MAAMC,OAAO,CAACJ,IAAIC,IAAI;AAC/E;AAEA;;CAEC,GACD,OAAO,SAASI,qBACdL,GAAuB;IAEvB,OAAOG,MAAMC,OAAO,CAACJ,IAAIC,IAAI;AAC/B;AAEA;;CAEC,GACD,OAAO,SAASK,gBACdN,GAAoB;IAEpB,OAAOG,MAAMC,OAAO,CAACJ,IAAIO,MAAM,KAAKP,IAAIO,MAAM,CAACC,MAAM,GAAG;AAC1D"}