json-object-editor 0.10.503 → 0.10.505

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/CHANGELOG.md CHANGED
@@ -22,6 +22,18 @@
22
22
  - Hydrate includes full core field definitions from server/fields/core.js (not just names)
23
23
  - Manifest now includes { joe: { name, version, hostname } }; mcp-test shows this
24
24
 
25
+ 504 - Secure test pages + shared nav
26
+ - Secured /mcp-test.html and /mcp-export.html with standard JOE auth (root and JOEPATH paths)
27
+ - Added shared top nav between MCP Test and MCP Export pages
28
+ - MCP Export shows instance info (name/version/host) from manifest
29
+ - Added privacy_policy_url and terms_of_service_url to manifest; added public /privacy and /terms pages
30
+ - New Setting: PRIVACY_CONTACT used for contact email on /privacy and /terms
31
+
32
+ 505 - Prompt page and shared nav consolidation
33
+ - Added /mcp-prompt.html (concise starter instructions for Custom GPT/Assistants)
34
+ - Extracted shared nav to /JsonObjectEditor/_www/mcp-nav.js and used across Test/Export/Privacy/Terms
35
+ - Nav now shows instance name/version/host and links to Privacy/Terms (named windows)
36
+
25
37
  ### 0.10.500
26
38
  500 - MCP integration (initial)
27
39
  - MCP core module with JSON-RPC 2.0 endpoint (/mcp) protected by auth
@@ -19,8 +19,10 @@
19
19
  </style>
20
20
  </head>
21
21
  <body>
22
+ <div id="mcp-nav"></div>
23
+ <script src="/JsonObjectEditor/_www/mcp-nav.js"></script>
22
24
  <h1>JOE MCP → Assistant Config Export</h1>
23
- <div class="small">Generate copy/paste config for Custom GPT Actions (OpenAPI) and Assistants (tools array).</div>
25
+ <div class="small">Generate copy/paste config for Custom GPT Actions (OpenAPI) and Assistants (tools array).</div>
24
26
 
25
27
  <div class="grid">
26
28
  <section>
@@ -57,7 +59,13 @@
57
59
  </section>
58
60
 
59
61
  <section>
60
- <h3>4) JSON-RPC request template</h3>
62
+ <h3>4) Starter Agent Instructions</h3>
63
+ <div class="small">Copy into your Custom GPT or Assistant system prompt. Keep it brief and expand as needed.</div>
64
+ <textarea id="starter" readonly></textarea>
65
+ </section>
66
+
67
+ <section>
68
+ <h3>5) JSON-RPC request template</h3>
61
69
  <div class="small">When the Assistant calls a tool, POST this body to <code>/mcp</code>.</div>
