diff --git a/__tests__/directory/v3/index.test.ts b/__tests__/directory/v3/index.test.ts index 1b282d6..fdf74cf 100644 --- a/__tests__/directory/v3/index.test.ts +++ b/__tests__/directory/v3/index.test.ts @@ -1179,6 +1179,7 @@ describe("DirectoryV3", () => { const result = await directory.getManifest(); expect(result).toEqual({ body: "test", + model: {}, etag: "", updatedAt: undefined, }); diff --git a/__tests__/integration/index.test.ts b/__tests__/integration/index.test.ts index 8156287..c3d3e04 100644 --- a/__tests__/integration/index.test.ts +++ b/__tests__/integration/index.test.ts @@ -12,8 +12,10 @@ import { DirectoryServiceV3, DirectoryV3, displayStateMap, + HEADER_ASERTO_MANIFEST_REQUEST, ImportMsgCase, ImportOpCode, + MANIFEST_REQUEST_DEFAULT, NotFoundError, policyContext, policyInstance, @@ -71,6 +73,7 @@ describe("Integration", () => { expect(res.status).toBe(200); expect(res.body).toEqual({ check: true, + context: {}, trace: [], }); }); @@ -601,11 +604,39 @@ describe("Integration", () => { expect(res.status).toBe(200); expect(res.body).toEqual([ - {}, - {}, { - object: { recv: "2", set: "2", delete: "0", error: "0" }, - relation: { recv: "1", set: "1", delete: "0", error: "0" }, + counter: { + delete: "0", + error: "0", + recv: "2", + set: "2", + type: "object", + }, + }, + { + counter: { + delete: "0", + error: "0", + recv: "1", + set: "1", + type: "relation", + }, + }, + { + object: { + recv: "2", + set: "2", + delete: "0", + error: "0", + type: "object", + }, + relation: { + recv: "1", + set: "1", + delete: "0", + error: "0", + type: "relation", + }, }, ]); }); @@ -948,7 +979,14 @@ describe("Integration", () => { it("get manifest serializes to json", async () => { const GetManifest = async (_req: Request, res: Response) => { try { - const manifest = await directoryClient.getManifest(); + const manifest = await directoryClient.getManifest( + {}, + { + headers: { + [HEADER_ASERTO_MANIFEST_REQUEST]: MANIFEST_REQUEST_DEFAULT, + }, + }, + ); res.status(200).send(manifest); } catch (error) { console.error(error); @@ -971,6 +1009,7 @@ model: # object type definitions types: + ### display_name: User ### # user represents a user that can be granted role(s) user: relations: @@ -980,19 +1019,19 @@ types: ### display_name: user#in_management_chain ### in_management_chain: manager | manager->in_management_chain - + ### display_name: Group ### # group represents a collection of users and/or (nested) groups group: relations: member: user | group#member - + ### display_name: Identity ### # identity represents a collection of identities for users identity: relations: identifier: user - + ### display_name: Resource Creator ### # resource creator represents a user type that can create new resources resource-creator: relations: @@ -1017,6 +1056,7 @@ types: expect(res.body).toEqual({ body: expectedBody, + model: {}, updatedAt: expect.any(String), etag: expect.any(String), }); diff --git a/lib/directory/v3/index.ts b/lib/directory/v3/index.ts index 2ee6839..8020314 100644 --- a/lib/directory/v3/index.ts +++ b/lib/directory/v3/index.ts @@ -9,17 +9,18 @@ import { ImportRequestSchema, } from "@aserto/node-directory/src/gen/cjs/aserto/directory/importer/v3/importer_pb"; import { + MetadataSchema, Model, SetManifestRequestSchema, } from "@aserto/node-directory/src/gen/cjs/aserto/directory/model/v3/model_pb"; import { Body, DeleteManifestRequest, - GetManifestRequest, Metadata, } from "@aserto/node-directory/src/gen/cjs/aserto/directory/model/v3/model_pb"; import { CheckRequestSchema, + ChecksRequestSchema, GetGraphRequestSchema, GetObjectManyRequestSchema, GetObjectRequestSchema, @@ -63,6 +64,8 @@ import { DsRegistry } from "./serializer"; import { CheckRequest, CheckResponse, + ChecksRequest, + ChecksResponse, DeleteManifestResponse, DeleteObjectRequest, DeleteObjectResponse, @@ -73,6 +76,7 @@ import { ExportResponse, GetGraphRequest, GetGraphResponse, + GetManifestRequest, GetManifestResponse, GetObjectManyRequest, GetObjectManyResponse, @@ -129,6 +133,18 @@ export enum ImportMsgCase { const ADDRESS_REGEX = /https?:\/\//; +export const HEADER_ASERTO_MANIFEST_REQUEST = + "Aserto-Manifest-Request" as const; + +// Return the manifest metadata and body. +export const MANIFEST_REQUEST_DEFAULT = "" as const; +// Only return the manifest metadata. +export const MANIFEST_REQUEST_METADATA_ONLY = "metadata-only" as const; +// Only return the manifest metadata and model. +export const MANIFEST_REQUEST_MODEL_ONLY = "model-only" as const; +// Return the manifest metadata, body, and model. +export const MANIFEST_REQUEST_WITH_MODEL = "with-model" as const; + export class DirectoryV3 { ReaderClient: Client; WriterClient: Client; @@ -313,6 +329,22 @@ export class DirectoryV3 { } } + async checks( + params: ChecksRequest, + options?: CallOptions, + ): Promise { + try { + const response = await this.ReaderClient.checks( + create(ChecksRequestSchema, params), + options, + ); + + return this.registry.serializeResponse(response); + } catch (error) { + throw handleError(error, "checks"); + } + } + async object( params: GetObjectRequest, options?: CallOptions, @@ -526,28 +558,51 @@ export class DirectoryV3 { }; }); - const bodyData = data + return this.buildManifestResponse(data); + } catch (error) { + throw handleError(error, "getManifest"); + } + } + + private buildManifestResponse( + data: { [x: string]: JsonObject | Metadata | Body | undefined }[], + ) { + let bodyData: Uint8Array[] = [new Uint8Array()]; + let modelData: JsonObject = {}; + let metadata: Metadata = create(MetadataSchema, {}); + let body: string = ""; + + metadata = data[0]?.metadata as Metadata; + + bodyData = data + .map((el) => { + return el["body"]; + }) + .filter((el) => el !== undefined) + .map((el) => { + return (el as Body)?.data; + }); + + body = new TextDecoder().decode(mergeUint8Arrays(...bodyData)); + + modelData = + data .map((el) => { - return el["body"]; + return el["model"]; }) .filter((el) => el !== undefined) .map((el) => { - return (el as Body)?.data; - }); - - const body = new TextDecoder().decode(mergeUint8Arrays(...bodyData)); - const metadata = data[0]?.metadata as Metadata; - - return { - body, - updatedAt: metadata?.updatedAt - ? this.registry.serializeResponse(metadata?.updatedAt) - : undefined, - etag: metadata?.etag, - }; - } catch (error) { - throw handleError(error, "getManifest"); - } + return el as JsonObject; + })?.[0] || {}; + + return { + body, + model: modelData, + updatedAt: metadata?.updatedAt + ? this.registry.serializeResponse(metadata?.updatedAt) + : undefined, + etag: metadata?.etag, + }; } async setManifest( diff --git a/lib/directory/v3/types.ts b/lib/directory/v3/types.ts index db35bbf..a047207 100644 --- a/lib/directory/v3/types.ts +++ b/lib/directory/v3/types.ts @@ -17,9 +17,12 @@ import { DeleteManifestResponse as DeleteManifestResponse$, SetManifestResponse as SetManifestResponse$, } from "@aserto/node-directory/src/gen/cjs/aserto/directory/model/v3/model_pb"; +import { GetManifestRequest as GetManifestRequest$ } from "@aserto/node-directory/src/gen/cjs/aserto/directory/model/v3/model_pb"; import { CheckRequest as CheckRequest$, CheckResponse as CheckResponse$, + ChecksRequest as ChecksRequest$, + ChecksResponse as ChecksResponse$, GetGraphRequest as GetGraphRequest$, GetGraphResponse as GetGraphResponse$, GetObjectManyRequest as GetObjectManyRequest$, @@ -49,6 +52,7 @@ import { DescFile, DescMessage, DescService, + JsonObject, Registry, } from "@bufbuild/protobuf"; import { Timestamp } from "@bufbuild/protobuf/wkt"; @@ -170,6 +174,13 @@ export type DeleteRelationRequest = Optional< >; export type CheckRequest = Optional, "trace">; +export type ChecksRequest = Omit< + ChecksRequest$, + "$typeName" | "default" | "checks" +> & { + default?: CheckRequest; + checks: CheckRequest[]; +}; export type GetGraphRequest = Optional< Omit, @@ -205,8 +216,14 @@ export type ImportRequest = Omit< "$typeName" >; +export type GetManifestRequest = Omit< + GetManifestRequest$, + "$typeName" | "$unknown" +>; + export type GetManifestResponse = { body: string; + model: JsonObject; updatedAt: Timestamp | undefined; etag: string; }; @@ -217,6 +234,13 @@ export type PaginationResponse = Omit< >; export type CheckResponse = Omit; +export type ChecksResponse = Omit< + ChecksResponse$, + "$typeName" | "$unknown" | "checks" +> & { + checks: CheckResponse[]; +}; + export type GetGraphResponse = Omit< GetGraphResponse$, "$typeName" | "$unknown" diff --git a/lib/index.ts b/lib/index.ts index 22eeac7..b81d19b 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -17,7 +17,12 @@ import { createImportRequest, DirectoryServiceV3, DirectoryV3, + HEADER_ASERTO_MANIFEST_REQUEST, ImportMsgCase, + MANIFEST_REQUEST_DEFAULT, + MANIFEST_REQUEST_METADATA_ONLY, + MANIFEST_REQUEST_MODEL_ONLY, + MANIFEST_REQUEST_WITH_MODEL, objectPropertiesAsStruct, readAsyncIterable, serializeAsyncIterable, @@ -39,11 +44,16 @@ export { DirectoryV3, DirectoryV3Config, displayStateMap, + HEADER_ASERTO_MANIFEST_REQUEST, identityContext, ImportMsgCase, is, jwtAuthz, JWTIdentityMapper, + MANIFEST_REQUEST_DEFAULT, + MANIFEST_REQUEST_METADATA_ONLY, + MANIFEST_REQUEST_MODEL_ONLY, + MANIFEST_REQUEST_WITH_MODEL, ManualIdentityMapper, Middleware, ObjectIDFromVar, diff --git a/package.json b/package.json index f7e3185..1a9e979 100644 --- a/package.json +++ b/package.json @@ -45,10 +45,10 @@ "homepage": "https://github.com/aserto-dev/aserto-node#readme", "dependencies": { "@aserto/node-authorizer": "^0.21.0", - "@aserto/node-directory": "^0.32.0", + "@aserto/node-directory": "^0.33.0", "@bufbuild/protobuf": "^2.2.3", - "@connectrpc/connect": "^2.0.0", - "@connectrpc/connect-node": "^2.0.0", + "@connectrpc/connect": "^2.0.1", + "@connectrpc/connect-node": "^2.0.1", "express": "^4.21.2", "jwt-decode": "^4.0.0" }, diff --git a/yarn.lock b/yarn.lock index 114f649..c0ab45e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20,11 +20,11 @@ __metadata: resolution: "@aserto/aserto-node@workspace:." dependencies: "@aserto/node-authorizer": "npm:^0.21.0" - "@aserto/node-directory": "npm:^0.32.0" + "@aserto/node-directory": "npm:^0.33.0" "@babel/core": "npm:^7.25.2" "@bufbuild/protobuf": "npm:^2.2.3" - "@connectrpc/connect": "npm:^2.0.0" - "@connectrpc/connect-node": "npm:^2.0.0" + "@connectrpc/connect": "npm:^2.0.1" + "@connectrpc/connect-node": "npm:^2.0.1" "@eslint/compat": "npm:^1.2.2" "@eslint/eslintrc": "npm:^3.1.0" "@eslint/js": "npm:^9.13.0" @@ -63,12 +63,12 @@ __metadata: languageName: node linkType: hard -"@aserto/node-directory@npm:^0.32.0": - version: 0.32.0 - resolution: "@aserto/node-directory@npm:0.32.0" +"@aserto/node-directory@npm:^0.33.0": + version: 0.33.0 + resolution: "@aserto/node-directory@npm:0.33.0" dependencies: - "@bufbuild/protobuf": "npm:^2.2.2" - checksum: 10/06f797b049d01fab3e826b63a908d99a970b738d2f1e4a9531cf6167744ca4482439f35c413686e2985bfd789a2979048b9299bee08f60cf2462613e2a0fbcf2 + "@bufbuild/protobuf": "npm:^2.2.3" + checksum: 10/992e68f2857bca25b0a64b23ec23e2fa5d9ae93bbb26078a40e9ea71aad89154c427e89024d1ce1e7817f7ca1588b661f2a53ba499a89a579d8cf7e055f5eaff languageName: node linkType: hard @@ -448,22 +448,22 @@ __metadata: languageName: node linkType: hard -"@connectrpc/connect-node@npm:^2.0.0": - version: 2.0.0 - resolution: "@connectrpc/connect-node@npm:2.0.0" +"@connectrpc/connect-node@npm:^2.0.1": + version: 2.0.1 + resolution: "@connectrpc/connect-node@npm:2.0.1" peerDependencies: "@bufbuild/protobuf": ^2.2.0 - "@connectrpc/connect": 2.0.0 - checksum: 10/439aa16bd016ed96577bb547d02d6abc4e2fa8e290f46fffbea6e000b932845fe9071d5c334b1398df8081d9373faca9f17ecb9f69292a4636496ab842e2c3b5 + "@connectrpc/connect": 2.0.1 + checksum: 10/7149540fb378e38dab9917133cb8282a5b2c90ef2b75bbfb2e2b67716a186e2b61b5ca429a57f96fbfba14b35b560d5ce3d0d911dd05be1ec5efe94c943f12d0 languageName: node linkType: hard -"@connectrpc/connect@npm:^2.0.0": - version: 2.0.0 - resolution: "@connectrpc/connect@npm:2.0.0" +"@connectrpc/connect@npm:^2.0.1": + version: 2.0.1 + resolution: "@connectrpc/connect@npm:2.0.1" peerDependencies: "@bufbuild/protobuf": ^2.2.0 - checksum: 10/85c675cf76a1463f638c8fca696484d3d9a044f4e15b6800d1370ebdc0ff183a4960d11af93ea6bc84546fe3d122feee3a928d1a638617c0e327cfb30b7d63df + checksum: 10/6e1093e6d890af10c8497acfed3ad27e60dacc7f41511ff5824bac6f2b00bd4a6ede07d261ce8097bff314a1e0aebd27e1e01eb2fb83cfbdaafd273c8ae75ae3 languageName: node linkType: hard