@common-stack/server-stack 8.0.1-alpha.2 → 8.2.1-alpha.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/LICENSE +34 -21
- package/lib/MainStackServer.cjs +126 -143
- package/lib/MainStackServer.cjs.map +1 -1
- package/lib/MainStackServer.d.ts +12 -6
- package/lib/MainStackServer.mjs +126 -143
- package/lib/MainStackServer.mjs.map +1 -1
- package/lib/StackServer.cjs +23 -66
- package/lib/StackServer.cjs.map +1 -1
- package/lib/StackServer.d.ts +4 -5
- package/lib/StackServer.mjs +23 -66
- package/lib/StackServer.mjs.map +1 -1
- package/lib/api/schema-builder.cjs +13 -12
- package/lib/api/schema-builder.cjs.map +1 -1
- package/lib/api/schema-builder.mjs +13 -12
- package/lib/api/schema-builder.mjs.map +1 -1
- package/lib/api/sub-graph-schema-builder.cjs +147 -0
- package/lib/api/sub-graph-schema-builder.cjs.map +1 -0
- package/lib/api/sub-graph-schema-builder.d.ts +24 -0
- package/lib/api/sub-graph-schema-builder.mjs +147 -0
- package/lib/api/sub-graph-schema-builder.mjs.map +1 -0
- package/lib/config/env-config.cjs +6 -0
- package/lib/config/env-config.cjs.map +1 -1
- package/lib/config/env-config.d.ts +6 -0
- package/lib/config/env-config.mjs +6 -0
- package/lib/config/env-config.mjs.map +1 -1
- package/lib/examples/tenant-feature-example.d.ts +13 -0
- package/lib/examples/tenant-feature-integration.d.ts +14 -0
- package/lib/features/multi-module-example.d.ts +17 -0
- package/lib/index.cjs +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.mjs +1 -1
- package/lib/infrastructure/container-module.cjs +27 -0
- package/lib/infrastructure/container-module.cjs.map +1 -0
- package/lib/infrastructure/container-module.d.ts +3 -0
- package/lib/infrastructure/container-module.mjs +27 -0
- package/lib/infrastructure/container-module.mjs.map +1 -0
- package/lib/infrastructure/example-workflows.d.ts +16 -0
- package/lib/infrastructure/index.d.ts +5 -0
- package/lib/infrastructure/infrastructure-factory.cjs +172 -0
- package/lib/infrastructure/infrastructure-factory.cjs.map +1 -0
- package/lib/infrastructure/infrastructure-factory.d.ts +36 -0
- package/lib/infrastructure/infrastructure-factory.mjs +172 -0
- package/lib/infrastructure/infrastructure-factory.mjs.map +1 -0
- package/lib/infrastructure/inngest-factory.cjs +47 -0
- package/lib/infrastructure/inngest-factory.cjs.map +1 -0
- package/lib/infrastructure/inngest-factory.d.ts +8 -0
- package/lib/infrastructure/inngest-factory.mjs +47 -0
- package/lib/infrastructure/inngest-factory.mjs.map +1 -0
- package/lib/infrastructure/types.d.ts +28 -0
- package/lib/infrastructure/usage-examples.d.ts +9 -0
- package/lib/infrastructure/workflow-orchestrator.cjs +59 -0
- package/lib/infrastructure/workflow-orchestrator.cjs.map +1 -0
- package/lib/infrastructure/workflow-orchestrator.d.ts +10 -0
- package/lib/infrastructure/workflow-orchestrator.mjs +59 -0
- package/lib/infrastructure/workflow-orchestrator.mjs.map +1 -0
- package/lib/inngest/client-id-generator.d.ts +29 -0
- package/lib/inngest/handler-factory.d.ts +24 -0
- package/lib/inngest/middleware/auto-resolve-invoke.middleware.cjs +275 -0
- package/lib/inngest/middleware/auto-resolve-invoke.middleware.cjs.map +1 -0
- package/lib/inngest/middleware/auto-resolve-invoke.middleware.d.ts +111 -0
- package/lib/inngest/middleware/auto-resolve-invoke.middleware.mjs +275 -0
- package/lib/inngest/middleware/auto-resolve-invoke.middleware.mjs.map +1 -0
- package/lib/inngest/middleware/function-reference-helper.cjs +363 -0
- package/lib/inngest/middleware/function-reference-helper.cjs.map +1 -0
- package/lib/inngest/middleware/function-reference-helper.d.ts +211 -0
- package/lib/inngest/middleware/function-reference-helper.mjs +363 -0
- package/lib/inngest/middleware/function-reference-helper.mjs.map +1 -0
- package/lib/inngest/middleware/index.d.ts +31 -0
- package/lib/inngest/middleware/types.d.ts +162 -0
- package/lib/inngest/multi-module-functions.d.ts +133 -0
- package/lib/inngest/setup.cjs +55 -0
- package/lib/inngest/setup.cjs.map +1 -0
- package/lib/inngest/setup.d.ts +10 -0
- package/lib/inngest/setup.mjs +55 -0
- package/lib/inngest/setup.mjs.map +1 -0
- package/lib/interfaces/graphql-request-context.d.ts +20 -0
- package/lib/interfaces/index.d.ts +1 -0
- package/lib/middleware/index.d.ts +5 -0
- package/lib/middleware/redis-client.cjs +18 -0
- package/lib/middleware/redis-client.cjs.map +1 -0
- package/lib/middleware/redis-client.d.ts +16 -0
- package/lib/middleware/redis-client.mjs +18 -0
- package/lib/middleware/redis-client.mjs.map +1 -0
- package/lib/plugins/index.d.ts +1 -0
- package/lib/plugins/invalidateCachePlugin.cjs +33 -10
- package/lib/plugins/invalidateCachePlugin.cjs.map +1 -1
- package/lib/plugins/invalidateCachePlugin.mjs +33 -10
- package/lib/plugins/invalidateCachePlugin.mjs.map +1 -1
- package/lib/plugins/responseCachePlugin.cjs +63 -0
- package/lib/plugins/responseCachePlugin.cjs.map +1 -0
- package/lib/plugins/responseCachePlugin.d.ts +12 -0
- package/lib/plugins/responseCachePlugin.mjs +63 -0
- package/lib/plugins/responseCachePlugin.mjs.map +1 -0
- package/lib/servers/ExpressApp.cjs +8 -3
- package/lib/servers/ExpressApp.cjs.map +1 -1
- package/lib/servers/ExpressApp.d.ts +1 -1
- package/lib/servers/ExpressApp.mjs +8 -3
- package/lib/servers/ExpressApp.mjs.map +1 -1
- package/lib/servers/GraphqlServer.cjs +10 -36
- package/lib/servers/GraphqlServer.cjs.map +1 -1
- package/lib/servers/GraphqlServer.d.ts +8 -6
- package/lib/servers/GraphqlServer.mjs +10 -36
- package/lib/servers/GraphqlServer.mjs.map +1 -1
- package/lib/servers/GraphqlWs.cjs +3 -44
- package/lib/servers/GraphqlWs.cjs.map +1 -1
- package/lib/servers/GraphqlWs.mjs +3 -44
- package/lib/servers/GraphqlWs.mjs.map +1 -1
- package/lib/servers/WebsocketMultipathUpdate.cjs +4 -2
- package/lib/servers/WebsocketMultipathUpdate.cjs.map +1 -1
- package/lib/servers/WebsocketMultipathUpdate.mjs +4 -2
- package/lib/servers/WebsocketMultipathUpdate.mjs.map +1 -1
- package/lib/servers/mongodb-migration-update.d.ts +1 -1
- package/lib/servers/websocket-context.cjs +70 -0
- package/lib/servers/websocket-context.cjs.map +1 -0
- package/lib/servers/websocket-context.d.ts +30 -0
- package/lib/servers/websocket-context.mjs +70 -0
- package/lib/servers/websocket-context.mjs.map +1 -0
- package/lib/utils/add-shareable-directive-to-schema.cjs +44 -0
- package/lib/utils/add-shareable-directive-to-schema.cjs.map +1 -0
- package/lib/utils/add-shareable-directive-to-schema.d.ts +1 -0
- package/lib/utils/add-shareable-directive-to-schema.mjs +44 -0
- package/lib/utils/add-shareable-directive-to-schema.mjs.map +1 -0
- package/lib/utils/index.d.ts +3 -0
- package/lib/utils/safe-model-factory.d.ts +18 -0
- package/package.json +15 -11
- package/lib/api/resolver.cjs +0 -12
- package/lib/api/resolver.cjs.map +0 -1
- package/lib/api/resolver.mjs +0 -12
- package/lib/api/resolver.mjs.map +0 -1
- package/lib/api/root-schema.graphqls.cjs +0 -2
- package/lib/api/root-schema.graphqls.cjs.map +0 -1
- package/lib/api/root-schema.graphqls.mjs +0 -2
- package/lib/api/root-schema.graphqls.mjs.map +0 -1
- package/lib/api/scalar.cjs +0 -16
- package/lib/api/scalar.cjs.map +0 -1
- package/lib/api/scalar.mjs +0 -16
- package/lib/api/scalar.mjs.map +0 -1
- package/lib/graphql/directives/index.cjs +0 -10
- package/lib/graphql/directives/index.cjs.map +0 -1
- package/lib/graphql/directives/index.d.ts +0 -7
- package/lib/graphql/directives/index.mjs +0 -10
- package/lib/graphql/directives/index.mjs.map +0 -1
- package/lib/graphql/index.d.ts +0 -2
- package/lib/graphql/schema/directives.graphql.cjs +0 -1
- package/lib/graphql/schema/directives.graphql.cjs.map +0 -1
- package/lib/graphql/schema/directives.graphql.mjs +0 -1
- package/lib/graphql/schema/directives.graphql.mjs.map +0 -1
- package/lib/graphql/schema/index.cjs +0 -1
- package/lib/graphql/schema/index.cjs.map +0 -1
- package/lib/graphql/schema/index.d.ts +0 -1
- package/lib/graphql/schema/index.mjs +0 -1
- package/lib/graphql/schema/index.mjs.map +0 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Container } from 'inversify';
|
|
2
|
+
/**
|
|
3
|
+
* User management Inngest functions that depend on container services
|
|
4
|
+
*/
|
|
5
|
+
export declare const userInngestFunctions: ({ container, inngest, settings, }: {
|
|
6
|
+
container: Container;
|
|
7
|
+
inngest: any;
|
|
8
|
+
settings?: any;
|
|
9
|
+
}) => {
|
|
10
|
+
createUserFunction: {
|
|
11
|
+
id: string;
|
|
12
|
+
_type: string;
|
|
13
|
+
};
|
|
14
|
+
updateUserProfileFunction: {
|
|
15
|
+
id: string;
|
|
16
|
+
_type: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Email campaign Inngest functions that depend on container services
|
|
21
|
+
*/
|
|
22
|
+
export declare const emailCampaignInngestFunctions: ({ container, inngest, settings, }: {
|
|
23
|
+
container: Container;
|
|
24
|
+
inngest: any;
|
|
25
|
+
settings?: any;
|
|
26
|
+
}) => {
|
|
27
|
+
sendCampaignFunction: {
|
|
28
|
+
id: string;
|
|
29
|
+
_type: string;
|
|
30
|
+
};
|
|
31
|
+
trackEmailOpenFunction: {
|
|
32
|
+
id: string;
|
|
33
|
+
_type: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Analytics Inngest functions that depend on container services
|
|
38
|
+
*/
|
|
39
|
+
export declare const analyticsInngestFunctions: ({ container, inngest, settings, }: {
|
|
40
|
+
container: Container;
|
|
41
|
+
inngest: any;
|
|
42
|
+
settings?: any;
|
|
43
|
+
}) => {
|
|
44
|
+
generateReportFunction: {
|
|
45
|
+
id: string;
|
|
46
|
+
_type: string;
|
|
47
|
+
};
|
|
48
|
+
trackUserEventFunction: {
|
|
49
|
+
id: string;
|
|
50
|
+
_type: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* AI Page Creator functions that depend on container services
|
|
55
|
+
*/
|
|
56
|
+
export declare const aiPageCreatorInngestFunctions: ({ container, inngest, settings, }: {
|
|
57
|
+
container: Container;
|
|
58
|
+
inngest: any;
|
|
59
|
+
settings?: any;
|
|
60
|
+
}) => {
|
|
61
|
+
codeAgentFunction: {
|
|
62
|
+
id: string;
|
|
63
|
+
_type: string;
|
|
64
|
+
};
|
|
65
|
+
sendMessageFunction: {
|
|
66
|
+
id: string;
|
|
67
|
+
_type: string;
|
|
68
|
+
};
|
|
69
|
+
processPageFunction: {
|
|
70
|
+
id: string;
|
|
71
|
+
_type: string;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Export array of all function factories for easy registration
|
|
76
|
+
*/
|
|
77
|
+
export declare const allInngestFunctionFactories: ((({ container, inngest, settings, }: {
|
|
78
|
+
container: Container;
|
|
79
|
+
inngest: any;
|
|
80
|
+
settings?: any;
|
|
81
|
+
}) => {
|
|
82
|
+
createUserFunction: {
|
|
83
|
+
id: string;
|
|
84
|
+
_type: string;
|
|
85
|
+
};
|
|
86
|
+
updateUserProfileFunction: {
|
|
87
|
+
id: string;
|
|
88
|
+
_type: string;
|
|
89
|
+
};
|
|
90
|
+
}) | (({ container, inngest, settings, }: {
|
|
91
|
+
container: Container;
|
|
92
|
+
inngest: any;
|
|
93
|
+
settings?: any;
|
|
94
|
+
}) => {
|
|
95
|
+
sendCampaignFunction: {
|
|
96
|
+
id: string;
|
|
97
|
+
_type: string;
|
|
98
|
+
};
|
|
99
|
+
trackEmailOpenFunction: {
|
|
100
|
+
id: string;
|
|
101
|
+
_type: string;
|
|
102
|
+
};
|
|
103
|
+
}) | (({ container, inngest, settings, }: {
|
|
104
|
+
container: Container;
|
|
105
|
+
inngest: any;
|
|
106
|
+
settings?: any;
|
|
107
|
+
}) => {
|
|
108
|
+
generateReportFunction: {
|
|
109
|
+
id: string;
|
|
110
|
+
_type: string;
|
|
111
|
+
};
|
|
112
|
+
trackUserEventFunction: {
|
|
113
|
+
id: string;
|
|
114
|
+
_type: string;
|
|
115
|
+
};
|
|
116
|
+
}) | (({ container, inngest, settings, }: {
|
|
117
|
+
container: Container;
|
|
118
|
+
inngest: any;
|
|
119
|
+
settings?: any;
|
|
120
|
+
}) => {
|
|
121
|
+
codeAgentFunction: {
|
|
122
|
+
id: string;
|
|
123
|
+
_type: string;
|
|
124
|
+
};
|
|
125
|
+
sendMessageFunction: {
|
|
126
|
+
id: string;
|
|
127
|
+
_type: string;
|
|
128
|
+
};
|
|
129
|
+
processPageFunction: {
|
|
130
|
+
id: string;
|
|
131
|
+
_type: string;
|
|
132
|
+
};
|
|
133
|
+
}))[];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict';var express=require('inngest/express'),functionReferenceHelper=require('./middleware/function-reference-helper.cjs');/**
|
|
2
|
+
* Sets up Inngest functions from the Feature system and registers the handler
|
|
3
|
+
*/
|
|
4
|
+
async function setupInngestFunctions(modules, app, serviceContainer, logger) {
|
|
5
|
+
try {
|
|
6
|
+
// Get Inngest client from the container (already bound in infraModule)
|
|
7
|
+
const inngestClient = serviceContainer.get('INNGEST_CLIENT');
|
|
8
|
+
logger.info('✅ Retrieved Inngest client from service container');
|
|
9
|
+
// Load Inngest functions from all modules
|
|
10
|
+
// The improved loadInngestFunctions now handles both array and object returns
|
|
11
|
+
const inngestFunctions = await modules.loadInngestFunctions({
|
|
12
|
+
container: serviceContainer,
|
|
13
|
+
inngest: inngestClient,
|
|
14
|
+
settings: {},
|
|
15
|
+
});
|
|
16
|
+
if (inngestFunctions.length > 0) {
|
|
17
|
+
logger.info(`✅ Loaded ${inngestFunctions.length} Inngest functions from Feature system`);
|
|
18
|
+
// Log function IDs for debugging
|
|
19
|
+
const functionIds = inngestFunctions
|
|
20
|
+
.filter((fn) => fn && fn.id)
|
|
21
|
+
.map((fn) => (typeof fn.id === 'function' ? fn.id() : fn.id))
|
|
22
|
+
.join(', ');
|
|
23
|
+
logger.debug(`Registering Inngest functions: ${functionIds}`);
|
|
24
|
+
// ✨ Register functions with global registry for referenceFunction() helper
|
|
25
|
+
logger.info('📝 Registering functions with global function registry...');
|
|
26
|
+
try {
|
|
27
|
+
functionReferenceHelper.globalFunctionRegistry.register(inngestFunctions);
|
|
28
|
+
logger.info(`✅ Registered ${functionReferenceHelper.globalFunctionRegistry.count} functions for referenceFunction() helper`);
|
|
29
|
+
logger.info('💡 You can now use: referenceFunction("function-id") or auto-invoke in step.invoke()');
|
|
30
|
+
}
|
|
31
|
+
catch (registryError) {
|
|
32
|
+
logger.error('❌ Error registering functions with global registry:', registryError);
|
|
33
|
+
}
|
|
34
|
+
// Register Inngest handler
|
|
35
|
+
logger.info('📞 Calling serve() to register Inngest handler...');
|
|
36
|
+
const inngestHandler = express.serve({
|
|
37
|
+
client: inngestClient,
|
|
38
|
+
functions: inngestFunctions,
|
|
39
|
+
});
|
|
40
|
+
logger.info('✅ serve() completed successfully');
|
|
41
|
+
app.use('/api/inngest', inngestHandler);
|
|
42
|
+
logger.info(`✅ Inngest handler registered at /api/inngest with ${inngestFunctions.length} functions`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
logger.info('No Inngest functions found - handler not registered');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
logger.warn('Inngest handler registration failed:', error?.message || String(error));
|
|
50
|
+
logger.debug('Full error stack:', error?.stack || error);
|
|
51
|
+
if (error && typeof error === 'object') {
|
|
52
|
+
logger.debug('Error keys:', Object.keys(error));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}exports.setupInngestFunctions=setupInngestFunctions;//# sourceMappingURL=setup.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.cjs","sources":["../../src/inngest/setup.ts"],"sourcesContent":[null],"names":["globalFunctionRegistry","serve"],"mappings":"kIAWA;;AAEG;AACI,eAAe,qBAAqB,CACvC,OAAgB,EAChB,GAAY,EACZ,gBAA2B,EAC3B,MAAe,EAAA;AAEf,IAAA,IAAI;;QAEA,MAAM,aAAa,GAAG,gBAAgB,CAAC,GAAG,CAAU,gBAAgB,CAAC,CAAC;AACtE,QAAA,MAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;;;AAIjE,QAAA,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,oBAAoB,CAAC;AACxD,YAAA,SAAS,EAAE,gBAAgB;AAC3B,YAAA,OAAO,EAAE,aAAa;AACtB,YAAA,QAAQ,EAAE,EAAE;AACf,SAAA,CAAC,CAAC;AAEH,QAAA,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;YAC7B,MAAM,CAAC,IAAI,CAAC,CAAA,SAAA,EAAY,gBAAgB,CAAC,MAAM,CAAwC,sCAAA,CAAA,CAAC,CAAC;;YAGzF,MAAM,WAAW,GAAG,gBAAgB;iBAC/B,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;iBAC3B,GAAG,CAAC,CAAC,EAAE,MAAM,OAAO,EAAE,CAAC,EAAE,KAAK,UAAU,GAAG,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;iBAC5D,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,YAAA,MAAM,CAAC,KAAK,CAAC,kCAAkC,WAAW,CAAA,CAAE,CAAC,CAAC;;AAG9D,YAAA,MAAM,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;AACzE,YAAA,IAAI;AACA,gBAAAA,8CAAsB,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;gBAClD,MAAM,CAAC,IAAI,CAAC,CAAA,aAAA,EAAgBA,8CAAsB,CAAC,KAAK,CAA2C,yCAAA,CAAA,CAAC,CAAC;AACrG,gBAAA,MAAM,CAAC,IAAI,CAAC,sFAAsF,CAAC,CAAC;aACvG;YAAC,OAAO,aAAa,EAAE;AACpB,gBAAA,MAAM,CAAC,KAAK,CAAC,qDAAqD,EAAE,aAAa,CAAC,CAAC;aACtF;;AAGD,YAAA,MAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;YACjE,MAAM,cAAc,GAAGC,aAAK,CAAC;AACzB,gBAAA,MAAM,EAAE,aAAa;AACrB,gBAAA,SAAS,EAAE,gBAAgB;AAC9B,aAAA,CAAC,CAAC;AACH,YAAA,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;AAEhD,YAAA,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,CAAA,kDAAA,EAAqD,gBAAgB,CAAC,MAAM,CAAY,UAAA,CAAA,CAAC,CAAC;SACzG;aAAM;AACH,YAAA,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;SACtE;KACJ;IAAC,OAAO,KAAK,EAAE;AACZ,QAAA,MAAM,CAAC,IAAI,CAAC,sCAAsC,EAAE,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACrF,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,EAAE,KAAK,IAAI,KAAK,CAAC,CAAC;AACzD,QAAA,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AACpC,YAAA,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;SACnD;KACJ;AACL"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Express } from 'express';
|
|
2
|
+
import { Container } from 'inversify';
|
|
3
|
+
import { CdmLogger } from '@cdm-logger/core';
|
|
4
|
+
import { Feature } from '@common-stack/server-core';
|
|
5
|
+
type ILogger = CdmLogger.ILogger;
|
|
6
|
+
/**
|
|
7
|
+
* Sets up Inngest functions from the Feature system and registers the handler
|
|
8
|
+
*/
|
|
9
|
+
export declare function setupInngestFunctions(modules: Feature, app: Express, serviceContainer: Container, logger: ILogger): Promise<void>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {serve}from'inngest/express';import {globalFunctionRegistry}from'./middleware/function-reference-helper.mjs';/**
|
|
2
|
+
* Sets up Inngest functions from the Feature system and registers the handler
|
|
3
|
+
*/
|
|
4
|
+
async function setupInngestFunctions(modules, app, serviceContainer, logger) {
|
|
5
|
+
try {
|
|
6
|
+
// Get Inngest client from the container (already bound in infraModule)
|
|
7
|
+
const inngestClient = serviceContainer.get('INNGEST_CLIENT');
|
|
8
|
+
logger.info('✅ Retrieved Inngest client from service container');
|
|
9
|
+
// Load Inngest functions from all modules
|
|
10
|
+
// The improved loadInngestFunctions now handles both array and object returns
|
|
11
|
+
const inngestFunctions = await modules.loadInngestFunctions({
|
|
12
|
+
container: serviceContainer,
|
|
13
|
+
inngest: inngestClient,
|
|
14
|
+
settings: {},
|
|
15
|
+
});
|
|
16
|
+
if (inngestFunctions.length > 0) {
|
|
17
|
+
logger.info(`✅ Loaded ${inngestFunctions.length} Inngest functions from Feature system`);
|
|
18
|
+
// Log function IDs for debugging
|
|
19
|
+
const functionIds = inngestFunctions
|
|
20
|
+
.filter((fn) => fn && fn.id)
|
|
21
|
+
.map((fn) => (typeof fn.id === 'function' ? fn.id() : fn.id))
|
|
22
|
+
.join(', ');
|
|
23
|
+
logger.debug(`Registering Inngest functions: ${functionIds}`);
|
|
24
|
+
// ✨ Register functions with global registry for referenceFunction() helper
|
|
25
|
+
logger.info('📝 Registering functions with global function registry...');
|
|
26
|
+
try {
|
|
27
|
+
globalFunctionRegistry.register(inngestFunctions);
|
|
28
|
+
logger.info(`✅ Registered ${globalFunctionRegistry.count} functions for referenceFunction() helper`);
|
|
29
|
+
logger.info('💡 You can now use: referenceFunction("function-id") or auto-invoke in step.invoke()');
|
|
30
|
+
}
|
|
31
|
+
catch (registryError) {
|
|
32
|
+
logger.error('❌ Error registering functions with global registry:', registryError);
|
|
33
|
+
}
|
|
34
|
+
// Register Inngest handler
|
|
35
|
+
logger.info('📞 Calling serve() to register Inngest handler...');
|
|
36
|
+
const inngestHandler = serve({
|
|
37
|
+
client: inngestClient,
|
|
38
|
+
functions: inngestFunctions,
|
|
39
|
+
});
|
|
40
|
+
logger.info('✅ serve() completed successfully');
|
|
41
|
+
app.use('/api/inngest', inngestHandler);
|
|
42
|
+
logger.info(`✅ Inngest handler registered at /api/inngest with ${inngestFunctions.length} functions`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
logger.info('No Inngest functions found - handler not registered');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
logger.warn('Inngest handler registration failed:', error?.message || String(error));
|
|
50
|
+
logger.debug('Full error stack:', error?.stack || error);
|
|
51
|
+
if (error && typeof error === 'object') {
|
|
52
|
+
logger.debug('Error keys:', Object.keys(error));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}export{setupInngestFunctions};//# sourceMappingURL=setup.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.mjs","sources":["../../src/inngest/setup.ts"],"sourcesContent":[null],"names":[],"mappings":"oHAWA;;AAEG;AACI,eAAe,qBAAqB,CACvC,OAAgB,EAChB,GAAY,EACZ,gBAA2B,EAC3B,MAAe,EAAA;AAEf,IAAA,IAAI;;QAEA,MAAM,aAAa,GAAG,gBAAgB,CAAC,GAAG,CAAU,gBAAgB,CAAC,CAAC;AACtE,QAAA,MAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;;;AAIjE,QAAA,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,oBAAoB,CAAC;AACxD,YAAA,SAAS,EAAE,gBAAgB;AAC3B,YAAA,OAAO,EAAE,aAAa;AACtB,YAAA,QAAQ,EAAE,EAAE;AACf,SAAA,CAAC,CAAC;AAEH,QAAA,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;YAC7B,MAAM,CAAC,IAAI,CAAC,CAAA,SAAA,EAAY,gBAAgB,CAAC,MAAM,CAAwC,sCAAA,CAAA,CAAC,CAAC;;YAGzF,MAAM,WAAW,GAAG,gBAAgB;iBAC/B,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;iBAC3B,GAAG,CAAC,CAAC,EAAE,MAAM,OAAO,EAAE,CAAC,EAAE,KAAK,UAAU,GAAG,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;iBAC5D,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,YAAA,MAAM,CAAC,KAAK,CAAC,kCAAkC,WAAW,CAAA,CAAE,CAAC,CAAC;;AAG9D,YAAA,MAAM,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;AACzE,YAAA,IAAI;AACA,gBAAA,sBAAsB,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;gBAClD,MAAM,CAAC,IAAI,CAAC,CAAA,aAAA,EAAgB,sBAAsB,CAAC,KAAK,CAA2C,yCAAA,CAAA,CAAC,CAAC;AACrG,gBAAA,MAAM,CAAC,IAAI,CAAC,sFAAsF,CAAC,CAAC;aACvG;YAAC,OAAO,aAAa,EAAE;AACpB,gBAAA,MAAM,CAAC,KAAK,CAAC,qDAAqD,EAAE,aAAa,CAAC,CAAC;aACtF;;AAGD,YAAA,MAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;YACjE,MAAM,cAAc,GAAG,KAAK,CAAC;AACzB,gBAAA,MAAM,EAAE,aAAa;AACrB,gBAAA,SAAS,EAAE,gBAAgB;AAC9B,aAAA,CAAC,CAAC;AACH,YAAA,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;AAEhD,YAAA,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,CAAA,kDAAA,EAAqD,gBAAgB,CAAC,MAAM,CAAY,UAAA,CAAA,CAAC,CAAC;SACzG;aAAM;AACH,YAAA,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;SACtE;KACJ;IAAC,OAAO,KAAK,EAAE;AACZ,QAAA,MAAM,CAAC,IAAI,CAAC,sCAAsC,EAAE,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACrF,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,EAAE,KAAK,IAAI,KAAK,CAAC,CAAC;AACzD,QAAA,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AACpC,YAAA,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;SACnD;KACJ;AACL"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ServiceBroker } from 'moleculer';
|
|
2
|
+
export type GraphqlRequestContext = {
|
|
3
|
+
overallCachePolicy: {
|
|
4
|
+
scope: string;
|
|
5
|
+
maxAge: number;
|
|
6
|
+
};
|
|
7
|
+
user: {
|
|
8
|
+
sub: string;
|
|
9
|
+
};
|
|
10
|
+
req: {
|
|
11
|
+
currentPageUriSegments: {
|
|
12
|
+
authority: string;
|
|
13
|
+
};
|
|
14
|
+
tenant?: string;
|
|
15
|
+
};
|
|
16
|
+
queriesToInvalidate: string[];
|
|
17
|
+
tenantId?: string;
|
|
18
|
+
accountId?: string;
|
|
19
|
+
moleculerBroker?: ServiceBroker;
|
|
20
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { redisClientMiddleware } from './redis-client';
|
|
2
|
+
export { contextServicesMiddleware } from './services';
|
|
3
|
+
export { corsMiddleware } from './cors';
|
|
4
|
+
export { errorMiddleware } from './error';
|
|
5
|
+
export { sentryMiddleware, sentryErrorHandlerMiddleware } from './sentry';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';/**
|
|
2
|
+
* Redis Client Middleware
|
|
3
|
+
*
|
|
4
|
+
* This middleware attaches the Redis client to the request object,
|
|
5
|
+
* making it available for session storage and other Redis operations.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Creates middleware that attaches Redis client to request object
|
|
9
|
+
* @param redisClient - The Redis client instance
|
|
10
|
+
* @returns Express middleware function
|
|
11
|
+
*/
|
|
12
|
+
function redisClientMiddleware(redisClient) {
|
|
13
|
+
return (req, res, next) => {
|
|
14
|
+
// Attach Redis client to request object
|
|
15
|
+
req.redisClient = redisClient;
|
|
16
|
+
next();
|
|
17
|
+
};
|
|
18
|
+
}exports.redisClientMiddleware=redisClientMiddleware;//# sourceMappingURL=redis-client.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-client.cjs","sources":["../../src/middleware/redis-client.ts"],"sourcesContent":[null],"names":[],"mappings":"aAAA;;;;;AAKG;AAQH;;;;AAIG;AACG,SAAU,qBAAqB,CAAC,WAAgB,EAAA;AAClD,IAAA,OAAO,CAAC,GAAuB,EAAE,GAAa,EAAE,IAAkB,KAAI;;AAElE,QAAA,GAAG,CAAC,WAAW,GAAG,WAAW,CAAC;AAC9B,QAAA,IAAI,EAAE,CAAC;AACX,KAAC,CAAC;AACN"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redis Client Middleware
|
|
3
|
+
*
|
|
4
|
+
* This middleware attaches the Redis client to the request object,
|
|
5
|
+
* making it available for session storage and other Redis operations.
|
|
6
|
+
*/
|
|
7
|
+
import { Request, Response, NextFunction } from 'express';
|
|
8
|
+
export interface RedisClientRequest extends Request {
|
|
9
|
+
redisClient?: any;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates middleware that attaches Redis client to request object
|
|
13
|
+
* @param redisClient - The Redis client instance
|
|
14
|
+
* @returns Express middleware function
|
|
15
|
+
*/
|
|
16
|
+
export declare function redisClientMiddleware(redisClient: any): (req: RedisClientRequest, res: Response, next: NextFunction) => void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redis Client Middleware
|
|
3
|
+
*
|
|
4
|
+
* This middleware attaches the Redis client to the request object,
|
|
5
|
+
* making it available for session storage and other Redis operations.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Creates middleware that attaches Redis client to request object
|
|
9
|
+
* @param redisClient - The Redis client instance
|
|
10
|
+
* @returns Express middleware function
|
|
11
|
+
*/
|
|
12
|
+
function redisClientMiddleware(redisClient) {
|
|
13
|
+
return (req, res, next) => {
|
|
14
|
+
// Attach Redis client to request object
|
|
15
|
+
req.redisClient = redisClient;
|
|
16
|
+
next();
|
|
17
|
+
};
|
|
18
|
+
}export{redisClientMiddleware};//# sourceMappingURL=redis-client.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-client.mjs","sources":["../../src/middleware/redis-client.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;AAKG;AAQH;;;;AAIG;AACG,SAAU,qBAAqB,CAAC,WAAgB,EAAA;AAClD,IAAA,OAAO,CAAC,GAAuB,EAAE,GAAa,EAAE,IAAkB,KAAI;;AAElE,QAAA,GAAG,CAAC,WAAW,GAAG,WAAW,CAAC;AAC9B,QAAA,IAAI,EAAE,CAAC;AACX,KAAC,CAAC;AACN"}
|
package/lib/plugins/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict';var envConfig=require('../config/env-config.cjs');const invalidateCachePlugin = ({ cache: redisClient, invalidateCacheKeyGenerator, }) => ({
|
|
1
|
+
'use strict';var _=require('lodash-es'),serverCore=require('@common-stack/server-core'),envConfig=require('../config/env-config.cjs');const invalidateCachePlugin = ({ cache: redisClient, invalidateCacheKeyGenerator, }) => ({
|
|
2
2
|
requestDidStart(requestContext) {
|
|
3
3
|
return {
|
|
4
4
|
willSendResponse: async (responseContext) => {
|
|
@@ -8,26 +8,49 @@
|
|
|
8
8
|
}
|
|
9
9
|
try {
|
|
10
10
|
const hasErrors = !!requestContext.errors?.length;
|
|
11
|
-
const {
|
|
11
|
+
const { schema } = requestContext;
|
|
12
|
+
const { queriesToInvalidate, user, req } = requestContext.contextValue;
|
|
13
|
+
const tenantId = serverCore.extractTenantId(req?.currentPageUriSegments?.authority);
|
|
12
14
|
const [{ operation }] = responseContext.document.definitions;
|
|
13
15
|
const isMutation = operation === 'mutation';
|
|
14
16
|
if (hasErrors || !queriesToInvalidate?.length || !isMutation) {
|
|
15
17
|
return;
|
|
16
18
|
}
|
|
17
|
-
// this to get the
|
|
18
19
|
const nestedKeys = await Promise.all(queriesToInvalidate.map(async (query) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
// Build keys in order of specificity
|
|
21
|
+
let keys = [];
|
|
22
|
+
const cachePolicy = serverCore.getDirectiveArgsFromSchema({
|
|
23
|
+
schema,
|
|
24
|
+
queryName: query,
|
|
25
|
+
directiveName: serverCore.CACHE_CONTROL_DIRECTIVE,
|
|
26
|
+
});
|
|
27
|
+
const isPrivate = cachePolicy.scope?.toLowerCase() === 'private';
|
|
28
|
+
// Add tenant-specific key if tenant exists
|
|
29
|
+
if (tenantId) {
|
|
30
|
+
keys.push(`${envConfig.config.APP_NAME}:${tenantId}:${query}:*`);
|
|
31
|
+
// Add user-specific key if user exists
|
|
32
|
+
if (user?.sub && isPrivate) {
|
|
33
|
+
keys.push(`${envConfig.config.APP_NAME}:${tenantId}:${user.sub}:${query}:*`);
|
|
24
34
|
}
|
|
25
35
|
}
|
|
26
|
-
|
|
36
|
+
// Add global key as fallback
|
|
37
|
+
keys.push(`${envConfig.config.APP_NAME}:${query}:*`);
|
|
38
|
+
// Allow custom key generation if provided
|
|
39
|
+
if (typeof invalidateCacheKeyGenerator === 'function') {
|
|
40
|
+
keys = keys.map((key) => invalidateCacheKeyGenerator(requestContext, responseContext, key));
|
|
41
|
+
}
|
|
42
|
+
const matchedKeys = await Promise.all(keys.map(async (key) => {
|
|
43
|
+
const matchingKeys = await redisClient.keys(key);
|
|
44
|
+
if (matchingKeys.length) {
|
|
45
|
+
return matchingKeys;
|
|
46
|
+
}
|
|
47
|
+
return [];
|
|
48
|
+
}));
|
|
49
|
+
return matchedKeys.flat();
|
|
27
50
|
}));
|
|
28
51
|
const keys = nestedKeys.flat();
|
|
29
52
|
if (keys?.length) {
|
|
30
|
-
await redisClient.del(keys);
|
|
53
|
+
await redisClient.del(_.uniq(keys));
|
|
31
54
|
}
|
|
32
55
|
}
|
|
33
56
|
catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invalidateCachePlugin.cjs","sources":["../../src/plugins/invalidateCachePlugin.ts"],"sourcesContent":[null],"names":["config"],"mappings":"
|
|
1
|
+
{"version":3,"file":"invalidateCachePlugin.cjs","sources":["../../src/plugins/invalidateCachePlugin.ts"],"sourcesContent":[null],"names":["extractTenantId","getDirectiveArgsFromSchema","CACHE_CONTROL_DIRECTIVE","config","uniq"],"mappings":"sIAcO,MAAM,qBAAqB,GAAG,CAAC,EAClC,KAAK,EAAE,WAAW,EAClB,2BAA2B,GAI9B,MACI;AACG,IAAA,eAAe,CAAC,cAA4D,EAAA;QACxE,OAAO;AACH,YAAA,gBAAgB,EAAE,OAAO,eAA+D,KAAI;;gBAExF,IAAI,CAAC,cAAc,EAAE;oBACjB,OAAO;iBACV;AACD,gBAAA,IAAI;oBACA,MAAM,SAAS,GAAG,CAAC,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC;AAClD,oBAAA,MAAM,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC;oBAClC,MAAM,EAAE,mBAAmB,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,cAAc,CAAC,YAAY,CAAC;oBACvE,MAAM,QAAQ,GAAGA,0BAAe,CAAC,GAAG,EAAE,sBAAsB,EAAE,SAAS,CAAC,CAAC;oBACzE,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,WAAwC,CAAC;AAC1F,oBAAA,MAAM,UAAU,GAAG,SAAS,KAAK,UAAU,CAAC;oBAC5C,IAAI,SAAS,IAAI,CAAC,mBAAmB,EAAE,MAAM,IAAI,CAAC,UAAU,EAAE;wBAC1D,OAAO;qBACV;AAED,oBAAA,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAChC,mBAAmB,CAAC,GAAG,CAAC,OAAO,KAAa,KAAI;;wBAE5C,IAAI,IAAI,GAAa,EAAE,CAAC;wBACxB,MAAM,WAAW,GAAsBC,qCAA0B,CAAC;4BAC9D,MAAM;AACN,4BAAA,SAAS,EAAE,KAAK;AAChB,4BAAA,aAAa,EAAEC,kCAAuB;AACzC,yBAAA,CAAC,CAAC;wBACH,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,SAAS,CAAC;;wBAEjE,IAAI,QAAQ,EAAE;AACV,4BAAA,IAAI,CAAC,IAAI,CAAC,CAAA,EAAGC,gBAAM,CAAC,QAAQ,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,EAAI,KAAK,CAAA,EAAA,CAAI,CAAC,CAAC;;AAEvD,4BAAA,IAAI,IAAI,EAAE,GAAG,IAAI,SAAS,EAAE;AACxB,gCAAA,IAAI,CAAC,IAAI,CAAC,CAAG,EAAAA,gBAAM,CAAC,QAAQ,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,EAAI,IAAI,CAAC,GAAG,IAAI,KAAK,CAAA,EAAA,CAAI,CAAC,CAAC;6BACtE;yBACJ;;wBAED,IAAI,CAAC,IAAI,CAAC,CAAG,EAAAA,gBAAM,CAAC,QAAQ,CAAI,CAAA,EAAA,KAAK,CAAI,EAAA,CAAA,CAAC,CAAC;;AAG3C,wBAAA,IAAI,OAAO,2BAA2B,KAAK,UAAU,EAAE;AACnD,4BAAA,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,KAChB,2BAA2B,CAAC,cAAc,EAAE,eAAe,EAAE,GAAG,CAAC,CACpE,CAAC;yBACL;AACD,wBAAA,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CACjC,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,KAAI;4BACnB,MAAM,YAAY,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACjD,4BAAA,IAAI,YAAY,CAAC,MAAM,EAAE;AACrB,gCAAA,OAAO,YAAY,CAAC;6BACvB;AACD,4BAAA,OAAO,EAAE,CAAC;yBACb,CAAC,CACL,CAAC;AACF,wBAAA,OAAO,WAAW,CAAC,IAAI,EAAE,CAAC;qBAC7B,CAAC,CACL,CAAC;AACF,oBAAA,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;AAC/B,oBAAA,IAAI,IAAI,EAAE,MAAM,EAAE;wBACd,MAAM,WAAW,CAAC,GAAG,CAACC,MAAI,CAAC,IAAI,CAAC,CAAC,CAAC;qBACrC;iBACJ;gBAAC,OAAO,CAAC,EAAE;AACR,oBAAA,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;AACvE,oBAAA,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;iBAClC;aACJ;SACJ,CAAC;KACL;AACJ,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {config}from'../config/env-config.mjs';const invalidateCachePlugin = ({ cache: redisClient, invalidateCacheKeyGenerator, }) => ({
|
|
1
|
+
import {uniq}from'lodash-es';import {extractTenantId,getDirectiveArgsFromSchema,CACHE_CONTROL_DIRECTIVE}from'@common-stack/server-core';import {config}from'../config/env-config.mjs';const invalidateCachePlugin = ({ cache: redisClient, invalidateCacheKeyGenerator, }) => ({
|
|
2
2
|
requestDidStart(requestContext) {
|
|
3
3
|
return {
|
|
4
4
|
willSendResponse: async (responseContext) => {
|
|
@@ -8,26 +8,49 @@ import {config}from'../config/env-config.mjs';const invalidateCachePlugin = ({ c
|
|
|
8
8
|
}
|
|
9
9
|
try {
|
|
10
10
|
const hasErrors = !!requestContext.errors?.length;
|
|
11
|
-
const {
|
|
11
|
+
const { schema } = requestContext;
|
|
12
|
+
const { queriesToInvalidate, user, req } = requestContext.contextValue;
|
|
13
|
+
const tenantId = extractTenantId(req?.currentPageUriSegments?.authority);
|
|
12
14
|
const [{ operation }] = responseContext.document.definitions;
|
|
13
15
|
const isMutation = operation === 'mutation';
|
|
14
16
|
if (hasErrors || !queriesToInvalidate?.length || !isMutation) {
|
|
15
17
|
return;
|
|
16
18
|
}
|
|
17
|
-
// this to get the
|
|
18
19
|
const nestedKeys = await Promise.all(queriesToInvalidate.map(async (query) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
// Build keys in order of specificity
|
|
21
|
+
let keys = [];
|
|
22
|
+
const cachePolicy = getDirectiveArgsFromSchema({
|
|
23
|
+
schema,
|
|
24
|
+
queryName: query,
|
|
25
|
+
directiveName: CACHE_CONTROL_DIRECTIVE,
|
|
26
|
+
});
|
|
27
|
+
const isPrivate = cachePolicy.scope?.toLowerCase() === 'private';
|
|
28
|
+
// Add tenant-specific key if tenant exists
|
|
29
|
+
if (tenantId) {
|
|
30
|
+
keys.push(`${config.APP_NAME}:${tenantId}:${query}:*`);
|
|
31
|
+
// Add user-specific key if user exists
|
|
32
|
+
if (user?.sub && isPrivate) {
|
|
33
|
+
keys.push(`${config.APP_NAME}:${tenantId}:${user.sub}:${query}:*`);
|
|
24
34
|
}
|
|
25
35
|
}
|
|
26
|
-
|
|
36
|
+
// Add global key as fallback
|
|
37
|
+
keys.push(`${config.APP_NAME}:${query}:*`);
|
|
38
|
+
// Allow custom key generation if provided
|
|
39
|
+
if (typeof invalidateCacheKeyGenerator === 'function') {
|
|
40
|
+
keys = keys.map((key) => invalidateCacheKeyGenerator(requestContext, responseContext, key));
|
|
41
|
+
}
|
|
42
|
+
const matchedKeys = await Promise.all(keys.map(async (key) => {
|
|
43
|
+
const matchingKeys = await redisClient.keys(key);
|
|
44
|
+
if (matchingKeys.length) {
|
|
45
|
+
return matchingKeys;
|
|
46
|
+
}
|
|
47
|
+
return [];
|
|
48
|
+
}));
|
|
49
|
+
return matchedKeys.flat();
|
|
27
50
|
}));
|
|
28
51
|
const keys = nestedKeys.flat();
|
|
29
52
|
if (keys?.length) {
|
|
30
|
-
await redisClient.del(keys);
|
|
53
|
+
await redisClient.del(uniq(keys));
|
|
31
54
|
}
|
|
32
55
|
}
|
|
33
56
|
catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invalidateCachePlugin.mjs","sources":["../../src/plugins/invalidateCachePlugin.ts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"invalidateCachePlugin.mjs","sources":["../../src/plugins/invalidateCachePlugin.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';var serverCore=require('@common-stack/server-core'),_=require('lodash-es'),apolloCachePlugin=require('@apollo/server-plugin-response-cache');const cachePlugin = apolloCachePlugin.default ?? apolloCachePlugin;
|
|
2
|
+
const isCacheable = (requestContext) => {
|
|
3
|
+
const { document, schema } = requestContext;
|
|
4
|
+
const cache = serverCore.getDirectiveArgsFromSchema({
|
|
5
|
+
schema,
|
|
6
|
+
document,
|
|
7
|
+
directiveName: serverCore.CACHE_CONTROL_DIRECTIVE,
|
|
8
|
+
});
|
|
9
|
+
if (!cache)
|
|
10
|
+
return false;
|
|
11
|
+
if (cache.scope && !cache.maxAge) {
|
|
12
|
+
cache.maxAge = 86400;
|
|
13
|
+
}
|
|
14
|
+
if (!requestContext.overallCachePolicy) {
|
|
15
|
+
// eslint-disable-next-line no-param-reassign
|
|
16
|
+
// to support test cases
|
|
17
|
+
requestContext.overallCachePolicy = {};
|
|
18
|
+
}
|
|
19
|
+
// eslint-disable-next-line no-param-reassign
|
|
20
|
+
requestContext.overallCachePolicy.maxAge = cache.maxAge;
|
|
21
|
+
return cache.maxAge > 0;
|
|
22
|
+
};
|
|
23
|
+
const generateCacheKey = ({ logger, cacheKeyGenerator }) => (requestContext) => {
|
|
24
|
+
if (!isCacheable(requestContext)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const { request, contextValue, document, schema } = requestContext;
|
|
28
|
+
const { user, req } = contextValue ?? {};
|
|
29
|
+
const { query, variables } = request;
|
|
30
|
+
const cacheControlDirective = serverCore.getDirectiveArgsFromSchema({
|
|
31
|
+
schema,
|
|
32
|
+
document,
|
|
33
|
+
directiveName: serverCore.CACHE_CONTROL_DIRECTIVE,
|
|
34
|
+
});
|
|
35
|
+
const { scope } = cacheControlDirective ?? {};
|
|
36
|
+
const isPrivate = scope?.toLowerCase() === 'private';
|
|
37
|
+
const tenantId = req.tenant ?? serverCore.extractTenantId(req?.currentPageUriSegments?.authority);
|
|
38
|
+
const cacheKey = serverCore.generateQueryCacheKey({
|
|
39
|
+
query,
|
|
40
|
+
variables,
|
|
41
|
+
logger,
|
|
42
|
+
userId: isPrivate ? user?.sub || null : null,
|
|
43
|
+
tenantId,
|
|
44
|
+
});
|
|
45
|
+
try {
|
|
46
|
+
if (typeof cacheKeyGenerator === 'function') {
|
|
47
|
+
const generatedKey = cacheKeyGenerator(requestContext, cacheKey);
|
|
48
|
+
return generatedKey || cacheKey;
|
|
49
|
+
}
|
|
50
|
+
return cacheKey;
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
console.warn('GenerateCacheKey Failed %s', e.message);
|
|
54
|
+
return cacheKey;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const responseCachePlugin = ({ logger, cacheKeyGenerator }) => cachePlugin({
|
|
58
|
+
sessionId: ({ contextValue }) => Promise.resolve(contextValue?.user?.sub ?? null),
|
|
59
|
+
generateCacheKey: generateCacheKey({ logger, cacheKeyGenerator }),
|
|
60
|
+
shouldWriteToCache: (ctx) =>
|
|
61
|
+
// Cache only successful responses
|
|
62
|
+
isCacheable(ctx) && _.isEmpty(ctx?.response?.body?.singleResult.errors),
|
|
63
|
+
});exports.generateCacheKey=generateCacheKey;exports.isCacheable=isCacheable;exports.responseCachePlugin=responseCachePlugin;//# sourceMappingURL=responseCachePlugin.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"responseCachePlugin.cjs","sources":["../../src/plugins/responseCachePlugin.ts"],"sourcesContent":[null],"names":["getDirectiveArgsFromSchema","CACHE_CONTROL_DIRECTIVE","extractTenantId","generateQueryCacheKey","isEmpty"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GraphQLRequestContext } from '@apollo/server';
|
|
2
|
+
import { ILogger } from '@cdm-logger/core/lib/interface';
|
|
3
|
+
import { GraphqlRequestContext } from '../interfaces';
|
|
4
|
+
import { KeyGenerator } from '../servers/GraphqlServer';
|
|
5
|
+
type ApolloCachePluginOptions = {
|
|
6
|
+
logger: ILogger;
|
|
7
|
+
cacheKeyGenerator: KeyGenerator;
|
|
8
|
+
};
|
|
9
|
+
export declare const isCacheable: (requestContext: GraphQLRequestContext<GraphqlRequestContext>) => boolean;
|
|
10
|
+
export declare const generateCacheKey: ({ logger, cacheKeyGenerator }: ApolloCachePluginOptions) => (requestContext: GraphQLRequestContext<GraphqlRequestContext>) => string;
|
|
11
|
+
export declare const responseCachePlugin: ({ logger, cacheKeyGenerator }: ApolloCachePluginOptions) => any;
|
|
12
|
+
export {};
|