@sundaeswap/sprinkles 0.1.1 → 0.2.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"tx-dialog.test.js","names":["describe","test","expect","mock","beforeEach","Type","selectCalls","selectResponses","module","input","password","select","opts","push","response","shift","undefined","search","clipboardContent","clipboardShouldFail","default","writeSync","content","Error","Sprinkle","TestSchema","Object","name","String","sprinkle","logs","origLog","console","log","args","join","mockTx","toCbor","repeat","body","requiredSigners","certs","withdrawals","mockBlaze","wallet","getUsedAddresses","TxDialog","cborLog","find","l","includes","toBeDefined","length","toBeLessThan","toContain","menuCall","choiceNames","choices","map","c","not","HotWallet","hotWalletProto","prototype","mockWallet","create","txCbor","toBe","some","truncatedLog","fullLog","origWarn","warn","beforeSignCalled","signTransaction","tx","submitTransaction","beforeSign"],"sources":["../../../../src/Sprinkle/__tests__/tx-dialog.test.ts"],"sourcesContent":["import { describe, test, expect, mock, beforeEach } from \"bun:test\";\nimport { Type } from \"@sinclair/typebox\";\n\n// Track select calls\nlet selectCalls: any[] = [];\nlet selectResponses: any[] = [];\n\n// Mock @inquirer/prompts\nmock.module(\"@inquirer/prompts\", () => ({\n input: mock(async () => \"test\"),\n password: mock(async () => \"secret\"),\n select: mock(async (opts: any) => {\n selectCalls.push(opts);\n const response = selectResponses.shift();\n if (response === undefined) {\n // Default: return -1 (Back/Exit)\n return -1;\n }\n return response;\n }),\n search: mock(async () => \"result\"),\n}));\n\n// Mock clipboardy\nlet clipboardContent = \"\";\nlet clipboardShouldFail = false;\nmock.module(\"clipboardy\", () => ({\n default: {\n writeSync: (content: string) => {\n if (clipboardShouldFail) throw new Error(\"clipboard not available\");\n clipboardContent = content;\n },\n },\n}));\n\nconst { Sprinkle } = await import(\"../../index.js\");\n\nconst TestSchema = Type.Object({\n name: Type.String(),\n});\n\ndescribe(\"TxDialog (2.6)\", () => {\n beforeEach(() => {\n selectCalls = [];\n selectResponses = [];\n clipboardContent = \"\";\n clipboardShouldFail = false;\n });\n\n test(\"shows truncated CBOR by default\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog\");\n const logs: string[] = [];\n const origLog = console.log;\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n // Just exit immediately\n selectResponses = [-1];\n\n const mockTx = {\n toCbor: () => \"a\".repeat(100),\n body: () => ({\n requiredSigners: () => null,\n certs: () => null,\n withdrawals: () => null,\n }),\n };\n\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n // Should show truncated CBOR (50 chars + ...)\n const cborLog = logs.find(l => l.includes(\"Transaction CBOR:\"));\n expect(cborLog).toBeDefined();\n expect(cborLog!.length).toBeLessThan(100);\n expect(cborLog).toContain(\"...\");\n });\n\n test(\"menu items for non-HotWallet include Expand, Copy, no Sign\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog2\");\n const origLog = console.log;\n console.log = () => {};\n\n selectResponses = [-1];\n\n const mockTx = {\n toCbor: () => \"deadbeef\",\n body: () => ({\n requiredSigners: () => null,\n certs: () => null,\n withdrawals: () => null,\n }),\n };\n\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n // Check the select call had Expand and Copy but not Sign\n const menuCall = selectCalls[0];\n expect(menuCall).toBeDefined();\n const choiceNames = menuCall.choices.map((c: any) => c.name);\n expect(choiceNames).toContain(\"Expand CBOR\");\n expect(choiceNames).toContain(\"Copy CBOR to clipboard\");\n expect(choiceNames).not.toContain(\"Sign and submit transaction\");\n });\n\n test(\"menu items for HotWallet include Sign\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog3\");\n const origLog = console.log;\n console.log = () => {};\n\n // Need to import HotWallet to use instanceof\n const { HotWallet } = await import(\"@blaze-cardano/sdk\");\n\n selectResponses = [-1];\n\n const mockTx = {\n toCbor: () => \"deadbeef\",\n body: () => ({\n requiredSigners: () => null,\n certs: () => null,\n withdrawals: () => null,\n }),\n };\n\n // Create a mock that passes instanceof HotWallet check\n // We need to use Object.create to set the prototype\n const hotWalletProto = HotWallet.prototype;\n const mockWallet = Object.create(hotWalletProto);\n mockWallet.getUsedAddresses = async () => [];\n\n const mockBlaze = {\n wallet: mockWallet,\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n const menuCall = selectCalls[0];\n expect(menuCall).toBeDefined();\n const choiceNames = menuCall.choices.map((c: any) => c.name);\n expect(choiceNames).toContain(\"Sign and submit transaction\");\n });\n\n test(\"copy CBOR to clipboard works\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog4\");\n const origLog = console.log;\n const logs: string[] = [];\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n // Select \"Copy CBOR to clipboard\" (index 1), then Back (-1)\n selectResponses = [1, -1];\n\n const txCbor = \"deadbeefcafebabe\";\n const mockTx = {\n toCbor: () => txCbor,\n body: () => ({\n requiredSigners: () => null,\n certs: () => null,\n withdrawals: () => null,\n }),\n };\n\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n expect(clipboardContent).toBe(txCbor);\n expect(logs.some(l => l.includes(\"copied to clipboard\"))).toBe(true);\n });\n\n test(\"clipboard failure falls back to expanded view\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog5\");\n const origLog = console.log;\n const logs: string[] = [];\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n clipboardShouldFail = true;\n\n // Select \"Copy CBOR to clipboard\" (index 1), \n // It will fail and call showDialog again with expanded=true\n // Then Back (-1) from the expanded menu, then Back from outer\n selectResponses = [1, -1, -1];\n\n const txCbor = \"a\".repeat(100);\n const mockTx = {\n toCbor: () => txCbor,\n body: () => ({\n requiredSigners: () => null,\n certs: () => null,\n withdrawals: () => null,\n }),\n };\n\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n expect(logs.some(l => l.includes(\"Failed to copy\"))).toBe(true);\n // After failure it should show the full CBOR without truncation\n expect(logs.some(l => l.includes(txCbor) && !l.includes(\"...\"))).toBe(true);\n });\n\n test(\"expand CBOR shows full content\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog6\");\n const origLog = console.log;\n const logs: string[] = [];\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n // Select \"Expand CBOR\" (index 0), then Back (-1) from expanded, then Back from outer\n selectResponses = [0, -1, -1];\n\n const txCbor = \"b\".repeat(100);\n const mockTx = {\n toCbor: () => txCbor,\n body: () => ({\n requiredSigners: () => null,\n certs: () => null,\n withdrawals: () => null,\n }),\n };\n\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n // First call shows truncated, second shows full\n const truncatedLog = logs.find(l => l.includes(\"...\") && l.includes(\"Transaction CBOR:\"));\n const fullLog = logs.find(l => l.includes(txCbor) && !l.includes(\"...\"));\n expect(truncatedLog).toBeDefined();\n expect(fullLog).toBeDefined();\n });\n\n test(\"beforeSign hook is called before signing\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog7\");\n const origLog = console.log;\n const origWarn = console.warn;\n console.log = () => {};\n console.warn = () => {};\n\n const { HotWallet } = await import(\"@blaze-cardano/sdk\");\n\n let beforeSignCalled = false;\n\n // Select \"Sign and submit\" (index 2 - after Expand and Copy), then Back\n selectResponses = [2, -1];\n\n const mockTx = {\n toCbor: () => \"deadbeef\",\n body: () => ({\n requiredSigners: () => null,\n certs: () => null,\n withdrawals: () => null,\n }),\n };\n\n const hotWalletProto = HotWallet.prototype;\n const mockWallet = Object.create(hotWalletProto);\n mockWallet.getUsedAddresses = async () => [];\n\n const mockBlaze = {\n wallet: mockWallet,\n signTransaction: async (tx: any) => tx,\n submitTransaction: async () => \"txhash123\",\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any, {\n beforeSign: async () => {\n beforeSignCalled = true;\n },\n });\n console.log = origLog;\n console.warn = origWarn;\n\n expect(beforeSignCalled).toBe(true);\n });\n});\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"tx-dialog.test.js","names":["describe","test","expect","mock","beforeEach","Type","selectCalls","selectResponses","confirmResponses","inputResponses","module","input","response","shift","password","select","opts","push","undefined","confirm","search","clipboardContent","clipboardShouldFail","default","writeSync","content","Error","Sprinkle","TestSchema","Object","name","String","createMockTx","cbor","toCbor","body","requiredSigners","certs","withdrawals","witnessSet","vkeys","setVkeys","setWitnessSet","sprinkle","logs","origLog","console","log","args","join","mockTx","repeat","mockBlaze","wallet","getUsedAddresses","TxDialog","cborLog","find","l","includes","toBeDefined","length","toBeLessThan","toContain","txLog","sigLog","menuCall","choiceNames","choices","map","c","not","HotWallet","hotWalletProto","prototype","mockWallet","create","txCbor","toBe","some","truncatedLog","fullLog","origWarn","warn","beforeSignCalled","signTransaction","tx","size","toCore","beforeSign","firstMenuChoices","secondMenuChoices","result","action","txId","toBeUndefined","submitTransaction","values","toString","origErr","error","errors"],"sources":["../../../../src/Sprinkle/__tests__/tx-dialog.test.ts"],"sourcesContent":["import { describe, test, expect, mock, beforeEach } from \"bun:test\";\nimport { Type } from \"@sinclair/typebox\";\n\n// Track calls and responses\nlet selectCalls: any[] = [];\nlet selectResponses: string[] = [];\nlet confirmResponses: boolean[] = [];\nlet inputResponses: string[] = [];\n\n// Mock @inquirer/prompts\nmock.module(\"@inquirer/prompts\", () => ({\n input: mock(async () => {\n const response = inputResponses.shift();\n return response ?? \"\";\n }),\n password: mock(async () => \"secret\"),\n select: mock(async (opts: any) => {\n selectCalls.push(opts);\n const response = selectResponses.shift();\n if (response === undefined) {\n return \"cancel\";\n }\n return response;\n }),\n confirm: mock(async () => {\n const response = confirmResponses.shift();\n return response ?? false;\n }),\n search: mock(async () => \"result\"),\n}));\n\n// Mock clipboardy\nlet clipboardContent = \"\";\nlet clipboardShouldFail = false;\nmock.module(\"clipboardy\", () => ({\n default: {\n writeSync: (content: string) => {\n if (clipboardShouldFail) throw new Error(\"clipboard not available\");\n clipboardContent = content;\n },\n },\n}));\n\nconst { Sprinkle } = await import(\"../../index.js\");\n\nconst TestSchema = Type.Object({\n name: Type.String(),\n});\n\n// Helper to create a mock transaction\nconst createMockTx = (cbor = \"deadbeef\") => ({\n toCbor: () => cbor,\n body: () => ({\n toCbor: () => cbor,\n requiredSigners: () => null,\n certs: () => null,\n withdrawals: () => null,\n }),\n witnessSet: () => ({\n vkeys: () => null,\n setVkeys: () => {},\n }),\n setWitnessSet: () => {},\n});\n\ndescribe(\"TxDialog\", () => {\n beforeEach(() => {\n selectCalls = [];\n selectResponses = [];\n confirmResponses = [];\n inputResponses = [];\n clipboardContent = \"\";\n clipboardShouldFail = false;\n });\n\n describe(\"Display\", () => {\n test(\"shows truncated CBOR by default\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog\");\n const logs: string[] = [];\n const origLog = console.log;\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n selectResponses = [\"cancel\"];\n\n const mockTx = createMockTx(\"a\".repeat(100));\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n const cborLog = logs.find((l) => l.includes(\"Transaction CBOR:\"));\n expect(cborLog).toBeDefined();\n expect(cborLog!.length).toBeLessThan(100);\n expect(cborLog).toContain(\"...\");\n });\n\n test(\"shows transaction hash\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-hash\");\n const logs: string[] = [];\n const origLog = console.log;\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n selectResponses = [\"cancel\"];\n\n const mockTx = createMockTx();\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n const txLog = logs.find((l) => l.includes(\"Transaction:\"));\n expect(txLog).toBeDefined();\n });\n\n test(\"shows signature count\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-sigs\");\n const logs: string[] = [];\n const origLog = console.log;\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n selectResponses = [\"cancel\"];\n\n const mockTx = createMockTx();\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n const sigLog = logs.find((l) => l.includes(\"Signatures:\"));\n expect(sigLog).toBeDefined();\n expect(sigLog).toContain(\"0\");\n });\n });\n\n describe(\"Menu options\", () => {\n test(\"non-HotWallet has Expand, Copy, Import, Submit, Cancel - no Sign\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog2\");\n const origLog = console.log;\n console.log = () => {};\n\n selectResponses = [\"cancel\"];\n\n const mockTx = createMockTx();\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n const menuCall = selectCalls[0];\n expect(menuCall).toBeDefined();\n const choiceNames = menuCall.choices.map((c: any) => c.name);\n expect(choiceNames).toContain(\"Expand CBOR\");\n expect(choiceNames).toContain(\"Copy CBOR to clipboard\");\n expect(choiceNames).toContain(\"Import signatures from CBOR\");\n expect(choiceNames).toContain(\"Submit transaction\");\n expect(choiceNames).toContain(\"Cancel\");\n expect(choiceNames).not.toContain(\"Sign with this wallet\");\n });\n\n test(\"HotWallet has Sign option\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog3\");\n const origLog = console.log;\n console.log = () => {};\n\n const { HotWallet } = await import(\"@blaze-cardano/sdk\");\n\n selectResponses = [\"cancel\"];\n\n const mockTx = createMockTx();\n\n const hotWalletProto = HotWallet.prototype;\n const mockWallet = Object.create(hotWalletProto);\n mockWallet.getUsedAddresses = async () => [];\n\n const mockBlaze = {\n wallet: mockWallet,\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n const menuCall = selectCalls[0];\n expect(menuCall).toBeDefined();\n const choiceNames = menuCall.choices.map((c: any) => c.name);\n expect(choiceNames).toContain(\"Sign with this wallet\");\n });\n });\n\n describe(\"Copy CBOR\", () => {\n test(\"copies CBOR to clipboard\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog4\");\n const origLog = console.log;\n const logs: string[] = [];\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n selectResponses = [\"copy\", \"cancel\"];\n\n const txCbor = \"deadbeefcafebabe\";\n const mockTx = createMockTx(txCbor);\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n expect(clipboardContent).toBe(txCbor);\n expect(logs.some((l) => l.includes(\"copied to clipboard\"))).toBe(true);\n });\n\n test(\"clipboard failure falls back to expanded view\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog5\");\n const origLog = console.log;\n const logs: string[] = [];\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n clipboardShouldFail = true;\n\n selectResponses = [\"copy\", \"cancel\"];\n\n const txCbor = \"a\".repeat(100);\n const mockTx = createMockTx(txCbor);\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n expect(logs.some((l) => l.includes(\"Failed to copy\"))).toBe(true);\n });\n });\n\n describe(\"Expand CBOR\", () => {\n test(\"shows full content when expanded\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog6\");\n const origLog = console.log;\n const logs: string[] = [];\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n selectResponses = [\"expand\", \"cancel\"];\n\n const txCbor = \"b\".repeat(100);\n const mockTx = createMockTx(txCbor);\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n // First shows truncated, second shows full\n const truncatedLog = logs.find(\n (l) => l.includes(\"...\") && l.includes(\"Transaction CBOR:\"),\n );\n const fullLog = logs.find(\n (l) => l.includes(txCbor) && !l.includes(\"...\"),\n );\n expect(truncatedLog).toBeDefined();\n expect(fullLog).toBeDefined();\n });\n });\n\n describe(\"Sign\", () => {\n test(\"beforeSign hook is called before signing\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog7\");\n const origLog = console.log;\n const origWarn = console.warn;\n console.log = () => {};\n console.warn = () => {};\n\n const { HotWallet } = await import(\"@blaze-cardano/sdk\");\n\n let beforeSignCalled = false;\n\n selectResponses = [\"sign\", \"cancel\"];\n\n const mockTx = createMockTx();\n\n const hotWalletProto = HotWallet.prototype;\n const mockWallet = Object.create(hotWalletProto);\n mockWallet.getUsedAddresses = async () => [];\n\n const mockBlaze = {\n wallet: mockWallet,\n signTransaction: async (tx: any) => ({\n witnessSet: () => ({\n vkeys: () => ({\n size: () => 1,\n toCore: () => [[\"vkey123\", \"sig123\"]],\n }),\n }),\n }),\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any, {\n beforeSign: async () => {\n beforeSignCalled = true;\n },\n });\n console.log = origLog;\n console.warn = origWarn;\n\n expect(beforeSignCalled).toBe(true);\n });\n\n test(\"Sign option hidden after signing\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-signed\");\n const origLog = console.log;\n const origWarn = console.warn;\n console.log = () => {};\n console.warn = () => {};\n\n const { HotWallet } = await import(\"@blaze-cardano/sdk\");\n\n selectResponses = [\"sign\", \"cancel\"];\n\n const mockTx = createMockTx();\n\n const hotWalletProto = HotWallet.prototype;\n const mockWallet = Object.create(hotWalletProto);\n mockWallet.getUsedAddresses = async () => [];\n\n const mockBlaze = {\n wallet: mockWallet,\n signTransaction: async (tx: any) => ({\n witnessSet: () => ({\n vkeys: () => ({\n size: () => 1,\n toCore: () => [[\"vkey123\", \"sig123\"]],\n }),\n }),\n }),\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n console.warn = origWarn;\n\n // First menu should have Sign, second should not\n expect(selectCalls.length).toBe(2);\n const firstMenuChoices = selectCalls[0].choices.map((c: any) => c.name);\n const secondMenuChoices = selectCalls[1].choices.map((c: any) => c.name);\n expect(firstMenuChoices).toContain(\"Sign with this wallet\");\n expect(secondMenuChoices).not.toContain(\"Sign with this wallet\");\n });\n });\n\n describe(\"Return values\", () => {\n test(\"returns cancelled when user cancels\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-cancel\");\n const origLog = console.log;\n console.log = () => {};\n\n selectResponses = [\"cancel\"];\n\n const mockTx = createMockTx();\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n const result = await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n expect(result.action).toBe(\"cancelled\");\n expect(result.tx).toBeDefined();\n expect(result.txId).toBeUndefined();\n });\n\n test(\"returns signed when user signs then cancels\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-signed2\");\n const origLog = console.log;\n const origWarn = console.warn;\n console.log = () => {};\n console.warn = () => {};\n\n const { HotWallet } = await import(\"@blaze-cardano/sdk\");\n\n selectResponses = [\"sign\", \"cancel\"];\n\n const mockTx = createMockTx();\n\n const hotWalletProto = HotWallet.prototype;\n const mockWallet = Object.create(hotWalletProto);\n mockWallet.getUsedAddresses = async () => [];\n\n const mockBlaze = {\n wallet: mockWallet,\n signTransaction: async (tx: any) => ({\n witnessSet: () => ({\n vkeys: () => ({\n size: () => 1,\n toCore: () => [[\"vkey123\", \"sig123\"]],\n }),\n }),\n }),\n };\n\n const result = await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n console.warn = origWarn;\n\n expect(result.action).toBe(\"signed\");\n expect(result.tx).toBeDefined();\n });\n\n test(\"returns submitted with txId on successful submit\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-submit\");\n const origLog = console.log;\n console.log = () => {};\n\n selectResponses = [\"submit\"];\n confirmResponses = [true]; // Confirm submit with no signatures\n\n const mockTx = createMockTx();\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n submitTransaction: async () => \"txhash123456\",\n };\n\n const result = await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n expect(result.action).toBe(\"submitted\");\n expect(result.txId).toBe(\"txhash123456\");\n expect(result.tx).toBeDefined();\n });\n });\n\n describe(\"Submit warnings\", () => {\n test(\"warns when submitting with no signatures\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-warn\");\n const origLog = console.log;\n console.log = () => {};\n\n // First try to submit, decline warning, then cancel\n selectResponses = [\"submit\", \"cancel\"];\n confirmResponses = [false];\n\n const mockTx = createMockTx();\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n const result = await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n // Should have returned to menu, then cancelled\n expect(result.action).toBe(\"cancelled\");\n expect(selectCalls.length).toBe(2);\n });\n });\n\n describe(\"Exit behavior\", () => {\n test(\"exits loop after successful submit\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-exit\");\n const origLog = console.log;\n console.log = () => {};\n\n selectResponses = [\"submit\"];\n confirmResponses = [true];\n\n const mockTx = createMockTx();\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n submitTransaction: async () => \"txhash789\",\n };\n\n const result = await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n // Should only have one menu call - no loop after submit\n expect(selectCalls.length).toBe(1);\n expect(result.action).toBe(\"submitted\");\n });\n });\n\n describe(\"Required signers display\", () => {\n test(\"shows required signers when present\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-req\");\n const logs: string[] = [];\n const origLog = console.log;\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n selectResponses = [\"cancel\"];\n\n const mockTx = {\n toCbor: () => \"deadbeef\",\n body: () => ({\n toCbor: () => \"deadbeef\",\n requiredSigners: () => ({\n values: () => [\n { toString: () => \"abc123def456\" },\n { toString: () => \"789ghi012jkl\" },\n ],\n }),\n certs: () => null,\n withdrawals: () => null,\n }),\n witnessSet: () => ({\n vkeys: () => null,\n }),\n };\n\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n // Should show \"X of Y required\" format\n expect(logs.some((l) => l.includes(\"of\") && l.includes(\"required\"))).toBe(\n true,\n );\n // Should show required signers list\n expect(logs.some((l) => l.includes(\"Required signers:\"))).toBe(true);\n });\n });\n\n describe(\"Import signatures\", () => {\n test(\"continues on empty CBOR input\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-import1\");\n const origLog = console.log;\n const logs: string[] = [];\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n\n selectResponses = [\"import\", \"cancel\"];\n inputResponses = [\"\"]; // Empty input\n\n const mockTx = createMockTx();\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n const result = await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n\n expect(logs.some((l) => l.includes(\"No CBOR provided\"))).toBe(true);\n expect(result.action).toBe(\"cancelled\");\n });\n\n test(\"handles invalid CBOR gracefully\", async () => {\n const sprinkle = new Sprinkle(TestSchema, \"/tmp/test-txdialog-import2\");\n const origLog = console.log;\n const origErr = console.error;\n const logs: string[] = [];\n const errors: string[] = [];\n console.log = (...args: any[]) => logs.push(args.join(\" \"));\n console.error = (...args: any[]) => errors.push(args.join(\" \"));\n\n selectResponses = [\"import\", \"cancel\"];\n inputResponses = [\"not-valid-cbor\"];\n\n const mockTx = createMockTx();\n const mockBlaze = {\n wallet: { getUsedAddresses: async () => [] },\n };\n\n const result = await sprinkle.TxDialog(mockBlaze as any, mockTx as any);\n console.log = origLog;\n console.error = origErr;\n\n expect(errors.some((l) => l.includes(\"Failed to import\"))).toBe(true);\n expect(result.action).toBe(\"cancelled\");\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
@@ -3,7 +3,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
3
3
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
4
4
  import { Blockfrost } from "@blaze-cardano/query";
5
5
  import { Blaze, ColdWallet, Core, HotWallet } from "@blaze-cardano/sdk";
6
- import { CborSet, VkeyWitness } from "@blaze-cardano/core";
6
+ import { CborSet, VkeyWitness, blake2b_256, TxCBOR } from "@blaze-cardano/core";
7
7
  import { confirm, input, password, search, select } from "@inquirer/prompts";
8
8
  import { Kind, Type, OptionalKind } from "@sinclair/typebox";
9
9
  import * as fs from "fs";
@@ -21,7 +21,7 @@ const isObject = t => t[Kind] === "Object";
21
21
  const isRef = t => t[Kind] === "Ref";
22
22
  const isString = t => t[Kind] === "String";
23
23
  const isThis = t => t[Kind] === "This";
24
- // const isTuple = (t: TSchema): t is TTuple => t[Kind] === "Tuple";
24
+ const isTuple = t => t[Kind] === "Tuple";
25
25
  const isUnion = t => t[Kind] === "Union";
26
26
  // const isAny = (t: TSchema): t is TAny => t[Kind] === "Any";
27
27
 
@@ -618,112 +618,359 @@ export class Sprinkle {
618
618
  saveSettings() {
619
619
  this.saveProfile();
620
620
  }
621
+
622
+ // --- TxDialog Helpers ---
623
+
624
+ /**
625
+ * Get the payment key hash from a HotWallet's first address
626
+ */
627
+ async getWalletPaymentKeyHash(wallet) {
628
+ try {
629
+ const addresses = await wallet.getUsedAddresses();
630
+ const address = addresses[0];
631
+ if (!address) return null;
632
+ const paymentCredential = address.asBase()?.getPaymentCredential();
633
+ return paymentCredential?.hash?.toString() ?? null;
634
+ } catch {
635
+ return null;
636
+ }
637
+ }
638
+
639
+ /**
640
+ * Count the number of vkey signatures in a transaction's witness set
641
+ */
642
+ countSignatures(tx) {
643
+ const vkeys = tx.witnessSet().vkeys();
644
+ return vkeys ? vkeys.size() : 0;
645
+ }
646
+
647
+ /**
648
+ * Check if a specific public key has already signed the transaction
649
+ * Compares by vkey (public key bytes)
650
+ */
651
+ hasVkeySigned(tx, vkeyHex) {
652
+ const vkeys = tx.witnessSet().vkeys();
653
+ if (!vkeys) return false;
654
+ const vkeyArray = vkeys.toCore();
655
+ return vkeyArray.some(([vkey]) => vkey === vkeyHex);
656
+ }
657
+
658
+ /**
659
+ * Get the list of required signer key hashes from the transaction body
660
+ */
661
+ getRequiredSigners(tx) {
662
+ const requiredSigners = tx.body().requiredSigners();
663
+ if (!requiredSigners) return [];
664
+ return Array.from(requiredSigners.values()).map(s => s.toString());
665
+ }
666
+
667
+ /**
668
+ * Compute the transaction body hash for display
669
+ */
670
+ getTxBodyHash(tx) {
671
+ const bodyCbor = tx.body().toCbor();
672
+ return blake2b_256(bodyCbor);
673
+ }
674
+
675
+ /**
676
+ * Format a hash for display: first 8 chars + ... + last 8 chars
677
+ */
678
+ formatHash(hash) {
679
+ if (hash.length <= 20) return hash;
680
+ return `${hash.slice(0, 8)}...${hash.slice(-8)}`;
681
+ }
682
+
683
+ /**
684
+ * Merge signatures from source transaction into target transaction.
685
+ * Prevents duplicate signatures by comparing vkey (public key).
686
+ * Returns the count of newly added signatures.
687
+ */
688
+ mergeSignatures(target, source) {
689
+ const targetWs = target.witnessSet();
690
+ const sourceWs = source.witnessSet();
691
+ const targetVkeys = targetWs.vkeys()?.toCore() ?? [];
692
+ const sourceVkeys = sourceWs.vkeys()?.toCore() ?? [];
693
+
694
+ // Find vkeys in source that aren't in target (by comparing public key)
695
+ const existingPubKeys = new Set(targetVkeys.map(([vkey]) => vkey));
696
+ const newVkeys = sourceVkeys.filter(([vkey]) => !existingPubKeys.has(vkey));
697
+ if (newVkeys.length === 0) {
698
+ return 0;
699
+ }
700
+
701
+ // Merge the new vkeys into target
702
+ targetWs.setVkeys(CborSet.fromCore([...targetVkeys, ...newVkeys], VkeyWitness.fromCore));
703
+ target.setWitnessSet(targetWs);
704
+ return newVkeys.length;
705
+ }
621
706
  async TxDialog(blaze, tx, opts) {
622
- const txCbor = tx.toCbor();
707
+ let currentTx = tx;
623
708
  let expanded = false;
624
- const showDialog = async () => {
709
+ let hasSignedThisSession = false;
710
+
711
+ // Check if wallet can sign (is HotWallet)
712
+ const isHotWallet = blaze.wallet instanceof HotWallet;
713
+
714
+ // Get wallet's vkeys for detecting if already signed
715
+ let walletVkeys = [];
716
+ if (isHotWallet) {
717
+ try {
718
+ // Sign a dummy to get the wallet's public keys
719
+ // We'll use this to check if wallet has already signed
720
+ const wallet = blaze.wallet;
721
+ const addresses = await wallet.getUsedAddresses();
722
+ const address = addresses[0];
723
+ if (address) {
724
+ // We can't easily get vkeys without signing, so we'll track after first sign
725
+ }
726
+ } catch {
727
+ // Ignore errors in setup
728
+ }
729
+ }
730
+ while (true) {
731
+ // Display transaction status
732
+ const txHash = this.getTxBodyHash(currentTx);
733
+ const sigCount = this.countSignatures(currentTx);
734
+ const requiredSigners = this.getRequiredSigners(currentTx);
735
+ console.log("");
736
+ console.log(`Transaction: ${this.formatHash(txHash)}`);
737
+ if (requiredSigners.length > 0) {
738
+ console.log(`Signatures: ${sigCount} of ${requiredSigners.length} required`);
739
+ console.log("Required signers:");
740
+ for (const signer of requiredSigners) {
741
+ console.log(` - ${this.formatHash(signer)}`);
742
+ }
743
+ } else {
744
+ console.log(`Signatures: ${sigCount}`);
745
+ }
746
+
747
+ // Display CBOR
748
+ const txCbor = currentTx.toCbor();
625
749
  if (expanded) {
626
750
  console.log("Transaction CBOR:", txCbor);
627
751
  } else {
628
752
  console.log("Transaction CBOR:", `${String(txCbor).slice(0, 50)}...`);
629
753
  }
630
- const menuItems = [];
754
+
755
+ // Build dynamic menu choices
756
+ const choices = [];
757
+
758
+ // "Sign with this wallet" - only if HotWallet and hasn't signed this session
759
+ if (isHotWallet && !hasSignedThisSession) {
760
+ choices.push({
761
+ name: "Sign with this wallet",
762
+ value: "sign"
763
+ });
764
+ }
765
+
766
+ // CBOR options
631
767
  if (!expanded) {
632
- menuItems.push({
633
- title: "Expand CBOR",
634
- action: async () => {
635
- expanded = true;
636
- await showDialog();
637
- }
768
+ choices.push({
769
+ name: "Expand CBOR",
770
+ value: "expand"
638
771
  });
639
772
  }
640
- menuItems.push({
641
- title: "Copy CBOR to clipboard",
642
- action: async () => {
643
- try {
644
- const {
645
- default: clipboard
646
- } = await import("clipboardy");
647
- clipboard.writeSync(String(txCbor));
648
- console.log("Transaction CBOR copied to clipboard.");
649
- } catch (e) {
650
- console.log("Failed to copy to clipboard, expanding instead.");
651
- expanded = true;
652
- await showDialog();
653
- }
654
- }
773
+ choices.push({
774
+ name: "Copy CBOR to clipboard",
775
+ value: "copy"
776
+ });
777
+ choices.push({
778
+ name: "Import signatures from CBOR",
779
+ value: "import"
655
780
  });
656
- if (blaze.wallet instanceof HotWallet) {
657
- menuItems.push({
658
- title: "Sign and submit transaction",
659
- action: async () => {
660
- if (opts?.beforeSign) {
661
- await opts.beforeSign();
662
- }
663
781
 
664
- // Detect if stake key signature is required
665
- let needsStakeKey = false;
666
- try {
667
- const wallet = blaze.wallet;
668
- const addresses = await wallet.getUsedAddresses();
669
- const userAddress = addresses[0];
670
- if (userAddress) {
671
- const stakeCredential = userAddress.asBase()?.getStakeCredential();
672
- const stakeKeyHash = stakeCredential?.hash?.toString();
673
- if (stakeKeyHash) {
674
- const requiredSigners = tx.body().requiredSigners();
675
- if (requiredSigners) {
676
- const signerArray = Array.from(requiredSigners.values());
677
- needsStakeKey = signerArray.some(signer => signer.toString() === stakeKeyHash);
678
- }
679
- const certs = tx.body().certs();
680
- const hasCertificates = certs && certs.size() > 0;
681
- const withdrawals = tx.body().withdrawals();
682
- const hasWithdrawals = withdrawals && withdrawals.size > 0;
683
- if (hasCertificates || hasWithdrawals) {
684
- needsStakeKey = true;
685
- }
686
- }
782
+ // Submit and cancel
783
+ choices.push({
784
+ name: "Submit transaction",
785
+ value: "submit"
786
+ });
787
+ choices.push({
788
+ name: "Cancel",
789
+ value: "cancel"
790
+ });
791
+ const selection = await select({
792
+ message: "Select an option:",
793
+ choices
794
+ });
795
+
796
+ // Handle selection
797
+ if (selection === "sign") {
798
+ if (opts?.beforeSign) {
799
+ await opts.beforeSign();
800
+ }
801
+
802
+ // Detect if stake key signature is required
803
+ let needsStakeKey = false;
804
+ try {
805
+ const wallet = blaze.wallet;
806
+ const addresses = await wallet.getUsedAddresses();
807
+ const userAddress = addresses[0];
808
+ if (userAddress) {
809
+ const stakeCredential = userAddress.asBase()?.getStakeCredential();
810
+ const stakeKeyHash = stakeCredential?.hash?.toString();
811
+ if (stakeKeyHash) {
812
+ const reqSigners = currentTx.body().requiredSigners();
813
+ if (reqSigners) {
814
+ const signerArray = Array.from(reqSigners.values());
815
+ needsStakeKey = signerArray.some(signer => signer.toString() === stakeKeyHash);
687
816
  }
688
- if (needsStakeKey) {
689
- console.log("Transaction requires stake key signature.");
690
- } else {
691
- console.log("Transaction requires payment key signature only.");
817
+ const certs = currentTx.body().certs();
818
+ const hasCertificates = certs && certs.size() > 0;
819
+ const withdrawals = currentTx.body().withdrawals();
820
+ const hasWithdrawals = withdrawals && withdrawals.size > 0;
821
+ if (hasCertificates || hasWithdrawals) {
822
+ needsStakeKey = true;
692
823
  }
693
- } catch (error) {
694
- console.warn("Could not determine stake key requirement, signing with payment key only.");
695
- console.warn(`Error: ${error.message}`);
696
824
  }
697
- let signedTx;
698
- if (needsStakeKey) {
699
- const signed = await blaze.wallet.signTransaction(tx, true, true);
700
- const ws = tx.witnessSet();
701
- const vkeys = ws.vkeys()?.toCore() ?? [];
702
- const signedKeys = signed.vkeys();
703
- if (!signedKeys) {
704
- throw new Error("signTransaction: no signed keys in wallet witness response");
705
- }
706
- if (signedKeys.toCore().some(([vkey]) => vkeys.some(([key2]) => vkey === key2))) {
707
- throw new Error("signTransaction: some keys were already signed");
708
- }
709
- ws.setVkeys(CborSet.fromCore([...signedKeys.toCore(), ...vkeys], VkeyWitness.fromCore));
710
- tx.setWitnessSet(ws);
711
- signedTx = tx;
825
+ }
826
+ if (needsStakeKey) {
827
+ console.log("Transaction requires stake key signature.");
828
+ } else {
829
+ console.log("Transaction requires payment key signature only.");
830
+ }
831
+ } catch (error) {
832
+ console.warn("Could not determine stake key requirement, signing with payment key only.");
833
+ console.warn(`Error: ${error.message}`);
834
+ }
835
+ try {
836
+ if (needsStakeKey) {
837
+ const wallet = blaze.wallet;
838
+ const signed = await wallet.signTransaction(currentTx, true, true);
839
+ const ws = currentTx.witnessSet();
840
+ const existingVkeys = ws.vkeys()?.toCore() ?? [];
841
+ const signedKeys = signed.vkeys();
842
+ if (!signedKeys) {
843
+ throw new Error("signTransaction: no signed keys in wallet witness response");
844
+ }
845
+
846
+ // Check for duplicates before adding
847
+ const newSignedKeys = signedKeys.toCore();
848
+ const existingPubKeys = new Set(existingVkeys.map(([vkey]) => vkey));
849
+ const uniqueNewKeys = newSignedKeys.filter(([vkey]) => !existingPubKeys.has(vkey));
850
+ if (uniqueNewKeys.length === 0) {
851
+ console.log("Wallet has already signed this transaction.");
712
852
  } else {
713
- signedTx = await blaze.signTransaction(tx);
853
+ ws.setVkeys(CborSet.fromCore([...existingVkeys, ...uniqueNewKeys], VkeyWitness.fromCore));
854
+ currentTx.setWitnessSet(ws);
855
+ console.log(`Added ${uniqueNewKeys.length} signature(s).`);
856
+ hasSignedThisSession = true;
857
+ }
858
+ } else {
859
+ const signedTx = await blaze.signTransaction(currentTx);
860
+ // Merge signatures from signed tx into current tx
861
+ const added = this.mergeSignatures(currentTx, signedTx);
862
+ if (added > 0) {
863
+ console.log(`Added ${added} signature(s).`);
864
+ hasSignedThisSession = true;
865
+ } else {
866
+ console.log("Wallet has already signed this transaction.");
714
867
  }
715
- const txId = await blaze.submitTransaction(signedTx);
716
- console.log(`Transaction submitted: ${txId}`);
717
868
  }
869
+ } catch (error) {
870
+ console.error(`Signing failed: ${error.message}`);
871
+ }
872
+ // Continue loop after signing
873
+ continue;
874
+ }
875
+ if (selection === "expand") {
876
+ expanded = true;
877
+ continue;
878
+ }
879
+ if (selection === "copy") {
880
+ try {
881
+ const {
882
+ default: clipboard
883
+ } = await import("clipboardy");
884
+ clipboard.writeSync(String(currentTx.toCbor()));
885
+ console.log("Transaction CBOR copied to clipboard.");
886
+ } catch {
887
+ console.log("Failed to copy to clipboard, expanding instead.");
888
+ expanded = true;
889
+ }
890
+ continue;
891
+ }
892
+ if (selection === "import") {
893
+ const cborInput = await input({
894
+ message: "Paste transaction CBOR (hex):"
718
895
  });
896
+ if (!cborInput || cborInput.trim() === "") {
897
+ console.log("No CBOR provided.");
898
+ continue;
899
+ }
900
+ try {
901
+ const importedTx = Core.Transaction.fromCbor(TxCBOR(cborInput.trim()));
902
+
903
+ // Validate body hash matches
904
+ const currentHash = this.getTxBodyHash(currentTx);
905
+ const importedHash = this.getTxBodyHash(importedTx);
906
+ if (currentHash !== importedHash) {
907
+ const proceed = await confirm({
908
+ message: `Warning: Imported transaction has different body hash.\nCurrent: ${this.formatHash(currentHash)}\nImported: ${this.formatHash(importedHash)}\nProceed anyway?`,
909
+ default: false
910
+ });
911
+ if (!proceed) {
912
+ console.log("Import cancelled.");
913
+ continue;
914
+ }
915
+ }
916
+
917
+ // Merge signatures
918
+ const added = this.mergeSignatures(currentTx, importedTx);
919
+ const sourceVkeys = importedTx.witnessSet().vkeys();
920
+ const sourceCount = sourceVkeys ? sourceVkeys.size() : 0;
921
+ const skipped = sourceCount - added;
922
+ if (added > 0) {
923
+ console.log(`Added ${added} new signature(s).`);
924
+ }
925
+ if (skipped > 0) {
926
+ console.log(`Skipped ${skipped} duplicate signature(s).`);
927
+ }
928
+ if (added === 0 && skipped === 0) {
929
+ console.log("No signatures found in imported transaction.");
930
+ }
931
+ } catch (error) {
932
+ console.error(`Failed to import CBOR: ${error.message}`);
933
+ }
934
+ continue;
719
935
  }
720
- const txMenu = {
721
- title: "Transaction Menu",
722
- items: menuItems
723
- };
724
- await this._showMenu(txMenu, false);
725
- };
726
- await showDialog();
936
+ if (selection === "submit") {
937
+ const sigCount = this.countSignatures(currentTx);
938
+ if (sigCount === 0) {
939
+ const proceed = await confirm({
940
+ message: "Warning: Transaction has no signatures. Submit anyway?",
941
+ default: false
942
+ });
943
+ if (!proceed) {
944
+ continue;
945
+ }
946
+ }
947
+ try {
948
+ const txId = await blaze.submitTransaction(currentTx);
949
+ console.log(`Transaction submitted: ${txId}`);
950
+ return {
951
+ action: "submitted",
952
+ txId,
953
+ tx: currentTx
954
+ };
955
+ } catch (error) {
956
+ console.error(`Submit failed: ${error.message}`);
957
+ // Continue loop to allow retry or other actions
958
+ continue;
959
+ }
960
+ }
961
+ if (selection === "cancel") {
962
+ if (hasSignedThisSession) {
963
+ return {
964
+ action: "signed",
965
+ tx: currentTx
966
+ };
967
+ }
968
+ return {
969
+ action: "cancelled",
970
+ tx: currentTx
971
+ };
972
+ }
973
+ }
727
974
  }
728
975
  async EditStruct(type, current) {
729
976
  return this._editStruct(type, ["root"], current);
@@ -886,6 +1133,16 @@ export class Sprinkle {
886
1133
  }
887
1134
  return arr;
888
1135
  }
1136
+ if (isTuple(type)) {
1137
+ const items = type.items ?? [];
1138
+ const result = [];
1139
+ for (let i = 0; i < items.length; i++) {
1140
+ const itemType = items[i];
1141
+ const value = await this._fillInStruct(itemType, path.concat([`[${i}]`]), defs, def ? def[i] : undefined);
1142
+ result.push(value);
1143
+ }
1144
+ return result;
1145
+ }
889
1146
  throw new Error(`Unable to fill in struct for type at path ${path.join(".")}`);
890
1147
  }
891
1148
  resolveType(type, path, defs) {