easctl 0.1.0 → 0.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easctl",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "CLI tool for the Ethereum Attestation Service — create, revoke, and query attestations from the command line",
5
5
  "bin": {
6
6
  "easctl": "./dist/index.js"
@@ -4,6 +4,7 @@ vi.mock('../../graphql.js', () => ({
4
4
  graphqlQuery: vi.fn(),
5
5
  QUERIES: {
6
6
  getSchemata: 'query GetSchemata',
7
+ getSchemataByCreator: 'query GetSchemataByCreator',
7
8
  },
8
9
  }));
9
10
 
@@ -27,15 +28,14 @@ describe('query-schemas command', () => {
27
28
  await querySchemasCommand.parseAsync(['node', 'test', ...args]);
28
29
  }
29
30
 
30
- it('queries schemas by creator with default skip', async () => {
31
+ it('queries latest schemas without creator', async () => {
31
32
  (graphqlQuery as any).mockResolvedValue({
32
33
  schemata: [{ id: '0xs1', schema: 'uint256 x' }, { id: '0xs2', schema: 'string y' }],
33
34
  });
34
35
 
35
- await runCommand(['-a', '0xCreator']);
36
+ await runCommand([]);
36
37
 
37
38
  expect(graphqlQuery).toHaveBeenCalledWith('ethereum', QUERIES.getSchemata, {
38
- creator: '0xCreator',
39
39
  take: 10,
40
40
  skip: 0,
41
41
  });
@@ -45,6 +45,20 @@ describe('query-schemas command', () => {
45
45
  });
46
46
  });
47
47
 
48
+ it('queries schemas by creator when provided', async () => {
49
+ (graphqlQuery as any).mockResolvedValue({
50
+ schemata: [{ id: '0xs1', schema: 'uint256 x' }],
51
+ });
52
+
53
+ await runCommand(['-a', '0xCreator']);
54
+
55
+ expect(graphqlQuery).toHaveBeenCalledWith('ethereum', QUERIES.getSchemataByCreator, {
56
+ creator: '0xCreator',
57
+ take: 10,
58
+ skip: 0,
59
+ });
60
+ });
61
+
48
62
  it('passes custom limit', async () => {
49
63
  (graphqlQuery as any).mockResolvedValue({ schemata: [] });
50
64
 
@@ -52,7 +66,7 @@ describe('query-schemas command', () => {
52
66
 
53
67
  expect(graphqlQuery).toHaveBeenCalledWith(
54
68
  'ethereum',
55
- QUERIES.getSchemata,
69
+ QUERIES.getSchemataByCreator,
56
70
  expect.objectContaining({ take: 50 })
57
71
  );
58
72
  });
@@ -64,7 +78,7 @@ describe('query-schemas command', () => {
64
78
 
65
79
  expect(graphqlQuery).toHaveBeenCalledWith(
66
80
  'ethereum',
67
- QUERIES.getSchemata,
81
+ QUERIES.getSchemataByCreator,
68
82
  expect.objectContaining({ skip: 15 })
69
83
  );
70
84
  });
@@ -72,7 +86,7 @@ describe('query-schemas command', () => {
72
86
  it('returns empty results with count 0', async () => {
73
87
  (graphqlQuery as any).mockResolvedValue({ schemata: [] });
74
88
 
75
- await runCommand(['-a', '0xCreator']);
89
+ await runCommand([]);
76
90
 
77
91
  expect(output).toHaveBeenCalledWith({
78
92
  success: true,
@@ -83,7 +97,7 @@ describe('query-schemas command', () => {
83
97
  it('handles missing schemata key in response', async () => {
84
98
  (graphqlQuery as any).mockResolvedValue({});
85
99
 
86
- await runCommand(['-a', '0xCreator']);
100
+ await runCommand([]);
87
101
 
88
102
  expect(output).toHaveBeenCalledWith({
89
103
  success: true,
@@ -93,7 +107,7 @@ describe('query-schemas command', () => {
93
107
 
94
108
  it('passes GraphQL errors to handleError', async () => {
95
109
  (graphqlQuery as any).mockRejectedValue(new Error('network timeout'));
96
- await runCommand(['-a', '0xCreator']);
110
+ await runCommand([]);
97
111
  const { handleError } = await import('../../output.js');
98
112
  expect(handleError).toHaveBeenCalledWith(expect.any(Error));
99
113
  const err = (handleError as any).mock.calls[0][0] as Error;
@@ -103,7 +117,7 @@ describe('query-schemas command', () => {
103
117
  it('uses specified chain', async () => {
104
118
  (graphqlQuery as any).mockResolvedValue({ schemata: [] });
105
119
 
106
- await runCommand(['-a', '0xCreator', '-c', 'polygon']);
120
+ await runCommand(['-c', 'polygon']);
107
121
 
108
122
  expect(graphqlQuery).toHaveBeenCalledWith('polygon', QUERIES.getSchemata, expect.any(Object));
109
123
  });
@@ -137,12 +137,19 @@ describe('graphql module', () => {
137
137
  expect(QUERIES.getAttestationsByAttester).toContain('decodedDataJson');
138
138
  });
139
139
 
140
- it('getSchemata queries schemata root field with creator filter', () => {
141
- expect(QUERIES.getSchemata).toContain('$creator: String');
140
+ it('getSchemata queries schemata without creator filter', () => {
142
141
  expect(QUERIES.getSchemata).toContain('$take: Int');
143
142
  expect(QUERIES.getSchemata).toMatch(/schemata\s*\(/);
144
143
  expect(QUERIES.getSchemata).toContain('schema');
145
- expect(QUERIES.getSchemata).toContain('creator');
144
+ expect(QUERIES.getSchemata).not.toContain('$creator');
145
+ });
146
+
147
+ it('getSchemataByCreator queries schemata with creator filter', () => {
148
+ expect(QUERIES.getSchemataByCreator).toContain('$creator: String!');
149
+ expect(QUERIES.getSchemataByCreator).toContain('$take: Int');
150
+ expect(QUERIES.getSchemataByCreator).toMatch(/schemata\s*\(/);
151
+ expect(QUERIES.getSchemataByCreator).toContain('schema');
152
+ expect(QUERIES.getSchemataByCreator).toContain('creator');
146
153
  });
147
154
  });
148
155
  });
@@ -4,24 +4,25 @@ import { output, handleError } from '../output.js';
4
4
  import { validateAddress } from '../validation.js';
5
5
 
6
6
  export const querySchemasCommand = new Command('query-schemas')
7
- .description('Query schemas by creator from the EAS GraphQL API')
8
- .requiredOption('-a, --creator <address>', 'Creator address')
7
+ .description('Query latest schemas from the EAS GraphQL API, optionally filtered by creator')
8
+ .option('-a, --creator <address>', 'Filter by creator address')
9
9
  .option('-n, --limit <number>', 'Max results to return', '10')
10
10
  .option('--skip <number>', 'Number of results to skip (for pagination)', '0')
11
11
  .option('-c, --chain <name>', 'Chain name', 'ethereum')
12
12
  .action(async (opts) => {
13
13
  try {
14
- validateAddress(opts.creator, 'creator');
14
+ if (opts.creator) validateAddress(opts.creator, 'creator');
15
15
 
16
16
  const take = parseInt(opts.limit, 10);
17
17
  const skip = parseInt(opts.skip, 10);
18
18
  if (isNaN(take) || take < 1) throw new Error('--limit must be a positive integer');
19
19
  if (isNaN(skip) || skip < 0) throw new Error('--skip must be a non-negative integer');
20
- const data = await graphqlQuery(opts.chain, QUERIES.getSchemata, {
21
- creator: opts.creator,
22
- take,
23
- skip,
24
- });
20
+
21
+ const query = opts.creator ? QUERIES.getSchemataByCreator : QUERIES.getSchemata;
22
+ const variables: Record<string, unknown> = { take, skip };
23
+ if (opts.creator) variables.creator = opts.creator;
24
+
25
+ const data = await graphqlQuery(opts.chain, query, variables);
25
26
 
26
27
  const schemas = data.schemata || [];
27
28
 
package/src/graphql.ts CHANGED
@@ -118,7 +118,22 @@ export const QUERIES = {
118
118
  }
119
119
  `,
120
120
  getSchemata: `
121
- query GetSchemata($creator: String, $take: Int, $skip: Int) {
121
+ query GetSchemata($take: Int, $skip: Int) {
122
+ schemata(
123
+ take: $take
124
+ skip: $skip
125
+ orderBy: [{ time: desc }]
126
+ ) {
127
+ id
128
+ schema
129
+ creator
130
+ revocable
131
+ time
132
+ }
133
+ }
134
+ `,
135
+ getSchemataByCreator: `
136
+ query GetSchemataByCreator($creator: String!, $take: Int, $skip: Int) {
122
137
  schemata(
123
138
  where: { creator: { equals: $creator } }
124
139
  take: $take