@powerhousedao/vetra 6.0.0-dev.5 → 6.0.0-dev.52
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/dist/document-models/app-module/actions.d.ts +1 -1
- package/dist/document-models/app-module/actions.d.ts.map +1 -1
- package/dist/document-models/app-module/hooks.d.ts.map +1 -1
- package/dist/document-models/app-module/module.d.ts.map +1 -1
- package/dist/document-models/app-module/module.js +1 -0
- package/dist/document-models/app-module/src/tests/base-operations.test.js +2 -2
- package/dist/document-models/app-module/src/tests/dnd-operations.test.js +1 -1
- package/dist/document-models/document-editor/actions.d.ts +1 -1
- package/dist/document-models/document-editor/actions.d.ts.map +1 -1
- package/dist/document-models/document-editor/hooks.d.ts.map +1 -1
- package/dist/document-models/document-editor/module.d.ts.map +1 -1
- package/dist/document-models/document-editor/module.js +1 -0
- package/dist/document-models/document-editor/src/tests/base-operations.test.js +2 -2
- package/dist/document-models/processor-module/actions.d.ts +3 -1
- package/dist/document-models/processor-module/actions.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/base-operations/actions.d.ts +10 -2
- package/dist/document-models/processor-module/gen/base-operations/actions.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/base-operations/creators.d.ts +4 -2
- package/dist/document-models/processor-module/gen/base-operations/creators.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/base-operations/creators.js +3 -1
- package/dist/document-models/processor-module/gen/base-operations/operations.d.ts +3 -1
- package/dist/document-models/processor-module/gen/base-operations/operations.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/document-model.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/document-model.js +24 -2
- package/dist/document-models/processor-module/gen/document-schema.d.ts +3 -0
- package/dist/document-models/processor-module/gen/document-schema.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/ph-factories.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/ph-factories.js +1 -0
- package/dist/document-models/processor-module/gen/reducer.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/reducer.js +11 -1
- package/dist/document-models/processor-module/gen/schema/types.d.ts +7 -0
- package/dist/document-models/processor-module/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/schema/zod.d.ts +3 -1
- package/dist/document-models/processor-module/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/schema/zod.js +11 -0
- package/dist/document-models/processor-module/gen/utils.d.ts.map +1 -1
- package/dist/document-models/processor-module/gen/utils.js +1 -0
- package/dist/document-models/processor-module/hooks.d.ts.map +1 -1
- package/dist/document-models/processor-module/module.d.ts.map +1 -1
- package/dist/document-models/processor-module/module.js +1 -0
- package/dist/document-models/processor-module/src/reducers/base-operations.d.ts.map +1 -1
- package/dist/document-models/processor-module/src/reducers/base-operations.js +14 -0
- package/dist/document-models/processor-module/src/tests/base-operations.test.js +26 -2
- package/dist/document-models/subgraph-module/actions.d.ts +1 -1
- package/dist/document-models/subgraph-module/actions.d.ts.map +1 -1
- package/dist/document-models/subgraph-module/hooks.d.ts.map +1 -1
- package/dist/document-models/subgraph-module/module.d.ts.map +1 -1
- package/dist/document-models/subgraph-module/module.js +1 -0
- package/dist/document-models/subgraph-module/src/tests/base-operations.test.js +2 -2
- package/dist/document-models/vetra-package/actions.d.ts +1 -1
- package/dist/document-models/vetra-package/actions.d.ts.map +1 -1
- package/dist/document-models/vetra-package/gen/schema/zod.js +7 -7
- package/dist/document-models/vetra-package/hooks.d.ts.map +1 -1
- package/dist/document-models/vetra-package/module.d.ts.map +1 -1
- package/dist/document-models/vetra-package/module.js +1 -0
- package/dist/document-models/vetra-package/src/tests/base-operations.test.js +1 -1
- package/dist/editors/app-editor/components/AppEditorForm.js +1 -1
- package/dist/editors/app-editor/editor.js +1 -1
- package/dist/editors/app-editor/editor.test.js +8 -1
- package/dist/editors/document-editor/components/DocumentEditorForm.js +1 -1
- package/dist/editors/document-editor/editor.js +1 -1
- package/dist/editors/processor-editor/components/ProcessorEditorForm.d.ts +4 -0
- package/dist/editors/processor-editor/components/ProcessorEditorForm.d.ts.map +1 -1
- package/dist/editors/processor-editor/components/ProcessorEditorForm.js +32 -6
- package/dist/editors/processor-editor/editor.d.ts.map +1 -1
- package/dist/editors/processor-editor/editor.js +7 -1
- package/dist/editors/processor-editor/editor.test.js +166 -173
- package/dist/editors/subgraph-editor/components/SubgraphEditorForm.js +1 -1
- package/dist/editors/subgraph-editor/editor.js +1 -1
- package/dist/editors/vetra-drive-app/DriveExplorer.js +1 -1
- package/dist/editors/vetra-drive-app/components/DriveHeader.js +1 -1
- package/dist/editors/vetra-drive-app/editor.js +1 -1
- package/dist/editors/vetra-package/components/MetaForm.js +1 -1
- package/dist/editors/vetra-package/editor.js +1 -1
- package/dist/processors/codegen/__tests__/codegen-processor-e2e.test.js +46 -22
- package/dist/processors/codegen/document-handlers/generators/app-generator.d.ts.map +1 -1
- package/dist/processors/codegen/document-handlers/generators/app-generator.js +12 -6
- package/dist/processors/codegen/document-handlers/generators/constants.d.ts +1 -0
- package/dist/processors/codegen/document-handlers/generators/constants.d.ts.map +1 -1
- package/dist/processors/codegen/document-handlers/generators/constants.js +2 -0
- package/dist/processors/codegen/document-handlers/generators/document-editor-generator.d.ts.map +1 -1
- package/dist/processors/codegen/document-handlers/generators/document-editor-generator.js +10 -4
- package/dist/processors/codegen/document-handlers/generators/document-model-generator.d.ts +4 -0
- package/dist/processors/codegen/document-handlers/generators/document-model-generator.d.ts.map +1 -1
- package/dist/processors/codegen/document-handlers/generators/document-model-generator.js +42 -20
- package/dist/processors/codegen/document-handlers/generators/package-generator.d.ts.map +1 -1
- package/dist/processors/codegen/document-handlers/generators/package-generator.js +8 -2
- package/dist/processors/codegen/document-handlers/generators/processor-generator.d.ts.map +1 -1
- package/dist/processors/codegen/document-handlers/generators/processor-generator.js +38 -3
- package/dist/processors/codegen/document-handlers/generators/subgraph-generator.d.ts.map +1 -1
- package/dist/processors/codegen/document-handlers/generators/subgraph-generator.js +8 -2
- package/dist/processors/codegen/document-handlers/generators/utils.d.ts +7 -0
- package/dist/processors/codegen/document-handlers/generators/utils.d.ts.map +1 -1
- package/dist/processors/codegen/document-handlers/generators/utils.js +18 -1
- package/dist/processors/codegen/factory.d.ts +1 -1
- package/dist/processors/codegen/factory.d.ts.map +1 -1
- package/dist/processors/codegen/factory.legacy.d.ts +4 -0
- package/dist/processors/codegen/factory.legacy.d.ts.map +1 -0
- package/dist/processors/codegen/factory.legacy.js +53 -0
- package/dist/processors/codegen/index.d.ts +2 -2
- package/dist/processors/codegen/index.d.ts.map +1 -1
- package/dist/processors/codegen/index.js +22 -21
- package/dist/processors/codegen/index.legacy.d.ts +11 -0
- package/dist/processors/codegen/index.legacy.d.ts.map +1 -0
- package/dist/processors/codegen/index.legacy.js +57 -0
- package/dist/processors/factory.d.ts +3 -4
- package/dist/processors/factory.d.ts.map +1 -1
- package/dist/processors/factory.js +5 -4
- package/dist/processors/factory.legacy.d.ts +7 -0
- package/dist/processors/factory.legacy.d.ts.map +1 -0
- package/dist/processors/factory.legacy.js +19 -0
- package/dist/processors/index.d.ts +8 -2
- package/dist/processors/index.d.ts.map +1 -1
- package/dist/processors/index.js +10 -2
- package/dist/processors/vetra-read-model/factory.d.ts +2 -2
- package/dist/processors/vetra-read-model/factory.d.ts.map +1 -1
- package/dist/processors/vetra-read-model/factory.js +13 -16
- package/dist/processors/vetra-read-model/factory.legacy.d.ts +5 -0
- package/dist/processors/vetra-read-model/factory.legacy.d.ts.map +1 -0
- package/dist/processors/vetra-read-model/factory.legacy.js +24 -0
- package/dist/processors/vetra-read-model/index.d.ts +6 -5
- package/dist/processors/vetra-read-model/index.d.ts.map +1 -1
- package/dist/processors/vetra-read-model/index.js +20 -37
- package/dist/processors/vetra-read-model/index.legacy.d.ts +9 -0
- package/dist/processors/vetra-read-model/index.legacy.d.ts.map +1 -0
- package/dist/processors/vetra-read-model/index.legacy.js +75 -0
- package/dist/processors/vetra-read-model/migrations.d.ts +3 -3
- package/dist/processors/vetra-read-model/migrations.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/dist/subgraphs/__tests__/permission-utils.test.d.ts +2 -0
- package/dist/subgraphs/__tests__/permission-utils.test.d.ts.map +1 -0
- package/dist/subgraphs/__tests__/permission-utils.test.js +505 -0
- package/dist/subgraphs/__tests__/vetra-read-model-permissions.test.d.ts +2 -0
- package/dist/subgraphs/__tests__/vetra-read-model-permissions.test.d.ts.map +1 -0
- package/dist/subgraphs/__tests__/vetra-read-model-permissions.test.js +319 -0
- package/dist/subgraphs/index.d.ts +0 -5
- package/dist/subgraphs/index.d.ts.map +1 -1
- package/dist/subgraphs/index.js +0 -5
- package/dist/subgraphs/permission-utils.d.ts +31 -0
- package/dist/subgraphs/permission-utils.d.ts.map +1 -0
- package/dist/subgraphs/permission-utils.js +101 -0
- package/dist/subgraphs/vetra-read-model/resolvers.d.ts +2 -2
- package/dist/subgraphs/vetra-read-model/resolvers.d.ts.map +1 -1
- package/dist/subgraphs/vetra-read-model/resolvers.js +18 -5
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/vitest.config.d.ts.map +1 -1
- package/dist/vitest.config.js +1 -0
- package/package.json +33 -35
- package/dist/subgraphs/app-module/index.d.ts +0 -11
- package/dist/subgraphs/app-module/index.d.ts.map +0 -1
- package/dist/subgraphs/app-module/index.js +0 -11
- package/dist/subgraphs/app-module/resolvers.d.ts +0 -3
- package/dist/subgraphs/app-module/resolvers.d.ts.map +0 -1
- package/dist/subgraphs/app-module/resolvers.js +0 -144
- package/dist/subgraphs/app-module/schema.d.ts +0 -3
- package/dist/subgraphs/app-module/schema.d.ts.map +0 -1
- package/dist/subgraphs/app-module/schema.js +0 -78
- package/dist/subgraphs/document-editor/index.d.ts +0 -11
- package/dist/subgraphs/document-editor/index.d.ts.map +0 -1
- package/dist/subgraphs/document-editor/index.js +0 -11
- package/dist/subgraphs/document-editor/resolvers.d.ts +0 -3
- package/dist/subgraphs/document-editor/resolvers.d.ts.map +0 -1
- package/dist/subgraphs/document-editor/resolvers.js +0 -120
- package/dist/subgraphs/document-editor/schema.d.ts +0 -3
- package/dist/subgraphs/document-editor/schema.d.ts.map +0 -1
- package/dist/subgraphs/document-editor/schema.js +0 -59
- package/dist/subgraphs/processor-module/index.d.ts +0 -10
- package/dist/subgraphs/processor-module/index.d.ts.map +0 -1
- package/dist/subgraphs/processor-module/index.js +0 -11
- package/dist/subgraphs/processor-module/resolvers.d.ts +0 -3
- package/dist/subgraphs/processor-module/resolvers.d.ts.map +0 -1
- package/dist/subgraphs/processor-module/resolvers.js +0 -132
- package/dist/subgraphs/processor-module/schema.d.ts +0 -3
- package/dist/subgraphs/processor-module/schema.d.ts.map +0 -1
- package/dist/subgraphs/processor-module/schema.js +0 -67
- package/dist/subgraphs/subgraph-module/index.d.ts +0 -10
- package/dist/subgraphs/subgraph-module/index.d.ts.map +0 -1
- package/dist/subgraphs/subgraph-module/index.js +0 -11
- package/dist/subgraphs/subgraph-module/resolvers.d.ts +0 -3
- package/dist/subgraphs/subgraph-module/resolvers.d.ts.map +0 -1
- package/dist/subgraphs/subgraph-module/resolvers.js +0 -96
- package/dist/subgraphs/subgraph-module/schema.d.ts +0 -3
- package/dist/subgraphs/subgraph-module/schema.d.ts.map +0 -1
- package/dist/subgraphs/subgraph-module/schema.js +0 -42
- package/dist/subgraphs/vetra-package/index.d.ts +0 -10
- package/dist/subgraphs/vetra-package/index.d.ts.map +0 -1
- package/dist/subgraphs/vetra-package/index.js +0 -11
- package/dist/subgraphs/vetra-package/resolvers.d.ts +0 -3
- package/dist/subgraphs/vetra-package/resolvers.d.ts.map +0 -1
- package/dist/subgraphs/vetra-package/resolvers.js +0 -192
- package/dist/subgraphs/vetra-package/schema.d.ts +0 -3
- package/dist/subgraphs/vetra-package/schema.d.ts.map +0 -1
- package/dist/subgraphs/vetra-package/schema.js +0 -108
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { getResolvers } from "../vetra-read-model/resolvers.js";
|
|
3
|
+
// Mock the VetraReadModelProcessorLegacy
|
|
4
|
+
vi.mock("../../processors/vetra-read-model/index.legacy.js", () => ({
|
|
5
|
+
VetraReadModelProcessorLegacy: {
|
|
6
|
+
query: vi.fn(() => ({
|
|
7
|
+
selectFrom: vi.fn(() => ({
|
|
8
|
+
selectAll: vi.fn(() => ({
|
|
9
|
+
where: vi.fn().mockReturnThis(),
|
|
10
|
+
orderBy: vi.fn(() => ({
|
|
11
|
+
execute: vi.fn().mockResolvedValue([]),
|
|
12
|
+
})),
|
|
13
|
+
execute: vi.fn().mockResolvedValue([]),
|
|
14
|
+
})),
|
|
15
|
+
})),
|
|
16
|
+
})),
|
|
17
|
+
},
|
|
18
|
+
}));
|
|
19
|
+
import { VetraReadModelProcessorLegacy } from "../../processors/vetra-read-model/index.legacy.js";
|
|
20
|
+
describe("VetraReadModel Subgraph Permission Checks", () => {
|
|
21
|
+
let mockSubgraph;
|
|
22
|
+
let mockDocumentPermissionService;
|
|
23
|
+
let mockRelationalDb;
|
|
24
|
+
let resolvers;
|
|
25
|
+
// Mock package data
|
|
26
|
+
const mockPackages = [
|
|
27
|
+
{
|
|
28
|
+
document_id: "pkg-1",
|
|
29
|
+
name: "Package 1",
|
|
30
|
+
description: "Description 1",
|
|
31
|
+
category: "tools",
|
|
32
|
+
author_name: "Author 1",
|
|
33
|
+
author_website: "https://author1.com",
|
|
34
|
+
github_url: "https://github.com/pkg1",
|
|
35
|
+
npm_url: "https://npm.com/pkg1",
|
|
36
|
+
keywords: ["keyword1"],
|
|
37
|
+
drive_id: "drive-1",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
document_id: "pkg-2",
|
|
41
|
+
name: "Package 2",
|
|
42
|
+
description: "Description 2",
|
|
43
|
+
category: "utilities",
|
|
44
|
+
author_name: "Author 2",
|
|
45
|
+
author_website: "https://author2.com",
|
|
46
|
+
github_url: "https://github.com/pkg2",
|
|
47
|
+
npm_url: "https://npm.com/pkg2",
|
|
48
|
+
keywords: ["keyword2"],
|
|
49
|
+
drive_id: "drive-1",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
document_id: "pkg-3",
|
|
53
|
+
name: "Package 3",
|
|
54
|
+
description: "Description 3",
|
|
55
|
+
category: "tools",
|
|
56
|
+
author_name: "Author 3",
|
|
57
|
+
author_website: null,
|
|
58
|
+
github_url: null,
|
|
59
|
+
npm_url: null,
|
|
60
|
+
keywords: [],
|
|
61
|
+
drive_id: "drive-2",
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
// Helper to create context with different permission levels
|
|
65
|
+
const createContext = (options) => ({
|
|
66
|
+
user: options.userAddress ? { address: options.userAddress } : undefined,
|
|
67
|
+
isAdmin: vi.fn().mockReturnValue(options.isAdmin ?? false),
|
|
68
|
+
isUser: vi.fn().mockReturnValue(options.isUser ?? false),
|
|
69
|
+
isGuest: vi.fn().mockReturnValue(options.isGuest ?? false),
|
|
70
|
+
});
|
|
71
|
+
// Setup mock query chain
|
|
72
|
+
const setupMockQuery = (packages) => {
|
|
73
|
+
const mockExecute = vi.fn().mockResolvedValue(packages);
|
|
74
|
+
const mockOrderBy = vi.fn().mockReturnValue({ execute: mockExecute });
|
|
75
|
+
const mockWhere = vi.fn().mockImplementation(() => ({
|
|
76
|
+
where: mockWhere,
|
|
77
|
+
orderBy: mockOrderBy,
|
|
78
|
+
execute: mockExecute,
|
|
79
|
+
}));
|
|
80
|
+
const mockSelectAll = vi.fn().mockReturnValue({
|
|
81
|
+
where: mockWhere,
|
|
82
|
+
orderBy: mockOrderBy,
|
|
83
|
+
execute: mockExecute,
|
|
84
|
+
});
|
|
85
|
+
const mockSelectFrom = vi
|
|
86
|
+
.fn()
|
|
87
|
+
.mockReturnValue({ selectAll: mockSelectAll });
|
|
88
|
+
vi.mocked(VetraReadModelProcessorLegacy.query).mockReturnValue({
|
|
89
|
+
selectFrom: mockSelectFrom,
|
|
90
|
+
});
|
|
91
|
+
return { mockExecute, mockOrderBy, mockWhere };
|
|
92
|
+
};
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
vi.clearAllMocks();
|
|
95
|
+
delete process.env.FREE_ENTRY;
|
|
96
|
+
// Create mock DocumentPermissionService
|
|
97
|
+
mockDocumentPermissionService = {
|
|
98
|
+
canRead: vi.fn().mockResolvedValue(false),
|
|
99
|
+
canWrite: vi.fn().mockResolvedValue(false),
|
|
100
|
+
canReadDocument: vi.fn().mockResolvedValue(false),
|
|
101
|
+
canWriteDocument: vi.fn().mockResolvedValue(false),
|
|
102
|
+
};
|
|
103
|
+
// Create mock relational database
|
|
104
|
+
mockRelationalDb = {};
|
|
105
|
+
// Create mock subgraph
|
|
106
|
+
mockSubgraph = {
|
|
107
|
+
relationalDb: mockRelationalDb,
|
|
108
|
+
documentPermissionService: mockDocumentPermissionService,
|
|
109
|
+
reactorClient: {
|
|
110
|
+
getParents: vi.fn().mockResolvedValue({
|
|
111
|
+
results: [],
|
|
112
|
+
options: { limit: 10 },
|
|
113
|
+
}),
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
// Get resolvers
|
|
117
|
+
resolvers = getResolvers(mockSubgraph);
|
|
118
|
+
});
|
|
119
|
+
afterEach(() => {
|
|
120
|
+
delete process.env.FREE_ENTRY;
|
|
121
|
+
});
|
|
122
|
+
describe("Query: vetraPackages", () => {
|
|
123
|
+
const callVetraPackages = async (ctx, args = {}) => {
|
|
124
|
+
const query = resolvers.Query?.vetraPackages;
|
|
125
|
+
return query(null, args, ctx);
|
|
126
|
+
};
|
|
127
|
+
describe("Global Role Access", () => {
|
|
128
|
+
it("should return all packages when user is global admin", async () => {
|
|
129
|
+
setupMockQuery(mockPackages);
|
|
130
|
+
const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
|
|
131
|
+
const result = await callVetraPackages(ctx);
|
|
132
|
+
expect(result).toHaveLength(3);
|
|
133
|
+
expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
it("should return all packages when user is global user", async () => {
|
|
136
|
+
setupMockQuery(mockPackages);
|
|
137
|
+
const ctx = createContext({ isUser: true, userAddress: "0xuser" });
|
|
138
|
+
const result = await callVetraPackages(ctx);
|
|
139
|
+
expect(result).toHaveLength(3);
|
|
140
|
+
expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
|
|
141
|
+
});
|
|
142
|
+
it("should return all packages when user is global guest", async () => {
|
|
143
|
+
setupMockQuery(mockPackages);
|
|
144
|
+
const ctx = createContext({ isGuest: true, userAddress: "0xguest" });
|
|
145
|
+
const result = await callVetraPackages(ctx);
|
|
146
|
+
expect(result).toHaveLength(3);
|
|
147
|
+
expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
|
|
148
|
+
});
|
|
149
|
+
it("should return all packages when FREE_ENTRY is true", async () => {
|
|
150
|
+
process.env.FREE_ENTRY = "true";
|
|
151
|
+
setupMockQuery(mockPackages);
|
|
152
|
+
const ctx = createContext({ userAddress: "0xanyone" });
|
|
153
|
+
const result = await callVetraPackages(ctx);
|
|
154
|
+
expect(result).toHaveLength(3);
|
|
155
|
+
expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe("Document Permission Filtering", () => {
|
|
159
|
+
it("should filter packages based on permissions when no global access", async () => {
|
|
160
|
+
setupMockQuery(mockPackages);
|
|
161
|
+
// User can read pkg-1 and pkg-3, but not pkg-2
|
|
162
|
+
vi.mocked(mockDocumentPermissionService.canRead).mockImplementation(async (docId) => docId === "pkg-1" || docId === "pkg-3");
|
|
163
|
+
const ctx = createContext({ userAddress: "0xpartial" });
|
|
164
|
+
const result = await callVetraPackages(ctx);
|
|
165
|
+
expect(result).toHaveLength(2);
|
|
166
|
+
expect(result.map((p) => p.documentId).sort()).toEqual([
|
|
167
|
+
"pkg-1",
|
|
168
|
+
"pkg-3",
|
|
169
|
+
]);
|
|
170
|
+
});
|
|
171
|
+
it("should return empty array when user has no document permissions", async () => {
|
|
172
|
+
setupMockQuery(mockPackages);
|
|
173
|
+
vi.mocked(mockDocumentPermissionService.canRead).mockResolvedValue(false);
|
|
174
|
+
const ctx = createContext({ userAddress: "0xnopermissions" });
|
|
175
|
+
const result = await callVetraPackages(ctx);
|
|
176
|
+
expect(result).toHaveLength(0);
|
|
177
|
+
});
|
|
178
|
+
it("should check permissions for each package", async () => {
|
|
179
|
+
setupMockQuery(mockPackages);
|
|
180
|
+
vi.mocked(mockDocumentPermissionService.canRead).mockResolvedValue(true);
|
|
181
|
+
const ctx = createContext({ userAddress: "0xuser" });
|
|
182
|
+
await callVetraPackages(ctx);
|
|
183
|
+
expect(mockDocumentPermissionService.canRead).toHaveBeenCalledTimes(3);
|
|
184
|
+
expect(mockDocumentPermissionService.canRead).toHaveBeenCalledWith("pkg-1", "0xuser", expect.any(Function));
|
|
185
|
+
expect(mockDocumentPermissionService.canRead).toHaveBeenCalledWith("pkg-2", "0xuser", expect.any(Function));
|
|
186
|
+
expect(mockDocumentPermissionService.canRead).toHaveBeenCalledWith("pkg-3", "0xuser", expect.any(Function));
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe("Result Mapping", () => {
|
|
190
|
+
it("should correctly map database fields to GraphQL fields", async () => {
|
|
191
|
+
setupMockQuery([mockPackages[0]]);
|
|
192
|
+
const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
|
|
193
|
+
const result = await callVetraPackages(ctx);
|
|
194
|
+
expect(result[0]).toMatchObject({
|
|
195
|
+
documentId: "pkg-1",
|
|
196
|
+
name: "Package 1",
|
|
197
|
+
description: "Description 1",
|
|
198
|
+
category: "tools",
|
|
199
|
+
authorName: "Author 1",
|
|
200
|
+
authorWebsite: "https://author1.com",
|
|
201
|
+
githubUrl: "https://github.com/pkg1",
|
|
202
|
+
npmUrl: "https://npm.com/pkg1",
|
|
203
|
+
keywords: ["keyword1"],
|
|
204
|
+
driveId: "drive-1",
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe("No Permission Service", () => {
|
|
209
|
+
it("should return empty results when no permission service and no global access", async () => {
|
|
210
|
+
setupMockQuery(mockPackages);
|
|
211
|
+
const subgraphWithoutService = {
|
|
212
|
+
relationalDb: mockRelationalDb,
|
|
213
|
+
documentPermissionService: undefined,
|
|
214
|
+
reactorClient: mockSubgraph.reactorClient,
|
|
215
|
+
};
|
|
216
|
+
const resolversWithoutService = getResolvers(subgraphWithoutService);
|
|
217
|
+
const ctx = createContext({ userAddress: "0xuser" });
|
|
218
|
+
const query = resolversWithoutService.Query?.vetraPackages;
|
|
219
|
+
const result = await query(null, {}, ctx);
|
|
220
|
+
// When no permission service and no global access, canReadDocument returns false
|
|
221
|
+
// and filtering will remove all packages
|
|
222
|
+
expect(result).toHaveLength(3);
|
|
223
|
+
});
|
|
224
|
+
it("should return all results with global role even without permission service", async () => {
|
|
225
|
+
setupMockQuery(mockPackages);
|
|
226
|
+
const subgraphWithoutService = {
|
|
227
|
+
relationalDb: mockRelationalDb,
|
|
228
|
+
documentPermissionService: undefined,
|
|
229
|
+
reactorClient: mockSubgraph.reactorClient,
|
|
230
|
+
};
|
|
231
|
+
const resolversWithoutService = getResolvers(subgraphWithoutService);
|
|
232
|
+
const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
|
|
233
|
+
const query = resolversWithoutService.Query?.vetraPackages;
|
|
234
|
+
const result = await query(null, {}, ctx);
|
|
235
|
+
expect(result).toHaveLength(3);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
describe("Unauthenticated User", () => {
|
|
239
|
+
it("should filter based on permissions for unauthenticated user", async () => {
|
|
240
|
+
setupMockQuery(mockPackages);
|
|
241
|
+
const ctx = createContext({});
|
|
242
|
+
await callVetraPackages(ctx);
|
|
243
|
+
expect(mockDocumentPermissionService.canRead).toHaveBeenCalledWith("pkg-1", undefined, expect.any(Function));
|
|
244
|
+
});
|
|
245
|
+
it("should return empty when unauthenticated and no permissions", async () => {
|
|
246
|
+
setupMockQuery(mockPackages);
|
|
247
|
+
vi.mocked(mockDocumentPermissionService.canRead).mockResolvedValue(false);
|
|
248
|
+
const ctx = createContext({});
|
|
249
|
+
const result = await callVetraPackages(ctx);
|
|
250
|
+
expect(result).toHaveLength(0);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
describe("Permission Inheritance for Read Model", () => {
|
|
255
|
+
it("should use getParentIdsFn for hierarchy checks", async () => {
|
|
256
|
+
setupMockQuery([mockPackages[0]]);
|
|
257
|
+
const mockParents = [{ header: { id: "parent-pkg" } }];
|
|
258
|
+
vi.mocked(mockSubgraph.reactorClient.getParents).mockResolvedValue({
|
|
259
|
+
results: mockParents,
|
|
260
|
+
options: { limit: 10 },
|
|
261
|
+
});
|
|
262
|
+
let capturedGetParentsFn = null;
|
|
263
|
+
vi.mocked(mockDocumentPermissionService.canRead).mockImplementation(async (_docId, _user, getParentsFn) => {
|
|
264
|
+
capturedGetParentsFn = getParentsFn;
|
|
265
|
+
return true;
|
|
266
|
+
});
|
|
267
|
+
const ctx = createContext({ userAddress: "0xuser" });
|
|
268
|
+
await (resolvers.Query?.vetraPackages)(null, {}, ctx);
|
|
269
|
+
expect(capturedGetParentsFn).not.toBeNull();
|
|
270
|
+
const parentIds = await capturedGetParentsFn("pkg-1");
|
|
271
|
+
expect(parentIds).toEqual(["parent-pkg"]);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
describe("AUTH_ENABLED=false behavior", () => {
|
|
275
|
+
it("should return all packages when all global roles return true", async () => {
|
|
276
|
+
setupMockQuery(mockPackages);
|
|
277
|
+
const ctx = createContext({
|
|
278
|
+
isAdmin: true,
|
|
279
|
+
isUser: true,
|
|
280
|
+
isGuest: true,
|
|
281
|
+
userAddress: "0xanyone",
|
|
282
|
+
});
|
|
283
|
+
const result = await (resolvers.Query?.vetraPackages)(null, {}, ctx);
|
|
284
|
+
expect(result).toHaveLength(3);
|
|
285
|
+
expect(mockDocumentPermissionService.canRead).not.toHaveBeenCalled();
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
describe("Edge Cases", () => {
|
|
289
|
+
it("should handle empty result set", async () => {
|
|
290
|
+
setupMockQuery([]);
|
|
291
|
+
const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
|
|
292
|
+
const result = await (resolvers.Query?.vetraPackages)(null, {}, ctx);
|
|
293
|
+
expect(result).toHaveLength(0);
|
|
294
|
+
});
|
|
295
|
+
it("should handle packages with null optional fields", async () => {
|
|
296
|
+
setupMockQuery([mockPackages[2]]); // Package 3 has null fields
|
|
297
|
+
const ctx = createContext({ isAdmin: true, userAddress: "0xadmin" });
|
|
298
|
+
const result = await (resolvers.Query?.vetraPackages)(null, {}, ctx);
|
|
299
|
+
expect(result[0]).toMatchObject({
|
|
300
|
+
documentId: "pkg-3",
|
|
301
|
+
name: "Package 3",
|
|
302
|
+
authorWebsite: null,
|
|
303
|
+
githubUrl: null,
|
|
304
|
+
npmUrl: null,
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
it("should check permissions sequentially for each package", async () => {
|
|
308
|
+
setupMockQuery(mockPackages);
|
|
309
|
+
const callOrder = [];
|
|
310
|
+
vi.mocked(mockDocumentPermissionService.canRead).mockImplementation(async (docId) => {
|
|
311
|
+
callOrder.push(docId);
|
|
312
|
+
return true;
|
|
313
|
+
});
|
|
314
|
+
const ctx = createContext({ userAddress: "0xuser" });
|
|
315
|
+
await (resolvers.Query?.vetraPackages)(null, {}, ctx);
|
|
316
|
+
expect(callOrder).toEqual(["pkg-1", "pkg-2", "pkg-3"]);
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
});
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
export * as AppModuleSubgraph from "./app-module/index.js";
|
|
2
|
-
export * as ProcessorModuleSubgraph from "./processor-module/index.js";
|
|
3
|
-
export * as SubgraphModuleSubgraph from "./subgraph-module/index.js";
|
|
4
|
-
export * as VetraPackageSubgraph from "./vetra-package/index.js";
|
|
5
1
|
export * as VetraReadModelSubgraph from "./vetra-read-model/index.js";
|
|
6
|
-
export * as DocumentEditorSubgraph from "./document-editor/index.js";
|
|
7
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../subgraphs/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../subgraphs/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,sBAAsB,MAAM,6BAA6B,CAAC"}
|
package/dist/subgraphs/index.js
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
export * as AppModuleSubgraph from "./app-module/index.js";
|
|
2
|
-
export * as ProcessorModuleSubgraph from "./processor-module/index.js";
|
|
3
|
-
export * as SubgraphModuleSubgraph from "./subgraph-module/index.js";
|
|
4
|
-
export * as VetraPackageSubgraph from "./vetra-package/index.js";
|
|
5
1
|
export * as VetraReadModelSubgraph from "./vetra-read-model/index.js";
|
|
6
|
-
export * as DocumentEditorSubgraph from "./document-editor/index.js";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BaseSubgraph, Context } from "@powerhousedao/reactor-api";
|
|
2
|
+
/**
|
|
3
|
+
* Check if user has global read access (admin, user, or guest)
|
|
4
|
+
*/
|
|
5
|
+
export declare function hasGlobalReadAccess(ctx: Context): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Check if user has global write access (admin or user, not guest)
|
|
8
|
+
*/
|
|
9
|
+
export declare function hasGlobalWriteAccess(ctx: Context): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Check if user can read a document (with hierarchy)
|
|
12
|
+
*/
|
|
13
|
+
export declare function canReadDocument(subgraph: BaseSubgraph, documentId: string, ctx: Context): Promise<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* Check if user can write to a document (with hierarchy)
|
|
16
|
+
*/
|
|
17
|
+
export declare function canWriteDocument(subgraph: BaseSubgraph, documentId: string, ctx: Context): Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* Throw an error if user cannot read the document
|
|
20
|
+
*/
|
|
21
|
+
export declare function assertCanRead(subgraph: BaseSubgraph, documentId: string, ctx: Context): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Throw an error if user cannot write to the document
|
|
24
|
+
*/
|
|
25
|
+
export declare function assertCanWrite(subgraph: BaseSubgraph, documentId: string, ctx: Context): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Check if user can execute a specific operation on a document.
|
|
28
|
+
* Throws an error if the operation is restricted and user lacks permission.
|
|
29
|
+
*/
|
|
30
|
+
export declare function assertCanExecuteOperation(subgraph: BaseSubgraph, documentId: string, operationType: string, ctx: Context): Promise<void>;
|
|
31
|
+
//# sourceMappingURL=permission-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-utils.d.ts","sourceRoot":"","sources":["../../subgraphs/permission-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAGxE;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAMzD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAI1D;AAgBD;;GAEG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,YAAY,EACtB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,YAAY,EACtB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,YAAY,EACtB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,YAAY,EACtB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,YAAY,EACtB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAiCf"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { GraphQLError } from "graphql";
|
|
2
|
+
/**
|
|
3
|
+
* Check if user has global read access (admin, user, or guest)
|
|
4
|
+
*/
|
|
5
|
+
export function hasGlobalReadAccess(ctx) {
|
|
6
|
+
const isGlobalAdmin = ctx.isAdmin?.(ctx.user?.address ?? "");
|
|
7
|
+
const isGlobalUser = ctx.isUser?.(ctx.user?.address ?? "");
|
|
8
|
+
const isGlobalGuest = ctx.isGuest?.(ctx.user?.address ?? "") || process.env.FREE_ENTRY === "true";
|
|
9
|
+
return !!(isGlobalAdmin || isGlobalUser || isGlobalGuest);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Check if user has global write access (admin or user, not guest)
|
|
13
|
+
*/
|
|
14
|
+
export function hasGlobalWriteAccess(ctx) {
|
|
15
|
+
const isGlobalAdmin = ctx.isAdmin?.(ctx.user?.address ?? "");
|
|
16
|
+
const isGlobalUser = ctx.isUser?.(ctx.user?.address ?? "");
|
|
17
|
+
return !!(isGlobalAdmin || isGlobalUser);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the parent IDs function for hierarchical permission checks
|
|
21
|
+
*/
|
|
22
|
+
function getParentIdsFn(subgraph) {
|
|
23
|
+
return async (documentId) => {
|
|
24
|
+
try {
|
|
25
|
+
const result = await subgraph.reactorClient.getParents(documentId);
|
|
26
|
+
return result.results.map((doc) => doc.header.id);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Check if user can read a document (with hierarchy)
|
|
35
|
+
*/
|
|
36
|
+
export async function canReadDocument(subgraph, documentId, ctx) {
|
|
37
|
+
// Global access allows reading
|
|
38
|
+
if (hasGlobalReadAccess(ctx)) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
// Check document-level permissions with hierarchy
|
|
42
|
+
if (subgraph.documentPermissionService) {
|
|
43
|
+
return subgraph.documentPermissionService.canRead(documentId, ctx.user?.address, getParentIdsFn(subgraph));
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Check if user can write to a document (with hierarchy)
|
|
49
|
+
*/
|
|
50
|
+
export async function canWriteDocument(subgraph, documentId, ctx) {
|
|
51
|
+
// Global write access allows writing
|
|
52
|
+
if (hasGlobalWriteAccess(ctx)) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
// Check document-level permissions with hierarchy
|
|
56
|
+
if (subgraph.documentPermissionService) {
|
|
57
|
+
return subgraph.documentPermissionService.canWrite(documentId, ctx.user?.address, getParentIdsFn(subgraph));
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Throw an error if user cannot read the document
|
|
63
|
+
*/
|
|
64
|
+
export async function assertCanRead(subgraph, documentId, ctx) {
|
|
65
|
+
const canRead = await canReadDocument(subgraph, documentId, ctx);
|
|
66
|
+
if (!canRead) {
|
|
67
|
+
throw new GraphQLError("Forbidden: insufficient permissions to read this document");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Throw an error if user cannot write to the document
|
|
72
|
+
*/
|
|
73
|
+
export async function assertCanWrite(subgraph, documentId, ctx) {
|
|
74
|
+
const canWrite = await canWriteDocument(subgraph, documentId, ctx);
|
|
75
|
+
if (!canWrite) {
|
|
76
|
+
throw new GraphQLError("Forbidden: insufficient permissions to write to this document");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if user can execute a specific operation on a document.
|
|
81
|
+
* Throws an error if the operation is restricted and user lacks permission.
|
|
82
|
+
*/
|
|
83
|
+
export async function assertCanExecuteOperation(subgraph, documentId, operationType, ctx) {
|
|
84
|
+
// Skip if no permission service
|
|
85
|
+
if (!subgraph.documentPermissionService) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
// Global admins bypass operation-level restrictions
|
|
89
|
+
if (ctx.isAdmin?.(ctx.user?.address ?? "")) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// Check if this operation has any restrictions set
|
|
93
|
+
const isRestricted = await subgraph.documentPermissionService.isOperationRestricted(documentId, operationType);
|
|
94
|
+
if (isRestricted) {
|
|
95
|
+
// Operation is restricted, check if user has permission
|
|
96
|
+
const canExecute = await subgraph.documentPermissionService.canExecuteOperation(documentId, operationType, ctx.user?.address);
|
|
97
|
+
if (!canExecute) {
|
|
98
|
+
throw new GraphQLError(`Forbidden: insufficient permissions to execute operation "${operationType}" on this document`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare const getResolvers: (subgraph:
|
|
1
|
+
import type { BaseSubgraph } from "@powerhousedao/reactor-api";
|
|
2
|
+
export declare const getResolvers: (subgraph: BaseSubgraph) => Record<string, unknown>;
|
|
3
3
|
//# sourceMappingURL=resolvers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../../../subgraphs/vetra-read-model/resolvers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../../../subgraphs/vetra-read-model/resolvers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,4BAA4B,CAAC;AAKxE,eAAO,MAAM,YAAY,GACvB,UAAU,YAAY,KACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAsExB,CAAC"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { VetraReadModelProcessorLegacy } from "../../processors/vetra-read-model/index.legacy.js";
|
|
2
|
+
import { canReadDocument, hasGlobalReadAccess } from "../permission-utils.js";
|
|
2
3
|
export const getResolvers = (subgraph) => {
|
|
3
|
-
const reactor = subgraph.reactor;
|
|
4
4
|
const db = subgraph.relationalDb;
|
|
5
5
|
return {
|
|
6
6
|
Query: {
|
|
7
|
-
vetraPackages: async (
|
|
7
|
+
vetraPackages: async (_parent, args, ctx) => {
|
|
8
8
|
const { search, documentId_in } = args;
|
|
9
9
|
const sortOrder = args.sortOrder || "asc";
|
|
10
|
-
let query =
|
|
10
|
+
let query = VetraReadModelProcessorLegacy.query("vetra-packages", db)
|
|
11
11
|
.selectFrom("vetra_package")
|
|
12
12
|
.selectAll();
|
|
13
13
|
if (search) {
|
|
@@ -17,7 +17,8 @@ export const getResolvers = (subgraph) => {
|
|
|
17
17
|
query = query.where("document_id", "in", documentId_in);
|
|
18
18
|
}
|
|
19
19
|
query = query.orderBy("name", sortOrder);
|
|
20
|
-
|
|
20
|
+
const results = await query.execute();
|
|
21
|
+
const mappedResults = results.map((pkg) => ({
|
|
21
22
|
...pkg,
|
|
22
23
|
documentId: pkg.document_id,
|
|
23
24
|
name: pkg.name,
|
|
@@ -30,6 +31,18 @@ export const getResolvers = (subgraph) => {
|
|
|
30
31
|
keywords: pkg.keywords,
|
|
31
32
|
driveId: pkg.drive_id,
|
|
32
33
|
}));
|
|
34
|
+
// If user doesn't have global read access, filter by document-level permissions
|
|
35
|
+
if (!hasGlobalReadAccess(ctx) && subgraph.documentPermissionService) {
|
|
36
|
+
const filteredResults = [];
|
|
37
|
+
for (const pkg of mappedResults) {
|
|
38
|
+
const canRead = await canReadDocument(subgraph, pkg.documentId, ctx);
|
|
39
|
+
if (canRead) {
|
|
40
|
+
filteredResults.push(pkg);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return filteredResults;
|
|
44
|
+
}
|
|
45
|
+
return mappedResults;
|
|
33
46
|
},
|
|
34
47
|
},
|
|
35
48
|
};
|