@aphexcms/cms-core 0.1.12 → 0.1.13
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 +21 -0
- package/dist/api/documents.d.ts +1 -0
- package/dist/api/documents.d.ts.map +1 -1
- package/dist/api/documents.js +9 -1
- package/dist/api/types.d.ts +24 -2
- package/dist/api/types.d.ts.map +1 -1
- package/dist/auth/auth-hooks.d.ts.map +1 -1
- package/dist/auth/auth-hooks.js +18 -4
- package/dist/cli/generate-types.js +218 -0
- package/dist/cli/index.js +86 -0
- package/dist/components/AdminApp.svelte +26 -55
- package/dist/components/AdminApp.svelte.d.ts +3 -5
- package/dist/components/AdminApp.svelte.d.ts.map +1 -1
- package/dist/components/admin/DocumentEditor.svelte +60 -14
- package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ReferenceField.svelte +2 -3
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
- package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts +8 -1
- package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts.map +1 -1
- package/dist/db/interfaces/asset.d.ts +22 -0
- package/dist/db/interfaces/asset.d.ts.map +1 -1
- package/dist/db/interfaces/document.d.ts +25 -0
- package/dist/db/interfaces/document.d.ts.map +1 -1
- package/dist/field-validation/utils.d.ts +19 -1
- package/dist/field-validation/utils.d.ts.map +1 -1
- package/dist/field-validation/utils.js +33 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +80 -12
- package/dist/lib/auth/provider.js +1 -0
- package/dist/lib/db/index.js +4 -0
- package/dist/lib/db/interfaces/asset.js +1 -0
- package/dist/lib/db/interfaces/document.js +1 -0
- package/dist/lib/db/interfaces/index.js +1 -0
- package/dist/lib/db/interfaces/organization.js +1 -0
- package/dist/lib/db/interfaces/schema.js +1 -0
- package/dist/lib/db/interfaces/user.js +1 -0
- package/dist/lib/email/index.js +4 -0
- package/dist/lib/email/interfaces/email.js +1 -0
- package/dist/lib/field-validation/rule.js +221 -0
- package/dist/lib/field-validation/utils.js +99 -0
- package/dist/lib/storage/interfaces/index.js +2 -0
- package/dist/lib/storage/interfaces/storage.js +1 -0
- package/dist/lib/types/asset.js +2 -0
- package/dist/lib/types/auth.js +41 -0
- package/dist/lib/types/config.js +1 -0
- package/dist/lib/types/document.js +1 -0
- package/dist/lib/types/filters.js +5 -0
- package/dist/lib/types/index.js +9 -0
- package/dist/lib/types/organization.js +3 -0
- package/dist/lib/types/schemas.js +1 -0
- package/dist/lib/types/sidebar.js +1 -0
- package/dist/lib/types/user.js +1 -0
- package/dist/local-api/auth-helpers.d.ts +65 -0
- package/dist/local-api/auth-helpers.d.ts.map +1 -0
- package/dist/local-api/auth-helpers.js +102 -0
- package/dist/local-api/collection-api.d.ts +138 -0
- package/dist/local-api/collection-api.d.ts.map +1 -0
- package/dist/local-api/collection-api.js +276 -0
- package/dist/local-api/index.d.ts +108 -0
- package/dist/local-api/index.d.ts.map +1 -0
- package/dist/local-api/index.js +157 -0
- package/dist/local-api/permissions.d.ts +45 -0
- package/dist/local-api/permissions.d.ts.map +1 -0
- package/dist/local-api/permissions.js +117 -0
- package/dist/local-api/types.d.ts +65 -0
- package/dist/local-api/types.d.ts.map +1 -0
- package/dist/local-api/types.js +4 -0
- package/dist/routes/documents-by-id.d.ts.map +1 -1
- package/dist/routes/documents-by-id.js +84 -63
- package/dist/routes/documents-publish.d.ts.map +1 -1
- package/dist/routes/documents-publish.js +57 -72
- package/dist/routes/documents-query.d.ts +24 -0
- package/dist/routes/documents-query.d.ts.map +1 -0
- package/dist/routes/documents-query.js +95 -0
- package/dist/routes/documents.d.ts.map +1 -1
- package/dist/routes/documents.js +80 -75
- package/dist/routes/index.d.ts +2 -0
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +2 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -0
- package/dist/types/config.d.ts +18 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/document.d.ts +1 -0
- package/dist/types/document.d.ts.map +1 -1
- package/dist/types/filters.d.ts +173 -0
- package/dist/types/filters.d.ts.map +1 -0
- package/dist/types/filters.js +5 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/schemas.d.ts +0 -5
- package/dist/types/schemas.d.ts.map +1 -1
- package/package.json +101 -95
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Benjamin Sinidol
|
|
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/dist/api/documents.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Document, DocumentListParams, CreateDocumentData, UpdateDocumentDa
|
|
|
2
2
|
export declare class DocumentsApi {
|
|
3
3
|
/**
|
|
4
4
|
* List documents with optional filtering
|
|
5
|
+
* NOTE: Requires 'type' parameter - use getByType() for convenience
|
|
5
6
|
*/
|
|
6
7
|
static list(params?: DocumentListParams): Promise<ApiResponse<Document[]>>;
|
|
7
8
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/lib/api/documents.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,QAAQ,EACR,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,MAAM,SAAS,CAAC;AAEjB,qBAAa,YAAY;IACxB
|
|
1
|
+
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/lib/api/documents.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,QAAQ,EACR,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,MAAM,SAAS,CAAC;AAEjB,qBAAa,YAAY;IACxB;;;OAGG;WACU,IAAI,CAAC,MAAM,GAAE,kBAAuB,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;IAYpF;;OAEG;WACU,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAIhE;;OAEG;WACU,MAAM,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAI7E;;OAEG;WACU,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAI7F;;OAEG;WACU,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAIhE;;OAEG;WACU,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAIlE;;OAEG;WACU,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAI/D;;OAEG;WACU,SAAS,CACrB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAM,GAC9C,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;IAInC;;OAEG;WACU,YAAY,CACxB,MAAM,GAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAM,GAC7C,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;IAInC;;OAEG;WACU,SAAS,CACrB,MAAM,GAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAM,GAC7C,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;CAGnC;AAGD,eAAO,MAAM,SAAS;;;;;;;;;;;CAWrB,CAAC"}
|
package/dist/api/documents.js
CHANGED
|
@@ -3,9 +3,17 @@ import { apiClient } from './client.js';
|
|
|
3
3
|
export class DocumentsApi {
|
|
4
4
|
/**
|
|
5
5
|
* List documents with optional filtering
|
|
6
|
+
* NOTE: Requires 'type' parameter - use getByType() for convenience
|
|
6
7
|
*/
|
|
7
8
|
static async list(params = {}) {
|
|
8
|
-
|
|
9
|
+
// Support both 'type' and legacy 'docType' parameter
|
|
10
|
+
const queryParams = {
|
|
11
|
+
...params,
|
|
12
|
+
type: params.type || params.docType
|
|
13
|
+
};
|
|
14
|
+
// Remove docType to avoid confusion
|
|
15
|
+
delete queryParams.docType;
|
|
16
|
+
return apiClient.get('/documents', queryParams);
|
|
9
17
|
}
|
|
10
18
|
/**
|
|
11
19
|
* Get document by ID
|
package/dist/api/types.d.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import type { Document, NewDocument } from '../types/index.js';
|
|
2
|
+
export interface PaginationMeta {
|
|
3
|
+
total: number;
|
|
4
|
+
page: number;
|
|
5
|
+
pageSize: number;
|
|
6
|
+
totalPages: number;
|
|
7
|
+
hasNextPage: boolean;
|
|
8
|
+
hasPrevPage: boolean;
|
|
9
|
+
}
|
|
2
10
|
export interface ApiResponse<T> {
|
|
3
11
|
success: boolean;
|
|
4
12
|
data?: T;
|
|
5
13
|
error?: string;
|
|
6
14
|
message?: string;
|
|
15
|
+
pagination?: PaginationMeta;
|
|
7
16
|
meta?: {
|
|
8
17
|
count: number;
|
|
9
18
|
limit: number;
|
|
@@ -12,12 +21,25 @@ export interface ApiResponse<T> {
|
|
|
12
21
|
};
|
|
13
22
|
}
|
|
14
23
|
export interface DocumentListParams {
|
|
24
|
+
type?: string;
|
|
15
25
|
docType?: string;
|
|
16
26
|
status?: string;
|
|
27
|
+
page?: number;
|
|
28
|
+
pageSize?: number;
|
|
17
29
|
limit?: number;
|
|
18
30
|
offset?: number;
|
|
31
|
+
depth?: number;
|
|
32
|
+
sort?: string;
|
|
33
|
+
perspective?: 'draft' | 'published';
|
|
34
|
+
}
|
|
35
|
+
export interface CreateDocumentData {
|
|
36
|
+
type: string;
|
|
37
|
+
data: Record<string, any>;
|
|
38
|
+
publish?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface UpdateDocumentData {
|
|
41
|
+
data: Record<string, any>;
|
|
42
|
+
publish?: boolean;
|
|
19
43
|
}
|
|
20
|
-
export type CreateDocumentData = Omit<NewDocument, 'id' | 'createdAt' | 'updatedAt' | 'publishedAt'>;
|
|
21
|
-
export type UpdateDocumentData = Partial<Pick<Document, 'draftData' | 'status'>>;
|
|
22
44
|
export type { Document, NewDocument };
|
|
23
45
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/api/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/api/types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG5D,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/api/types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG5D,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACrB;AAGD,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,UAAU,CAAC,EAAE,cAAc,CAAC;IAE5B,IAAI,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAC7B,CAAC;CACF;AAGD,MAAM,WAAW,kBAAkB;IAElC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;CACpC;AAGD,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAGD,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAGD,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-hooks.d.ts","sourceRoot":"","sources":["../../src/lib/auth/auth-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAQ,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,wBAAsB,cAAc,CACnC,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,YAAY,EAC1B,EAAE,EAAE,eAAe,GACjB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"auth-hooks.d.ts","sourceRoot":"","sources":["../../src/lib/auth/auth-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAQ,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,wBAAsB,cAAc,CACnC,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,YAAY,EAC1B,EAAE,EAAE,eAAe,GACjB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAoI1B"}
|
package/dist/auth/auth-hooks.js
CHANGED
|
@@ -50,11 +50,17 @@ export async function handleAuthHook(event, config, authProvider, db) {
|
|
|
50
50
|
// Otherwise, try session (for admin UI making API calls)
|
|
51
51
|
auth = await authProvider.getSession(event.request, db);
|
|
52
52
|
}
|
|
53
|
-
//
|
|
53
|
+
// Check if GraphQL plugin is configured
|
|
54
54
|
let graphqlEndpoint;
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
const hasGraphQLPlugin = config.plugins?.some((p) => {
|
|
56
|
+
if (typeof p === 'string')
|
|
57
|
+
return p === '@aphexcms/graphql-plugin';
|
|
58
|
+
if (typeof p === 'object')
|
|
59
|
+
return p.name === '@aphexcms/graphql-plugin';
|
|
60
|
+
return false;
|
|
61
|
+
});
|
|
62
|
+
if (hasGraphQLPlugin) {
|
|
63
|
+
graphqlEndpoint = '/api/graphql'; // Standard GraphQL endpoint
|
|
58
64
|
}
|
|
59
65
|
// Require authentication for protected API routes
|
|
60
66
|
const protectedApiRoutes = [
|
|
@@ -104,5 +110,13 @@ export async function handleAuthHook(event, config, authProvider, db) {
|
|
|
104
110
|
event.locals.auth = auth;
|
|
105
111
|
}
|
|
106
112
|
}
|
|
113
|
+
// 4. All other routes - try to populate auth if session exists (optional auth)
|
|
114
|
+
// This allows public pages to detect if user is logged in (like WordPress admin bar)
|
|
115
|
+
if (!event.locals.auth) {
|
|
116
|
+
const auth = await authProvider.getSession(event.request, db);
|
|
117
|
+
if (auth) {
|
|
118
|
+
event.locals.auth = auth;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
107
121
|
return null; // Tell the main hook to continue
|
|
108
122
|
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { isFieldRequired } from '../lib/field-validation/utils.js';
|
|
2
|
+
/**
|
|
3
|
+
* Map Aphex field types to TypeScript types
|
|
4
|
+
*/
|
|
5
|
+
function mapFieldTypeToTS(field, schemaMap) {
|
|
6
|
+
switch (field.type) {
|
|
7
|
+
case 'string':
|
|
8
|
+
case 'text':
|
|
9
|
+
case 'slug':
|
|
10
|
+
return 'string';
|
|
11
|
+
case 'number':
|
|
12
|
+
return 'number';
|
|
13
|
+
case 'boolean':
|
|
14
|
+
return 'boolean';
|
|
15
|
+
case 'image':
|
|
16
|
+
// Image fields store reference to asset
|
|
17
|
+
return 'string'; // Asset ID
|
|
18
|
+
case 'array': {
|
|
19
|
+
if (!('of' in field) || !field.of || field.of.length === 0) {
|
|
20
|
+
return 'unknown[]';
|
|
21
|
+
}
|
|
22
|
+
// Union of all possible array item types
|
|
23
|
+
const types = field.of
|
|
24
|
+
.map((ref) => {
|
|
25
|
+
const refSchema = schemaMap.get(ref.type);
|
|
26
|
+
if (refSchema && refSchema.type === 'object') {
|
|
27
|
+
return pascalCase(ref.type);
|
|
28
|
+
}
|
|
29
|
+
return 'unknown';
|
|
30
|
+
})
|
|
31
|
+
.filter((t) => t !== 'unknown');
|
|
32
|
+
if (types.length === 0) {
|
|
33
|
+
return 'unknown[]';
|
|
34
|
+
}
|
|
35
|
+
return types.length === 1 ? `${types[0]}[]` : `Array<${types.join(' | ')}>`;
|
|
36
|
+
}
|
|
37
|
+
case 'object': {
|
|
38
|
+
if (!('fields' in field) || !field.fields) {
|
|
39
|
+
return 'Record<string, unknown>';
|
|
40
|
+
}
|
|
41
|
+
// Generate inline interface for object fields
|
|
42
|
+
const props = field.fields
|
|
43
|
+
.map((f) => {
|
|
44
|
+
const tsType = mapFieldTypeToTS(f, schemaMap);
|
|
45
|
+
const optional = isFieldOptional(f) ? '?' : '';
|
|
46
|
+
return ` ${f.name}${optional}: ${tsType};`;
|
|
47
|
+
})
|
|
48
|
+
.join('\n');
|
|
49
|
+
return `{\n${props}\n}`;
|
|
50
|
+
}
|
|
51
|
+
case 'reference': {
|
|
52
|
+
// References store document ID as string
|
|
53
|
+
return 'string';
|
|
54
|
+
}
|
|
55
|
+
default:
|
|
56
|
+
return 'unknown';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Convert kebab-case or snake_case to PascalCase
|
|
61
|
+
*/
|
|
62
|
+
function pascalCase(str) {
|
|
63
|
+
return str
|
|
64
|
+
.split(/[-_]/)
|
|
65
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
66
|
+
.join('');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Determine if a field is optional based on validation rules
|
|
70
|
+
*/
|
|
71
|
+
function isFieldOptional(field) {
|
|
72
|
+
return !isFieldRequired(field);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Generate TypeScript interface for a schema type
|
|
76
|
+
*/
|
|
77
|
+
function generateInterface(schema, schemaMap) {
|
|
78
|
+
const interfaceName = pascalCase(schema.name);
|
|
79
|
+
const fields = schema.fields
|
|
80
|
+
.map((field) => {
|
|
81
|
+
const tsType = mapFieldTypeToTS(field, schemaMap);
|
|
82
|
+
const optional = isFieldOptional(field) ? '?' : '';
|
|
83
|
+
const comment = field.description ? ` /** ${field.description} */\n` : '';
|
|
84
|
+
return `${comment} ${field.name}${optional}: ${tsType};`;
|
|
85
|
+
})
|
|
86
|
+
.join('\n');
|
|
87
|
+
// Add id and _meta fields for document types
|
|
88
|
+
const isDocument = schema.type === 'document';
|
|
89
|
+
const metadataFields = isDocument
|
|
90
|
+
? ` /** Document ID */
|
|
91
|
+
id: string;
|
|
92
|
+
${fields}
|
|
93
|
+
/** Document metadata */
|
|
94
|
+
_meta?: {
|
|
95
|
+
type: string;
|
|
96
|
+
status: 'draft' | 'published';
|
|
97
|
+
organizationId: string;
|
|
98
|
+
createdAt: Date | null;
|
|
99
|
+
updatedAt: Date | null;
|
|
100
|
+
createdBy?: string;
|
|
101
|
+
updatedBy?: string;
|
|
102
|
+
publishedAt?: Date | null;
|
|
103
|
+
publishedHash?: string | null;
|
|
104
|
+
};`
|
|
105
|
+
: fields;
|
|
106
|
+
return `export interface ${interfaceName} {\n${metadataFields}\n}`;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Generate the Collections interface augmentation
|
|
110
|
+
*/
|
|
111
|
+
function generateCollectionsAugmentation(documentSchemas) {
|
|
112
|
+
const mappings = documentSchemas
|
|
113
|
+
.map((schema) => {
|
|
114
|
+
const interfaceName = pascalCase(schema.name);
|
|
115
|
+
return ` ${schema.name}: CollectionAPI<${interfaceName}>;`;
|
|
116
|
+
})
|
|
117
|
+
.join('\n');
|
|
118
|
+
return `declare module '@aphexcms/cms-core/server' {
|
|
119
|
+
interface Collections {
|
|
120
|
+
${mappings}
|
|
121
|
+
}
|
|
122
|
+
}`;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Generate complete TypeScript types file with module augmentation
|
|
126
|
+
*/
|
|
127
|
+
export function generateTypes(schemas) {
|
|
128
|
+
// Create schema map for lookups
|
|
129
|
+
const schemaMap = new Map(schemas.map((s) => [s.name, s]));
|
|
130
|
+
// Separate document and object types
|
|
131
|
+
const documentSchemas = schemas.filter((s) => s.type === 'document');
|
|
132
|
+
const objectSchemas = schemas.filter((s) => s.type === 'object');
|
|
133
|
+
// Generate interfaces for all schemas
|
|
134
|
+
const objectInterfaces = objectSchemas.map((s) => generateInterface(s, schemaMap)).join('\n\n');
|
|
135
|
+
const documentInterfaces = documentSchemas.map((s) => generateInterface(s, schemaMap)).join('\n\n');
|
|
136
|
+
// Generate Collections interface augmentation
|
|
137
|
+
const collectionsAugmentation = generateCollectionsAugmentation(documentSchemas);
|
|
138
|
+
// Build the complete file
|
|
139
|
+
const output = `/**
|
|
140
|
+
* Generated types for Aphex CMS
|
|
141
|
+
* This file is auto-generated - DO NOT EDIT manually
|
|
142
|
+
*/
|
|
143
|
+
import type { CollectionAPI } from '@aphexcms/cms-core/server';
|
|
144
|
+
|
|
145
|
+
// ============================================================================
|
|
146
|
+
// Object Types (nested in documents)
|
|
147
|
+
// ============================================================================
|
|
148
|
+
|
|
149
|
+
${objectInterfaces}
|
|
150
|
+
|
|
151
|
+
// ============================================================================
|
|
152
|
+
// Document Types (collections)
|
|
153
|
+
// ============================================================================
|
|
154
|
+
|
|
155
|
+
${documentInterfaces}
|
|
156
|
+
|
|
157
|
+
// ============================================================================
|
|
158
|
+
// Module Augmentation - Extends Collections interface globally
|
|
159
|
+
// ============================================================================
|
|
160
|
+
|
|
161
|
+
${collectionsAugmentation}
|
|
162
|
+
`;
|
|
163
|
+
return output;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* CLI helper to generate types from schema file
|
|
167
|
+
*/
|
|
168
|
+
export async function generateTypesFromConfig(schemaPath, outputPath) {
|
|
169
|
+
try {
|
|
170
|
+
// Resolve paths relative to current working directory
|
|
171
|
+
const path = await import('path');
|
|
172
|
+
const { pathToFileURL } = await import('url');
|
|
173
|
+
const fs = await import('fs/promises');
|
|
174
|
+
const absoluteSchemaPath = path.resolve(process.cwd(), schemaPath);
|
|
175
|
+
const absoluteOutputPath = path.resolve(process.cwd(), outputPath);
|
|
176
|
+
// If the schema file is TypeScript, compile it with esbuild first
|
|
177
|
+
let schemaModulePath = absoluteSchemaPath;
|
|
178
|
+
let tempFile = null;
|
|
179
|
+
if (absoluteSchemaPath.endsWith('.ts')) {
|
|
180
|
+
const { build } = await import('esbuild');
|
|
181
|
+
const tempOutFile = path.join(path.dirname(absoluteSchemaPath), '.temp-schema.mjs');
|
|
182
|
+
await build({
|
|
183
|
+
entryPoints: [absoluteSchemaPath],
|
|
184
|
+
bundle: true,
|
|
185
|
+
format: 'esm',
|
|
186
|
+
platform: 'node',
|
|
187
|
+
outfile: tempOutFile,
|
|
188
|
+
external: ['@aphexcms/*']
|
|
189
|
+
});
|
|
190
|
+
schemaModulePath = tempOutFile;
|
|
191
|
+
tempFile = tempOutFile;
|
|
192
|
+
}
|
|
193
|
+
// Dynamic import the schema types
|
|
194
|
+
// Use file:// URL for proper ESM import
|
|
195
|
+
const schemaModule = await import(pathToFileURL(schemaModulePath).href);
|
|
196
|
+
const schemas = schemaModule.schemaTypes || schemaModule.default;
|
|
197
|
+
// Clean up temp file if created
|
|
198
|
+
if (tempFile) {
|
|
199
|
+
try {
|
|
200
|
+
await fs.unlink(tempFile);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// Ignore cleanup errors
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (!schemas || !Array.isArray(schemas)) {
|
|
207
|
+
throw new Error('Invalid schema file: expected schemaTypes array export');
|
|
208
|
+
}
|
|
209
|
+
const generatedTypes = generateTypes(schemas);
|
|
210
|
+
// Write to output file
|
|
211
|
+
await fs.writeFile(absoluteOutputPath, generatedTypes, 'utf-8');
|
|
212
|
+
console.log(`✅ Types generated successfully at: ${absoluteOutputPath}`);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
console.error('❌ Failed to generate types:', error);
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Aphex CMS CLI
|
|
4
|
+
* Uses cac for command parsing + clack for interactive prompts
|
|
5
|
+
*/
|
|
6
|
+
import { intro, outro, spinner, text, cancel, isCancel } from '@clack/prompts';
|
|
7
|
+
import { cac } from 'cac';
|
|
8
|
+
import pc from 'picocolors';
|
|
9
|
+
import { generateTypesFromConfig } from './generate-types.js';
|
|
10
|
+
const cli = cac('aphex');
|
|
11
|
+
// Version from package.json
|
|
12
|
+
const version = '0.1.13';
|
|
13
|
+
// ASCII Art Banner
|
|
14
|
+
function printBanner() {
|
|
15
|
+
console.log(pc.cyan(`${pc.bold('⚡ Aphex CMS')}\n${pc.dim('A modern headless CMS')}`));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* aphex generate:types [schema-path] [output-path]
|
|
19
|
+
* Generate TypeScript types from schema
|
|
20
|
+
*/
|
|
21
|
+
cli
|
|
22
|
+
.command('generate:types [schema-path] [output-path]', 'Generate TypeScript types from schema')
|
|
23
|
+
.action(async (schemaPath, outputPath) => {
|
|
24
|
+
intro(pc.cyan('⚡ Aphex CMS - Type Generator'));
|
|
25
|
+
try {
|
|
26
|
+
// If paths not provided, prompt for them
|
|
27
|
+
if (!schemaPath) {
|
|
28
|
+
const result = await text({
|
|
29
|
+
message: 'Schema file path:',
|
|
30
|
+
placeholder: './src/lib/schemaTypes/index.ts',
|
|
31
|
+
defaultValue: './src/lib/schemaTypes/index.ts'
|
|
32
|
+
});
|
|
33
|
+
if (isCancel(result)) {
|
|
34
|
+
cancel('Operation cancelled.');
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
schemaPath = result;
|
|
38
|
+
}
|
|
39
|
+
if (!outputPath) {
|
|
40
|
+
const result = await text({
|
|
41
|
+
message: 'Output file path:',
|
|
42
|
+
placeholder: './src/lib/generated-types.ts',
|
|
43
|
+
defaultValue: './src/lib/generated-types.ts'
|
|
44
|
+
});
|
|
45
|
+
if (isCancel(result)) {
|
|
46
|
+
cancel('Operation cancelled.');
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
outputPath = result;
|
|
50
|
+
}
|
|
51
|
+
const s = spinner();
|
|
52
|
+
s.start('Generating types...');
|
|
53
|
+
await generateTypesFromConfig(schemaPath, outputPath);
|
|
54
|
+
s.stop(pc.green('✅ Types generated successfully!'));
|
|
55
|
+
outro(pc.dim(`Output: ${pc.cyan(outputPath)}`));
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
cancel(pc.red('Failed to generate types'));
|
|
59
|
+
console.error(error);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* aphex help
|
|
65
|
+
*/
|
|
66
|
+
cli.help();
|
|
67
|
+
/**
|
|
68
|
+
* aphex --version
|
|
69
|
+
*/
|
|
70
|
+
cli.version(version);
|
|
71
|
+
/**
|
|
72
|
+
* Default command - show banner and help
|
|
73
|
+
*/
|
|
74
|
+
cli.on('command:*', () => {
|
|
75
|
+
printBanner();
|
|
76
|
+
console.log(pc.red(`Unknown command: ${cli.args.join(' ')}\n`));
|
|
77
|
+
console.log(`Run ${pc.cyan('aphex --help')} to see available commands.`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
});
|
|
80
|
+
// Parse CLI args
|
|
81
|
+
cli.parse();
|
|
82
|
+
// If no command provided, show banner and help
|
|
83
|
+
if (!process.argv.slice(2).length) {
|
|
84
|
+
printBanner();
|
|
85
|
+
cli.outputHelp();
|
|
86
|
+
}
|
|
@@ -13,13 +13,12 @@
|
|
|
13
13
|
import DocumentEditor from './admin/DocumentEditor.svelte';
|
|
14
14
|
import type { DocumentType } from '../types/index';
|
|
15
15
|
import { documents } from '../api/index';
|
|
16
|
-
import { FileText } from 'lucide-svelte';
|
|
17
16
|
|
|
18
|
-
type InitDocumentType = Pick<DocumentType, 'name' | 'title' | 'description'
|
|
17
|
+
type InitDocumentType = Pick<DocumentType, 'name' | 'title' | 'description'>;
|
|
19
18
|
|
|
20
19
|
interface Props {
|
|
21
20
|
schemas: SchemaType[];
|
|
22
|
-
documentTypes:
|
|
21
|
+
documentTypes: InitDocumentType[];
|
|
23
22
|
schemaError?: { message: string } | null;
|
|
24
23
|
title?: string;
|
|
25
24
|
graphqlSettings?: { endpoint: string; enableGraphiQL: boolean } | null;
|
|
@@ -30,7 +29,7 @@
|
|
|
30
29
|
|
|
31
30
|
let {
|
|
32
31
|
schemas,
|
|
33
|
-
documentTypes
|
|
32
|
+
documentTypes,
|
|
34
33
|
schemaError = null,
|
|
35
34
|
title = 'Aphex CMS',
|
|
36
35
|
graphqlSettings = null,
|
|
@@ -39,16 +38,7 @@
|
|
|
39
38
|
handleTabChange = () => {}
|
|
40
39
|
}: Props = $props();
|
|
41
40
|
|
|
42
|
-
//
|
|
43
|
-
const documentTypes = $derived(
|
|
44
|
-
documentTypesFromServer.map((docType) => {
|
|
45
|
-
const schema = schemas.find((s) => s.name === docType.name);
|
|
46
|
-
return {
|
|
47
|
-
...docType,
|
|
48
|
-
icon: schema?.icon
|
|
49
|
-
};
|
|
50
|
-
})
|
|
51
|
-
);
|
|
41
|
+
// Set schema context for child components
|
|
52
42
|
|
|
53
43
|
const hasDocumentTypes = $derived(documentTypes.length > 0);
|
|
54
44
|
|
|
@@ -574,29 +564,32 @@
|
|
|
574
564
|
const previewConfig = schema?.preview;
|
|
575
565
|
|
|
576
566
|
documentsList = result.data.map((doc: any) => {
|
|
577
|
-
|
|
567
|
+
// With LocalAPI, data is already flattened at top level (not in draftData)
|
|
568
|
+
// The document itself IS the data, with _meta containing metadata
|
|
578
569
|
|
|
579
570
|
// Use preview config if available
|
|
580
571
|
const title = previewConfig?.select?.title
|
|
581
|
-
?
|
|
582
|
-
:
|
|
572
|
+
? doc[previewConfig.select.title] || `Untitled`
|
|
573
|
+
: doc.title || `Untitled`;
|
|
583
574
|
|
|
584
575
|
const subtitle = previewConfig?.select?.subtitle
|
|
585
|
-
?
|
|
576
|
+
? doc[previewConfig.select.subtitle]
|
|
586
577
|
: undefined;
|
|
587
578
|
|
|
579
|
+
// Metadata is in _meta field (from LocalAPI transformation)
|
|
580
|
+
const meta = doc._meta || {};
|
|
581
|
+
|
|
588
582
|
return {
|
|
589
583
|
id: doc.id,
|
|
590
584
|
title,
|
|
591
585
|
subtitle,
|
|
592
|
-
status:
|
|
593
|
-
publishedAt:
|
|
594
|
-
updatedAt:
|
|
595
|
-
createdAt:
|
|
596
|
-
hasChanges
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
JSON.stringify(doc.draftData) !== JSON.stringify(doc.publishedData)
|
|
586
|
+
status: meta.status || 'draft',
|
|
587
|
+
publishedAt: meta.publishedAt ? new Date(meta.publishedAt) : null,
|
|
588
|
+
updatedAt: meta.updatedAt ? new Date(meta.updatedAt) : null,
|
|
589
|
+
createdAt: meta.createdAt ? new Date(meta.createdAt) : null,
|
|
590
|
+
// hasChanges is tracked via publishedHash comparison
|
|
591
|
+
// If publishedHash is null, it's never been published or has unpublished changes
|
|
592
|
+
hasChanges: meta.status === 'published' && meta.publishedHash === null
|
|
600
593
|
};
|
|
601
594
|
});
|
|
602
595
|
} else {
|
|
@@ -740,12 +733,7 @@
|
|
|
740
733
|
>
|
|
741
734
|
<div class="flex items-center gap-3">
|
|
742
735
|
<div class="flex h-6 w-6 items-center justify-center">
|
|
743
|
-
|
|
744
|
-
{@const Icon = docType.icon}
|
|
745
|
-
<Icon class="text-muted-foreground h-4 w-4" />
|
|
746
|
-
{:else}
|
|
747
|
-
<FileText class="text-muted-foreground h-4 w-4" />
|
|
748
|
-
{/if}
|
|
736
|
+
<span class="text-muted-foreground">📄</span>
|
|
749
737
|
</div>
|
|
750
738
|
<div>
|
|
751
739
|
<h3 class="text-sm font-medium">{docType.title}s</h3>
|
|
@@ -778,7 +766,7 @@
|
|
|
778
766
|
<div
|
|
779
767
|
class="bg-muted/50 mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full"
|
|
780
768
|
>
|
|
781
|
-
<
|
|
769
|
+
<span class="text-muted-foreground text-xl">📄</span>
|
|
782
770
|
</div>
|
|
783
771
|
<h3 class="mb-2 font-medium">No content types found</h3>
|
|
784
772
|
<p class="text-muted-foreground mb-4 text-sm">
|
|
@@ -821,26 +809,19 @@
|
|
|
821
809
|
</div>
|
|
822
810
|
</button>
|
|
823
811
|
{:else}
|
|
824
|
-
{@const currentDocType = documentTypes.find(
|
|
825
|
-
(t) => t.name === selectedDocumentType
|
|
826
|
-
)}
|
|
827
812
|
<div class="border-border bg-muted/20 border-b p-3">
|
|
828
813
|
<div class="flex items-center justify-between">
|
|
829
814
|
<div class="flex items-center gap-3">
|
|
830
815
|
{#if windowWidth > 620}
|
|
831
816
|
<!-- Desktop: Icon -->
|
|
832
817
|
<div class="flex h-6 w-6 items-center justify-center">
|
|
833
|
-
|
|
834
|
-
{@const Icon = currentDocType.icon}
|
|
835
|
-
<Icon class="text-muted-foreground h-4 w-4" />
|
|
836
|
-
{:else}
|
|
837
|
-
<FileText class="text-muted-foreground h-4 w-4" />
|
|
838
|
-
{/if}
|
|
818
|
+
<span class="text-muted-foreground">📄</span>
|
|
839
819
|
</div>
|
|
840
820
|
{/if}
|
|
841
821
|
<div>
|
|
842
822
|
<h3 class="text-sm font-medium">
|
|
843
|
-
{(
|
|
823
|
+
{(documentTypes.find((t) => t.name === selectedDocumentType)?.title ||
|
|
824
|
+
selectedDocumentType) + 's'}
|
|
844
825
|
</h3>
|
|
845
826
|
<p class="text-muted-foreground text-xs">
|
|
846
827
|
{documentsList.length} document{documentsList.length !== 1 ? 's' : ''}
|
|
@@ -892,12 +873,7 @@
|
|
|
892
873
|
>
|
|
893
874
|
<div class="flex min-w-0 flex-1 items-center gap-3">
|
|
894
875
|
<div class="flex h-6 w-6 items-center justify-center">
|
|
895
|
-
|
|
896
|
-
{@const Icon = currentDocType.icon}
|
|
897
|
-
<Icon class="text-muted-foreground h-4 w-4" />
|
|
898
|
-
{:else}
|
|
899
|
-
<FileText class="text-muted-foreground h-4 w-4" />
|
|
900
|
-
{/if}
|
|
876
|
+
<span class="text-muted-foreground">📄</span>
|
|
901
877
|
</div>
|
|
902
878
|
<div class="min-w-0 flex-1">
|
|
903
879
|
<h3 class="truncate text-sm font-medium">{doc.title}</h3>
|
|
@@ -922,12 +898,7 @@
|
|
|
922
898
|
<div
|
|
923
899
|
class="bg-muted/50 mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full"
|
|
924
900
|
>
|
|
925
|
-
|
|
926
|
-
{@const Icon = currentDocType.icon}
|
|
927
|
-
<Icon class="text-muted-foreground h-8 w-8" />
|
|
928
|
-
{:else}
|
|
929
|
-
<FileText class="text-muted-foreground h-8 w-8" />
|
|
930
|
-
{/if}
|
|
901
|
+
<span class="text-muted-foreground text-xl">📄</span>
|
|
931
902
|
</div>
|
|
932
903
|
<h3 class="mb-2 font-medium">No documents found</h3>
|
|
933
904
|
<p class="text-muted-foreground text-sm">
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { SchemaType } from '../types/index.js';
|
|
2
|
+
import type { DocumentType } from '../types/index.js';
|
|
3
|
+
type InitDocumentType = Pick<DocumentType, 'name' | 'title' | 'description'>;
|
|
2
4
|
interface Props {
|
|
3
5
|
schemas: SchemaType[];
|
|
4
|
-
documentTypes:
|
|
5
|
-
name: string;
|
|
6
|
-
title: string;
|
|
7
|
-
description?: string;
|
|
8
|
-
}>;
|
|
6
|
+
documentTypes: InitDocumentType[];
|
|
9
7
|
schemaError?: {
|
|
10
8
|
message: string;
|
|
11
9
|
} | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminApp.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/AdminApp.svelte.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"AdminApp.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/AdminApp.svelte.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAIlD,KAAK,gBAAgB,GAAG,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,GAAG,aAAa,CAAC,CAAC;AAE7E,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,WAAW,GAAG,QAAQ,CAAA;KAAE,CAAC;IAC9C,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAm6BF,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|