json-object-editor 0.10.633 → 0.10.638

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-object-editor",
3
- "version": "0.10.633",
3
+ "version": "0.10.638",
4
4
  "description": "JOE the Json Object Editor | Platform Edition",
5
5
  "main": "app.js",
6
6
  "scripts": {
package/pages/joe.html CHANGED
@@ -4,10 +4,12 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name='viewport' content='initial-scale=1.0, user-scalable=no' />
6
6
  <title>${this.webconfig.name} JOE</title>
7
- <link rel="shortcut icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon">
8
- <link rel="icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon">
9
- <link rel="icon" sizes="192x192" href="/JsonObjectEditor/img/ico/android-icon-192x192.png">
10
- <link rel="apple-touch-icon" sizes="144x144" href="/JsonObjectEditor/img/ico/android-icon-144x144.png" />
7
+ <link rel="shortcut icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon" id="favicon-shortcut">
8
+ <link rel="icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon" id="favicon-icon">
9
+ <link rel="icon" sizes="192x192" href="/JsonObjectEditor/img/ico/android-icon-192x192.png" id="favicon-192">
10
+ <link rel="apple-touch-icon" sizes="144x144" href="/JsonObjectEditor/img/ico/android-icon-144x144.png" id="favicon-apple" />
11
+ <script src="/JsonObjectEditor/js/favicon-env.js"></script>
12
+
11
13
  <meta name="joe-notes" content="joe.html template" >
12
14
  <meta name="apple-mobile-web-app-capable" content="yes">
13
15
  <meta name="mobile-web-app-capable" content="yes">
@@ -6,10 +6,11 @@
6
6
  <meta name='viewport' content='initial-scale=1.0, user-scalable=no' >
7
7
  <title> ${this.webconfig.name} > ${APPNAME} </title>
8
8
  <script src="/JsonObjectEditor/js/libs/adapter-latest.js"></script>
9
- <link rel="shortcut icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon">
10
- <link rel="icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon">
11
- <link rel="icon" sizes="192x192" href="/JsonObjectEditor/img/ico/android-icon-192x192.png">
12
- <link rel="apple-touch-icon" sizes="144x144" href="/JsonObjectEditor/img/ico/android-icon-144x144.png" />
9
+ <link rel="shortcut icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon" id="favicon-shortcut">
10
+ <link rel="icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon" id="favicon-icon">
11
+ <link rel="icon" sizes="192x192" href="/JsonObjectEditor/img/ico/android-icon-192x192.png" id="favicon-192">
12
+ <link rel="apple-touch-icon" sizes="144x144" href="/JsonObjectEditor/img/ico/android-icon-144x144.png" id="favicon-apple" />
13
+ <script src="/JsonObjectEditor/js/favicon-env.js"></script>
13
14
 
14
15
  <meta name="joe-notes" content="template.html template" >
15
16
  <meta name="apple-mobile-web-app-capable" content="yes">
@@ -8,10 +8,11 @@
8
8
  <meta name='viewport' content='initial-scale=1.0, user-scalable=no' >
9
9
  <title> ${this.webconfig.name} > ${APPNAME} </title>
10
10
  <script src="/JsonObjectEditor/js/libs/adapter-latest.js"></script>
11
- <link rel="shortcut icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon">
12
- <link rel="icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon">
13
- <link rel="icon" sizes="192x192" href="/JsonObjectEditor/img/ico/android-icon-192x192.png">
14
- <link rel="apple-touch-icon" sizes="144x144" href="/JsonObjectEditor/img/ico/android-icon-144x144.png" />
11
+ <link rel="shortcut icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon" id="favicon-shortcut">
12
+ <link rel="icon" href="/JsonObjectEditor/favicon.ico" type="image/x-icon" id="favicon-icon">
13
+ <link rel="icon" sizes="192x192" href="/JsonObjectEditor/img/ico/android-icon-192x192.png" id="favicon-192">
14
+ <link rel="apple-touch-icon" sizes="144x144" href="/JsonObjectEditor/img/ico/android-icon-144x144.png" id="favicon-apple" />
15
+ <script src="/JsonObjectEditor/js/favicon-env.js"></script>
15
16
 
16
17
  <meta name="apple-mobile-web-app-capable" content="yes">
17
18
  <meta name="mobile-web-app-capable" content="yes">
package/readme.md CHANGED
@@ -37,10 +37,14 @@ JOE is software that allows you to manage data models via JSON objects. There ar
37
37
  - Auth
38
38
  - If users exist, `POST /mcp` requires cookie or Basic Auth (same as other APIs). If no users configured, it is effectively open.
39
39
 
40
- - Test page
41
- - JOE ships a simple tester at `/_www/mcp-test.html` inside the package.
42
- - Access via JOE path: `http://localhost:<PORT>/JsonObjectEditor/_www/mcp-test.html`
43
- - If your host app serves its own `_www`, the tester can also be available at the root (fallback) if running with the updated server that mounts JOE’s `_www` as a secondary static directory. Then: `http://localhost:<PORT>/mcp-test.html`
40
+ - Test pages
41
+ - JOE ships several debug/test pages in `/_www/`:
42
+ - `mcp-test.html` - Simple MCP tool tester
43
+ - `mcp-schemas.html` - Schema health and summary viewer
44
+ - `mcp-prompt.html` - MCP prompt/instructions viewer
45
+ - `matrix.html` - Interactive schema relationship visualization with D3.js force-directed graph
46
+ - Access via JOE path: `http://localhost:<PORT>/JsonObjectEditor/_www/<page>.html`
47
+ - If your host app serves its own `_www`, pages can also be available at the root (fallback) if running with the updated server that mounts JOE’s `_www` as a secondary static directory. Then: `http://localhost:<PORT>/<page>.html`
44
48
 
45
49
  - Tools
46
50
  - `listSchemas(name?)`, `getSchema(name)`
@@ -17,6 +17,8 @@ var apps = function(){
17
17
  (_joe.search({}).length)+ ' objects';
18
18
  if(_joe.User && _joe.User.role == 'super'){
19
19
  message+='<br/><br/><joe-button onclick="_joe.SERVER.Cache.reload()" class="joe-button joe-iconed-button joe-grey-button joe-red-button joe-reload-button"> reload cache </joe-button>';
20
+ //add horizontal rule then text links to schems page and matrix page
21
+ message+=`<hr/> <a href="/schemas.html">schemas</a> <a href="/matrix.html">matrix</a>`;
20
22
  }
21
23
  return message;
22
24
  },
@@ -39,6 +39,7 @@ function Apps(){
39
39
  title:specs.title||'<small>JOE Platform v'+JOE.VERSION+'</small>',
40
40
  cssclass:'w2 h1',
41
41
  content:function(){
42
+ var app = APPINFO || {};
42
43
  if(!_joe.Data || !_joe.Data.user){return 'loading data';}
43
44
  //console.log(_joe.Data.user);
44
45
 
@@ -74,6 +75,8 @@ function Apps(){
74
75
  message+='<joe-button onclick="_joe.SERVER.Cache.reload()" class="joe-button joe-iconed-button joe-grey-button joe-red-button joe-reload-button"> re-cache </joe-button>';
75
76
  }
76
77
  +'</div><joe-clear></joe-clear>';
78
+ //add horizontal rule then text links to schems page and matrix page
79
+ message+='<a href="/mcp-schemas.html?app='+app.title.toLowerCase()+'" target="mcp_schemas_win">schemas</a> <a href="/matrix.html?app='+app.title.toLowerCase()+'" target="matrix_win">matrix</a>';
77
80
  return message;
78
81
  }
79
82
 
@@ -580,16 +580,21 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
580
580
  }
581
581
 
582
582
  // Normalize model output that should contain JSON. Models often wrap JSON
583
- // in markdown fences (```json ... ```); this helper strips fences and
584
- // attempts to isolate the first well-formed JSON object substring.
583
+ // in markdown fences (```json ... ```), and may prepend/append prose. This
584
+ // helper strips fences and tries to isolate the first well-formed JSON
585
+ // object/array substring so JSON.parse has the best chance of succeeding.
585
586
  function extractJsonText(raw) {
586
587
  if (!raw) { return ''; }
587
588
  let t = String(raw).trim();
588
- // Strip leading ```... fence
589
- if (t.startsWith('```')) {
590
- const firstNewline = t.indexOf('\n');
589
+ // If there is any ```...``` fenced block, prefer its contents.
590
+ const fenceIdx = t.indexOf('```json') !== -1 ? t.indexOf('```json') : t.indexOf('```');
591
+ if (fenceIdx !== -1) {
592
+ let start = fenceIdx;
593
+ const firstNewline = t.indexOf('\n', start);
591
594
  if (firstNewline !== -1) {
592
595
  t = t.substring(firstNewline + 1);
596
+ } else {
597
+ t = t.substring(start + 3);
593
598
  }
594
599
  const lastFence = t.lastIndexOf('```');
595
600
  if (lastFence !== -1) {
@@ -597,12 +602,17 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
597
602
  }
598
603
  t = t.trim();
599
604
  }
600
- // If there's extra prose around the JSON, slice from first { to last }
601
- if (t[0] !== '{') {
605
+ // If there's extra prose around the JSON, slice from first {/[ to last }/]
606
+ if (t[0] !== '{' && t[0] !== '[') {
602
607
  const firstBrace = t.indexOf('{');
603
- const lastBrace = t.lastIndexOf('}');
604
- if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) {
605
- t = t.slice(firstBrace, lastBrace + 1);
608
+ const firstBracket = t.indexOf('[');
609
+ let first = -1;
610
+ if (firstBrace === -1) { first = firstBracket; }
611
+ else if (firstBracket === -1) { first = firstBrace; }
612
+ else { first = Math.min(firstBrace, firstBracket); }
613
+ const lastBrace = Math.max(t.lastIndexOf('}'), t.lastIndexOf(']'));
614
+ if (first !== -1 && lastBrace !== -1 && lastBrace > first) {
615
+ t = t.slice(first, lastBrace + 1);
606
616
  }
607
617
  }
608
618
  return t.trim();
@@ -656,7 +666,7 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
656
666
  }, null, ' ');
657
667
 
658
668
  const openai = newClient();
659
- const model = body.model || 'gpt-4o-mini';
669
+ const model = body.model || 'gpt-4o-mini';////'gpt-5-nano';
660
670
 
661
671
  // For simplicity and robustness, use plain text output and instruct the
662
672
  // model to return a strict JSON object. We previously attempted the
@@ -667,6 +677,14 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
667
677
  instructions: systemText,
668
678
  input: userInput
669
679
  };
680
+ // Optional web_search tool: if the caller sets allow_web truthy, expose
681
+ // the built-in web_search capability and let the model decide when to
682
+ // call it.
683
+ if (body.allow_web) {
684
+ coloredLog("allowing web search");
685
+ requestBase.tools = [{ type: 'web_search' }];
686
+ requestBase.tool_choice = 'auto';
687
+ }
670
688
 
671
689
  let response;
672
690
  if (assistantId) {
@@ -706,6 +724,13 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
706
724
  filteredPatch[f] = patch[f];
707
725
  }
708
726
  });
727
+ // If we got no fields back on the first attempt, retry once before
728
+ // giving up. Avoid infinite loops by marking a retry flag.
729
+ if (!Object.keys(filteredPatch).length && !body._retry) {
730
+ coloredLog('[autofill] empty patch, retrying once');
731
+ const retryBody = Object.assign({}, body, { _retry: true });
732
+ return await self.autofill(retryBody, req, res);
733
+ }
709
734
 
710
735
  // Optional save
711
736
  let savedItem = null;