@webiny/api-aco 6.6.0-alpha.0 → 6.6.0-alpha.1
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/AcoFeature.js +9 -2
- package/AcoFeature.js.map +1 -1
- package/AcoFolderSchemaFactory.d.ts +30 -0
- package/AcoFolderSchemaFactory.js +64 -0
- package/AcoFolderSchemaFactory.js.map +1 -0
- package/createAcoGraphQL.d.ts +3 -2
- package/createAcoGraphQL.js.map +1 -1
- package/domain/folder/abstractions.d.ts +12 -5
- package/domain/folder/abstractions.js +2 -2
- package/domain/folder/abstractions.js.map +1 -1
- package/features/ai/CreateFolderTool.d.ts +44 -0
- package/features/ai/CreateFolderTool.js +49 -0
- package/features/ai/CreateFolderTool.js.map +1 -0
- package/features/ai/CreateTeamTool.d.ts +43 -0
- package/features/ai/CreateTeamTool.js +47 -0
- package/features/ai/CreateTeamTool.js.map +1 -0
- package/features/ai/GrantFolderAccessTool.d.ts +72 -0
- package/features/ai/GrantFolderAccessTool.js +71 -0
- package/features/ai/GrantFolderAccessTool.js.map +1 -0
- package/features/ai/ListFoldersTool.d.ts +42 -0
- package/features/ai/ListFoldersTool.js +48 -0
- package/features/ai/ListFoldersTool.js.map +1 -0
- package/features/ai/ListRolesTool.d.ts +34 -0
- package/features/ai/ListRolesTool.js +39 -0
- package/features/ai/ListRolesTool.js.map +1 -0
- package/features/ai/ListTeamsTool.d.ts +34 -0
- package/features/ai/ListTeamsTool.js +39 -0
- package/features/ai/ListTeamsTool.js.map +1 -0
- package/features/ai/RevokeFolderAccessTool.d.ts +58 -0
- package/features/ai/RevokeFolderAccessTool.js +60 -0
- package/features/ai/RevokeFolderAccessTool.js.map +1 -0
- package/features/ai/assertTargetIsUsable.d.ts +10 -0
- package/features/ai/assertTargetIsUsable.js +14 -0
- package/features/ai/assertTargetIsUsable.js.map +1 -0
- package/features/ai/feature.d.ts +12 -0
- package/features/ai/feature.js +23 -0
- package/features/ai/feature.js.map +1 -0
- package/features/ai/index.d.ts +8 -0
- package/features/ai/index.js +8 -0
- package/features/ai/loadFolderPermissions.d.ts +16 -0
- package/features/ai/loadFolderPermissions.js +14 -0
- package/features/ai/loadFolderPermissions.js.map +1 -0
- package/features/flp/FolderLevelPermissions/FolderLevelPermissions.d.ts +3 -3
- package/features/flp/FolderLevelPermissions/FolderLevelPermissions.js +6 -6
- package/features/flp/FolderLevelPermissions/FolderLevelPermissions.js.map +1 -1
- package/features/flp/UpdateFlp/UpdateFlpUseCase.d.ts +3 -3
- package/features/flp/UpdateFlp/UpdateFlpUseCase.js +4 -3
- package/features/flp/UpdateFlp/UpdateFlpUseCase.js.map +1 -1
- package/features/flp/UpdateFlp/feature.js +2 -2
- package/features/flp/UpdateFlp/feature.js.map +1 -1
- package/features/folder/CreateFolder/CreateFolderRepository.d.ts +3 -3
- package/features/folder/CreateFolder/CreateFolderRepository.js +10 -7
- package/features/folder/CreateFolder/CreateFolderRepository.js.map +1 -1
- package/features/folder/DeleteFolder/DeleteFolderRepository.d.ts +3 -3
- package/features/folder/DeleteFolder/DeleteFolderRepository.js +6 -5
- package/features/folder/DeleteFolder/DeleteFolderRepository.js.map +1 -1
- package/features/folder/FolderModelProvider.d.ts +26 -0
- package/features/folder/FolderModelProvider.js +22 -0
- package/features/folder/FolderModelProvider.js.map +1 -0
- package/features/folder/GetAncestors/GetAncestorsRepository.d.ts +3 -3
- package/features/folder/GetAncestors/GetAncestorsRepository.js +6 -5
- package/features/folder/GetAncestors/GetAncestorsRepository.js.map +1 -1
- package/features/folder/GetFolder/GetFolderRepository.d.ts +3 -3
- package/features/folder/GetFolder/GetFolderRepository.js +6 -5
- package/features/folder/GetFolder/GetFolderRepository.js.map +1 -1
- package/features/folder/GetFolderHierarchy/GetFolderHierarchyRepository.d.ts +3 -3
- package/features/folder/GetFolderHierarchy/GetFolderHierarchyRepository.js +10 -8
- package/features/folder/GetFolderHierarchy/GetFolderHierarchyRepository.js.map +1 -1
- package/features/folder/ListFolders/ListFoldersRepository.d.ts +3 -3
- package/features/folder/ListFolders/ListFoldersRepository.js +8 -7
- package/features/folder/ListFolders/ListFoldersRepository.js.map +1 -1
- package/features/folder/UpdateFolder/UpdateFolderRepository.d.ts +3 -3
- package/features/folder/UpdateFolder/UpdateFolderRepository.js +11 -8
- package/features/folder/UpdateFolder/UpdateFolderRepository.js.map +1 -1
- package/folder/folder.gql.js +2 -2
- package/folder/folder.gql.js.map +1 -1
- package/package.json +23 -22
- package/AcoInitializer.d.ts +0 -25
- package/AcoInitializer.js +0 -79
- package/AcoInitializer.js.map +0 -1
package/AcoFeature.js
CHANGED
|
@@ -5,7 +5,10 @@ import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/i
|
|
|
5
5
|
import { HeadlessCms } from "@webiny/api-headless-cms/features/shared/abstractions.js";
|
|
6
6
|
import { addAcoBaseSchema } from "./createAcoGraphQL.js";
|
|
7
7
|
import { addFilterSchema } from "./filter/filter.gql.js";
|
|
8
|
-
import {
|
|
8
|
+
import { AcoFolderSchemaFactory } from "./AcoFolderSchemaFactory.js";
|
|
9
|
+
import { FolderModelProvider } from "./features/folder/FolderModelProvider.js";
|
|
10
|
+
import { CmsFlpFeature } from "./features/cms/index.js";
|
|
11
|
+
import { FeatureFlags } from "@webiny/api-core/features/featureFlags/abstractions.js";
|
|
9
12
|
import { CreateFlpTask } from "./flp/tasks/createFlp.task.js";
|
|
10
13
|
import { UpdateFlpTask } from "./flp/tasks/updateFlp.task.js";
|
|
11
14
|
import { DeleteFlpTask } from "./flp/tasks/deleteFlp.task.js";
|
|
@@ -36,6 +39,7 @@ import { GetFlpFeature } from "./features/flp/GetFlp/feature.js";
|
|
|
36
39
|
import { ListFolderLevelPermissionsTargetsFeature } from "./features/folder/ListFolderLevelPermissionsTargets/feature.js";
|
|
37
40
|
import { CreateFlpOnFolderCreatedFeature } from "./features/flp/CreateFlpOnFolderCreated/index.js";
|
|
38
41
|
import { EnsureFolderIsEmptyFeature } from "./features/folder/EnsureFolderIsEmpty/feature.js";
|
|
42
|
+
import { AcoAiToolsFeature } from "./features/ai/index.js";
|
|
39
43
|
class AcoSchemaFactoryImpl {
|
|
40
44
|
async execute(builder) {
|
|
41
45
|
addAcoBaseSchema(builder);
|
|
@@ -51,6 +55,7 @@ const AcoFeature = createFeature({
|
|
|
51
55
|
name: "Aco",
|
|
52
56
|
register (container) {
|
|
53
57
|
container.register(FolderModel);
|
|
58
|
+
AcoAiToolsFeature.register(container);
|
|
54
59
|
container.register(FilterPrivateModel);
|
|
55
60
|
container.register(CreateFlpTask);
|
|
56
61
|
container.register(UpdateFlpTask);
|
|
@@ -113,8 +118,10 @@ const AcoFeature = createFeature({
|
|
|
113
118
|
});
|
|
114
119
|
return filterCrudMethods;
|
|
115
120
|
});
|
|
116
|
-
container.register(
|
|
121
|
+
container.register(FolderModelProvider);
|
|
122
|
+
if (container.resolve(FeatureFlags).get().isEnabled("advancedAccessControlLayer.folderLevelPermissions")) CmsFlpFeature.register(container);
|
|
117
123
|
container.register(AcoSchemaFactory);
|
|
124
|
+
container.register(AcoFolderSchemaFactory);
|
|
118
125
|
}
|
|
119
126
|
});
|
|
120
127
|
export { AcoFeature };
|
package/AcoFeature.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AcoFeature.js","sources":["../src/AcoFeature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { GraphQLSchemaFactory } from \"@webiny/api-graphql/graphql/abstractions.js\";\nimport type { IGraphQLSchemaBuilder } from \"@webiny/api-graphql/features/GraphQLSchemaBuilder/abstractions.js\";\nimport type { Container } from \"@webiny/di\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { HeadlessCms } from \"@webiny/api-headless-cms/features/shared/abstractions.js\";\nimport { addAcoBaseSchema } from \"./createAcoGraphQL.js\";\nimport { addFilterSchema } from \"~/filter/filter.gql.js\";\nimport { AcoInitializer } from \"./AcoInitializer.js\";\nimport { CreateFlpTask } from \"~/flp/tasks/createFlp.task.js\";\nimport { UpdateFlpTask } from \"~/flp/tasks/updateFlp.task.js\";\nimport { DeleteFlpTask } from \"~/flp/tasks/deleteFlp.task.js\";\nimport { SyncFlpTask } from \"~/flp/tasks/syncFlp.task.js\";\nimport type { AcoStorageOperations } from \"~/types.js\";\nimport type { Tenant } from \"@webiny/api-core/types/tenancy.js\";\nimport { FolderModel } from \"~/domain/folder/folder.model.js\";\nimport { FilterPrivateModel } from \"~/filter/filter.model.js\";\n// Facade wiring (moved here from createAcoContext so the ACO facade can be a lazy DI factory).\nimport { createFilterOperations } from \"~/filter/filter.so.js\";\nimport { createFilterCrudMethods } from \"~/filter/filter.crud.js\";\nimport { createFlpCrudMethods } from \"~/flp/index.js\";\nimport {\n FolderLevelPermissions,\n FolderLevelPermissionsFeature\n} from \"~/features/flp/FolderLevelPermissions/index.js\";\nimport { UpdateFolderFeature } from \"~/features/folder/UpdateFolder/index.js\";\nimport { DeleteFolderFeature } from \"~/features/folder/DeleteFolder/index.js\";\nimport { CreateFolderFeature } from \"~/features/folder/CreateFolder/index.js\";\nimport { GetFolderFeature } from \"~/features/folder/GetFolder/index.js\";\nimport { ListFoldersFeature } from \"~/features/folder/ListFolders/index.js\";\nimport { GetFolderHierarchyFeature } from \"~/features/folder/GetFolderHierarchy/index.js\";\nimport { GetAncestorsFeature } from \"~/features/folder/GetAncestors/index.js\";\nimport { UpdateFlpOnFolderUpdatedFeature } from \"~/features/flp/UpdateFlpOnFolderUpdated/index.js\";\nimport { DeleteFlpOnFolderDeletedFeature } from \"~/features/flp/DeleteFlpOnFolderDeleted/index.js\";\nimport { EnsureHcmsFolderIsEmptyOnDeleteFeature } from \"~/features/folder/EnsureHcmsFolderIsEmptyOnDelete/index.js\";\nimport { CreateFlpFeature } from \"~/features/flp/CreateFlp/index.js\";\nimport { DeleteFlpFeature } from \"~/features/flp/DeleteFlp/index.js\";\nimport { UpdateFlpFeature } from \"~/features/flp/UpdateFlp/index.js\";\nimport { EnsureFolderIsEmptyOnDeleteFeature } from \"~/features/folder/EnsureFolderIsEmptyOnDelete/index.js\";\nimport {\n AcoFilterCrud,\n AcoFlpCrud,\n FilterStorageOperations,\n FlpStorageOperations\n} from \"~/features/folder/shared/abstractions.js\";\nimport { ListFlpsFeature } from \"~/features/flp/ListFlps/feature.js\";\nimport { GetFlpFeature } from \"~/features/flp/GetFlp/feature.js\";\nimport { ListFolderLevelPermissionsTargetsFeature } from \"~/features/folder/ListFolderLevelPermissionsTargets/feature.js\";\nimport { CreateFlpOnFolderCreatedFeature } from \"~/features/flp/CreateFlpOnFolderCreated/index.js\";\nimport { EnsureFolderIsEmptyFeature } from \"~/features/folder/EnsureFolderIsEmpty/feature.js\";\n\nclass AcoSchemaFactoryImpl implements GraphQLSchemaFactory.Interface {\n async execute(builder: IGraphQLSchemaBuilder): Promise<IGraphQLSchemaBuilder> {\n // Static ACO base + filter schema (DI-native contributors declaring their deps). The dynamic\n // folder schema (needs the per-tenant folder model) is still built by AcoInitializer.\n addAcoBaseSchema(builder);\n addFilterSchema(builder);\n return builder;\n }\n}\n\nconst AcoSchemaFactory = GraphQLSchemaFactory.createImplementation({\n implementation: AcoSchemaFactoryImpl,\n dependencies: []\n});\n\nexport const AcoFeature = createFeature({\n name: \"Aco\",\n register(container: Container) {\n container.register(FolderModel);\n container.register(FilterPrivateModel);\n\n // Background task definitions — pure wiring, no tenant/identity needed.\n container.register(CreateFlpTask);\n container.register(UpdateFlpTask);\n container.register(DeleteFlpTask);\n container.register(SyncFlpTask);\n\n // Folder + FLP use-case features — pure DI wiring (all lazy). Moved out of the per-request\n // initializer so they're registered for every event, not only GraphQL requests.\n FolderLevelPermissionsFeature.register(container);\n CreateFolderFeature.register(container);\n UpdateFolderFeature.register(container);\n DeleteFolderFeature.register(container);\n GetFolderFeature.register(container);\n ListFoldersFeature.register(container);\n ListFolderLevelPermissionsTargetsFeature.register(container);\n GetFolderHierarchyFeature.register(container);\n GetAncestorsFeature.register(container);\n EnsureFolderIsEmptyFeature.register(container);\n CreateFlpFeature.register(container);\n UpdateFlpFeature.register(container);\n DeleteFlpFeature.register(container);\n ListFlpsFeature.register(container);\n GetFlpFeature.register(container);\n CreateFlpOnFolderCreatedFeature.register(container);\n UpdateFlpOnFolderUpdatedFeature.register(container);\n DeleteFlpOnFolderDeletedFeature.register(container);\n EnsureFolderIsEmptyOnDeleteFeature.register(container);\n EnsureHcmsFolderIsEmptyOnDeleteFeature.register(container);\n\n // ===== Lazy ACO facade =====\n // Built on first resolve (post-auth) so the HeadlessCms facade (also lazy) is resolved on\n // demand. Memoised per request container. Consumers resolve AcoFlpCrud / AcoFilterCrud /\n // FilterStorageOperations via DI.\n const getTenant = (): Tenant => container.resolve(TenantContext).getTenant();\n\n let storageOperations: AcoStorageOperations | undefined;\n const getStorageOperations = (): AcoStorageOperations => {\n if (!storageOperations) {\n const cms = container.resolve(HeadlessCms);\n const identityContext = container.resolve(IdentityContext);\n storageOperations = {\n filter: createFilterOperations({ cms, identityContext, container }),\n flp: container.resolve(FlpStorageOperations)\n };\n }\n return storageOperations;\n };\n\n let flpCrudMethods: ReturnType<typeof createFlpCrudMethods> | undefined;\n const getFlpCrudMethods = () => {\n if (!flpCrudMethods) {\n flpCrudMethods = createFlpCrudMethods({\n getTenant,\n storageOperations: getStorageOperations()\n });\n }\n return flpCrudMethods;\n };\n container.registerFactory(AcoFlpCrud, () => getFlpCrudMethods());\n container.registerFactory(FilterStorageOperations, () => getStorageOperations().filter);\n\n let filterCrudMethods: ReturnType<typeof createFilterCrudMethods> | undefined;\n container.registerFactory(AcoFilterCrud, () => {\n if (!filterCrudMethods) {\n filterCrudMethods = createFilterCrudMethods({\n container,\n getTenant,\n storageOperations: getStorageOperations(),\n folderLevelPermissions: container.resolve(FolderLevelPermissions)\n });\n }\n return filterCrudMethods;\n });\n\n container.register(AcoInitializer);\n container.register(AcoSchemaFactory);\n }\n});\n"],"names":["AcoSchemaFactoryImpl","builder","addAcoBaseSchema","addFilterSchema","AcoSchemaFactory","GraphQLSchemaFactory","AcoFeature","createFeature","container","FolderModel","FilterPrivateModel","CreateFlpTask","UpdateFlpTask","DeleteFlpTask","SyncFlpTask","FolderLevelPermissionsFeature","CreateFolderFeature","UpdateFolderFeature","DeleteFolderFeature","GetFolderFeature","ListFoldersFeature","ListFolderLevelPermissionsTargetsFeature","GetFolderHierarchyFeature","GetAncestorsFeature","EnsureFolderIsEmptyFeature","CreateFlpFeature","UpdateFlpFeature","DeleteFlpFeature","ListFlpsFeature","GetFlpFeature","CreateFlpOnFolderCreatedFeature","UpdateFlpOnFolderUpdatedFeature","DeleteFlpOnFolderDeletedFeature","EnsureFolderIsEmptyOnDeleteFeature","EnsureHcmsFolderIsEmptyOnDeleteFeature","getTenant","TenantContext","storageOperations","getStorageOperations","cms","HeadlessCms","identityContext","IdentityContext","createFilterOperations","FlpStorageOperations","flpCrudMethods","getFlpCrudMethods","createFlpCrudMethods","AcoFlpCrud","FilterStorageOperations","filterCrudMethods","AcoFilterCrud","createFilterCrudMethods","FolderLevelPermissions","AcoInitializer"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAMA;IACF,MAAM,QAAQC,OAA8B,EAAkC;QAG1EC,iBAAiBD;QACjBE,gBAAgBF;QAChB,OAAOA;IACX;AACJ;AAEA,MAAMG,mBAAmBC,qBAAqB,oBAAoB,CAAC;IAC/D,gBAAgBL;IAChB,cAAc,EAAE;AACpB;AAEO,MAAMM,aAAaC,cAAc;IACpC,MAAM;IACN,UAASC,SAAoB;QACzBA,UAAU,QAAQ,CAACC;QACnBD,UAAU,QAAQ,CAACE;QAGnBF,UAAU,QAAQ,CAACG;QACnBH,UAAU,QAAQ,CAACI;QACnBJ,UAAU,QAAQ,CAACK;QACnBL,UAAU,QAAQ,CAACM;QAInBC,8BAA8B,QAAQ,CAACP;QACvCQ,oBAAoB,QAAQ,CAACR;QAC7BS,oBAAoB,QAAQ,CAACT;QAC7BU,oBAAoB,QAAQ,CAACV;QAC7BW,iBAAiB,QAAQ,CAACX;QAC1BY,mBAAmB,QAAQ,CAACZ;QAC5Ba,yCAAyC,QAAQ,CAACb;QAClDc,0BAA0B,QAAQ,CAACd;QACnCe,oBAAoB,QAAQ,CAACf;QAC7BgB,2BAA2B,QAAQ,CAAChB;QACpCiB,iBAAiB,QAAQ,CAACjB;QAC1BkB,iBAAiB,QAAQ,CAAClB;QAC1BmB,iBAAiB,QAAQ,CAACnB;QAC1BoB,gBAAgB,QAAQ,CAACpB;QACzBqB,cAAc,QAAQ,CAACrB;QACvBsB,gCAAgC,QAAQ,CAACtB;QACzCuB,gCAAgC,QAAQ,CAACvB;QACzCwB,gCAAgC,QAAQ,CAACxB;QACzCyB,mCAAmC,QAAQ,CAACzB;QAC5C0B,uCAAuC,QAAQ,CAAC1B;QAMhD,MAAM2B,YAAY,IAAc3B,UAAU,OAAO,CAAC4B,eAAe,SAAS;QAE1E,IAAIC;QACJ,MAAMC,uBAAuB;YACzB,IAAI,CAACD,mBAAmB;gBACpB,MAAME,MAAM/B,UAAU,OAAO,CAACgC;gBAC9B,MAAMC,kBAAkBjC,UAAU,OAAO,CAACkC;gBAC1CL,oBAAoB;oBAChB,QAAQM,uBAAuB;wBAAEJ;wBAAKE;wBAAiBjC;oBAAU;oBACjE,KAAKA,UAAU,OAAO,CAACoC;gBAC3B;YACJ;YACA,OAAOP;QACX;QAEA,IAAIQ;QACJ,MAAMC,oBAAoB;YACtB,IAAI,CAACD,gBACDA,iBAAiBE,qBAAqB;gBAClCZ;gBACA,mBAAmBG;YACvB;YAEJ,OAAOO;QACX;QACArC,UAAU,eAAe,CAACwC,YAAY,IAAMF;QAC5CtC,UAAU,eAAe,CAACyC,yBAAyB,IAAMX,uBAAuB,MAAM;QAEtF,IAAIY;QACJ1C,UAAU,eAAe,CAAC2C,eAAe;YACrC,IAAI,CAACD,mBACDA,oBAAoBE,wBAAwB;gBACxC5C;gBACA2B;gBACA,mBAAmBG;gBACnB,wBAAwB9B,UAAU,OAAO,CAAC6C;YAC9C;YAEJ,OAAOH;QACX;QAEA1C,UAAU,QAAQ,CAAC8C;QACnB9C,UAAU,QAAQ,CAACJ;IACvB;AACJ"}
|
|
1
|
+
{"version":3,"file":"AcoFeature.js","sources":["../src/AcoFeature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { GraphQLSchemaFactory } from \"@webiny/api-graphql/graphql/abstractions.js\";\nimport type { IGraphQLSchemaBuilder } from \"@webiny/api-graphql/features/GraphQLSchemaBuilder/abstractions.js\";\nimport type { Container } from \"@webiny/di\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { HeadlessCms } from \"@webiny/api-headless-cms/features/shared/abstractions.js\";\nimport { addAcoBaseSchema } from \"./createAcoGraphQL.js\";\nimport { addFilterSchema } from \"~/filter/filter.gql.js\";\nimport { AcoFolderSchemaFactory } from \"./AcoFolderSchemaFactory.js\";\nimport { FolderModelProvider } from \"~/features/folder/FolderModelProvider.js\";\nimport { CmsFlpFeature } from \"~/features/cms/index.js\";\nimport { FeatureFlags } from \"@webiny/api-core/features/featureFlags/abstractions.js\";\nimport { CreateFlpTask } from \"~/flp/tasks/createFlp.task.js\";\nimport { UpdateFlpTask } from \"~/flp/tasks/updateFlp.task.js\";\nimport { DeleteFlpTask } from \"~/flp/tasks/deleteFlp.task.js\";\nimport { SyncFlpTask } from \"~/flp/tasks/syncFlp.task.js\";\nimport type { AcoStorageOperations } from \"~/types.js\";\nimport type { Tenant } from \"@webiny/api-core/types/tenancy.js\";\nimport { FolderModel } from \"~/domain/folder/folder.model.js\";\nimport { FilterPrivateModel } from \"~/filter/filter.model.js\";\n// Facade wiring (moved here from createAcoContext so the ACO facade can be a lazy DI factory).\nimport { createFilterOperations } from \"~/filter/filter.so.js\";\nimport { createFilterCrudMethods } from \"~/filter/filter.crud.js\";\nimport { createFlpCrudMethods } from \"~/flp/index.js\";\nimport {\n FolderLevelPermissions,\n FolderLevelPermissionsFeature\n} from \"~/features/flp/FolderLevelPermissions/index.js\";\nimport { UpdateFolderFeature } from \"~/features/folder/UpdateFolder/index.js\";\nimport { DeleteFolderFeature } from \"~/features/folder/DeleteFolder/index.js\";\nimport { CreateFolderFeature } from \"~/features/folder/CreateFolder/index.js\";\nimport { GetFolderFeature } from \"~/features/folder/GetFolder/index.js\";\nimport { ListFoldersFeature } from \"~/features/folder/ListFolders/index.js\";\nimport { GetFolderHierarchyFeature } from \"~/features/folder/GetFolderHierarchy/index.js\";\nimport { GetAncestorsFeature } from \"~/features/folder/GetAncestors/index.js\";\nimport { UpdateFlpOnFolderUpdatedFeature } from \"~/features/flp/UpdateFlpOnFolderUpdated/index.js\";\nimport { DeleteFlpOnFolderDeletedFeature } from \"~/features/flp/DeleteFlpOnFolderDeleted/index.js\";\nimport { EnsureHcmsFolderIsEmptyOnDeleteFeature } from \"~/features/folder/EnsureHcmsFolderIsEmptyOnDelete/index.js\";\nimport { CreateFlpFeature } from \"~/features/flp/CreateFlp/index.js\";\nimport { DeleteFlpFeature } from \"~/features/flp/DeleteFlp/index.js\";\nimport { UpdateFlpFeature } from \"~/features/flp/UpdateFlp/index.js\";\nimport { EnsureFolderIsEmptyOnDeleteFeature } from \"~/features/folder/EnsureFolderIsEmptyOnDelete/index.js\";\nimport {\n AcoFilterCrud,\n AcoFlpCrud,\n FilterStorageOperations,\n FlpStorageOperations\n} from \"~/features/folder/shared/abstractions.js\";\nimport { ListFlpsFeature } from \"~/features/flp/ListFlps/feature.js\";\nimport { GetFlpFeature } from \"~/features/flp/GetFlp/feature.js\";\nimport { ListFolderLevelPermissionsTargetsFeature } from \"~/features/folder/ListFolderLevelPermissionsTargets/feature.js\";\nimport { CreateFlpOnFolderCreatedFeature } from \"~/features/flp/CreateFlpOnFolderCreated/index.js\";\nimport { EnsureFolderIsEmptyFeature } from \"~/features/folder/EnsureFolderIsEmpty/feature.js\";\nimport { AcoAiToolsFeature } from \"~/features/ai/index.js\";\n\nclass AcoSchemaFactoryImpl implements GraphQLSchemaFactory.Interface {\n async execute(builder: IGraphQLSchemaBuilder): Promise<IGraphQLSchemaBuilder> {\n // Static ACO base + filter schema (DI-native contributors declaring their deps). The\n // dynamic, per-tenant folder schema is built by AcoFolderSchemaFactory.\n addAcoBaseSchema(builder);\n addFilterSchema(builder);\n return builder;\n }\n}\n\nconst AcoSchemaFactory = GraphQLSchemaFactory.createImplementation({\n implementation: AcoSchemaFactoryImpl,\n dependencies: []\n});\n\nexport const AcoFeature = createFeature({\n name: \"Aco\",\n register(container: Container) {\n container.register(FolderModel);\n AcoAiToolsFeature.register(container);\n container.register(FilterPrivateModel);\n\n // Background task definitions — pure wiring, no tenant/identity needed.\n container.register(CreateFlpTask);\n container.register(UpdateFlpTask);\n container.register(DeleteFlpTask);\n container.register(SyncFlpTask);\n\n // Folder + FLP use-case features — pure DI wiring (all lazy). Moved out of the per-request\n // initializer so they're registered for every event, not only GraphQL requests.\n FolderLevelPermissionsFeature.register(container);\n CreateFolderFeature.register(container);\n UpdateFolderFeature.register(container);\n DeleteFolderFeature.register(container);\n GetFolderFeature.register(container);\n ListFoldersFeature.register(container);\n ListFolderLevelPermissionsTargetsFeature.register(container);\n GetFolderHierarchyFeature.register(container);\n GetAncestorsFeature.register(container);\n EnsureFolderIsEmptyFeature.register(container);\n CreateFlpFeature.register(container);\n UpdateFlpFeature.register(container);\n DeleteFlpFeature.register(container);\n ListFlpsFeature.register(container);\n GetFlpFeature.register(container);\n CreateFlpOnFolderCreatedFeature.register(container);\n UpdateFlpOnFolderUpdatedFeature.register(container);\n DeleteFlpOnFolderDeletedFeature.register(container);\n EnsureFolderIsEmptyOnDeleteFeature.register(container);\n EnsureHcmsFolderIsEmptyOnDeleteFeature.register(container);\n\n // ===== Lazy ACO facade =====\n // Built on first resolve (post-auth) so the HeadlessCms facade (also lazy) is resolved on\n // demand. Memoised per request container. Consumers resolve AcoFlpCrud / AcoFilterCrud /\n // FilterStorageOperations via DI.\n const getTenant = (): Tenant => container.resolve(TenantContext).getTenant();\n\n let storageOperations: AcoStorageOperations | undefined;\n const getStorageOperations = (): AcoStorageOperations => {\n if (!storageOperations) {\n const cms = container.resolve(HeadlessCms);\n const identityContext = container.resolve(IdentityContext);\n storageOperations = {\n filter: createFilterOperations({ cms, identityContext, container }),\n flp: container.resolve(FlpStorageOperations)\n };\n }\n return storageOperations;\n };\n\n let flpCrudMethods: ReturnType<typeof createFlpCrudMethods> | undefined;\n const getFlpCrudMethods = () => {\n if (!flpCrudMethods) {\n flpCrudMethods = createFlpCrudMethods({\n getTenant,\n storageOperations: getStorageOperations()\n });\n }\n return flpCrudMethods;\n };\n container.registerFactory(AcoFlpCrud, () => getFlpCrudMethods());\n container.registerFactory(FilterStorageOperations, () => getStorageOperations().filter);\n\n let filterCrudMethods: ReturnType<typeof createFilterCrudMethods> | undefined;\n container.registerFactory(AcoFilterCrud, () => {\n if (!filterCrudMethods) {\n filterCrudMethods = createFilterCrudMethods({\n container,\n getTenant,\n storageOperations: getStorageOperations(),\n folderLevelPermissions: container.resolve(FolderLevelPermissions)\n });\n }\n return filterCrudMethods;\n });\n\n // The per-tenant folder model is resolved on demand — see FolderModelProvider.\n container.register(FolderModelProvider);\n\n // CMS-entry folder-level-permission decorators, feature-flag gated. These must be\n // registered before any CMS-entry abstraction they wrap is first resolved, which is why\n // they used to sit in a pre-resolver initializer. Register time is strictly earlier and the\n // gate is valid here: the WCP license is refreshed before any feature registers (see\n // registerApiRequestStack).\n if (\n container\n .resolve(FeatureFlags)\n .get()\n .isEnabled(\"advancedAccessControlLayer.folderLevelPermissions\")\n ) {\n CmsFlpFeature.register(container);\n }\n\n container.register(AcoSchemaFactory);\n container.register(AcoFolderSchemaFactory);\n }\n});\n"],"names":["AcoSchemaFactoryImpl","builder","addAcoBaseSchema","addFilterSchema","AcoSchemaFactory","GraphQLSchemaFactory","AcoFeature","createFeature","container","FolderModel","AcoAiToolsFeature","FilterPrivateModel","CreateFlpTask","UpdateFlpTask","DeleteFlpTask","SyncFlpTask","FolderLevelPermissionsFeature","CreateFolderFeature","UpdateFolderFeature","DeleteFolderFeature","GetFolderFeature","ListFoldersFeature","ListFolderLevelPermissionsTargetsFeature","GetFolderHierarchyFeature","GetAncestorsFeature","EnsureFolderIsEmptyFeature","CreateFlpFeature","UpdateFlpFeature","DeleteFlpFeature","ListFlpsFeature","GetFlpFeature","CreateFlpOnFolderCreatedFeature","UpdateFlpOnFolderUpdatedFeature","DeleteFlpOnFolderDeletedFeature","EnsureFolderIsEmptyOnDeleteFeature","EnsureHcmsFolderIsEmptyOnDeleteFeature","getTenant","TenantContext","storageOperations","getStorageOperations","cms","HeadlessCms","identityContext","IdentityContext","createFilterOperations","FlpStorageOperations","flpCrudMethods","getFlpCrudMethods","createFlpCrudMethods","AcoFlpCrud","FilterStorageOperations","filterCrudMethods","AcoFilterCrud","createFilterCrudMethods","FolderLevelPermissions","FolderModelProvider","FeatureFlags","CmsFlpFeature","AcoFolderSchemaFactory"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,MAAMA;IACF,MAAM,QAAQC,OAA8B,EAAkC;QAG1EC,iBAAiBD;QACjBE,gBAAgBF;QAChB,OAAOA;IACX;AACJ;AAEA,MAAMG,mBAAmBC,qBAAqB,oBAAoB,CAAC;IAC/D,gBAAgBL;IAChB,cAAc,EAAE;AACpB;AAEO,MAAMM,aAAaC,cAAc;IACpC,MAAM;IACN,UAASC,SAAoB;QACzBA,UAAU,QAAQ,CAACC;QACnBC,kBAAkB,QAAQ,CAACF;QAC3BA,UAAU,QAAQ,CAACG;QAGnBH,UAAU,QAAQ,CAACI;QACnBJ,UAAU,QAAQ,CAACK;QACnBL,UAAU,QAAQ,CAACM;QACnBN,UAAU,QAAQ,CAACO;QAInBC,8BAA8B,QAAQ,CAACR;QACvCS,oBAAoB,QAAQ,CAACT;QAC7BU,oBAAoB,QAAQ,CAACV;QAC7BW,oBAAoB,QAAQ,CAACX;QAC7BY,iBAAiB,QAAQ,CAACZ;QAC1Ba,mBAAmB,QAAQ,CAACb;QAC5Bc,yCAAyC,QAAQ,CAACd;QAClDe,0BAA0B,QAAQ,CAACf;QACnCgB,oBAAoB,QAAQ,CAAChB;QAC7BiB,2BAA2B,QAAQ,CAACjB;QACpCkB,iBAAiB,QAAQ,CAAClB;QAC1BmB,iBAAiB,QAAQ,CAACnB;QAC1BoB,iBAAiB,QAAQ,CAACpB;QAC1BqB,gBAAgB,QAAQ,CAACrB;QACzBsB,cAAc,QAAQ,CAACtB;QACvBuB,gCAAgC,QAAQ,CAACvB;QACzCwB,gCAAgC,QAAQ,CAACxB;QACzCyB,gCAAgC,QAAQ,CAACzB;QACzC0B,mCAAmC,QAAQ,CAAC1B;QAC5C2B,uCAAuC,QAAQ,CAAC3B;QAMhD,MAAM4B,YAAY,IAAc5B,UAAU,OAAO,CAAC6B,eAAe,SAAS;QAE1E,IAAIC;QACJ,MAAMC,uBAAuB;YACzB,IAAI,CAACD,mBAAmB;gBACpB,MAAME,MAAMhC,UAAU,OAAO,CAACiC;gBAC9B,MAAMC,kBAAkBlC,UAAU,OAAO,CAACmC;gBAC1CL,oBAAoB;oBAChB,QAAQM,uBAAuB;wBAAEJ;wBAAKE;wBAAiBlC;oBAAU;oBACjE,KAAKA,UAAU,OAAO,CAACqC;gBAC3B;YACJ;YACA,OAAOP;QACX;QAEA,IAAIQ;QACJ,MAAMC,oBAAoB;YACtB,IAAI,CAACD,gBACDA,iBAAiBE,qBAAqB;gBAClCZ;gBACA,mBAAmBG;YACvB;YAEJ,OAAOO;QACX;QACAtC,UAAU,eAAe,CAACyC,YAAY,IAAMF;QAC5CvC,UAAU,eAAe,CAAC0C,yBAAyB,IAAMX,uBAAuB,MAAM;QAEtF,IAAIY;QACJ3C,UAAU,eAAe,CAAC4C,eAAe;YACrC,IAAI,CAACD,mBACDA,oBAAoBE,wBAAwB;gBACxC7C;gBACA4B;gBACA,mBAAmBG;gBACnB,wBAAwB/B,UAAU,OAAO,CAAC8C;YAC9C;YAEJ,OAAOH;QACX;QAGA3C,UAAU,QAAQ,CAAC+C;QAOnB,IACI/C,UACK,OAAO,CAACgD,cACR,GAAG,GACH,SAAS,CAAC,sDAEfC,cAAc,QAAQ,CAACjD;QAG3BA,UAAU,QAAQ,CAACJ;QACnBI,UAAU,QAAQ,CAACkD;IACvB;AACJ"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CoreGraphQLSchemaFactory } from "@webiny/api-graphql/graphql/abstractions.js";
|
|
2
|
+
import type { IGraphQLSchemaBuilder } from "@webiny/api-graphql/features/GraphQLSchemaBuilder/abstractions.js";
|
|
3
|
+
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
4
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
|
|
5
|
+
import { ListModelsUseCase } from "@webiny/api-headless-cms/features/contentModel/ListModels/index.js";
|
|
6
|
+
import { CmsModelFieldToGraphQLRegistry } from "@webiny/api-headless-cms/exports/api/cms/graphql.js";
|
|
7
|
+
import { FolderModelProvider } from "./domain/folder/abstractions.js";
|
|
8
|
+
/**
|
|
9
|
+
* Builds the dynamic folder GraphQL schema — the `Folder` type's fields are rendered from the
|
|
10
|
+
* tenant's folder model, so the shape differs per tenant.
|
|
11
|
+
*
|
|
12
|
+
* Previously done by `AcoInitializer`, which had to run as a per-request hook before any resolver:
|
|
13
|
+
* it fetched the model, then registered one `CoreGraphQLSchemaFactory` per generated plugin. That
|
|
14
|
+
* indirection is unnecessary — `CoreGraphQLSchemaFactory.execute()` is already awaited by
|
|
15
|
+
* `GraphQLSchemaComposer`, so this factory can be registered once at compose time and do its async
|
|
16
|
+
* work inside `execute()`, at the moment the schema is actually built.
|
|
17
|
+
*/
|
|
18
|
+
declare class AcoFolderSchemaFactoryImpl implements CoreGraphQLSchemaFactory.Interface {
|
|
19
|
+
private folderModelProvider;
|
|
20
|
+
private listModels;
|
|
21
|
+
private fieldRegistry;
|
|
22
|
+
private identityContext;
|
|
23
|
+
private tenantContext;
|
|
24
|
+
constructor(folderModelProvider: FolderModelProvider.Interface, listModels: ListModelsUseCase.Interface, fieldRegistry: CmsModelFieldToGraphQLRegistry.Interface, identityContext: IdentityContext.Interface, tenantContext: TenantContext.Interface);
|
|
25
|
+
execute(builder: IGraphQLSchemaBuilder): Promise<IGraphQLSchemaBuilder>;
|
|
26
|
+
}
|
|
27
|
+
export declare const AcoFolderSchemaFactory: typeof AcoFolderSchemaFactoryImpl & {
|
|
28
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-graphql/graphql/abstractions.core").ICoreGraphQLSchemaFactory>;
|
|
29
|
+
};
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { GraphQLSchemaPlugin } from "@webiny/api-graphql";
|
|
2
|
+
import { CoreGraphQLSchemaFactory } from "@webiny/api-graphql/graphql/abstractions.js";
|
|
3
|
+
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
4
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
|
|
5
|
+
import { ListModelsUseCase } from "@webiny/api-headless-cms/features/contentModel/ListModels/index.js";
|
|
6
|
+
import { CmsModelFieldToGraphQLRegistry } from "@webiny/api-headless-cms/exports/api/cms/graphql.js";
|
|
7
|
+
import { createGraphQLSchemaPluginFromFieldPlugins } from "@webiny/api-headless-cms/utils/getSchemaFromFieldPlugins.js";
|
|
8
|
+
import { FolderModelProvider } from "./domain/folder/abstractions.js";
|
|
9
|
+
import { createFoldersSchema } from "./folder/folder.gql.js";
|
|
10
|
+
class AcoFolderSchemaFactoryImpl {
|
|
11
|
+
constructor(folderModelProvider, listModels, fieldRegistry, identityContext, tenantContext){
|
|
12
|
+
this.folderModelProvider = folderModelProvider;
|
|
13
|
+
this.listModels = listModels;
|
|
14
|
+
this.fieldRegistry = fieldRegistry;
|
|
15
|
+
this.identityContext = identityContext;
|
|
16
|
+
this.tenantContext = tenantContext;
|
|
17
|
+
}
|
|
18
|
+
async execute(builder) {
|
|
19
|
+
if (!this.tenantContext.getTenant()) return builder;
|
|
20
|
+
const model = await this.folderModelProvider.get();
|
|
21
|
+
const models = await this.identityContext.withoutAuthorization(async ()=>{
|
|
22
|
+
const result = await this.listModels.execute();
|
|
23
|
+
if (result.isFail()) throw result.error;
|
|
24
|
+
return result.value;
|
|
25
|
+
});
|
|
26
|
+
const fieldPlugins = createGraphQLSchemaPluginFromFieldPlugins({
|
|
27
|
+
models,
|
|
28
|
+
type: "manage",
|
|
29
|
+
fieldRegistry: this.fieldRegistry,
|
|
30
|
+
createPlugin: ({ schema, type, fieldType })=>{
|
|
31
|
+
const plugin = new GraphQLSchemaPlugin(schema);
|
|
32
|
+
plugin.name = `aco.graphql.folder.schema.${type}.field.${fieldType}`;
|
|
33
|
+
return plugin;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
const folderPlugin = createFoldersSchema({
|
|
37
|
+
model,
|
|
38
|
+
models,
|
|
39
|
+
fieldRegistry: this.fieldRegistry
|
|
40
|
+
});
|
|
41
|
+
for (const plugin of [
|
|
42
|
+
...fieldPlugins,
|
|
43
|
+
folderPlugin
|
|
44
|
+
]){
|
|
45
|
+
if (plugin.schema.typeDefs) builder.addTypeDefs(plugin.schema.typeDefs);
|
|
46
|
+
if (plugin.schema.resolvers) builder.addLegacyResolvers(plugin.schema.resolvers);
|
|
47
|
+
if (plugin.schema.resolverDecorators) for (const [path, decorators] of Object.entries(plugin.schema.resolverDecorators))for (const decorator of decorators)builder.addResolverDecorator(path, decorator);
|
|
48
|
+
}
|
|
49
|
+
return builder;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const AcoFolderSchemaFactory = CoreGraphQLSchemaFactory.createImplementation({
|
|
53
|
+
implementation: AcoFolderSchemaFactoryImpl,
|
|
54
|
+
dependencies: [
|
|
55
|
+
FolderModelProvider,
|
|
56
|
+
ListModelsUseCase,
|
|
57
|
+
CmsModelFieldToGraphQLRegistry,
|
|
58
|
+
IdentityContext,
|
|
59
|
+
TenantContext
|
|
60
|
+
]
|
|
61
|
+
});
|
|
62
|
+
export { AcoFolderSchemaFactory };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=AcoFolderSchemaFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AcoFolderSchemaFactory.js","sources":["../src/AcoFolderSchemaFactory.ts"],"sourcesContent":["import { GraphQLSchemaPlugin } from \"@webiny/api-graphql\";\nimport { CoreGraphQLSchemaFactory } from \"@webiny/api-graphql/graphql/abstractions.js\";\nimport type { IGraphQLSchemaBuilder } from \"@webiny/api-graphql/features/GraphQLSchemaBuilder/abstractions.js\";\nimport type { IGraphQLSchemaPlugin } from \"@webiny/api-graphql/plugins/GraphQLSchemaPlugin.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\nimport { ListModelsUseCase } from \"@webiny/api-headless-cms/features/contentModel/ListModels/index.js\";\nimport { CmsModelFieldToGraphQLRegistry } from \"@webiny/api-headless-cms/exports/api/cms/graphql.js\";\nimport { createGraphQLSchemaPluginFromFieldPlugins } from \"@webiny/api-headless-cms/utils/getSchemaFromFieldPlugins.js\";\nimport { FolderModelProvider } from \"~/domain/folder/abstractions.js\";\nimport { createFoldersSchema } from \"~/folder/folder.gql.js\";\n\n/**\n * Builds the dynamic folder GraphQL schema — the `Folder` type's fields are rendered from the\n * tenant's folder model, so the shape differs per tenant.\n *\n * Previously done by `AcoInitializer`, which had to run as a per-request hook before any resolver:\n * it fetched the model, then registered one `CoreGraphQLSchemaFactory` per generated plugin. That\n * indirection is unnecessary — `CoreGraphQLSchemaFactory.execute()` is already awaited by\n * `GraphQLSchemaComposer`, so this factory can be registered once at compose time and do its async\n * work inside `execute()`, at the moment the schema is actually built.\n */\nclass AcoFolderSchemaFactoryImpl implements CoreGraphQLSchemaFactory.Interface {\n constructor(\n private folderModelProvider: FolderModelProvider.Interface,\n private listModels: ListModelsUseCase.Interface,\n private fieldRegistry: CmsModelFieldToGraphQLRegistry.Interface,\n private identityContext: IdentityContext.Interface,\n private tenantContext: TenantContext.Interface\n ) {}\n\n async execute(builder: IGraphQLSchemaBuilder): Promise<IGraphQLSchemaBuilder> {\n // On a fresh project there is no tenant until installation completes, and there is no model\n // to render a schema from. (This is what `isHeadlessCmsReady` checked in the initializer.)\n if (!this.tenantContext.getTenant()) {\n return builder;\n }\n\n const model = await this.folderModelProvider.get();\n\n // The model list feeds `ref` field rendering, so it must be the COMPLETE set — access\n // control filters models by permission, which would otherwise make the generated schema\n // vary by identity. Hence the unauthorized read, exactly as the initializer did.\n const models = await this.identityContext.withoutAuthorization(async () => {\n const result = await this.listModels.execute();\n if (result.isFail()) {\n throw result.error;\n }\n return result.value;\n });\n\n const fieldPlugins = createGraphQLSchemaPluginFromFieldPlugins({\n models,\n type: \"manage\",\n fieldRegistry: this.fieldRegistry,\n createPlugin: ({ schema, type, fieldType }) => {\n const plugin = new GraphQLSchemaPlugin(schema);\n plugin.name = `aco.graphql.folder.schema.${type}.field.${fieldType}`;\n return plugin;\n }\n });\n\n const folderPlugin = createFoldersSchema({\n model,\n models,\n fieldRegistry: this.fieldRegistry\n });\n\n for (const plugin of [...fieldPlugins, folderPlugin] as IGraphQLSchemaPlugin[]) {\n if (plugin.schema.typeDefs) {\n builder.addTypeDefs(plugin.schema.typeDefs);\n }\n if (plugin.schema.resolvers) {\n builder.addLegacyResolvers(plugin.schema.resolvers as Record<string, any>);\n }\n if (plugin.schema.resolverDecorators) {\n for (const [path, decorators] of Object.entries(plugin.schema.resolverDecorators)) {\n for (const decorator of decorators as any[]) {\n builder.addResolverDecorator(path, decorator);\n }\n }\n }\n }\n\n return builder;\n }\n}\n\nexport const AcoFolderSchemaFactory = CoreGraphQLSchemaFactory.createImplementation({\n implementation: AcoFolderSchemaFactoryImpl,\n dependencies: [\n FolderModelProvider,\n ListModelsUseCase,\n CmsModelFieldToGraphQLRegistry,\n IdentityContext,\n TenantContext\n ]\n});\n"],"names":["AcoFolderSchemaFactoryImpl","folderModelProvider","listModels","fieldRegistry","identityContext","tenantContext","builder","model","models","result","fieldPlugins","createGraphQLSchemaPluginFromFieldPlugins","schema","type","fieldType","plugin","GraphQLSchemaPlugin","folderPlugin","createFoldersSchema","path","decorators","Object","decorator","AcoFolderSchemaFactory","CoreGraphQLSchemaFactory","FolderModelProvider","ListModelsUseCase","CmsModelFieldToGraphQLRegistry","IdentityContext","TenantContext"],"mappings":";;;;;;;;;AAsBA,MAAMA;IACF,YACYC,mBAAkD,EAClDC,UAAuC,EACvCC,aAAuD,EACvDC,eAA0C,EAC1CC,aAAsC,CAChD;aALUJ,mBAAmB,GAAnBA;aACAC,UAAU,GAAVA;aACAC,aAAa,GAAbA;aACAC,eAAe,GAAfA;aACAC,aAAa,GAAbA;IACT;IAEH,MAAM,QAAQC,OAA8B,EAAkC;QAG1E,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,IAC7B,OAAOA;QAGX,MAAMC,QAAQ,MAAM,IAAI,CAAC,mBAAmB,CAAC,GAAG;QAKhD,MAAMC,SAAS,MAAM,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC;YAC3D,MAAMC,SAAS,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO;YAC5C,IAAIA,OAAO,MAAM,IACb,MAAMA,OAAO,KAAK;YAEtB,OAAOA,OAAO,KAAK;QACvB;QAEA,MAAMC,eAAeC,0CAA0C;YAC3DH;YACA,MAAM;YACN,eAAe,IAAI,CAAC,aAAa;YACjC,cAAc,CAAC,EAAEI,MAAM,EAAEC,IAAI,EAAEC,SAAS,EAAE;gBACtC,MAAMC,SAAS,IAAIC,oBAAoBJ;gBACvCG,OAAO,IAAI,GAAG,CAAC,0BAA0B,EAAEF,KAAK,OAAO,EAAEC,WAAW;gBACpE,OAAOC;YACX;QACJ;QAEA,MAAME,eAAeC,oBAAoB;YACrCX;YACAC;YACA,eAAe,IAAI,CAAC,aAAa;QACrC;QAEA,KAAK,MAAMO,UAAU;eAAIL;YAAcO;SAAa,CAA4B;YAC5E,IAAIF,OAAO,MAAM,CAAC,QAAQ,EACtBT,QAAQ,WAAW,CAACS,OAAO,MAAM,CAAC,QAAQ;YAE9C,IAAIA,OAAO,MAAM,CAAC,SAAS,EACvBT,QAAQ,kBAAkB,CAACS,OAAO,MAAM,CAAC,SAAS;YAEtD,IAAIA,OAAO,MAAM,CAAC,kBAAkB,EAChC,KAAK,MAAM,CAACI,MAAMC,WAAW,IAAIC,OAAO,OAAO,CAACN,OAAO,MAAM,CAAC,kBAAkB,EAC5E,KAAK,MAAMO,aAAaF,WACpBd,QAAQ,oBAAoB,CAACa,MAAMG;QAInD;QAEA,OAAOhB;IACX;AACJ;AAEO,MAAMiB,yBAAyBC,yBAAyB,oBAAoB,CAAC;IAChF,gBAAgBxB;IAChB,cAAc;QACVyB;QACAC;QACAC;QACAC;QACAC;KACH;AACL"}
|
package/createAcoGraphQL.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { IGraphQLSchemaBuilder } from "@webiny/api-graphql/features/GraphQLSchemaBuilder/abstractions.js";
|
|
2
2
|
/**
|
|
3
3
|
* The static ACO base schema (root Query.aco / Mutation.aco wrappers + shared types). The dynamic
|
|
4
|
-
* folder schema (field plugins + folders schema) is built
|
|
5
|
-
* the
|
|
4
|
+
* folder schema (field plugins + folders schema) is built by AcoFolderSchemaFactory, which awaits
|
|
5
|
+
* the per-tenant folder model when the schema is built. The filter schema comes from
|
|
6
|
+
* addFilterSchema.
|
|
6
7
|
*/
|
|
7
8
|
export declare const addAcoBaseSchema: (builder: IGraphQLSchemaBuilder) => void;
|
package/createAcoGraphQL.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createAcoGraphQL.js","sources":["../src/createAcoGraphQL.ts"],"sourcesContent":["import type { IGraphQLSchemaBuilder } from \"@webiny/api-graphql/features/GraphQLSchemaBuilder/abstractions.js\";\n\nconst BASE_TYPE_DEFS = /* GraphQL */ `\n type AcoQuery {\n _empty: String\n }\n\n type AcoMutation {\n _empty: String\n }\n\n type AcoMeta {\n hasMoreItems: Boolean\n totalCount: Int\n cursor: String\n }\n\n type AcoUser {\n id: ID\n displayName: String\n type: String\n }\n\n type AcoError {\n code: String\n message: String\n data: JSON\n stack: String\n }\n\n type AcoBooleanResponse {\n data: Boolean\n error: AcoError\n }\n\n enum AcoSortDirection {\n ASC\n DESC\n }\n\n input AcoSort {\n id: AcoSortDirection\n createdOn: AcoSortDirection\n modifiedOn: AcoSortDirection\n savedOn: AcoSortDirection\n title: AcoSortDirection\n }\n\n extend type Query {\n aco: AcoQuery\n }\n\n extend type Mutation {\n aco: AcoMutation\n }\n`;\n\n/**\n * The static ACO base schema (root Query.aco / Mutation.aco wrappers + shared types). The dynamic\n * folder schema (field plugins + folders schema) is built
|
|
1
|
+
{"version":3,"file":"createAcoGraphQL.js","sources":["../src/createAcoGraphQL.ts"],"sourcesContent":["import type { IGraphQLSchemaBuilder } from \"@webiny/api-graphql/features/GraphQLSchemaBuilder/abstractions.js\";\n\nconst BASE_TYPE_DEFS = /* GraphQL */ `\n type AcoQuery {\n _empty: String\n }\n\n type AcoMutation {\n _empty: String\n }\n\n type AcoMeta {\n hasMoreItems: Boolean\n totalCount: Int\n cursor: String\n }\n\n type AcoUser {\n id: ID\n displayName: String\n type: String\n }\n\n type AcoError {\n code: String\n message: String\n data: JSON\n stack: String\n }\n\n type AcoBooleanResponse {\n data: Boolean\n error: AcoError\n }\n\n enum AcoSortDirection {\n ASC\n DESC\n }\n\n input AcoSort {\n id: AcoSortDirection\n createdOn: AcoSortDirection\n modifiedOn: AcoSortDirection\n savedOn: AcoSortDirection\n title: AcoSortDirection\n }\n\n extend type Query {\n aco: AcoQuery\n }\n\n extend type Mutation {\n aco: AcoMutation\n }\n`;\n\n/**\n * The static ACO base schema (root Query.aco / Mutation.aco wrappers + shared types). The dynamic\n * folder schema (field plugins + folders schema) is built by AcoFolderSchemaFactory, which awaits\n * the per-tenant folder model when the schema is built. The filter schema comes from\n * addFilterSchema.\n */\nexport const addAcoBaseSchema = (builder: IGraphQLSchemaBuilder): void => {\n builder.addTypeDefs(BASE_TYPE_DEFS);\n builder.addResolver({ path: \"Query.aco\", dependencies: [], resolver: () => () => ({}) });\n builder.addResolver({ path: \"Mutation.aco\", dependencies: [], resolver: () => () => ({}) });\n};\n"],"names":["BASE_TYPE_DEFS","addAcoBaseSchema","builder"],"mappings":"AAEA,MAAMA,iBAA+B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDtC,CAAC;AAQM,MAAMC,mBAAmB,CAACC;IAC7BA,QAAQ,WAAW,CAACF;IACpBE,QAAQ,WAAW,CAAC;QAAE,MAAM;QAAa,cAAc,EAAE;QAAE,UAAU,IAAM,IAAO,EAAC;IAAG;IACtFA,QAAQ,WAAW,CAAC;QAAE,MAAM;QAAgB,cAAc,EAAE;QAAE,UAAU,IAAM,IAAO,EAAC;IAAG;AAC7F"}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { CmsModel } from "@webiny/api-headless-cms/types";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Provides the tenant's ACO folder CMS model.
|
|
4
|
+
*
|
|
5
|
+
* A provider rather than the model itself: fetching a model is asynchronous and tenant-dependent,
|
|
6
|
+
* while DI resolution is synchronous — so an already-resolved `CmsModel` could only be supplied by a
|
|
7
|
+
* per-request hook running before every consumer (what `AcoInitializer` used to do). Consumers
|
|
8
|
+
* `await get()` at the point of use.
|
|
5
9
|
*/
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
export interface IFolderModelProvider {
|
|
11
|
+
get(): Promise<CmsModel>;
|
|
12
|
+
}
|
|
13
|
+
export declare const FolderModelProvider: import("@webiny/di").Abstraction<IFolderModelProvider>;
|
|
14
|
+
export declare namespace FolderModelProvider {
|
|
15
|
+
type Interface = IFolderModelProvider;
|
|
9
16
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createAbstraction } from "@webiny/feature/api";
|
|
2
|
-
const
|
|
3
|
-
export {
|
|
2
|
+
const FolderModelProvider = createAbstraction("FolderModelProvider");
|
|
3
|
+
export { FolderModelProvider };
|
|
4
4
|
|
|
5
5
|
//# sourceMappingURL=abstractions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain/folder/abstractions.js","sources":["../../../src/domain/folder/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\nimport type { CmsModel } from \"@webiny/api-headless-cms/types\";\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"domain/folder/abstractions.js","sources":["../../../src/domain/folder/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\nimport type { CmsModel } from \"@webiny/api-headless-cms/types\";\n\n/**\n * Provides the tenant's ACO folder CMS model.\n *\n * A provider rather than the model itself: fetching a model is asynchronous and tenant-dependent,\n * while DI resolution is synchronous — so an already-resolved `CmsModel` could only be supplied by a\n * per-request hook running before every consumer (what `AcoInitializer` used to do). Consumers\n * `await get()` at the point of use.\n */\nexport interface IFolderModelProvider {\n get(): Promise<CmsModel>;\n}\n\nexport const FolderModelProvider = createAbstraction<IFolderModelProvider>(\"FolderModelProvider\");\n\nexport namespace FolderModelProvider {\n export type Interface = IFolderModelProvider;\n}\n"],"names":["FolderModelProvider","createAbstraction"],"mappings":";AAeO,MAAMA,sBAAsBC,kBAAwC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { IAiSdkTool } from "@webiny/api-core/features/ai/index.js";
|
|
3
|
+
import { CreateFolderUseCase } from "../../features/folder/CreateFolder/index.js";
|
|
4
|
+
declare const inputSchema: z.ZodObject<{
|
|
5
|
+
title: z.ZodString;
|
|
6
|
+
slug: z.ZodString;
|
|
7
|
+
type: z.ZodString;
|
|
8
|
+
parentId: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
type Input = z.infer<typeof inputSchema>;
|
|
11
|
+
interface CreatedFolder {
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
slug: string;
|
|
15
|
+
path: string;
|
|
16
|
+
type: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates a folder.
|
|
20
|
+
*
|
|
21
|
+
* Additive and reversible, so it is not flagged destructive — but it still changes the project, so it
|
|
22
|
+
* is not read-only either and therefore needs the user to approve the exact arguments.
|
|
23
|
+
*/
|
|
24
|
+
declare class CreateFolderToolImpl implements IAiSdkTool<Input> {
|
|
25
|
+
private createFolder;
|
|
26
|
+
readonly name = "createFolder";
|
|
27
|
+
readonly title = "Create folder";
|
|
28
|
+
readonly description = "Creates a folder in the File Manager ('FmFile') or under a content model ('cms:<modelId>'). Call listFolders first to pick a parent, or omit parentId for the root. Requires user approval.";
|
|
29
|
+
readonly inputSchema: z.ZodObject<{
|
|
30
|
+
title: z.ZodString;
|
|
31
|
+
slug: z.ZodString;
|
|
32
|
+
type: z.ZodString;
|
|
33
|
+
parentId: z.ZodOptional<z.ZodString>;
|
|
34
|
+
}, z.core.$strip>;
|
|
35
|
+
readonly annotations: {
|
|
36
|
+
readOnlyHint: boolean;
|
|
37
|
+
};
|
|
38
|
+
constructor(createFolder: CreateFolderUseCase.Interface);
|
|
39
|
+
execute(input: Input): Promise<CreatedFolder>;
|
|
40
|
+
}
|
|
41
|
+
export declare const CreateFolderTool: typeof CreateFolderToolImpl & {
|
|
42
|
+
__abstraction: import("@webiny/di").Abstraction<IAiSdkTool<any>>;
|
|
43
|
+
};
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AiSdkTool } from "@webiny/api-core/features/ai/index.js";
|
|
3
|
+
import { CreateFolderUseCase } from "../folder/CreateFolder/index.js";
|
|
4
|
+
const inputSchema = z.object({
|
|
5
|
+
title: z.string().describe("Human-readable folder name, e.g. 'Marketing'."),
|
|
6
|
+
slug: z.string().describe("URL-safe identifier, e.g. 'marketing'. Lowercase, hyphens instead of spaces."),
|
|
7
|
+
type: z.string().describe("Folder namespace: 'FmFile' for File Manager, or 'cms:<modelId>' for a content model's folders."),
|
|
8
|
+
parentId: z.string().optional().describe("Id of the parent folder. Omit to create at the root of that namespace.")
|
|
9
|
+
});
|
|
10
|
+
class CreateFolderToolImpl {
|
|
11
|
+
constructor(createFolder){
|
|
12
|
+
this.createFolder = createFolder;
|
|
13
|
+
this.name = "createFolder";
|
|
14
|
+
this.title = "Create folder";
|
|
15
|
+
this.description = "Creates a folder in the File Manager ('FmFile') or under a content model ('cms:<modelId>'). Call listFolders first to pick a parent, or omit parentId for the root. Requires user approval.";
|
|
16
|
+
this.inputSchema = inputSchema;
|
|
17
|
+
this.annotations = {
|
|
18
|
+
readOnlyHint: false
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async execute(input) {
|
|
22
|
+
const params = {
|
|
23
|
+
title: input.title,
|
|
24
|
+
slug: input.slug,
|
|
25
|
+
type: input.type,
|
|
26
|
+
parentId: null
|
|
27
|
+
};
|
|
28
|
+
if (input.parentId) params.parentId = input.parentId;
|
|
29
|
+
const result = await this.createFolder.execute(params);
|
|
30
|
+
if (result.isFail()) throw new Error(`Could not create the folder: ${result.error.message}`);
|
|
31
|
+
const folder = result.value;
|
|
32
|
+
return {
|
|
33
|
+
id: folder.id,
|
|
34
|
+
title: folder.title,
|
|
35
|
+
slug: folder.slug,
|
|
36
|
+
path: folder.path,
|
|
37
|
+
type: folder.type
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const CreateFolderTool = AiSdkTool.createImplementation({
|
|
42
|
+
implementation: CreateFolderToolImpl,
|
|
43
|
+
dependencies: [
|
|
44
|
+
CreateFolderUseCase
|
|
45
|
+
]
|
|
46
|
+
});
|
|
47
|
+
export { CreateFolderTool };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=CreateFolderTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/ai/CreateFolderTool.js","sources":["../../../src/features/ai/CreateFolderTool.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { AiSdkTool } from \"@webiny/api-core/features/ai/index.js\";\nimport type { IAiSdkTool } from \"@webiny/api-core/features/ai/index.js\";\nimport { CreateFolderUseCase } from \"~/features/folder/CreateFolder/index.js\";\n\nconst inputSchema = z.object({\n title: z.string().describe(\"Human-readable folder name, e.g. 'Marketing'.\"),\n slug: z\n .string()\n .describe(\"URL-safe identifier, e.g. 'marketing'. Lowercase, hyphens instead of spaces.\"),\n type: z\n .string()\n .describe(\n \"Folder namespace: 'FmFile' for File Manager, or 'cms:<modelId>' for a content model's folders.\"\n ),\n parentId: z\n .string()\n .optional()\n .describe(\"Id of the parent folder. Omit to create at the root of that namespace.\")\n});\n\ntype Input = z.infer<typeof inputSchema>;\n\ninterface CreatedFolder {\n id: string;\n title: string;\n slug: string;\n path: string;\n type: string;\n}\n\n/**\n * Creates a folder.\n *\n * Additive and reversible, so it is not flagged destructive — but it still changes the project, so it\n * is not read-only either and therefore needs the user to approve the exact arguments.\n */\nclass CreateFolderToolImpl implements IAiSdkTool<Input> {\n readonly name = \"createFolder\";\n readonly title = \"Create folder\";\n readonly description =\n \"Creates a folder in the File Manager ('FmFile') or under a content model ('cms:<modelId>'). Call listFolders first to pick a parent, or omit parentId for the root. Requires user approval.\";\n readonly inputSchema = inputSchema;\n readonly annotations = { readOnlyHint: false };\n\n constructor(private createFolder: CreateFolderUseCase.Interface) {}\n\n async execute(input: Input): Promise<CreatedFolder> {\n const params: {\n title: string;\n slug: string;\n type: string;\n parentId: string | null;\n } = {\n title: input.title,\n slug: input.slug,\n type: input.type,\n parentId: null\n };\n\n if (input.parentId) {\n params.parentId = input.parentId;\n }\n\n const result = await this.createFolder.execute(params);\n\n if (result.isFail()) {\n throw new Error(`Could not create the folder: ${result.error.message}`);\n }\n\n const folder = result.value;\n\n return {\n id: folder.id,\n title: folder.title,\n slug: folder.slug,\n path: folder.path,\n type: folder.type\n };\n }\n}\n\nexport const CreateFolderTool = AiSdkTool.createImplementation({\n implementation: CreateFolderToolImpl,\n dependencies: [CreateFolderUseCase]\n});\n"],"names":["inputSchema","z","CreateFolderToolImpl","createFolder","input","params","result","Error","folder","CreateFolderTool","AiSdkTool","CreateFolderUseCase"],"mappings":";;;AAKA,MAAMA,cAAcC,EAAE,MAAM,CAAC;IACzB,OAAOA,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,MAAMA,EAAAA,MACK,GACN,QAAQ,CAAC;IACd,MAAMA,EAAAA,MACK,GACN,QAAQ,CACL;IAER,UAAUA,EAAAA,MACC,GACN,QAAQ,GACR,QAAQ,CAAC;AAClB;AAkBA,MAAMC;IAQF,YAAoBC,YAA2C,CAAE;aAA7CA,YAAY,GAAZA;aAPX,IAAI,GAAG;aACP,KAAK,GAAG;aACR,WAAW,GAChB;aACK,WAAW,GAAGH;aACd,WAAW,GAAG;YAAE,cAAc;QAAM;IAEqB;IAElE,MAAM,QAAQI,KAAY,EAA0B;QAChD,MAAMC,SAKF;YACA,OAAOD,MAAM,KAAK;YAClB,MAAMA,MAAM,IAAI;YAChB,MAAMA,MAAM,IAAI;YAChB,UAAU;QACd;QAEA,IAAIA,MAAM,QAAQ,EACdC,OAAO,QAAQ,GAAGD,MAAM,QAAQ;QAGpC,MAAME,SAAS,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAACD;QAE/C,IAAIC,OAAO,MAAM,IACb,MAAM,IAAIC,MAAM,CAAC,6BAA6B,EAAED,OAAO,KAAK,CAAC,OAAO,EAAE;QAG1E,MAAME,SAASF,OAAO,KAAK;QAE3B,OAAO;YACH,IAAIE,OAAO,EAAE;YACb,OAAOA,OAAO,KAAK;YACnB,MAAMA,OAAO,IAAI;YACjB,MAAMA,OAAO,IAAI;YACjB,MAAMA,OAAO,IAAI;QACrB;IACJ;AACJ;AAEO,MAAMC,mBAAmBC,UAAU,oBAAoB,CAAC;IAC3D,gBAAgBR;IAChB,cAAc;QAACS;KAAoB;AACvC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { IAiSdkTool } from "@webiny/api-core/features/ai/index.js";
|
|
3
|
+
import { CreateTeam } from "@webiny/api-core/features/security/teams/CreateTeam/index.js";
|
|
4
|
+
declare const inputSchema: z.ZodObject<{
|
|
5
|
+
name: z.ZodString;
|
|
6
|
+
slug: z.ZodString;
|
|
7
|
+
description: z.ZodOptional<z.ZodString>;
|
|
8
|
+
roles: z.ZodArray<z.ZodString>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
type Input = z.infer<typeof inputSchema>;
|
|
11
|
+
interface CreatedTeam {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
slug: string;
|
|
15
|
+
roles: string[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates a team.
|
|
19
|
+
*
|
|
20
|
+
* Not read-only, so it needs approval: a team is an access-control object, and the roles it carries
|
|
21
|
+
* decide what its members can do. The user should see which roles are being granted before it exists.
|
|
22
|
+
*/
|
|
23
|
+
declare class CreateTeamToolImpl implements IAiSdkTool<Input> {
|
|
24
|
+
private createTeam;
|
|
25
|
+
readonly name = "createTeam";
|
|
26
|
+
readonly title = "Create team";
|
|
27
|
+
readonly description = "Creates a team with a set of roles. Call listRoles first and pass what it returns; do not guess role identifiers. Requires user approval.";
|
|
28
|
+
readonly inputSchema: z.ZodObject<{
|
|
29
|
+
name: z.ZodString;
|
|
30
|
+
slug: z.ZodString;
|
|
31
|
+
description: z.ZodOptional<z.ZodString>;
|
|
32
|
+
roles: z.ZodArray<z.ZodString>;
|
|
33
|
+
}, z.core.$strip>;
|
|
34
|
+
readonly annotations: {
|
|
35
|
+
readOnlyHint: boolean;
|
|
36
|
+
};
|
|
37
|
+
constructor(createTeam: CreateTeam.Interface);
|
|
38
|
+
execute(input: Input): Promise<CreatedTeam>;
|
|
39
|
+
}
|
|
40
|
+
export declare const CreateTeamTool: typeof CreateTeamToolImpl & {
|
|
41
|
+
__abstraction: import("@webiny/di").Abstraction<IAiSdkTool<any>>;
|
|
42
|
+
};
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AiSdkTool } from "@webiny/api-core/features/ai/index.js";
|
|
3
|
+
import { CreateTeam } from "@webiny/api-core/features/security/teams/CreateTeam/index.js";
|
|
4
|
+
import { descriptionOnCreate } from "@webiny/api-core/features/security/shared/index.js";
|
|
5
|
+
const inputSchema = z.object({
|
|
6
|
+
name: z.string().describe("Human-readable team name, e.g. 'Marketing'."),
|
|
7
|
+
slug: z.string().describe("URL-safe identifier, e.g. 'marketing'. Lowercase, hyphens instead of spaces."),
|
|
8
|
+
description: z.string().max(500).optional().describe("What the team is for. Shown in the admin UI. Omit it if the user did not say."),
|
|
9
|
+
roles: z.array(z.string()).describe("Roles from listRoles. Prefer the `id`; a `slug` is accepted and resolved for you. Resolve them with listRoles first, since an unknown value is rejected rather than stored.")
|
|
10
|
+
});
|
|
11
|
+
class CreateTeamToolImpl {
|
|
12
|
+
constructor(createTeam){
|
|
13
|
+
this.createTeam = createTeam;
|
|
14
|
+
this.name = "createTeam";
|
|
15
|
+
this.title = "Create team";
|
|
16
|
+
this.description = "Creates a team with a set of roles. Call listRoles first and pass what it returns; do not guess role identifiers. Requires user approval.";
|
|
17
|
+
this.inputSchema = inputSchema;
|
|
18
|
+
this.annotations = {
|
|
19
|
+
readOnlyHint: false
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
async execute(input) {
|
|
23
|
+
const result = await this.createTeam.execute({
|
|
24
|
+
name: input.name,
|
|
25
|
+
slug: input.slug,
|
|
26
|
+
description: descriptionOnCreate(input.description),
|
|
27
|
+
roles: input.roles
|
|
28
|
+
});
|
|
29
|
+
if (result.isFail()) throw new Error(`Could not create the team: ${result.error.message}`);
|
|
30
|
+
const team = result.value;
|
|
31
|
+
return {
|
|
32
|
+
id: team.id,
|
|
33
|
+
name: team.name,
|
|
34
|
+
slug: team.slug,
|
|
35
|
+
roles: team.roles
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const CreateTeamTool = AiSdkTool.createImplementation({
|
|
40
|
+
implementation: CreateTeamToolImpl,
|
|
41
|
+
dependencies: [
|
|
42
|
+
CreateTeam
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
export { CreateTeamTool };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=CreateTeamTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/ai/CreateTeamTool.js","sources":["../../../src/features/ai/CreateTeamTool.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { AiSdkTool } from \"@webiny/api-core/features/ai/index.js\";\nimport type { IAiSdkTool } from \"@webiny/api-core/features/ai/index.js\";\nimport { CreateTeam } from \"@webiny/api-core/features/security/teams/CreateTeam/index.js\";\nimport { descriptionOnCreate } from \"@webiny/api-core/features/security/shared/index.js\";\n\nconst inputSchema = z.object({\n name: z.string().describe(\"Human-readable team name, e.g. 'Marketing'.\"),\n slug: z\n .string()\n .describe(\"URL-safe identifier, e.g. 'marketing'. Lowercase, hyphens instead of spaces.\"),\n /*\n * Optional and capped, mirroring the use case's own schema. Requiring it made the model invent a\n * description for every team; `CreateTeam` treats an absent one as empty via `descriptionOnCreate`.\n */\n description: z\n .string()\n .max(500)\n .optional()\n .describe(\"What the team is for. Shown in the admin UI. Omit it if the user did not say.\"),\n roles: z\n .array(z.string())\n .describe(\n \"Roles from listRoles. Prefer the `id`; a `slug` is accepted and resolved for you. Resolve them with listRoles first, since an unknown value is rejected rather than stored.\"\n )\n});\n\ntype Input = z.infer<typeof inputSchema>;\n\ninterface CreatedTeam {\n id: string;\n name: string;\n slug: string;\n roles: string[];\n}\n\n/**\n * Creates a team.\n *\n * Not read-only, so it needs approval: a team is an access-control object, and the roles it carries\n * decide what its members can do. The user should see which roles are being granted before it exists.\n */\nclass CreateTeamToolImpl implements IAiSdkTool<Input> {\n readonly name = \"createTeam\";\n readonly title = \"Create team\";\n readonly description =\n \"Creates a team with a set of roles. Call listRoles first and pass what it returns; do not guess role identifiers. Requires user approval.\";\n readonly inputSchema = inputSchema;\n readonly annotations = { readOnlyHint: false };\n\n constructor(private createTeam: CreateTeam.Interface) {}\n\n async execute(input: Input): Promise<CreatedTeam> {\n /*\n * Roles go through untouched. `CreateTeam` accepts a role id or a slug and resolves either to\n * the id a team stores, so the tool has nothing to add: doing it here too would read the roles\n * a second time and leave two copies of the same rule to keep in step.\n */\n const result = await this.createTeam.execute({\n name: input.name,\n slug: input.slug,\n // An omitted description becomes \"\", the same mapping the use case applies to its own input.\n description: descriptionOnCreate(input.description),\n roles: input.roles\n });\n\n if (result.isFail()) {\n throw new Error(`Could not create the team: ${result.error.message}`);\n }\n\n const team = result.value;\n\n return {\n id: team.id,\n name: team.name,\n slug: team.slug,\n // From the created team, so the caller sees the resolved ids that were actually stored.\n roles: team.roles\n };\n }\n}\n\nexport const CreateTeamTool = AiSdkTool.createImplementation({\n implementation: CreateTeamToolImpl,\n dependencies: [CreateTeam]\n});\n"],"names":["inputSchema","z","CreateTeamToolImpl","createTeam","input","result","descriptionOnCreate","Error","team","CreateTeamTool","AiSdkTool","CreateTeam"],"mappings":";;;;AAMA,MAAMA,cAAcC,EAAE,MAAM,CAAC;IACzB,MAAMA,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,MAAMA,EAAAA,MACK,GACN,QAAQ,CAAC;IAKd,aAAaA,EAAAA,MACF,GACN,GAAG,CAAC,KACJ,QAAQ,GACR,QAAQ,CAAC;IACd,OAAOA,EAAAA,KACG,CAACA,EAAE,MAAM,IACd,QAAQ,CACL;AAEZ;AAiBA,MAAMC;IAQF,YAAoBC,UAAgC,CAAE;aAAlCA,UAAU,GAAVA;aAPX,IAAI,GAAG;aACP,KAAK,GAAG;aACR,WAAW,GAChB;aACK,WAAW,GAAGH;aACd,WAAW,GAAG;YAAE,cAAc;QAAM;IAEU;IAEvD,MAAM,QAAQI,KAAY,EAAwB;QAM9C,MAAMC,SAAS,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YACzC,MAAMD,MAAM,IAAI;YAChB,MAAMA,MAAM,IAAI;YAEhB,aAAaE,oBAAoBF,MAAM,WAAW;YAClD,OAAOA,MAAM,KAAK;QACtB;QAEA,IAAIC,OAAO,MAAM,IACb,MAAM,IAAIE,MAAM,CAAC,2BAA2B,EAAEF,OAAO,KAAK,CAAC,OAAO,EAAE;QAGxE,MAAMG,OAAOH,OAAO,KAAK;QAEzB,OAAO;YACH,IAAIG,KAAK,EAAE;YACX,MAAMA,KAAK,IAAI;YACf,MAAMA,KAAK,IAAI;YAEf,OAAOA,KAAK,KAAK;QACrB;IACJ;AACJ;AAEO,MAAMC,iBAAiBC,UAAU,oBAAoB,CAAC;IACzD,gBAAgBR;IAChB,cAAc;QAACS;KAAW;AAC9B"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { IAiSdkTool } from "@webiny/api-core/features/ai/index.js";
|
|
3
|
+
import { ListTeamsUseCase } from "@webiny/api-core/features/security/teams/ListTeams/index.js";
|
|
4
|
+
import { GetFolderUseCase } from "../../features/folder/GetFolder/index.js";
|
|
5
|
+
import { UpdateFolderUseCase } from "../../features/folder/UpdateFolder/index.js";
|
|
6
|
+
declare const inputSchema: z.ZodObject<{
|
|
7
|
+
folderId: z.ZodString;
|
|
8
|
+
target: z.ZodString;
|
|
9
|
+
level: z.ZodEnum<{
|
|
10
|
+
editor: "editor";
|
|
11
|
+
"no-access": "no-access";
|
|
12
|
+
owner: "owner";
|
|
13
|
+
public: "public";
|
|
14
|
+
viewer: "viewer";
|
|
15
|
+
}>;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
type Input = z.infer<typeof inputSchema>;
|
|
18
|
+
interface GrantResult {
|
|
19
|
+
folderId: string;
|
|
20
|
+
title: string;
|
|
21
|
+
path: string;
|
|
22
|
+
/**
|
|
23
|
+
* Every direct rule on the folder afterwards.
|
|
24
|
+
*
|
|
25
|
+
* This is the set the update was asked to store, not an independent read of it:
|
|
26
|
+
* `UpdateFolderWithFolderLevelPermissions` returns the permissions it derived from the input
|
|
27
|
+
* rather than the ones the repository wrote. Treating it as a verification would let the tool
|
|
28
|
+
* confirm its own request back to itself.
|
|
29
|
+
*/
|
|
30
|
+
permissions: {
|
|
31
|
+
target: string;
|
|
32
|
+
level: string;
|
|
33
|
+
}[];
|
|
34
|
+
/** True when the target already had a direct rule and its level was changed. */
|
|
35
|
+
replacedExistingLevel?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Grants one target access to one folder, leaving every other rule alone.
|
|
39
|
+
*
|
|
40
|
+
* Additive by design. The earlier tool took the complete permission set and replaced it, which meant
|
|
41
|
+
* approving a change showed what would be SET and said nothing about what would be removed — a rule
|
|
42
|
+
* the model omitted disappeared silently. One target per call keeps the approval honest: what the user
|
|
43
|
+
* sees in the plan is the whole change.
|
|
44
|
+
*/
|
|
45
|
+
declare class GrantFolderAccessToolImpl implements IAiSdkTool<Input> {
|
|
46
|
+
private getFolder;
|
|
47
|
+
private updateFolder;
|
|
48
|
+
private listTeams;
|
|
49
|
+
readonly name = "grantFolderAccess";
|
|
50
|
+
readonly title = "Grant folder access";
|
|
51
|
+
readonly description = "Grants one team or user a level of access on one folder, leaving all other permissions untouched. Use listFolders for the folder id and listTeams for a team slug. Requires user approval.";
|
|
52
|
+
readonly inputSchema: z.ZodObject<{
|
|
53
|
+
folderId: z.ZodString;
|
|
54
|
+
target: z.ZodString;
|
|
55
|
+
level: z.ZodEnum<{
|
|
56
|
+
editor: "editor";
|
|
57
|
+
"no-access": "no-access";
|
|
58
|
+
owner: "owner";
|
|
59
|
+
public: "public";
|
|
60
|
+
viewer: "viewer";
|
|
61
|
+
}>;
|
|
62
|
+
}, z.core.$strip>;
|
|
63
|
+
readonly annotations: {
|
|
64
|
+
readOnlyHint: boolean;
|
|
65
|
+
};
|
|
66
|
+
constructor(getFolder: GetFolderUseCase.Interface, updateFolder: UpdateFolderUseCase.Interface, listTeams: ListTeamsUseCase.Interface);
|
|
67
|
+
execute(input: Input): Promise<GrantResult>;
|
|
68
|
+
}
|
|
69
|
+
export declare const GrantFolderAccessTool: typeof GrantFolderAccessToolImpl & {
|
|
70
|
+
__abstraction: import("@webiny/di").Abstraction<IAiSdkTool<any>>;
|
|
71
|
+
};
|
|
72
|
+
export {};
|