@stonecrop/rockfoil 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rockfoil.d.ts +44 -0
- package/dist/rockfoil.js +40009 -0
- package/dist/rockfoil.js.map +1 -0
- package/dist/rockfoil.tsbuildinfo +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +2 -0
- package/dist/src/middleware/postgraphile.d.ts +7 -0
- package/dist/src/middleware/postgraphile.d.ts.map +1 -0
- package/dist/src/middleware/postgraphile.js +49 -0
- package/dist/src/types/index.d.ts +32 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +0 -0
- package/dist/tests/postgraphile.test.d.ts +2 -0
- package/dist/tests/postgraphile.test.d.ts.map +1 -0
- package/dist/tests/postgraphile.test.js +58 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/package.json +71 -0
- package/src/index.ts +2 -0
- package/src/middleware/postgraphile.ts +61 -0
- package/src/types/index.ts +33 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"5.9.3"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA;AACzC,cAAc,SAAS,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HookConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a PostGraphile plugin that wraps GraphQL query and mutation plans with before/after hooks
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export declare const createPglRockfoilPlugin: (hookMap: HookConfig) => GraphileConfig.Plugin;
|
|
7
|
+
//# sourceMappingURL=postgraphile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgraphile.d.ts","sourceRoot":"","sources":["../../../src/middleware/postgraphile.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,UAAU,CAAA;AAEpD;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAAI,SAAS,UAAU,0BAoD1D,CAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { wrapPlans } from 'postgraphile/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a PostGraphile plugin that wraps GraphQL query and mutation plans with before/after hooks
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export const createPglRockfoilPlugin = (hookMap) => {
|
|
7
|
+
const queryPlans = {};
|
|
8
|
+
const mutationPlans = {};
|
|
9
|
+
for (const [fieldname, plans] of Object.entries(hookMap)) {
|
|
10
|
+
if (plans.beforeQuery || plans.afterQuery) {
|
|
11
|
+
queryPlans[fieldname] = {
|
|
12
|
+
plan: (plan, $source, fieldArgs, info) => {
|
|
13
|
+
// Process before query hooks
|
|
14
|
+
if (plans.beforeQuery) {
|
|
15
|
+
plans.beforeQuery(plan, $source, fieldArgs, info);
|
|
16
|
+
}
|
|
17
|
+
// Execute the query plan
|
|
18
|
+
let $result = plan();
|
|
19
|
+
// Process after query hooks
|
|
20
|
+
if (plans.afterQuery) {
|
|
21
|
+
$result = plans.afterQuery($result, plan, $source, fieldArgs, info);
|
|
22
|
+
}
|
|
23
|
+
return $result;
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (plans.beforeMutation || plans.afterMutation) {
|
|
28
|
+
mutationPlans[fieldname] = {
|
|
29
|
+
plan: (plan, $source, fieldArgs, info) => {
|
|
30
|
+
// Process before mutation hooks
|
|
31
|
+
if (plans.beforeMutation) {
|
|
32
|
+
plans.beforeMutation(plan, $source, fieldArgs, info);
|
|
33
|
+
}
|
|
34
|
+
// Execute the mutation plan
|
|
35
|
+
let $result = plan();
|
|
36
|
+
// Process after mutation hooks
|
|
37
|
+
if (plans.afterMutation) {
|
|
38
|
+
$result = plans.afterMutation($result, plan, $source, fieldArgs, info);
|
|
39
|
+
}
|
|
40
|
+
return $result;
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return wrapPlans({
|
|
46
|
+
Query: queryPlans,
|
|
47
|
+
Mutation: mutationPlans,
|
|
48
|
+
});
|
|
49
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ExecutableStep, FieldArgs, FieldInfo } from 'postgraphile/grafast';
|
|
2
|
+
import type { PlanWrapperFn, PlanWrapperRule } from 'postgraphile/utils';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration object mapping field names to their before/after hooks for queries and mutations
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export interface HookConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Hook configuration for a specific field
|
|
10
|
+
*/
|
|
11
|
+
[fieldName: string]: {
|
|
12
|
+
/** Function to execute before a query operation */
|
|
13
|
+
beforeQuery?: PlanWrapperFn;
|
|
14
|
+
/** Function to execute after a query operation */
|
|
15
|
+
afterQuery?: (result: any, plan: any, $source: ExecutableStep, fieldArgs: FieldArgs, info: FieldInfo) => any;
|
|
16
|
+
/** Function to execute before a mutation operation */
|
|
17
|
+
beforeMutation?: PlanWrapperFn;
|
|
18
|
+
/** Function to execute after a mutation operation */
|
|
19
|
+
afterMutation?: (result: any, plan: any, $source: ExecutableStep, fieldArgs: FieldArgs, info: FieldInfo) => any;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Internal mapping of field names to their plan wrapper rules
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export interface HookPlan {
|
|
27
|
+
/**
|
|
28
|
+
* Plan wrapper rule for a specific field
|
|
29
|
+
*/
|
|
30
|
+
[fieldName: string]: PlanWrapperRule;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChF,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAExE;;;GAGG;AACH,MAAM,WAAW,UAAU;IAC1B;;OAEG;IACH,CAAC,SAAS,EAAE,MAAM,GAAG;QACpB,mDAAmD;QACnD,WAAW,CAAC,EAAE,aAAa,CAAA;QAC3B,kDAAkD;QAClD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,KAAK,GAAG,CAAA;QAC5G,sDAAsD;QACtD,cAAc,CAAC,EAAE,aAAa,CAAA;QAC9B,qDAAqD;QACrD,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,KAAK,GAAG,CAAA;KAC/G,CAAA;CACD;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACxB;;OAEG;IACH,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAAA;CACpC"}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgraphile.test.d.ts","sourceRoot":"","sources":["../../tests/postgraphile.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
// Mock postgraphile/utils with a simple implementation
|
|
3
|
+
vi.mock('postgraphile/utils', () => ({
|
|
4
|
+
wrapPlans: (config) => ({
|
|
5
|
+
name: 'TestPlugin',
|
|
6
|
+
version: '1.0.0',
|
|
7
|
+
_config: config, // Store config for testing
|
|
8
|
+
}),
|
|
9
|
+
}));
|
|
10
|
+
import { createPglRockfoilPlugin } from '../src/middleware/postgraphile';
|
|
11
|
+
describe('Rockfoil PostGraphile Plugin', () => {
|
|
12
|
+
describe('createPglRockfoilPlugin', () => {
|
|
13
|
+
it('should create a valid plugin with empty hook map', () => {
|
|
14
|
+
const plugin = createPglRockfoilPlugin({});
|
|
15
|
+
expect(plugin).toBeDefined();
|
|
16
|
+
expect(plugin.name).toBe('TestPlugin');
|
|
17
|
+
expect(plugin.version).toBe('1.0.0');
|
|
18
|
+
});
|
|
19
|
+
it('should create a plugin with query hooks', () => {
|
|
20
|
+
const hookMap = {
|
|
21
|
+
testField: {
|
|
22
|
+
beforeQuery: vi.fn(),
|
|
23
|
+
afterQuery: vi.fn(),
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
const plugin = createPglRockfoilPlugin(hookMap);
|
|
27
|
+
expect(plugin).toBeDefined();
|
|
28
|
+
expect(plugin.name).toBe('TestPlugin');
|
|
29
|
+
});
|
|
30
|
+
it('should create a plugin with mutation hooks', () => {
|
|
31
|
+
const hookMap = {
|
|
32
|
+
createTest: {
|
|
33
|
+
beforeMutation: vi.fn(),
|
|
34
|
+
afterMutation: vi.fn(),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
const plugin = createPglRockfoilPlugin(hookMap);
|
|
38
|
+
expect(plugin).toBeDefined();
|
|
39
|
+
expect(plugin.name).toBe('TestPlugin');
|
|
40
|
+
});
|
|
41
|
+
it('should handle complex hook map', () => {
|
|
42
|
+
const hookMap = {
|
|
43
|
+
field1: {
|
|
44
|
+
beforeQuery: vi.fn(),
|
|
45
|
+
},
|
|
46
|
+
field2: {
|
|
47
|
+
afterQuery: vi.fn(),
|
|
48
|
+
},
|
|
49
|
+
field3: {
|
|
50
|
+
beforeMutation: vi.fn(),
|
|
51
|
+
afterMutation: vi.fn(),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
const plugin = createPglRockfoilPlugin(hookMap);
|
|
55
|
+
expect(plugin).toBeDefined();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
|
2
|
+
// It should be published with your NPM package. It should not be tracked by Git.
|
|
3
|
+
{
|
|
4
|
+
"tsdocVersion": "0.12",
|
|
5
|
+
"toolPackages": [
|
|
6
|
+
{
|
|
7
|
+
"packageName": "@microsoft/api-extractor",
|
|
8
|
+
"packageVersion": "7.55.2"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stonecrop/rockfoil",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Tyler Matteson",
|
|
8
|
+
"email": "tyler@agritheory.com"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/agritheory/rockfoil#readme",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/agritheory/stonecrop",
|
|
14
|
+
"directory": "rockfoil"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/agritheory/stonecrop/issues"
|
|
18
|
+
},
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/src/index.d.ts",
|
|
23
|
+
"default": "./dist/rockfoil.js"
|
|
24
|
+
},
|
|
25
|
+
"require": "./dist/rockfoil.umd.cjs"
|
|
26
|
+
},
|
|
27
|
+
"./types": {
|
|
28
|
+
"import": "./dist/src/types/index.d.ts",
|
|
29
|
+
"require": "./dist/src/types/index.d.ts"
|
|
30
|
+
},
|
|
31
|
+
"./styles": "./dist/assets/index.css"
|
|
32
|
+
},
|
|
33
|
+
"typings": "./dist/index.d.ts",
|
|
34
|
+
"files": [
|
|
35
|
+
"dist/*",
|
|
36
|
+
"src/*"
|
|
37
|
+
],
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"graphql": "^16.12.0",
|
|
40
|
+
"postgraphile": "^5.0.0-rc.3"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@rushstack/heft": "^1.1.7",
|
|
44
|
+
"@types/node": "^22.19.5",
|
|
45
|
+
"@vitest/coverage-istanbul": "^4.0.17",
|
|
46
|
+
"@vitest/ui": "^4.0.17",
|
|
47
|
+
"graphile-build": "^5.0.0-rc.2",
|
|
48
|
+
"jsdom": "^27.4.0",
|
|
49
|
+
"madr": "^4.0.0",
|
|
50
|
+
"typescript": "^5.9.3",
|
|
51
|
+
"vite": "^7.3.1",
|
|
52
|
+
"vitest": "^4.0.17",
|
|
53
|
+
"stonecrop-rig": "0.2.22"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=22.5.0"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"_phase:build": "heft build && vite build && rushx docs",
|
|
60
|
+
"prepublish": "heft build && vite build && rushx docs",
|
|
61
|
+
"build": "heft build && vite build && rushx docs",
|
|
62
|
+
"dev": "vite",
|
|
63
|
+
"docs": "bash ../common/scripts/run-docs.sh rockfoil",
|
|
64
|
+
"lint": "eslint .",
|
|
65
|
+
"preview": "vite preview",
|
|
66
|
+
"test": "vitest run --coverage.enabled false",
|
|
67
|
+
"test:watch": "vitest watch",
|
|
68
|
+
"test:coverage": "vitest run --coverage",
|
|
69
|
+
"test:ui": "vitest --ui"
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { wrapPlans } from 'postgraphile/utils'
|
|
2
|
+
|
|
3
|
+
import type { HookConfig, HookPlan } from '../types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a PostGraphile plugin that wraps GraphQL query and mutation plans with before/after hooks
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export const createPglRockfoilPlugin = (hookMap: HookConfig) => {
|
|
10
|
+
const queryPlans: HookPlan = {}
|
|
11
|
+
const mutationPlans: HookPlan = {}
|
|
12
|
+
|
|
13
|
+
for (const [fieldname, plans] of Object.entries(hookMap)) {
|
|
14
|
+
if (plans.beforeQuery || plans.afterQuery) {
|
|
15
|
+
queryPlans[fieldname] = {
|
|
16
|
+
plan: (plan, $source, fieldArgs, info) => {
|
|
17
|
+
// Process before query hooks
|
|
18
|
+
if (plans.beforeQuery) {
|
|
19
|
+
plans.beforeQuery(plan, $source, fieldArgs, info)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Execute the query plan
|
|
23
|
+
let $result = plan()
|
|
24
|
+
|
|
25
|
+
// Process after query hooks
|
|
26
|
+
if (plans.afterQuery) {
|
|
27
|
+
$result = plans.afterQuery($result, plan, $source, fieldArgs, info)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return $result
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (plans.beforeMutation || plans.afterMutation) {
|
|
36
|
+
mutationPlans[fieldname] = {
|
|
37
|
+
plan: (plan, $source, fieldArgs, info) => {
|
|
38
|
+
// Process before mutation hooks
|
|
39
|
+
if (plans.beforeMutation) {
|
|
40
|
+
plans.beforeMutation(plan, $source, fieldArgs, info)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Execute the mutation plan
|
|
44
|
+
let $result = plan()
|
|
45
|
+
|
|
46
|
+
// Process after mutation hooks
|
|
47
|
+
if (plans.afterMutation) {
|
|
48
|
+
$result = plans.afterMutation($result, plan, $source, fieldArgs, info)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return $result
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return wrapPlans({
|
|
58
|
+
Query: queryPlans,
|
|
59
|
+
Mutation: mutationPlans,
|
|
60
|
+
})
|
|
61
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ExecutableStep, FieldArgs, FieldInfo } from 'postgraphile/grafast'
|
|
2
|
+
import type { PlanWrapperFn, PlanWrapperRule } from 'postgraphile/utils'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Configuration object mapping field names to their before/after hooks for queries and mutations
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export interface HookConfig {
|
|
9
|
+
/**
|
|
10
|
+
* Hook configuration for a specific field
|
|
11
|
+
*/
|
|
12
|
+
[fieldName: string]: {
|
|
13
|
+
/** Function to execute before a query operation */
|
|
14
|
+
beforeQuery?: PlanWrapperFn
|
|
15
|
+
/** Function to execute after a query operation */
|
|
16
|
+
afterQuery?: (result: any, plan: any, $source: ExecutableStep, fieldArgs: FieldArgs, info: FieldInfo) => any
|
|
17
|
+
/** Function to execute before a mutation operation */
|
|
18
|
+
beforeMutation?: PlanWrapperFn
|
|
19
|
+
/** Function to execute after a mutation operation */
|
|
20
|
+
afterMutation?: (result: any, plan: any, $source: ExecutableStep, fieldArgs: FieldArgs, info: FieldInfo) => any
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Internal mapping of field names to their plan wrapper rules
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
export interface HookPlan {
|
|
29
|
+
/**
|
|
30
|
+
* Plan wrapper rule for a specific field
|
|
31
|
+
*/
|
|
32
|
+
[fieldName: string]: PlanWrapperRule
|
|
33
|
+
}
|