@dypai-ai/mcp 1.5.23 → 1.5.24
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 +1 -1
- package/src/index.js +7 -6
- package/src/tools/sync/pull.js +2 -0
- package/src/tools/sync/validate.js +25 -1
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1078,10 +1078,11 @@ Mental translations: "edge function" → workflow with one code node; "cron" →
|
|
|
1078
1078
|
3. **Treating \`dypai_push\` as a deploy** — it's "save as draft", not publish. Live traffic is untouched until \`manage_drafts(publish, confirm:true)\`. Push freely, only ask the user before publish.
|
|
1079
1079
|
4. **\`public\` auth_mode with \`\${current_user_id}\`** — no JWT → placeholder empty → SQL fails or returns wrong data. Use \`jwt\` if you need the user.
|
|
1080
1080
|
5. **Missing \`return: true\`** — endpoint returns \`null\`. Every path that should produce an HTTP response needs one node with \`return: true\`.
|
|
1081
|
-
6. **SQL return + \`output.type: object\` without \`response_cardinality\` or \`set_fields\`** — runtime body is \`[{...}]\` but the frontend expects \`{...}\`. Add top-level \`response_cardinality: single\` for direct SQL returns, or compose the public object with \`set_fields\`. \`dypai_validate\` errors with \`response_cardinality_required\`. Do not unwrap arrays in frontend code.
|
|
1082
|
-
7. **\`
|
|
1083
|
-
8.
|
|
1084
|
-
9. **
|
|
1081
|
+
6. **SQL return + \`output.type: object\` without \`response_cardinality\` or \`set_fields\`** — runtime body is \`[{...}]\` but the frontend expects \`{...}\`. Add top-level \`response_cardinality: single\` for direct SQL returns, or compose the public object with \`set_fields operation: compose\`. \`dypai_validate\` errors with \`response_cardinality_required\`. Do not unwrap arrays in frontend code.
|
|
1082
|
+
7. **\`set_fields\` without \`operation\`** — runtime throws \`Unknown Set Fields operation: undefined\`. Wrapper responses need \`operation: compose\`; adding fields to upstream data uses \`operation: set\`. \`dypai_validate\` / \`backend_validate\` error with \`set_fields_operation_missing\`.
|
|
1083
|
+
8. **\`tool_ids\` in YAML instead of \`tools\`** — write \`tools: [name1, name2]\`. \`tool_ids\` bypasses the codec and fails silently in prod.
|
|
1084
|
+
9. **Putting workflow placeholders inside \`javascript_code.code\`** — code is raw JavaScript, so JS template literals like \`\${where.join(" AND ")}\` are safe and not rendered by DYPAI. Pass workflow values via \`input_data\`, \`ctx.nodes\`, \`ctx.user\`, or \`ctx.env\`; do not write \`\${input.email}\` inside code or set \`code\` from another node output.
|
|
1085
|
+
10. **Human endpoint names** — \`name: Listar videos\` in \`list-videos.yaml\` creates a draft the frontend cannot call as \`list-videos\`. \`dypai_validate\` and \`dypai_push\` reject this; fix the slug instead of testing around it.
|
|
1085
1086
|
|
|
1086
1087
|
→ Longer list of common pitfalls + fixes: \`search_docs("troubleshooting")\`.
|
|
1087
1088
|
|
|
@@ -1102,7 +1103,7 @@ Mental translations: "edge function" → workflow with one code node; "cron" →
|
|
|
1102
1103
|
|
|
1103
1104
|
SDK is pre-configured at \`src/lib/dypai.ts\` (or \`src/dypai.ts\`). Import \`dypai\` from there. Every method returns \`{ data, error }\` — never throws.
|
|
1104
1105
|
|
|
1105
|
-
- **API**: \`dypai.api.get(name)\`, \`.post(name, body)\`, \`.put()\`, \`.delete()\`, \`.upload(name, file)\`, \`.stream(name, body)\`. \`response.data\` matches the endpoint \`output\` schema — if SQL returns row arrays, declare \`response_cardinality: single\` or use \`set_fields\`; never unwrap in the UI.
|
|
1106
|
+
- **API**: \`dypai.api.get(name)\`, \`.post(name, body)\`, \`.put()\`, \`.delete()\`, \`.upload(name, file)\`, \`.stream(name, body)\`. \`response.data\` matches the endpoint \`output\` schema — if SQL returns row arrays, declare \`response_cardinality: single\` or use \`set_fields operation: compose\`; never unwrap in the UI.
|
|
1106
1107
|
- **Auth**: \`dypai.auth.signInWithPassword()\`, \`.signUp()\`, \`.signOut()\`, \`.getSession()\`. **Never** create login/signup workflows — auth is built-in.
|
|
1107
1108
|
- **Hooks**: \`useAuth\`, \`useEndpoint\`, \`useAction\`, \`useUpload\`, \`useRealtime\`, \`<ProtectedRoute>\`.
|
|
1108
1109
|
- **Rule**: NEVER \`fetch()\` directly — always through the SDK.
|
|
@@ -1143,7 +1144,7 @@ async function handleRequest(msg) {
|
|
|
1143
1144
|
return makeResponse(id, {
|
|
1144
1145
|
protocolVersion: "2024-11-05",
|
|
1145
1146
|
capabilities: { tools: {} },
|
|
1146
|
-
serverInfo: { name: "dypai", version: "1.5.
|
|
1147
|
+
serverInfo: { name: "dypai", version: "1.5.24" },
|
|
1147
1148
|
instructions: SERVER_INSTRUCTIONS,
|
|
1148
1149
|
})
|
|
1149
1150
|
}
|
package/src/tools/sync/pull.js
CHANGED
|
@@ -287,6 +287,7 @@ workflow:
|
|
|
287
287
|
# \`return: true\` — it marks that node's output as the HTTP body.
|
|
288
288
|
- id: build_response
|
|
289
289
|
type: set_fields
|
|
290
|
+
operation: compose
|
|
290
291
|
return: true
|
|
291
292
|
fields:
|
|
292
293
|
order_id: \${nodes.insert_order.id}
|
|
@@ -297,6 +298,7 @@ workflow:
|
|
|
297
298
|
# Multiple return nodes are fine as long as only one runs per execution.
|
|
298
299
|
- id: out_of_stock
|
|
299
300
|
type: set_fields
|
|
301
|
+
operation: compose
|
|
300
302
|
return: true
|
|
301
303
|
fields:
|
|
302
304
|
error: out_of_stock
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
* Outside the window, sql_table_not_found triggers a remote verification. */
|
|
31
31
|
const SCHEMA_FRESHNESS_MS = 5 * 60 * 1000 // 5 minutes
|
|
32
32
|
const VALID_RESPONSE_CARDINALITIES = new Set(["single", "many", "zero_or_one"])
|
|
33
|
+
const VALID_SET_FIELDS_OPERATIONS = new Set(["set", "compose", "rename", "remove", "keep", "merge"])
|
|
33
34
|
const DATABASE_ROW_ARRAY_OPS = new Set([
|
|
34
35
|
"query",
|
|
35
36
|
"custom_query",
|
|
@@ -804,7 +805,8 @@ function buildNodeOutputContracts(nodes, fileMap, ctx) {
|
|
|
804
805
|
const params = nodeParams(node)
|
|
805
806
|
|
|
806
807
|
if (nodeType === "set_fields") {
|
|
807
|
-
const op = nodeField(node, params, "operation")
|
|
808
|
+
const op = nodeField(node, params, "operation")
|
|
809
|
+
if (!op) continue
|
|
808
810
|
const fields = nodeField(node, params, "fields")
|
|
809
811
|
if (fields && typeof fields === "object" && !Array.isArray(fields)) {
|
|
810
812
|
contracts.set(node.id, {
|
|
@@ -1437,6 +1439,28 @@ function validateEndpoint(entry, ctx) {
|
|
|
1437
1439
|
}
|
|
1438
1440
|
}
|
|
1439
1441
|
}
|
|
1442
|
+
|
|
1443
|
+
if (nodeType === "set_fields") {
|
|
1444
|
+
const params = nodeParams(node)
|
|
1445
|
+
const op = nodeField(node, params, "operation")
|
|
1446
|
+
if (!op) {
|
|
1447
|
+
diagnostics.push({
|
|
1448
|
+
severity: "error",
|
|
1449
|
+
rule: "set_fields_operation_missing",
|
|
1450
|
+
endpoint: name, file, loc: `workflow.nodes[${node.id || "?"}]`,
|
|
1451
|
+
message: `set_fields node '${node.id || "(no id)"}' is missing operation.`,
|
|
1452
|
+
fix_hint: "Add operation: compose when building a fresh response object, or operation: set when adding fields to upstream input.",
|
|
1453
|
+
})
|
|
1454
|
+
} else if (!VALID_SET_FIELDS_OPERATIONS.has(op)) {
|
|
1455
|
+
diagnostics.push({
|
|
1456
|
+
severity: "error",
|
|
1457
|
+
rule: "set_fields_operation_invalid",
|
|
1458
|
+
endpoint: name, file, loc: `workflow.nodes[${node.id || "?"}].operation`,
|
|
1459
|
+
message: `set_fields node '${node.id || "(no id)"}' has unsupported operation '${op}'.`,
|
|
1460
|
+
fix_hint: `Use one of: ${[...VALID_SET_FIELDS_OPERATIONS].join(", ")}.`,
|
|
1461
|
+
})
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1440
1464
|
if (node.tool_ids !== undefined && node.tools === undefined) {
|
|
1441
1465
|
const toolIds = Array.isArray(node.tool_ids) ? node.tool_ids : []
|
|
1442
1466
|
const legacyUuidToolIds = toolIds.length === 0 || toolIds.every(isUuidString)
|