@enfyra/mcp-server 0.1.69 → 0.1.71
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/README.md +1 -1
- package/dist/lib/config-local-adapters.d.ts +18 -0
- package/dist/lib/config-local-adapters.js +271 -0
- package/dist/lib/config-local-adapters.js.map +1 -0
- package/dist/lib/config-local-contracts.d.ts +28 -0
- package/dist/lib/config-local-contracts.js +200 -0
- package/dist/lib/config-local-contracts.js.map +1 -0
- package/dist/lib/config-local-prompts.d.ts +10 -0
- package/dist/lib/config-local-prompts.js +185 -0
- package/dist/lib/config-local-prompts.js.map +1 -0
- package/dist/lib/config-local-types.d.ts +23 -0
- package/dist/lib/config-local-types.js +2 -0
- package/dist/lib/config-local-types.js.map +1 -0
- package/dist/lib/config-local.js +3 -649
- package/dist/lib/config-local.js.map +1 -1
- package/dist/lib/discovery-tools.d.ts +4 -0
- package/dist/lib/discovery-tools.js +546 -0
- package/dist/lib/discovery-tools.js.map +1 -0
- package/dist/lib/dynamic-repository-builder.d.ts +1 -1
- package/dist/lib/dynamic-script-context-contract.d.ts +100 -0
- package/dist/lib/dynamic-script-context-contract.js +163 -0
- package/dist/lib/dynamic-script-context-contract.js.map +1 -0
- package/dist/lib/enfyra-mcp-server.d.ts +3 -0
- package/dist/lib/enfyra-mcp-server.js +79 -0
- package/dist/lib/enfyra-mcp-server.js.map +1 -0
- package/dist/lib/enfyra-tool-logic.d.ts +7 -0
- package/dist/lib/enfyra-tool-logic.js +8 -0
- package/dist/lib/enfyra-tool-logic.js.map +1 -0
- package/dist/lib/enfyra-tool-types.d.ts +27 -0
- package/dist/lib/enfyra-tool-types.js +2 -0
- package/dist/lib/enfyra-tool-types.js.map +1 -0
- package/dist/lib/extension-api-builders.d.ts +17 -0
- package/dist/lib/extension-api-builders.js +235 -0
- package/dist/lib/extension-api-builders.js.map +1 -0
- package/dist/lib/extension-component-builders.d.ts +87 -0
- package/dist/lib/extension-component-builders.js +623 -0
- package/dist/lib/extension-component-builders.js.map +1 -0
- package/dist/lib/extension-contract-review.d.ts +26 -0
- package/dist/lib/extension-contract-review.js +187 -0
- package/dist/lib/extension-contract-review.js.map +1 -0
- package/dist/lib/extension-theme-contract.d.ts +63 -0
- package/dist/lib/extension-theme-contract.js +417 -0
- package/dist/lib/extension-theme-contract.js.map +1 -0
- package/dist/lib/identity-tools.d.ts +4 -0
- package/dist/lib/identity-tools.js +46 -0
- package/dist/lib/identity-tools.js.map +1 -0
- package/dist/lib/log-tools.d.ts +4 -0
- package/dist/lib/log-tools.js +65 -0
- package/dist/lib/log-tools.js.map +1 -0
- package/dist/lib/mcp-example-connect.d.ts +9 -0
- package/dist/lib/mcp-example-connect.js +442 -0
- package/dist/lib/mcp-example-connect.js.map +1 -0
- package/dist/lib/mcp-example-extensions.d.ts +9 -0
- package/dist/lib/mcp-example-extensions.js +729 -0
- package/dist/lib/mcp-example-extensions.js.map +1 -0
- package/dist/lib/mcp-example-files.d.ts +9 -0
- package/dist/lib/mcp-example-files.js +51 -0
- package/dist/lib/mcp-example-files.js.map +1 -0
- package/dist/lib/mcp-example-flows.d.ts +9 -0
- package/dist/lib/mcp-example-flows.js +76 -0
- package/dist/lib/mcp-example-flows.js.map +1 -0
- package/dist/lib/mcp-example-graphql.d.ts +9 -0
- package/dist/lib/mcp-example-graphql.js +57 -0
- package/dist/lib/mcp-example-graphql.js.map +1 -0
- package/dist/lib/mcp-example-handlers-hooks.d.ts +9 -0
- package/dist/lib/mcp-example-handlers-hooks.js +328 -0
- package/dist/lib/mcp-example-handlers-hooks.js.map +1 -0
- package/dist/lib/mcp-example-oauth-setup.d.ts +9 -0
- package/dist/lib/mcp-example-oauth-setup.js +41 -0
- package/dist/lib/mcp-example-oauth-setup.js.map +1 -0
- package/dist/lib/mcp-example-permissions-rls.d.ts +9 -0
- package/dist/lib/mcp-example-permissions-rls.js +210 -0
- package/dist/lib/mcp-example-permissions-rls.js.map +1 -0
- package/dist/lib/mcp-example-queries-deep.d.ts +9 -0
- package/dist/lib/mcp-example-queries-deep.js +220 -0
- package/dist/lib/mcp-example-queries-deep.js.map +1 -0
- package/dist/lib/mcp-example-schema-relations.d.ts +9 -0
- package/dist/lib/mcp-example-schema-relations.js +148 -0
- package/dist/lib/mcp-example-schema-relations.js.map +1 -0
- package/dist/lib/mcp-example-websocket.d.ts +9 -0
- package/dist/lib/mcp-example-websocket.js +103 -0
- package/dist/lib/mcp-example-websocket.js.map +1 -0
- package/dist/lib/mcp-examples.d.ts +5 -5
- package/dist/lib/mcp-examples.js +22 -2394
- package/dist/lib/mcp-examples.js.map +1 -1
- package/dist/lib/method-tools.d.ts +4 -0
- package/dist/lib/method-tools.js +217 -0
- package/dist/lib/method-tools.js.map +1 -0
- package/dist/lib/package-tools.d.ts +4 -0
- package/dist/lib/package-tools.js +98 -0
- package/dist/lib/package-tools.js.map +1 -0
- package/dist/lib/platform-data-operations.d.ts +24 -0
- package/dist/lib/platform-data-operations.js +71 -0
- package/dist/lib/platform-data-operations.js.map +1 -0
- package/dist/lib/platform-endpoint-workflow.d.ts +42 -0
- package/dist/lib/platform-endpoint-workflow.js +382 -0
- package/dist/lib/platform-endpoint-workflow.js.map +1 -0
- package/dist/lib/platform-extension-source.d.ts +487 -0
- package/dist/lib/platform-extension-source.js +524 -0
- package/dist/lib/platform-extension-source.js.map +1 -0
- package/dist/lib/platform-extension-tools.d.ts +1 -0
- package/dist/lib/platform-extension-tools.js +416 -0
- package/dist/lib/platform-extension-tools.js.map +1 -0
- package/dist/lib/platform-extension-ui.d.ts +4 -0
- package/dist/lib/platform-extension-ui.js +5 -0
- package/dist/lib/platform-extension-ui.js.map +1 -0
- package/dist/lib/platform-extension-workflow.d.ts +54 -0
- package/dist/lib/platform-extension-workflow.js +194 -0
- package/dist/lib/platform-extension-workflow.js.map +1 -0
- package/dist/lib/platform-flow-operations.d.ts +554 -0
- package/dist/lib/platform-flow-operations.js +317 -0
- package/dist/lib/platform-flow-operations.js.map +1 -0
- package/dist/lib/platform-flow-tools.d.ts +1 -0
- package/dist/lib/platform-flow-tools.js +248 -0
- package/dist/lib/platform-flow-tools.js.map +1 -0
- package/dist/lib/platform-operation-logic.d.ts +10 -0
- package/dist/lib/platform-operation-logic.js +11 -0
- package/dist/lib/platform-operation-logic.js.map +1 -0
- package/dist/lib/platform-operation-tools.d.ts +1 -324
- package/dist/lib/platform-operation-tools.js +13 -4620
- package/dist/lib/platform-operation-tools.js.map +1 -1
- package/dist/lib/platform-operation-types.d.ts +46 -0
- package/dist/lib/platform-operation-types.js +2 -0
- package/dist/lib/platform-operation-types.js.map +1 -0
- package/dist/lib/platform-policy-tools.d.ts +1 -0
- package/dist/lib/platform-policy-tools.js +248 -0
- package/dist/lib/platform-policy-tools.js.map +1 -0
- package/dist/lib/platform-resource-operations.d.ts +124 -0
- package/dist/lib/platform-resource-operations.js +109 -0
- package/dist/lib/platform-resource-operations.js.map +1 -0
- package/dist/lib/platform-resource-tools.d.ts +1 -0
- package/dist/lib/platform-resource-tools.js +70 -0
- package/dist/lib/platform-resource-tools.js.map +1 -0
- package/dist/lib/platform-route-operations.d.ts +222 -0
- package/dist/lib/platform-route-operations.js +290 -0
- package/dist/lib/platform-route-operations.js.map +1 -0
- package/dist/lib/platform-route-tools.d.ts +1 -0
- package/dist/lib/platform-route-tools.js +307 -0
- package/dist/lib/platform-route-tools.js.map +1 -0
- package/dist/lib/platform-shared-operations.d.ts +7 -0
- package/dist/lib/platform-shared-operations.js +4 -0
- package/dist/lib/platform-shared-operations.js.map +1 -0
- package/dist/lib/platform-websocket-tools.d.ts +1 -0
- package/dist/lib/platform-websocket-tools.js +70 -0
- package/dist/lib/platform-websocket-tools.js.map +1 -0
- package/dist/lib/record-tools.d.ts +4 -0
- package/dist/lib/record-tools.js +418 -0
- package/dist/lib/record-tools.js.map +1 -0
- package/dist/lib/required-knowledge.d.ts +1 -1
- package/dist/lib/required-knowledge.js +3 -2
- package/dist/lib/required-knowledge.js.map +1 -1
- package/dist/lib/route-access-tools.d.ts +4 -0
- package/dist/lib/route-access-tools.js +172 -0
- package/dist/lib/route-access-tools.js.map +1 -0
- package/dist/lib/route-definition-tools.d.ts +4 -0
- package/dist/lib/route-definition-tools.js +285 -0
- package/dist/lib/route-definition-tools.js.map +1 -0
- package/dist/lib/route-inspection-tools.d.ts +4 -0
- package/dist/lib/route-inspection-tools.js +319 -0
- package/dist/lib/route-inspection-tools.js.map +1 -0
- package/dist/lib/route-tools.d.ts +1 -0
- package/dist/lib/route-tools.js +9 -0
- package/dist/lib/route-tools.js.map +1 -0
- package/dist/lib/runtime-zone-registry.d.ts +27 -0
- package/dist/lib/runtime-zone-registry.js +81 -0
- package/dist/lib/runtime-zone-registry.js.map +1 -0
- package/dist/lib/runtime-zone-search.d.ts +303 -0
- package/dist/lib/runtime-zone-search.js +596 -0
- package/dist/lib/runtime-zone-search.js.map +1 -0
- package/dist/lib/runtime-zone-tools.d.ts +2 -307
- package/dist/lib/runtime-zone-tools.js +2 -674
- package/dist/lib/runtime-zone-tools.js.map +1 -1
- package/dist/lib/schema-column-tools.d.ts +3 -0
- package/dist/lib/schema-column-tools.js +80 -0
- package/dist/lib/schema-column-tools.js.map +1 -0
- package/dist/lib/schema-mutation-coordinator.d.ts +28 -0
- package/dist/lib/schema-mutation-coordinator.js +154 -0
- package/dist/lib/schema-mutation-coordinator.js.map +1 -0
- package/dist/lib/schema-relation-contracts.d.ts +39 -0
- package/dist/lib/schema-relation-contracts.js +160 -0
- package/dist/lib/schema-relation-contracts.js.map +1 -0
- package/dist/lib/schema-relation-tools.d.ts +3 -0
- package/dist/lib/schema-relation-tools.js +61 -0
- package/dist/lib/schema-relation-tools.js.map +1 -0
- package/dist/lib/schema-table-contracts.d.ts +28 -0
- package/dist/lib/schema-table-contracts.js +263 -0
- package/dist/lib/schema-table-contracts.js.map +1 -0
- package/dist/lib/schema-table-tools.d.ts +3 -0
- package/dist/lib/schema-table-tools.js +297 -0
- package/dist/lib/schema-table-tools.js.map +1 -0
- package/dist/lib/schema-tool-operations.d.ts +150 -0
- package/dist/lib/schema-tool-operations.js +468 -0
- package/dist/lib/schema-tool-operations.js.map +1 -0
- package/dist/lib/schema-tool-types.d.ts +38 -0
- package/dist/lib/schema-tool-types.js +2 -0
- package/dist/lib/schema-tool-types.js.map +1 -0
- package/dist/lib/schema-verification.d.ts +14 -0
- package/dist/lib/schema-verification.js +105 -0
- package/dist/lib/schema-verification.js.map +1 -0
- package/dist/lib/script-tools.d.ts +4 -0
- package/dist/lib/script-tools.js +127 -0
- package/dist/lib/script-tools.js.map +1 -0
- package/dist/lib/system-tools.d.ts +4 -0
- package/dist/lib/system-tools.js +41 -0
- package/dist/lib/system-tools.js.map +1 -0
- package/dist/lib/table-tool-logic.d.ts +5 -0
- package/dist/lib/table-tool-logic.js +6 -0
- package/dist/lib/table-tool-logic.js.map +1 -0
- package/dist/lib/table-tools.d.ts +1 -84
- package/dist/lib/table-tools.js +7 -1522
- package/dist/lib/table-tools.js.map +1 -1
- package/dist/lib/tool-catalog.d.ts +2 -1
- package/dist/lib/tool-catalog.js +23 -2
- package/dist/lib/tool-catalog.js.map +1 -1
- package/dist/lib/tool-metadata-operations.d.ts +27 -0
- package/dist/lib/tool-metadata-operations.js +93 -0
- package/dist/lib/tool-metadata-operations.js.map +1 -0
- package/dist/lib/tool-permission-profile.d.ts +37 -0
- package/dist/lib/tool-permission-profile.js +106 -0
- package/dist/lib/tool-permission-profile.js.map +1 -0
- package/dist/lib/tool-record-operations.d.ts +102 -0
- package/dist/lib/tool-record-operations.js +260 -0
- package/dist/lib/tool-record-operations.js.map +1 -0
- package/dist/lib/tool-route-inspection.d.ts +47 -0
- package/dist/lib/tool-route-inspection.js +168 -0
- package/dist/lib/tool-route-inspection.js.map +1 -0
- package/dist/lib/tool-routing.d.ts +3 -417
- package/dist/lib/tool-routing.js +3 -1038
- package/dist/lib/tool-routing.js.map +1 -1
- package/dist/lib/tool-runtime-config.d.ts +33 -0
- package/dist/lib/tool-runtime-config.js +237 -0
- package/dist/lib/tool-runtime-config.js.map +1 -0
- package/dist/lib/tool-script-operations.d.ts +34 -0
- package/dist/lib/tool-script-operations.js +153 -0
- package/dist/lib/tool-script-operations.js.map +1 -0
- package/dist/lib/workflow-definitions.d.ts +366 -0
- package/dist/lib/workflow-definitions.js +703 -0
- package/dist/lib/workflow-definitions.js.map +1 -0
- package/dist/lib/workflow-planner.d.ts +45 -0
- package/dist/lib/workflow-planner.js +338 -0
- package/dist/lib/workflow-planner.js.map +1 -0
- package/dist/lib/workflow-types.d.ts +39 -0
- package/dist/lib/workflow-types.js +2 -0
- package/dist/lib/workflow-types.js.map +1 -0
- package/dist/mcp-server-entry.d.ts +0 -3
- package/dist/mcp-server-entry.js +2 -3249
- package/dist/mcp-server-entry.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
export const connectExamples = {
|
|
2
|
+
title: 'Connect SSR and browser apps to Enfyra',
|
|
3
|
+
useWhen: 'Use when connecting Nuxt, Next, Angular, or another browser app to Enfyra for REST, login, OAuth, refresh, files, GraphQL, or Socket.IO; adapt the framework wrapper while preserving the app-origin proxy and cookie boundary.',
|
|
4
|
+
examples: [
|
|
5
|
+
{
|
|
6
|
+
name: 'Nuxt routeRules for REST and Socket.IO',
|
|
7
|
+
code: `export default defineNuxtConfig({
|
|
8
|
+
routeRules: {
|
|
9
|
+
"/enfyra/**": {
|
|
10
|
+
proxy: {
|
|
11
|
+
to: \`\${process.env.ENFYRA_API_URL}/**\`,
|
|
12
|
+
fetchOptions: { redirect: "manual" }
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"/socket.io/**": {
|
|
16
|
+
proxy: \`\${process.env.ENFYRA_APP_URL}/ws/socket.io/**\`
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
})`,
|
|
20
|
+
notes: [
|
|
21
|
+
'Browser code calls app-origin routes such as /enfyra/login, /enfyra/me, /enfyra/logout, and /enfyra/<table>.',
|
|
22
|
+
'Keep redirects manual so OAuth and the set-cookie bridge return their redirect response to the browser.',
|
|
23
|
+
'Proxy to the Enfyra app /api bridge, not the raw Enfyra server. The Enfyra app bridge reads and refreshes cookies, then injects Authorization for protected ESV requests.',
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'Next rewrites for REST and Socket.IO',
|
|
28
|
+
code: `const nextConfig = {
|
|
29
|
+
async rewrites() {
|
|
30
|
+
return [
|
|
31
|
+
{
|
|
32
|
+
source: "/enfyra/:path*",
|
|
33
|
+
destination: \`\${process.env.ENFYRA_API_URL}/:path*\`
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
source: "/socket.io/",
|
|
37
|
+
destination: \`\${process.env.ENFYRA_APP_URL}/ws/socket.io/\`
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default nextConfig`,
|
|
44
|
+
notes: [
|
|
45
|
+
'Use rewrites for browser traffic, including the OAuth cookie bridge.',
|
|
46
|
+
'The destination is the Enfyra app /api bridge. Do not point the browser rewrite at a raw ESV origin.',
|
|
47
|
+
'For server components, forward the incoming Cookie header when fetching through the third app origin.',
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'Angular dev proxy for REST and Socket.IO',
|
|
52
|
+
code: `// src/proxy.conf.json
|
|
53
|
+
{
|
|
54
|
+
"/enfyra/**": {
|
|
55
|
+
"target": "https://demo.enfyra.io/api",
|
|
56
|
+
"secure": true,
|
|
57
|
+
"changeOrigin": true,
|
|
58
|
+
"pathRewrite": {
|
|
59
|
+
"^/enfyra": ""
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"/socket.io/**": {
|
|
63
|
+
"target": "https://demo.enfyra.io/api/ws",
|
|
64
|
+
"secure": true,
|
|
65
|
+
"changeOrigin": true,
|
|
66
|
+
"ws": true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// angular.json
|
|
71
|
+
{
|
|
72
|
+
"projects": {
|
|
73
|
+
"app": {
|
|
74
|
+
"architect": {
|
|
75
|
+
"serve": {
|
|
76
|
+
"options": {
|
|
77
|
+
"proxyConfig": "src/proxy.conf.json"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}`,
|
|
84
|
+
notes: [
|
|
85
|
+
'Browser code still calls /enfyra/login, /enfyra/me, /enfyra/logout, and /enfyra/<table>.',
|
|
86
|
+
'The /enfyra proxy strips the prefix before forwarding to the Enfyra API origin.',
|
|
87
|
+
'The /socket.io proxy forwards to the Enfyra app bridge /ws/socket.io while keeping the browser transport path as /socket.io.',
|
|
88
|
+
'Restart ng serve after changing proxy.conf.json.',
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'Password login and current user fetch',
|
|
93
|
+
code: `await fetch("/enfyra/login", {
|
|
94
|
+
method: "POST",
|
|
95
|
+
credentials: "include",
|
|
96
|
+
headers: { "Content-Type": "application/json" },
|
|
97
|
+
body: JSON.stringify({ email, password, remember: true })
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const me = await fetch("/enfyra/me", {
|
|
101
|
+
credentials: "include"
|
|
102
|
+
}).then((res) => res.ok ? res.json() : null)`,
|
|
103
|
+
notes: [
|
|
104
|
+
'The third app proxy maps /enfyra/login to the Enfyra app /api/login cookie endpoint; use /login, not raw /auth/login, in browser cookie mode.',
|
|
105
|
+
'The Enfyra app bridge owns refresh and Bearer forwarding to ESV while HttpOnly cookies stay outside browser JavaScript.',
|
|
106
|
+
'Do not read or store JWTs in browser JavaScript in proxy-cookie mode.',
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: 'Nuxt client plugin for authenticated realtime',
|
|
111
|
+
code: `// composables/useRealtime.ts
|
|
112
|
+
import { io, type Socket } from "socket.io-client"
|
|
113
|
+
import { readonly, ref, shallowRef } from "vue"
|
|
114
|
+
|
|
115
|
+
const socket = shallowRef<Socket | null>(null)
|
|
116
|
+
const isConnected = ref(false)
|
|
117
|
+
|
|
118
|
+
export function useRealtime() {
|
|
119
|
+
function connect() {
|
|
120
|
+
if (import.meta.server) return null
|
|
121
|
+
if (socket.value) return socket.value
|
|
122
|
+
|
|
123
|
+
const nextSocket = io("/chat", {
|
|
124
|
+
path: "/socket.io",
|
|
125
|
+
withCredentials: true,
|
|
126
|
+
reconnection: true,
|
|
127
|
+
reconnectionAttempts: Infinity,
|
|
128
|
+
reconnectionDelay: 2000,
|
|
129
|
+
reconnectionDelayMax: 30000
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
nextSocket.on("connect", () => {
|
|
133
|
+
isConnected.value = true
|
|
134
|
+
})
|
|
135
|
+
nextSocket.on("disconnect", () => {
|
|
136
|
+
isConnected.value = false
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
socket.value = nextSocket
|
|
140
|
+
return nextSocket
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function disconnect() {
|
|
144
|
+
if (!socket.value) return
|
|
145
|
+
socket.value.disconnect()
|
|
146
|
+
socket.value = null
|
|
147
|
+
isConnected.value = false
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function onMessage(handler) {
|
|
151
|
+
const activeSocket = socket.value ?? connect()
|
|
152
|
+
if (!activeSocket) return () => {}
|
|
153
|
+
activeSocket.on("chat:message", handler)
|
|
154
|
+
return () => activeSocket.off("chat:message", handler)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return { socket, isConnected: readonly(isConnected), connect, disconnect, onMessage }
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// plugins/realtime.client.ts
|
|
161
|
+
import { watch } from "vue"
|
|
162
|
+
|
|
163
|
+
export default defineNuxtPlugin(() => {
|
|
164
|
+
const { me } = useAuth()
|
|
165
|
+
const realtime = useRealtime()
|
|
166
|
+
|
|
167
|
+
watch(
|
|
168
|
+
me,
|
|
169
|
+
user => {
|
|
170
|
+
if (user) realtime.connect()
|
|
171
|
+
else realtime.disconnect()
|
|
172
|
+
},
|
|
173
|
+
{ immediate: true }
|
|
174
|
+
)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
// pages/chat.vue
|
|
178
|
+
const realtime = useRealtime()
|
|
179
|
+
let stopRealtime = () => {}
|
|
180
|
+
|
|
181
|
+
onMounted(() => {
|
|
182
|
+
stopRealtime = realtime.onMessage(event => {
|
|
183
|
+
// Update local UI state, then debounce REST refresh if full state is needed.
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
onUnmounted(() => {
|
|
188
|
+
stopRealtime()
|
|
189
|
+
})`,
|
|
190
|
+
notes: [
|
|
191
|
+
'Create the socket once in a client-only plugin after auth has resolved; pages should not own the initial connection lifecycle.',
|
|
192
|
+
'Use the websocket namespace path from live metadata, such as /chat, and keep the transport path as /socket.io.',
|
|
193
|
+
'Proxy /socket.io/** to the Enfyra app bridge /ws/socket.io/** so cookies are same-origin.',
|
|
194
|
+
'Route components add event listeners and remove them on unmount; they can optimistically update local state and debounce REST refreshes.',
|
|
195
|
+
'Disconnect the singleton socket when the current user/session clears.',
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: 'Angular HttpClient auth service and route guard',
|
|
200
|
+
code: `// app.config.ts
|
|
201
|
+
import { ApplicationConfig, inject } from "@angular/core"
|
|
202
|
+
import { provideRouter, CanActivateFn, Router } from "@angular/router"
|
|
203
|
+
import { HttpInterceptorFn, provideHttpClient, withInterceptors } from "@angular/common/http"
|
|
204
|
+
import { catchError, map, of } from "rxjs"
|
|
205
|
+
|
|
206
|
+
import { routes } from "./app.routes"
|
|
207
|
+
import { EnfyraAuthService } from "./enfyra-auth.service"
|
|
208
|
+
|
|
209
|
+
export const enfyraCredentialsInterceptor: HttpInterceptorFn = (req, next) => {
|
|
210
|
+
if (!req.url.startsWith("/enfyra/")) return next(req)
|
|
211
|
+
return next(req.clone({ withCredentials: true }))
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export const requireUserGuard: CanActivateFn = () => {
|
|
215
|
+
const auth = inject(EnfyraAuthService)
|
|
216
|
+
const router = inject(Router)
|
|
217
|
+
|
|
218
|
+
return auth.loadMe().pipe(
|
|
219
|
+
map(user => user ? true : router.createUrlTree(["/login"])),
|
|
220
|
+
catchError(() => of(router.createUrlTree(["/login"])))
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export const appConfig: ApplicationConfig = {
|
|
225
|
+
providers: [
|
|
226
|
+
provideHttpClient(withInterceptors([enfyraCredentialsInterceptor])),
|
|
227
|
+
provideRouter(routes)
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// enfyra-auth.service.ts
|
|
232
|
+
import { Injectable, signal } from "@angular/core"
|
|
233
|
+
import { HttpClient } from "@angular/common/http"
|
|
234
|
+
import { Observable, tap } from "rxjs"
|
|
235
|
+
|
|
236
|
+
type EnfyraUser = { id: string | number; email?: string }
|
|
237
|
+
|
|
238
|
+
@Injectable({ providedIn: "root" })
|
|
239
|
+
export class EnfyraAuthService {
|
|
240
|
+
readonly user = signal<EnfyraUser | null>(null)
|
|
241
|
+
|
|
242
|
+
constructor(private readonly http: HttpClient) {}
|
|
243
|
+
|
|
244
|
+
login(email: string, password: string): Observable<unknown> {
|
|
245
|
+
return this.http.post("/enfyra/login", { email, password, remember: true }).pipe(
|
|
246
|
+
tap(() => this.loadMe().subscribe())
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
loadMe(): Observable<EnfyraUser | null> {
|
|
251
|
+
return this.http.get<EnfyraUser | null>("/enfyra/me").pipe(
|
|
252
|
+
tap(user => this.user.set(user))
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
logout(): Observable<unknown> {
|
|
257
|
+
return this.http.post("/enfyra/logout", {}).pipe(
|
|
258
|
+
tap(() => this.user.set(null))
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
startGoogleOAuth(returnPath = "/") {
|
|
263
|
+
const redirect = new URL(returnPath, window.location.origin)
|
|
264
|
+
const url = new URL("/api/auth/google", "https://demo.enfyra.io")
|
|
265
|
+
url.searchParams.set("redirect", redirect.toString())
|
|
266
|
+
url.searchParams.set("cookieBridgePrefix", "/enfyra")
|
|
267
|
+
window.location.href = url.toString()
|
|
268
|
+
}
|
|
269
|
+
}`,
|
|
270
|
+
notes: [
|
|
271
|
+
'Use HttpClient with a credentials interceptor for /enfyra/* calls so cookies are sent consistently.',
|
|
272
|
+
'The guard is only for user experience; Enfyra route permissions and server-side owner checks remain authoritative.',
|
|
273
|
+
'Keep the current user in an Angular service or store; do not read JWTs from cookies or URLs.',
|
|
274
|
+
'OAuth starts at the Enfyra app /api/auth/google URL, not the local /enfyra path. It returns through the local cookie bridge before Angular loads /enfyra/me.',
|
|
275
|
+
],
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: 'Next client provider for authenticated realtime',
|
|
279
|
+
code: `"use client"
|
|
280
|
+
|
|
281
|
+
// app/realtime-provider.tsx
|
|
282
|
+
import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react"
|
|
283
|
+
import { io, type Socket } from "socket.io-client"
|
|
284
|
+
|
|
285
|
+
type RealtimeContextValue = {
|
|
286
|
+
socket: Socket | null
|
|
287
|
+
isConnected: boolean
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const RealtimeContext = createContext<RealtimeContextValue>({
|
|
291
|
+
socket: null,
|
|
292
|
+
isConnected: false
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
export function RealtimeProvider({
|
|
296
|
+
user,
|
|
297
|
+
children
|
|
298
|
+
}: {
|
|
299
|
+
user: { id: string | number } | null
|
|
300
|
+
children: React.ReactNode
|
|
301
|
+
}) {
|
|
302
|
+
const socketRef = useRef<Socket | null>(null)
|
|
303
|
+
const [isConnected, setConnected] = useState(false)
|
|
304
|
+
|
|
305
|
+
useEffect(() => {
|
|
306
|
+
if (!user) {
|
|
307
|
+
socketRef.current?.disconnect()
|
|
308
|
+
socketRef.current = null
|
|
309
|
+
setConnected(false)
|
|
310
|
+
return
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (socketRef.current) return
|
|
314
|
+
|
|
315
|
+
const socket = io("/chat", {
|
|
316
|
+
path: "/socket.io",
|
|
317
|
+
withCredentials: true,
|
|
318
|
+
reconnection: true,
|
|
319
|
+
reconnectionAttempts: Infinity,
|
|
320
|
+
reconnectionDelay: 2000,
|
|
321
|
+
reconnectionDelayMax: 30000
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
socket.on("connect", () => setConnected(true))
|
|
325
|
+
socket.on("disconnect", () => setConnected(false))
|
|
326
|
+
socketRef.current = socket
|
|
327
|
+
|
|
328
|
+
return () => {
|
|
329
|
+
socket.off("connect")
|
|
330
|
+
socket.off("disconnect")
|
|
331
|
+
socket.disconnect()
|
|
332
|
+
socketRef.current = null
|
|
333
|
+
setConnected(false)
|
|
334
|
+
}
|
|
335
|
+
}, [user])
|
|
336
|
+
|
|
337
|
+
const value = useMemo(
|
|
338
|
+
() => ({ socket: socketRef.current, isConnected }),
|
|
339
|
+
[isConnected]
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
return <RealtimeContext.Provider value={value}>{children}</RealtimeContext.Provider>
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export function useRealtime() {
|
|
346
|
+
return useContext(RealtimeContext)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// app/chat/page.tsx
|
|
350
|
+
// const { socket } = useRealtime()
|
|
351
|
+
// useEffect(() => {
|
|
352
|
+
// if (!socket) return
|
|
353
|
+
// const onMessage = event => {
|
|
354
|
+
// // Update local UI state, then debounce REST refresh if full state is needed.
|
|
355
|
+
// }
|
|
356
|
+
// socket.on("chat:message", onMessage)
|
|
357
|
+
// return () => socket.off("chat:message", onMessage)
|
|
358
|
+
// }, [socket])`,
|
|
359
|
+
notes: [
|
|
360
|
+
'Create the Socket.IO client once in a top-level client provider after the current user is known.',
|
|
361
|
+
'Use the websocket namespace path from live metadata, such as /chat, and keep the transport path as /socket.io.',
|
|
362
|
+
'Proxy /socket.io through Next rewrites to the Enfyra app bridge /ws/socket.io so cookies remain same-origin.',
|
|
363
|
+
'Pages/components should only subscribe/unsubscribe listeners; they should not create independent socket connections.',
|
|
364
|
+
'Disconnect the singleton socket when the current user/session clears.',
|
|
365
|
+
],
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
name: 'Angular singleton Socket.IO realtime service',
|
|
369
|
+
code: `// enfyra-realtime.service.ts
|
|
370
|
+
import { Injectable, computed, effect, signal } from "@angular/core"
|
|
371
|
+
import { io, Socket } from "socket.io-client"
|
|
372
|
+
|
|
373
|
+
import { EnfyraAuthService } from "./enfyra-auth.service"
|
|
374
|
+
|
|
375
|
+
@Injectable({ providedIn: "root" })
|
|
376
|
+
export class EnfyraRealtimeService {
|
|
377
|
+
private socket: Socket | null = null
|
|
378
|
+
private readonly connected = signal(false)
|
|
379
|
+
readonly isConnected = computed(() => this.connected())
|
|
380
|
+
|
|
381
|
+
constructor(private readonly auth: EnfyraAuthService) {
|
|
382
|
+
effect(() => {
|
|
383
|
+
const user = this.auth.user()
|
|
384
|
+
if (user) this.connect()
|
|
385
|
+
else this.disconnect()
|
|
386
|
+
})
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
connect() {
|
|
390
|
+
if (this.socket) return this.socket
|
|
391
|
+
|
|
392
|
+
this.socket = io("/chat", {
|
|
393
|
+
path: "/socket.io",
|
|
394
|
+
withCredentials: true,
|
|
395
|
+
reconnection: true,
|
|
396
|
+
reconnectionAttempts: Infinity,
|
|
397
|
+
reconnectionDelay: 2000,
|
|
398
|
+
reconnectionDelayMax: 30000
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
this.socket.on("connect", () => this.connected.set(true))
|
|
402
|
+
this.socket.on("disconnect", () => this.connected.set(false))
|
|
403
|
+
return this.socket
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
disconnect() {
|
|
407
|
+
this.socket?.disconnect()
|
|
408
|
+
this.socket = null
|
|
409
|
+
this.connected.set(false)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
onMessage(handler: (event: unknown) => void) {
|
|
413
|
+
const activeSocket = this.connect()
|
|
414
|
+
activeSocket.on("chat:message", handler)
|
|
415
|
+
return () => activeSocket.off("chat:message", handler)
|
|
416
|
+
}
|
|
417
|
+
}`,
|
|
418
|
+
notes: [
|
|
419
|
+
'Create one app-level Socket.IO connection after auth is known.',
|
|
420
|
+
'Use the websocket namespace path from live metadata, such as /chat, and keep the transport path as /socket.io.',
|
|
421
|
+
'Components subscribe with onMessage and call the returned cleanup function in ngOnDestroy.',
|
|
422
|
+
'Do not create a new socket per routed component.',
|
|
423
|
+
],
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
name: 'Google OAuth button',
|
|
427
|
+
code: `const redirect = new URL("/chat", window.location.origin)
|
|
428
|
+
const url = new URL("/api/auth/google", "https://demo.enfyra.io")
|
|
429
|
+
url.searchParams.set("redirect", redirect.toString())
|
|
430
|
+
url.searchParams.set("cookieBridgePrefix", "/enfyra")
|
|
431
|
+
window.location.href = url.toString()`,
|
|
432
|
+
notes: [
|
|
433
|
+
'redirect must be absolute and must include the app origin.',
|
|
434
|
+
'Start OAuth on the Enfyra app URL. Do not start it at the third app /enfyra proxy path.',
|
|
435
|
+
'cookieBridgePrefix is the app proxy prefix that forwards to Enfyra API routes.',
|
|
436
|
+
'Enfyra redirects through {redirect.origin}{cookieBridgePrefix}/auth/set-cookies before returning to redirect.',
|
|
437
|
+
'After returning, call /enfyra/me to load the authenticated user; do not parse tokens from the URL in proxy-cookie mode.',
|
|
438
|
+
],
|
|
439
|
+
},
|
|
440
|
+
],
|
|
441
|
+
};
|
|
442
|
+
//# sourceMappingURL=mcp-example-connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-example-connect.js","sourceRoot":"","sources":["../../src/lib/mcp-example-connect.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG;IAC3B,KAAK,EAAE,wCAAwC;IAC/C,OAAO,EAAE,iOAAiO;IAC1O,QAAQ,EAAE;QACR;YACE,IAAI,EAAE,wCAAwC;YAC9C,IAAI,EAAE;;;;;;;;;;;;GAYX;YACK,KAAK,EAAE;gBACL,8GAA8G;gBAC9G,yGAAyG;gBACzG,2KAA2K;aAC5K;SACF;QACD;YACE,IAAI,EAAE,sCAAsC;YAC5C,IAAI,EAAE;;;;;;;;;;;;;;;0BAeY;YAClB,KAAK,EAAE;gBACL,sEAAsE;gBACtE,sGAAsG;gBACtG,uGAAuG;aACxG;SACF;QACD;YACE,IAAI,EAAE,0CAA0C;YAChD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BZ;YACM,KAAK,EAAE;gBACL,0FAA0F;gBAC1F,iFAAiF;gBACjF,8HAA8H;gBAC9H,kDAAkD;aACnD;SACF;QACD;YACE,IAAI,EAAE,uCAAuC;YAC7C,IAAI,EAAE;;;;;;;;;6CAS+B;YACrC,KAAK,EAAE;gBACL,+IAA+I;gBAC/I,yHAAyH;gBACzH,uEAAuE;aACxE;SACF;QACD;YACE,IAAI,EAAE,+CAA+C;YACrD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EX;YACK,KAAK,EAAE;gBACL,gIAAgI;gBAChI,gHAAgH;gBAChH,2FAA2F;gBAC3F,0IAA0I;gBAC1I,uEAAuE;aACxE;SACF;QACD;YACE,IAAI,EAAE,iDAAiD;YACvD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqEZ;YACM,KAAK,EAAE;gBACL,qGAAqG;gBACrG,oHAAoH;gBACpH,8FAA8F;gBAC9F,8JAA8J;aAC/J;SACF;QACD;YACE,IAAI,EAAE,iDAAiD;YACvD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBA+EE;YACR,KAAK,EAAE;gBACL,kGAAkG;gBAClG,gHAAgH;gBAChH,8GAA8G;gBAC9G,sHAAsH;gBACtH,uEAAuE;aACxE;SACF;QACD;YACE,IAAI,EAAE,8CAA8C;YACpD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgDZ;YACM,KAAK,EAAE;gBACL,gEAAgE;gBAChE,gHAAgH;gBAChH,4FAA4F;gBAC5F,kDAAkD;aACnD;SACF;QACD;YACE,IAAI,EAAE,qBAAqB;YAC3B,IAAI,EAAE;;;;sCAIwB;YAC9B,KAAK,EAAE;gBACL,4DAA4D;gBAC5D,yFAAyF;gBACzF,gFAAgF;gBAChF,+GAA+G;gBAC/G,yHAAyH;aAC1H;SACF;KACF;CACF,CAAC"}
|