62
70
  <pre>{
63
71
  "jsonrpc": "2.0",
@@ -110,7 +118,7 @@
110
118
 
111
119
  const schema = {
112
120
  openapi: '3.1.0',
113
- info: { title: 'JOE MCP Bridge', version: '1.0.0' },
121
+ info: { title: 'JOE MCP Bridge' + ((manifest.joe&&manifest.joe.name)||'JOE'), version: '1.0.0' },
114
122
  servers: [{ url: serverUrl.replace(/\/$/,'') }],
115
123
  paths: {
116
124
  '/mcp': {
@@ -162,6 +170,7 @@
162
170
 
163
171
  const url = base.value.replace(/\/$/,'') + manifestPath.value;
164
172
  const manifest = await fetchJSON(url);
173
+ // Instance info handled by shared nav script
165
174
  manifestOut.style.display='block';
166
175
  manifestOut.textContent = JSON.stringify(manifest, null, 2);
167
176
 
@@ -171,6 +180,33 @@
171
180
  const openapi = buildOpenAPI(manifest, base.value);
172
181
  openapiEl.value = JSON.stringify(openapi, null, 2);
173
182
 
183
+ // Starter prompt (concise)
184
+ const joeName = (manifest.joe && manifest.joe.name) || 'JOE';
185
+ const starter = [
186
+ `You are a data assistant for ${joeName} (JOE). Use only the provided tools.`,
187
+ '',
188
+ 'Autonomy:',
189
+ '- Act autonomously; if a tool can answer, call it immediately (no permission prompts).',
190
+ '- Do not offer multiple-choice options; pick the best action.',
191
+ '- Ask one brief clarification only if a required parameter is missing.',
192
+ '- On a new session: call hydrate {} first, then proceed.',
193
+ '- Keep results scoped (limit 10–25). Flatten is optional and off by default; enable only when needed.',
194
+ '- Never expose secrets/tokens. Confirm with the user before saveObject.',
195
+ '',
196
+ 'Typical flow:',
197
+ '- listSchemas {}, getSchema { "name": "<schema>" }',
198
+ '- search { "query": { "itemtype": "<schema>" }, "limit": 10 } (cache) or { "source": "storage" } when authoritative results are needed',
199
+ '- getObject { "_id": "<id>", "schema": "<schema>" } for a single item',
200
+ '- saveObject { "object": { ... } } only on explicit user request',
201
+ '',
202
+ 'Examples:',
203
+ '- listSchemas {}',
204
+ '- getSchema { "name": "client" }',
205
+ '- search { "schema": "client", "source": "storage", "query": { "status": "active" }, "limit": 10 }',
206
+ '- getObject { "_id": "123", "schema": "client" }'
207
+ ].join('\n');
208
+ $('starter').value = starter;
209
+
174
210
  setStatus('Manifest loaded. Config generated.', true);
175
211
  }catch(e){
176
212
  setStatus(e.message||String(e), false);
@@ -0,0 +1,42 @@
1
+ ;(function(){
2
+ function buildNav(){
3
+ var nav = document.createElement('nav');
4
+ nav.setAttribute('style','display:flex;gap:10px;align-items:center;margin-bottom:8px');
5
+ nav.innerHTML = [
6
+ '<a href="/mcp-test.html" target="mcp_test_win" rel="noopener">MCP Test</a>',
7
+ '<a href="/mcp-export.html" target="mcp_export_win" rel="noopener">MCP Export</a>',
8
+ '<a href="/mcp-prompt.html" target="mcp_prompt_win" rel="noopener">MCP Prompt</a>',
9
+ '<span style="margin-left:auto"></span>',
10
+ '<span id="mcp-nav-info" class="small" style="opacity:.8;margin-right:10px"></span>',
11
+ '<a href="/privacy" target="privacy_win" rel="noopener">Privacy</a>',
12
+ '<a href="/terms" target="terms_win" rel="noopener">Terms</a>'
13
+ ].join('');
14
+ return nav;
15
+ }
16
+ function insert(){
17
+ var placeholder = document.getElementById('mcp-nav');
18
+ var nav = buildNav();
19
+ if(placeholder){
20
+ placeholder.parentNode.replaceChild(nav, placeholder);
21
+ }else{
22
+ document.body.insertBefore(nav, document.body.firstChild);
23
+ }
24
+ }
25
+ async function updateInstance(){
26
+ try{
27
+ var res = await fetch('/.well-known/mcp/manifest.json');
28
+ if(!res.ok) return;
29
+ var m = await res.json();
30
+ var info = document.getElementById('mcp-nav-info');
31
+ if(info && m && m.joe){
32
+ info.textContent = 'Name: '+(m.joe.name||'JOE')+' | Version: '+(m.joe.version||'')+' | Host: '+(m.joe.hostname||'');
33
+ }
34
+ }catch(e){}
35
+ }
36
+ if(document.readyState === 'loading'){
37
+ document.addEventListener('DOMContentLoaded', insert);
38
+ document.addEventListener('DOMContentLoaded', updateInstance);
39
+ }else{ insert(); updateInstance(); }
40
+ })();
41
+
42
+
@@ -0,0 +1,29 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>JOE MCP Prompt</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <style>
8
+ body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;margin:20px;}
9
+ textarea{width:100%;height:360px;font-family:ui-monospace,Menlo,Consolas,monospace}
10
+ .small{font-size:12px;color:#666}
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <div id="mcp-nav"></div>
15
+ <script src="/JsonObjectEditor/_www/mcp-nav.js"></script>
16
+ <h1>Starter Agent Instructions</h1>
17
+ <div class="small">Copy into your Custom GPT or Assistant system prompt. Adjust as needed.</div>
18
+ <textarea readonly id="prompt"></textarea>
19
+ <script>
20
+ (function(){
21
+ const text = [
22
+ `You are a data assistant for JOE. Use only the provided tools.\n\nAutonomy:\n- Act autonomously; if a tool can answer, call it immediately (no permission prompts).\n- Do not offer multiple-choice options; pick the best action.\n- Ask one brief clarification only if a required parameter is missing.\n- On a new session: call hydrate {} first, then proceed.\n- Keep results scoped (limit 10–25). Flatten is optional and off by default; enable only when needed.\n- Never expose secrets/tokens. Confirm with the user before saveObject.\n\nTypical flow:\n- listSchemas {}, getSchema { "name": "<schema>" }\n- search { "query": { "itemtype": "<schema>" }, "limit": 10 } (cache) or { "source": "storage" } for authoritative results\n- getObject { "_id": "<id>", "schema": "<schema>" }\n- saveObject { "object": { ... } } only on explicit user request\n\nExamples:\n- listSchemas {}\n- getSchema { "name": "client" }\n- search { "schema": "client", "source": "storage", "query": { "status": "active" }, "limit": 10 }\n- getObject { "_id": "123", "schema": "client" }`
23
+ ].join('\n');
24
+ document.getElementById('prompt').value = text;
25
+ })();
26
+ </script>
27
+ </body>
28
+ </html>
29
+
@@ -17,9 +17,10 @@
17
17
  </style>
18
18
  </head>
19
19
  <body>
20
+ <div id="mcp-nav"></div>
21
+ <script src="/JsonObjectEditor/_www/mcp-nav.js"></script>
20
22
  <h1>JOE MCP Test</h1>
21
23
  <div class="small">Use this page to discover tools and call the JSON-RPC endpoint.</div>
22
- <pre id="instanceInfo" class="small">Loading instance info…</pre>
23
24
 
24
25
  <h3>Manifest</h3>
25
26
  <div class="row">
@@ -83,10 +84,7 @@
83
84
  try{
84
85
  const url = base.value.replace(/\/$/,'') + '/.well-known/mcp/manifest.json';
85
86
  manifest = await fetchJSON(url);
86
- // Instance info
87
- if (manifest.joe){
88
- $('instanceInfo').textContent = `Name: ${manifest.joe.name} | Version: ${manifest.joe.version} | Host: ${manifest.joe.hostname}`;
89
- }
87
+ // Instance info handled by shared nav script
90
88
  (manifest.tools||[]).forEach(t=>{
91
89
  const opt=document.createElement('option');
92
90
  opt.value=t.name; opt.textContent=t.name;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-object-editor",
3
- "version": "0.10.503",
3
+ "version": "0.10.505",
4
4
  "description": "JOE the Json Object Editor | Platform Edition",
5
5
  "main": "app.js",
6
6
  "scripts": {
package/readme.md CHANGED
@@ -31,6 +31,8 @@ JOE is software that allows you to manage data models via JSON objects. There ar
31
31
  - Endpoints
32
32
  - Manifest (public): `GET /.well-known/mcp/manifest.json`
33
33
  - JSON-RPC (auth): `POST /mcp`
34
+ - Privacy (public): `/privacy` (uses Setting `PRIVACY_CONTACT` for contact email)
35
+ - Terms (public): `/terms`
34
36
 
35
37
  - Auth
36
38
  - If users exist, `POST /mcp` requires cookie or Basic Auth (same as other APIs). If no users configured, it is effectively open.
@@ -42,7 +44,7 @@ JOE is software that allows you to manage data models via JSON objects. There ar
42
44
 
43
45
  - Tools
44
46
  - `listSchemas(name?)`, `getSchema(name)`
45
- - `getObject(_id, schema?)` (flattens by default; supports `depth` override)
47
+ - `getObject(_id, schema?)` (supports optional `flatten` and `depth`)
46
48
  - `search` (preferred): unified tool for cache and storage
47
49
  - Params: `{ schema?, query?, ids?, source?: 'cache'|'storage', limit?, flatten?, depth? }`
48
50
  - Defaults to cache across all collections; add `schema` to filter; set `source:"storage"` to query a specific schema in the DB.
@@ -117,6 +119,7 @@ JOE is software that allows you to manage data models via JSON objects. There ar
117
119
 
118
120
  - Troubleshooting
119
121
  - If you see a payload like `{ originalURL: "/...", site: "no site found" }`, the request hit the Sites catch-all. Ensure MCP routes are initialized before Sites (handled by default in `server/init.js` via `MCP.init()`), and use the correct URL: `/.well-known/mcp/manifest.json` or `/mcp`.
122
+ - To update contact email on /privacy and /terms, set Setting `PRIVACY_CONTACT`.
120
123
 
121
124
  ## SERVER/PLATFORM mode
122
125
  check port 2099
@@ -63,7 +63,7 @@ MCP.tools = {
63
63
  },
64
64
 
65
65
  // Convenience: fetch a single object by _id (schema optional). Prefer cache; fallback to storage.
66
- getObject: async ({ _id, schema, flatten = true, depth = 1 }, _ctx) => {
66
+ getObject: async ({ _id, schema, flatten = false, depth = 1 }, _ctx) => {
67
67
  if (!_id) throw new Error("Missing required param '_id'");
68
68
  // Fast path via global lookup
69
69
  let obj = (JOE && JOE.Cache && JOE.Cache.findByID) ? (JOE.Cache.findByID(_id) || null) : null;
@@ -185,11 +185,11 @@ MCP.tools = {
185
185
  MCP.descriptions = {
186
186
  listSchemas: "List all available JOE schema names.",
187
187
  getSchema: "Retrieve a full schema definition by name.",
188
- getObject: "Fetch a single object by _id (schema optional). Flattens by default.",
188
+ getObject: "Fetch a single object by _id (schema optional). Supports optional flatten.",
189
189
  // getObjectsByIds: "Deprecated - use 'search' with ids.",
190
190
  // queryObjects: "Deprecated - use 'search'.",
191
191
  // searchCache: "Deprecated - use 'search'.",
192
- search: "Unified search. Defaults to cache; set source=storage to query DB.",
192
+ search: "Unified search. Defaults to cache; set source=storage to query DB. Flatten is optional (false by default).",
193
193
  saveObject: "Create/update an object; triggers events/history.",
194
194
  hydrate: "Describe core fields, statuses, tags, and inferred field shapes for an optional schema."
195
195
  };
@@ -278,7 +278,10 @@ MCP.manifest = async function (req, res) {
278
278
  version: (JOE && JOE.VERSION) || '',
279
279
  hostname: (JOE && JOE.webconfig && JOE.webconfig.hostname) || ''
280
280
  };
281
- return res.json({ version: "1.0", joe, tools });
281
+ const base = req.protocol+':'+(req.get('host')||'');
282
+ const privacyUrl = base+'/'+'privacy';
283
+ const termsUrl = base+'/'+'terms';
284
+ return res.json({ version: "1.0", joe, privacy_policy_url: privacyUrl, terms_of_service_url: termsUrl, tools });
282
285
  } catch (e) {
283
286
  console.log('[MCP] manifest error:', e);
284
287
  return res.status(500).json({ error: e.message || 'manifest error' });
@@ -104,6 +104,65 @@ server.use(function(req, res, next) {
104
104
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
105
105
  next();
106
106
  });
107
+ // Public Privacy & Terms pages
108
+ server.get(['/privacy','/privacy-policy'],function(req,res){
109
+ const host = req.protocol+'://'+req.get('host');
110
+ const name = (JOE && JOE.webconfig && JOE.webconfig.name) || 'JOE';
111
+ const updated = new Date().toISOString().split('T')[0];
112
+ const contact = (JOE && JOE.Utils && JOE.Utils.Settings && JOE.Utils.Settings('PRIVACY_CONTACT')) || 'admin@example.com';
113
+ res.send(`
114
+ <!doctype html>
115
+ <html><head><meta charset="utf-8"><title>Privacy Policy - ${name}</title></head>
116
+ <body style="font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif;padding:20px;max-width:900px;line-height:1.6">
117
+ <div id="mcp-nav"></div>
118
+ <script src="${JOE.webconfig.joepath}_www/mcp-nav.js"></script>
119
+ <h1>Privacy Policy for JOE MCP Interface</h1>
120
+ <p><em>Last updated: ${updated}</em></p>
121
+ <h3>Data Processed</h3>
122
+ <p>The JOE MCP interface allows AI systems to retrieve structured data from the JOE platform, such as schemas, objects, and metadata. It does not store, sell, or share personal data.</p>
123
+ <h3>Data Sources</h3>
124
+ <p>All information returned by this interface comes from the JOE instance it’s connected to (${host}). Access to internal data is subject to your JOE configuration and authentication.</p>
125
+ <h3>Third-Party Access</h3>
126
+ <p>This API may be called by authorized OpenAI models or assistants when configured by a verified user. Calls are only executed when explicitly invoked as part of an agent’s reasoning process.</p>
127
+ <h3>Logging</h3>
128
+ <p>Standard request logs (timestamps, method calls, and errors) may be recorded for security and debugging. Logs do not include object contents or personal data.</p>
129
+ <h3>Security</h3>
130
+ <p>All connections are made over HTTPS. No credentials or session tokens are shared with external systems.</p>
131
+ <h3>Contact</h3>
132
+ <p>For privacy concerns, contact ${contact}.</p>
133
+ </body></html>`);
134
+ });
135
+ server.get(['/terms','/terms-of-service'],function(req,res){
136
+ const host = req.protocol+'://'+req.get('host');
137
+ const name = (JOE && JOE.webconfig && JOE.webconfig.name) || 'JOE';
138
+ const updated = new Date().toISOString().split('T')[0];
139
+ const contact = (JOE && JOE.Utils && JOE.Utils.Settings && JOE.Utils.Settings('PRIVACY_CONTACT')) || 'admin@example.com';
140
+ res.send(`
141
+ <!doctype html>
142
+ <html><head><meta charset="utf-8"><title>Terms of Service - ${name}</title></head>
143
+ <body style="font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif;padding:20px;max-width:900px;line-height:1.6">
144
+ <div id="mcp-nav"></div>
145
+ <script src="${JOE.webconfig.joepath}_www/mcp-nav.js"></script>
146
+ <h1>Terms of Service for JOE MCP Interface</h1>
147
+ <p><em>Last updated: ${updated}</em></p>
148
+ <p>Use of this interface implies consent to log and process structured data requests for schema and object retrieval purposes. Access is governed by your JOE configuration and authentication. Do not submit sensitive data unless you are authorized to do so.</p>
149
+ <p>For questions, contact ${contact}.</p>
150
+ </body></html>`);
151
+ });
152
+ // Secure MCP test/export pages with standard auth (root and JOEPATH paths)
153
+ server.get('/mcp-test.html',auth,function(req,res){
154
+ res.sendFile(path.join(JOE.joedir,'_www','mcp-test.html'));
155
+ });
156
+ server.get('/mcp-export.html',auth,function(req,res){
157
+ res.sendFile(path.join(JOE.joedir,'_www','mcp-export.html'));
158
+ });
159
+ server.get(JOE.webconfig.joepath+'_www/mcp-test.html',auth,function(req,res){
160
+ res.sendFile(path.join(JOE.joedir,'_www','mcp-test.html'));
161
+ });
162
+ server.get(JOE.webconfig.joepath+'_www/mcp-export.html',auth,function(req,res){
163
+ res.sendFile(path.join(JOE.joedir,'_www','mcp-export.html'));
164
+ });
165
+
107
166
  server.use(JOE.webconfig.joepath,express.static(JOE.joedir));
108
167
 
109
168
  //USER