@thyme-sh/sdk 0.2.0

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/README.md ADDED
@@ -0,0 +1,256 @@
1
+ # @thyme-sh/sdk
2
+
3
+ SDK for authoring Web3 automation tasks with Thyme.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @thyme-sh/sdk zod viem
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Create a task with embedded schema:
14
+
15
+ ```typescript
16
+ import { defineTask, z } from '@thyme-sh/sdk'
17
+ import { encodeFunctionData } from 'viem'
18
+
19
+ const abi = [
20
+ {
21
+ name: 'updatePrice',
22
+ type: 'function',
23
+ stateMutability: 'nonpayable',
24
+ inputs: [{ name: 'price', type: 'uint256' }],
25
+ outputs: [],
26
+ },
27
+ {
28
+ name: 'getPrice',
29
+ type: 'function',
30
+ stateMutability: 'view',
31
+ inputs: [],
32
+ outputs: [{ type: 'uint256' }],
33
+ },
34
+ ] as const
35
+
36
+ export default defineTask({
37
+ // Define your arguments schema with type-safe Ethereum addresses
38
+ schema: z.object({
39
+ oracleAddress: z.address(), // Validates and returns viem's Address type
40
+ threshold: z.number().min(0),
41
+ }),
42
+
43
+ // Main execution logic
44
+ async run(ctx) {
45
+ const { oracleAddress, threshold } = ctx.args
46
+
47
+ // Read from blockchain using the public client
48
+ const lastPrice = await ctx.client.readContract({
49
+ address: oracleAddress,
50
+ abi,
51
+ functionName: 'getPrice',
52
+ })
53
+
54
+ // Your logic here
55
+ const price = await fetchPrice()
56
+
57
+ if (price > threshold && price !== lastPrice) {
58
+ return {
59
+ canExec: true,
60
+ calls: [{
61
+ to: oracleAddress,
62
+ data: encodeFunctionData({
63
+ abi,
64
+ functionName: 'updatePrice',
65
+ args: [price],
66
+ }),
67
+ }]
68
+ }
69
+ }
70
+
71
+ return {
72
+ canExec: false,
73
+ message: 'Price below threshold or unchanged'
74
+ }
75
+ },
76
+
77
+ // Optional: Handle successful execution
78
+ async onSuccess(ctx, txHashes) {
79
+ console.log('Executed:', txHashes)
80
+ },
81
+
82
+ // Optional: Handle failed execution
83
+ async onFail(ctx, error) {
84
+ console.error('Failed:', error.message)
85
+ },
86
+ })
87
+ ```
88
+
89
+ ## Schema Validation
90
+
91
+ The SDK provides an extended Zod instance with Ethereum-specific validators:
92
+
93
+ ### `z.address()`
94
+
95
+ Validates an Ethereum address and returns viem's `Address` type:
96
+
97
+ ```typescript
98
+ import { defineTask, z } from '@thyme-sh/sdk'
99
+
100
+ export default defineTask({
101
+ schema: z.object({
102
+ targetAddress: z.address(), // Validates checksum and format
103
+ }),
104
+ async run(ctx) {
105
+ // ctx.args.targetAddress is typed as Address from viem
106
+ return {
107
+ canExec: true,
108
+ calls: [{
109
+ to: ctx.args.targetAddress,
110
+ data: '0x',
111
+ }]
112
+ }
113
+ }
114
+ })
115
+ ```
116
+
117
+ You can also use standard Zod validators:
118
+
119
+ ```typescript
120
+ schema: z.object({
121
+ address: z.address(),
122
+ amount: z.bigint().positive(),
123
+ enabled: z.boolean(),
124
+ metadata: z.string().optional(),
125
+ })
126
+ ```
127
+
128
+ ## Public Client
129
+
130
+ The context includes a viem `PublicClient` for reading blockchain data:
131
+
132
+ ```typescript
133
+ import { defineTask, z } from '@thyme-sh/sdk'
134
+
135
+ export default defineTask({
136
+ schema: z.object({
137
+ tokenAddress: z.address(),
138
+ threshold: z.bigint(),
139
+ }),
140
+
141
+ async run(ctx) {
142
+ // Read contract state
143
+ const totalSupply = await ctx.client.readContract({
144
+ address: ctx.args.tokenAddress,
145
+ abi: [{
146
+ name: 'totalSupply',
147
+ type: 'function',
148
+ stateMutability: 'view',
149
+ inputs: [],
150
+ outputs: [{ type: 'uint256' }],
151
+ }],
152
+ functionName: 'totalSupply',
153
+ })
154
+
155
+ // Get block data
156
+ const blockNumber = await ctx.client.getBlockNumber()
157
+ const block = await ctx.client.getBlock({ blockNumber })
158
+
159
+ // Get balance
160
+ const balance = await ctx.client.getBalance({
161
+ address: ctx.args.tokenAddress,
162
+ })
163
+
164
+ if (totalSupply > ctx.args.threshold) {
165
+ return {
166
+ canExec: true,
167
+ calls: [...]
168
+ }
169
+ }
170
+
171
+ return {
172
+ canExec: false,
173
+ message: 'Threshold not met'
174
+ }
175
+ }
176
+ })
177
+ ```
178
+
179
+ The client is configured using the `RPC_URL` environment variable in your `.env` file.
180
+
181
+ ## Encoding Function Calls
182
+
183
+ Use viem's `encodeFunctionData` to encode function calls:
184
+
185
+ ```typescript
186
+ import { defineTask, z } from '@thyme-sh/sdk'
187
+ import { encodeFunctionData } from 'viem'
188
+
189
+ const abi = [
190
+ 'function transfer(address to, uint256 amount) returns (bool)',
191
+ ] as const
192
+
193
+ export default defineTask({
194
+ schema: z.object({
195
+ token: z.address(),
196
+ recipient: z.address(),
197
+ }),
198
+
199
+ async run(ctx) {
200
+ return {
201
+ canExec: true,
202
+ calls: [{
203
+ to: ctx.args.token,
204
+ data: encodeFunctionData({
205
+ abi,
206
+ functionName: 'transfer',
207
+ args: [ctx.args.recipient, 1000n],
208
+ }),
209
+ }]
210
+ }
211
+ }
212
+ })
213
+ ```
214
+
215
+ Viem's `encodeFunctionData` provides full type safety and validation.
216
+
217
+ ## API
218
+
219
+ ### `defineTask(definition)`
220
+
221
+ Define a Web3 automation task.
222
+
223
+ #### Parameters
224
+
225
+ - `definition.schema` - Zod schema for validating task arguments
226
+ - `definition.run` - Main execution function that returns whether to execute and what calls to make
227
+ - `definition.onSuccess` - Optional callback on successful execution
228
+ - `definition.onFail` - Optional callback on failed execution
229
+
230
+ #### Returns
231
+
232
+ The task definition (for type inference).
233
+
234
+ ## Types
235
+
236
+ ### `ThymeContext<TArgs>`
237
+
238
+ Context provided to task execution:
239
+ - `args` - User-provided arguments validated against schema
240
+ - `client` - Viem public client for reading blockchain data
241
+
242
+ ### `TaskResult`
243
+
244
+ Result from task execution:
245
+ - `{ canExec: true, calls: Call[] }` - Execute these calls
246
+ - `{ canExec: false, message: string }` - Don't execute, with reason
247
+
248
+ ### `Call`
249
+
250
+ A call to execute on-chain:
251
+ - `to` - Target contract address
252
+ - `data` - Encoded function call data
253
+
254
+ ## License
255
+
256
+ MIT
@@ -0,0 +1,310 @@
1
+ import { z } from 'zod';
2
+ import { PublicClient, Address, Hex } from 'viem';
3
+
4
+ /**
5
+ * Context provided to task execution
6
+ */
7
+ interface ThymeContext<TArgs> {
8
+ /** User-provided arguments validated against schema */
9
+ args: TArgs;
10
+ /** Viem public client for reading blockchain data */
11
+ client: PublicClient;
12
+ }
13
+ /**
14
+ * A call to be executed on-chain
15
+ */
16
+ interface Call {
17
+ /** Target contract address */
18
+ to: Address;
19
+ /** Encoded function call data */
20
+ data: Hex;
21
+ }
22
+ /**
23
+ * Result when task determines execution should proceed
24
+ */
25
+ interface SuccessResult {
26
+ canExec: true;
27
+ /** Array of calls to execute on-chain */
28
+ calls: Call[];
29
+ }
30
+ /**
31
+ * Result when task determines execution should not proceed
32
+ */
33
+ interface FailResult {
34
+ canExec: false;
35
+ /** Reason why execution should not proceed */
36
+ message: string;
37
+ }
38
+ /**
39
+ * Result returned from task execution
40
+ */
41
+ type TaskResult = SuccessResult | FailResult;
42
+ /**
43
+ * Task definition with schema and execution logic
44
+ */
45
+ interface TaskDefinition<TSchema extends z.ZodType> {
46
+ /** Zod schema for validating task arguments */
47
+ schema: TSchema;
48
+ /** Main execution function */
49
+ run: (ctx: ThymeContext<z.infer<TSchema>>) => Promise<TaskResult>;
50
+ }
51
+
52
+ /**
53
+ * Define a Web3 automation task
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * import { defineTask, z } from '@thyme-sh/sdk'
58
+ * import { encodeFunctionData } from 'viem'
59
+ *
60
+ * const abi = [
61
+ * 'function transfer(address to, uint256 amount) returns (bool)',
62
+ * ] as const
63
+ *
64
+ * export default defineTask({
65
+ * schema: z.object({
66
+ * targetAddress: z.address(),
67
+ * }),
68
+ * async run(ctx) {
69
+ * return {
70
+ * canExec: true,
71
+ * calls: [{
72
+ * to: ctx.args.targetAddress,
73
+ * data: encodeFunctionData({
74
+ * abi,
75
+ * functionName: 'transfer',
76
+ * args: [recipientAddress, 1000n],
77
+ * }),
78
+ * }]
79
+ * }
80
+ * }
81
+ * })
82
+ * ```
83
+ */
84
+ declare function defineTask<TSchema extends z.ZodType>(definition: TaskDefinition<TSchema>): TaskDefinition<TSchema>;
85
+
86
+ /**
87
+ * Extended Zod with Ethereum address validation
88
+ */
89
+ declare const zodExtended: {
90
+ /**
91
+ * Validates an Ethereum address and returns viem's Address type
92
+ * Accepts both checksummed and non-checksummed addresses
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * import { zodExtended as z } from '@thyme-sh/sdk'
97
+ *
98
+ * const schema = z.object({
99
+ * targetAddress: z.address(),
100
+ * })
101
+ * ```
102
+ */
103
+ address: () => z.ZodEffects<z.ZodEffects<z.ZodString, `0x${string}`, string>, `0x${string}`, string>;
104
+ setErrorMap(map: z.ZodErrorMap): void;
105
+ getErrorMap(): z.ZodErrorMap;
106
+ defaultErrorMap: z.ZodErrorMap;
107
+ addIssueToContext(ctx: z.ParseContext, issueData: z.IssueData): void;
108
+ makeIssue: (params: {
109
+ data: any;
110
+ path: (string | number)[];
111
+ errorMaps: z.ZodErrorMap[];
112
+ issueData: z.IssueData;
113
+ }) => z.ZodIssue;
114
+ EMPTY_PATH: z.ParsePath;
115
+ ParseStatus: typeof z.ParseStatus;
116
+ INVALID: z.INVALID;
117
+ DIRTY: <T>(value: T) => z.DIRTY<T>;
118
+ OK: <T>(value: T) => z.OK<T>;
119
+ isAborted: (x: z.ParseReturnType<any>) => x is z.INVALID;
120
+ isDirty: <T>(x: z.ParseReturnType<T>) => x is z.OK<T> | z.DIRTY<T>;
121
+ isValid: <T>(x: z.ParseReturnType<T>) => x is z.OK<T>;
122
+ isAsync: <T>(x: z.ParseReturnType<T>) => x is z.AsyncParseReturnType<T>;
123
+ util: typeof z.util;
124
+ objectUtil: typeof z.objectUtil;
125
+ ZodParsedType: {
126
+ string: "string";
127
+ nan: "nan";
128
+ number: "number";
129
+ integer: "integer";
130
+ float: "float";
131
+ boolean: "boolean";
132
+ date: "date";
133
+ bigint: "bigint";
134
+ symbol: "symbol";
135
+ function: "function";
136
+ undefined: "undefined";
137
+ null: "null";
138
+ array: "array";
139
+ object: "object";
140
+ unknown: "unknown";
141
+ promise: "promise";
142
+ void: "void";
143
+ never: "never";
144
+ map: "map";
145
+ set: "set";
146
+ };
147
+ getParsedType: (data: any) => z.ZodParsedType;
148
+ datetimeRegex(args: {
149
+ precision?: number | null;
150
+ offset?: boolean;
151
+ local?: boolean;
152
+ }): RegExp;
153
+ custom<T>(check?: (data: any) => any, _params?: string | (Partial<z.util.Omit<z.ZodCustomIssue, "code">> & {
154
+ fatal?: boolean;
155
+ }) | ((input: any) => Partial<z.util.Omit<z.ZodCustomIssue, "code">> & {
156
+ fatal?: boolean;
157
+ }), fatal?: boolean): z.ZodType<T, z.ZodTypeDef, T>;
158
+ ZodType: typeof z.ZodType;
159
+ ZodString: typeof z.ZodString;
160
+ ZodNumber: typeof z.ZodNumber;
161
+ ZodBigInt: typeof z.ZodBigInt;
162
+ ZodBoolean: typeof z.ZodBoolean;
163
+ ZodDate: typeof z.ZodDate;
164
+ ZodSymbol: typeof z.ZodSymbol;
165
+ ZodUndefined: typeof z.ZodUndefined;
166
+ ZodNull: typeof z.ZodNull;
167
+ ZodAny: typeof z.ZodAny;
168
+ ZodUnknown: typeof z.ZodUnknown;
169
+ ZodNever: typeof z.ZodNever;
170
+ ZodVoid: typeof z.ZodVoid;
171
+ ZodArray: typeof z.ZodArray;
172
+ ZodObject: typeof z.ZodObject;
173
+ ZodUnion: typeof z.ZodUnion;
174
+ ZodDiscriminatedUnion: typeof z.ZodDiscriminatedUnion;
175
+ ZodIntersection: typeof z.ZodIntersection;
176
+ ZodTuple: typeof z.ZodTuple;
177
+ ZodRecord: typeof z.ZodRecord;
178
+ ZodMap: typeof z.ZodMap;
179
+ ZodSet: typeof z.ZodSet;
180
+ ZodFunction: typeof z.ZodFunction;
181
+ ZodLazy: typeof z.ZodLazy;
182
+ ZodLiteral: typeof z.ZodLiteral;
183
+ ZodEnum: typeof z.ZodEnum;
184
+ ZodNativeEnum: typeof z.ZodNativeEnum;
185
+ ZodPromise: typeof z.ZodPromise;
186
+ ZodEffects: typeof z.ZodEffects;
187
+ ZodTransformer: typeof z.ZodEffects;
188
+ ZodOptional: typeof z.ZodOptional;
189
+ ZodNullable: typeof z.ZodNullable;
190
+ ZodDefault: typeof z.ZodDefault;
191
+ ZodCatch: typeof z.ZodCatch;
192
+ ZodNaN: typeof z.ZodNaN;
193
+ BRAND: typeof z.BRAND;
194
+ ZodBranded: typeof z.ZodBranded;
195
+ ZodPipeline: typeof z.ZodPipeline;
196
+ ZodReadonly: typeof z.ZodReadonly;
197
+ Schema: typeof z.ZodType;
198
+ ZodSchema: typeof z.ZodType;
199
+ late: {
200
+ object: <Shape extends z.ZodRawShape>(shape: () => Shape, params?: z.RawCreateParams) => z.ZodObject<Shape, "strip">;
201
+ };
202
+ ZodFirstPartyTypeKind: typeof z.ZodFirstPartyTypeKind;
203
+ coerce: {
204
+ string: (typeof z.ZodString)["create"];
205
+ number: (typeof z.ZodNumber)["create"];
206
+ boolean: (typeof z.ZodBoolean)["create"];
207
+ bigint: (typeof z.ZodBigInt)["create"];
208
+ date: (typeof z.ZodDate)["create"];
209
+ };
210
+ any: (params?: z.RawCreateParams) => z.ZodAny;
211
+ array: <El extends z.ZodTypeAny>(schema: El, params?: z.RawCreateParams) => z.ZodArray<El>;
212
+ bigint: (params?: z.RawCreateParams & {
213
+ coerce?: boolean;
214
+ }) => z.ZodBigInt;
215
+ boolean: (params?: z.RawCreateParams & {
216
+ coerce?: boolean;
217
+ }) => z.ZodBoolean;
218
+ date: (params?: z.RawCreateParams & {
219
+ coerce?: boolean;
220
+ }) => z.ZodDate;
221
+ discriminatedUnion: typeof z.ZodDiscriminatedUnion.create;
222
+ effect: <I extends z.ZodTypeAny>(schema: I, effect: z.Effect<I["_output"]>, params?: z.RawCreateParams) => z.ZodEffects<I, I["_output"]>;
223
+ enum: {
224
+ <U extends string, T extends Readonly<[U, ...U[]]>>(values: T, params?: z.RawCreateParams): z.ZodEnum<z.Writeable<T>>;
225
+ <U extends string, T extends [U, ...U[]]>(values: T, params?: z.RawCreateParams): z.ZodEnum<T>;
226
+ };
227
+ function: typeof z.ZodFunction.create;
228
+ instanceof: <T extends abstract new (..._: any[]) => {}>(cls: T, params?: Partial<z.util.Omit<z.ZodCustomIssue, "code">> & {
229
+ fatal?: boolean;
230
+ }) => z.ZodType<InstanceType<T>, z.ZodTypeDef, InstanceType<T>>;
231
+ intersection: <TSchema extends z.ZodTypeAny, USchema extends z.ZodTypeAny>(left: TSchema, right: USchema, params?: z.RawCreateParams) => z.ZodIntersection<TSchema, USchema>;
232
+ lazy: <Inner extends z.ZodTypeAny>(getter: () => Inner, params?: z.RawCreateParams) => z.ZodLazy<Inner>;
233
+ literal: <Value extends z.Primitive>(value: Value, params?: z.RawCreateParams) => z.ZodLiteral<Value>;
234
+ map: <KeySchema extends z.ZodTypeAny = z.ZodTypeAny, ValueSchema extends z.ZodTypeAny = z.ZodTypeAny>(keyType: KeySchema, valueType: ValueSchema, params?: z.RawCreateParams) => z.ZodMap<KeySchema, ValueSchema>;
235
+ nan: (params?: z.RawCreateParams) => z.ZodNaN;
236
+ nativeEnum: <Elements extends z.EnumLike>(values: Elements, params?: z.RawCreateParams) => z.ZodNativeEnum<Elements>;
237
+ never: (params?: z.RawCreateParams) => z.ZodNever;
238
+ null: (params?: z.RawCreateParams) => z.ZodNull;
239
+ nullable: <Inner extends z.ZodTypeAny>(type: Inner, params?: z.RawCreateParams) => z.ZodNullable<Inner>;
240
+ number: (params?: z.RawCreateParams & {
241
+ coerce?: boolean;
242
+ }) => z.ZodNumber;
243
+ object: <Shape extends z.ZodRawShape>(shape: Shape, params?: z.RawCreateParams) => z.ZodObject<Shape, "strip", z.ZodTypeAny, z.objectOutputType<Shape, z.ZodTypeAny, "strip">, z.objectInputType<Shape, z.ZodTypeAny, "strip">>;
244
+ oboolean: () => z.ZodOptional<z.ZodBoolean>;
245
+ onumber: () => z.ZodOptional<z.ZodNumber>;
246
+ optional: <Inner extends z.ZodTypeAny>(type: Inner, params?: z.RawCreateParams) => z.ZodOptional<Inner>;
247
+ ostring: () => z.ZodOptional<z.ZodString>;
248
+ pipeline: typeof z.ZodPipeline.create;
249
+ preprocess: <I extends z.ZodTypeAny>(preprocess: (arg: unknown, ctx: z.RefinementCtx) => unknown, schema: I, params?: z.RawCreateParams) => z.ZodEffects<I, I["_output"], unknown>;
250
+ promise: <Inner extends z.ZodTypeAny>(schema: Inner, params?: z.RawCreateParams) => z.ZodPromise<Inner>;
251
+ record: typeof z.ZodRecord.create;
252
+ set: <ValueSchema extends z.ZodTypeAny = z.ZodTypeAny>(valueType: ValueSchema, params?: z.RawCreateParams) => z.ZodSet<ValueSchema>;
253
+ strictObject: <Shape extends z.ZodRawShape>(shape: Shape, params?: z.RawCreateParams) => z.ZodObject<Shape, "strict">;
254
+ string: (params?: z.RawCreateParams & {
255
+ coerce?: true;
256
+ }) => z.ZodString;
257
+ symbol: (params?: z.RawCreateParams) => z.ZodSymbol;
258
+ transformer: <I extends z.ZodTypeAny>(schema: I, effect: z.Effect<I["_output"]>, params?: z.RawCreateParams) => z.ZodEffects<I, I["_output"]>;
259
+ tuple: <Items extends [z.ZodTypeAny, ...z.ZodTypeAny[]] | []>(schemas: Items, params?: z.RawCreateParams) => z.ZodTuple<Items, null>;
260
+ undefined: (params?: z.RawCreateParams) => z.ZodUndefined;
261
+ union: <Options extends Readonly<[z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]]>>(types: Options, params?: z.RawCreateParams) => z.ZodUnion<Options>;
262
+ unknown: (params?: z.RawCreateParams) => z.ZodUnknown;
263
+ void: (params?: z.RawCreateParams) => z.ZodVoid;
264
+ NEVER: never;
265
+ ZodIssueCode: {
266
+ invalid_type: "invalid_type";
267
+ invalid_literal: "invalid_literal";
268
+ custom: "custom";
269
+ invalid_union: "invalid_union";
270
+ invalid_union_discriminator: "invalid_union_discriminator";
271
+ invalid_enum_value: "invalid_enum_value";
272
+ unrecognized_keys: "unrecognized_keys";
273
+ invalid_arguments: "invalid_arguments";
274
+ invalid_return_type: "invalid_return_type";
275
+ invalid_date: "invalid_date";
276
+ invalid_string: "invalid_string";
277
+ too_small: "too_small";
278
+ too_big: "too_big";
279
+ invalid_intersection_types: "invalid_intersection_types";
280
+ not_multiple_of: "not_multiple_of";
281
+ not_finite: "not_finite";
282
+ };
283
+ quotelessJson: (obj: any) => string;
284
+ ZodError: typeof z.ZodError;
285
+ };
286
+ /**
287
+ * Type helper to infer the schema type
288
+ */
289
+ type InferSchema<T extends z.ZodType> = z.infer<T>;
290
+
291
+ interface CompressResult {
292
+ zipBuffer: Uint8Array;
293
+ checksum: string;
294
+ }
295
+ interface DecompressResult {
296
+ source: string;
297
+ bundle: string;
298
+ }
299
+ /**
300
+ * Compress source and bundle into a ZIP archive
301
+ * Uses fflate for fast, modern compression
302
+ */
303
+ declare function compressTask(source: string, bundle: string): CompressResult;
304
+ /**
305
+ * Decompress ZIP archive and extract source and bundle files
306
+ * Uses fflate for fast decompression
307
+ */
308
+ declare function decompressTask(zipBuffer: Uint8Array | ArrayBuffer): DecompressResult;
309
+
310
+ export { type Call, type CompressResult, type DecompressResult, type FailResult, type InferSchema, type SuccessResult, type TaskDefinition, type TaskResult, type ThymeContext, compressTask, decompressTask, defineTask, zodExtended as z };
package/dist/index.js ADDED
@@ -0,0 +1,78 @@
1
+ // src/task.ts
2
+ function defineTask(definition) {
3
+ return definition;
4
+ }
5
+
6
+ // src/schema.ts
7
+ import { getAddress, isAddress } from "viem";
8
+ import { z } from "zod";
9
+ var zodExtended = {
10
+ ...z,
11
+ /**
12
+ * Validates an Ethereum address and returns viem's Address type
13
+ * Accepts both checksummed and non-checksummed addresses
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { zodExtended as z } from '@thyme-sh/sdk'
18
+ *
19
+ * const schema = z.object({
20
+ * targetAddress: z.address(),
21
+ * })
22
+ * ```
23
+ */
24
+ address: () => z.string().refine((val) => isAddress(val), {
25
+ message: "Invalid Ethereum address"
26
+ }).transform((val) => getAddress(val))
27
+ };
28
+
29
+ // src/archive.ts
30
+ import { strFromU8, strToU8, unzipSync, zipSync } from "fflate";
31
+ function compressTask(source, bundle) {
32
+ const files = {
33
+ "source.ts": strToU8(source),
34
+ "bundle.js": strToU8(bundle)
35
+ };
36
+ const compressed = zipSync(files, {
37
+ level: 6
38
+ // Balanced compression
39
+ });
40
+ let hash = 0;
41
+ for (let i = 0; i < compressed.length; i++) {
42
+ const byte = compressed[i];
43
+ if (byte !== void 0) {
44
+ hash = (hash << 5) - hash + byte;
45
+ hash = hash & hash;
46
+ }
47
+ }
48
+ const checksum = Math.abs(hash).toString(16);
49
+ return {
50
+ zipBuffer: compressed,
51
+ checksum
52
+ };
53
+ }
54
+ function decompressTask(zipBuffer) {
55
+ const uint8Array = zipBuffer instanceof ArrayBuffer ? new Uint8Array(zipBuffer) : zipBuffer;
56
+ const decompressed = unzipSync(uint8Array);
57
+ const sourceBytes = decompressed["source.ts"];
58
+ const bundleBytes = decompressed["bundle.js"];
59
+ if (!sourceBytes) {
60
+ throw new Error("source.ts not found in ZIP archive");
61
+ }
62
+ if (!bundleBytes) {
63
+ throw new Error("bundle.js not found in ZIP archive");
64
+ }
65
+ const source = strFromU8(sourceBytes);
66
+ const bundle = strFromU8(bundleBytes);
67
+ return {
68
+ source,
69
+ bundle
70
+ };
71
+ }
72
+ export {
73
+ compressTask,
74
+ decompressTask,
75
+ defineTask,
76
+ zodExtended as z
77
+ };
78
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/task.ts","../src/schema.ts","../src/archive.ts"],"sourcesContent":["import type { z } from 'zod'\nimport type { TaskDefinition } from './types'\n\n/**\n * Define a Web3 automation task\n *\n * @example\n * ```typescript\n * import { defineTask, z } from '@thyme-sh/sdk'\n * import { encodeFunctionData } from 'viem'\n *\n * const abi = [\n * 'function transfer(address to, uint256 amount) returns (bool)',\n * ] as const\n *\n * export default defineTask({\n * schema: z.object({\n * targetAddress: z.address(),\n * }),\n * async run(ctx) {\n * return {\n * canExec: true,\n * calls: [{\n * to: ctx.args.targetAddress,\n * data: encodeFunctionData({\n * abi,\n * functionName: 'transfer',\n * args: [recipientAddress, 1000n],\n * }),\n * }]\n * }\n * }\n * })\n * ```\n */\nexport function defineTask<TSchema extends z.ZodType>(\n\tdefinition: TaskDefinition<TSchema>,\n): TaskDefinition<TSchema> {\n\treturn definition\n}\n","import { type Address, getAddress, isAddress } from 'viem'\nimport { z } from 'zod'\n\n/**\n * Extended Zod with Ethereum address validation\n */\nexport const zodExtended = {\n\t...z,\n\t/**\n\t * Validates an Ethereum address and returns viem's Address type\n\t * Accepts both checksummed and non-checksummed addresses\n\t *\n\t * @example\n\t * ```typescript\n\t * import { zodExtended as z } from '@thyme-sh/sdk'\n\t *\n\t * const schema = z.object({\n\t * targetAddress: z.address(),\n\t * })\n\t * ```\n\t */\n\taddress: () =>\n\t\tz\n\t\t\t.string()\n\t\t\t.refine((val): val is Address => isAddress(val), {\n\t\t\t\tmessage: 'Invalid Ethereum address',\n\t\t\t})\n\t\t\t.transform((val) => getAddress(val)),\n}\n\n/**\n * Type helper to infer the schema type\n */\nexport type InferSchema<T extends z.ZodType> = z.infer<T>\n","import { strFromU8, strToU8, unzipSync, zipSync } from 'fflate'\n\nexport interface CompressResult {\n\tzipBuffer: Uint8Array\n\tchecksum: string\n}\n\nexport interface DecompressResult {\n\tsource: string\n\tbundle: string\n}\n\n/**\n * Compress source and bundle into a ZIP archive\n * Uses fflate for fast, modern compression\n */\nexport function compressTask(source: string, bundle: string): CompressResult {\n\t// Create ZIP archive with both files\n\tconst files = {\n\t\t'source.ts': strToU8(source),\n\t\t'bundle.js': strToU8(bundle),\n\t}\n\n\tconst compressed = zipSync(files, {\n\t\tlevel: 6, // Balanced compression\n\t})\n\n\t// Calculate checksum (simple hash for now)\n\tlet hash = 0\n\tfor (let i = 0; i < compressed.length; i++) {\n\t\tconst byte = compressed[i]\n\t\tif (byte !== undefined) {\n\t\t\thash = (hash << 5) - hash + byte\n\t\t\thash = hash & hash // Convert to 32bit integer\n\t\t}\n\t}\n\tconst checksum = Math.abs(hash).toString(16)\n\n\treturn {\n\t\tzipBuffer: compressed,\n\t\tchecksum,\n\t}\n}\n\n/**\n * Decompress ZIP archive and extract source and bundle files\n * Uses fflate for fast decompression\n */\nexport function decompressTask(\n\tzipBuffer: Uint8Array | ArrayBuffer,\n): DecompressResult {\n\t// Convert ArrayBuffer to Uint8Array if needed\n\tconst uint8Array =\n\t\tzipBuffer instanceof ArrayBuffer ? new Uint8Array(zipBuffer) : zipBuffer\n\n\t// Decompress ZIP\n\tconst decompressed = unzipSync(uint8Array)\n\n\t// Extract files\n\tconst sourceBytes = decompressed['source.ts']\n\tconst bundleBytes = decompressed['bundle.js']\n\n\tif (!sourceBytes) {\n\t\tthrow new Error('source.ts not found in ZIP archive')\n\t}\n\n\tif (!bundleBytes) {\n\t\tthrow new Error('bundle.js not found in ZIP archive')\n\t}\n\n\t// Convert bytes to strings\n\tconst source = strFromU8(sourceBytes)\n\tconst bundle = strFromU8(bundleBytes)\n\n\treturn {\n\t\tsource,\n\t\tbundle,\n\t}\n}\n"],"mappings":";AAmCO,SAAS,WACf,YAC0B;AAC1B,SAAO;AACR;;;ACvCA,SAAuB,YAAY,iBAAiB;AACpD,SAAS,SAAS;AAKX,IAAM,cAAc;AAAA,EAC1B,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcH,SAAS,MACR,EACE,OAAO,EACP,OAAO,CAAC,QAAwB,UAAU,GAAG,GAAG;AAAA,IAChD,SAAS;AAAA,EACV,CAAC,EACA,UAAU,CAAC,QAAQ,WAAW,GAAG,CAAC;AACtC;;;AC5BA,SAAS,WAAW,SAAS,WAAW,eAAe;AAgBhD,SAAS,aAAa,QAAgB,QAAgC;AAE5E,QAAM,QAAQ;AAAA,IACb,aAAa,QAAQ,MAAM;AAAA,IAC3B,aAAa,QAAQ,MAAM;AAAA,EAC5B;AAEA,QAAM,aAAa,QAAQ,OAAO;AAAA,IACjC,OAAO;AAAA;AAAA,EACR,CAAC;AAGD,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC3C,UAAM,OAAO,WAAW,CAAC;AACzB,QAAI,SAAS,QAAW;AACvB,cAAQ,QAAQ,KAAK,OAAO;AAC5B,aAAO,OAAO;AAAA,IACf;AAAA,EACD;AACA,QAAM,WAAW,KAAK,IAAI,IAAI,EAAE,SAAS,EAAE;AAE3C,SAAO;AAAA,IACN,WAAW;AAAA,IACX;AAAA,EACD;AACD;AAMO,SAAS,eACf,WACmB;AAEnB,QAAM,aACL,qBAAqB,cAAc,IAAI,WAAW,SAAS,IAAI;AAGhE,QAAM,eAAe,UAAU,UAAU;AAGzC,QAAM,cAAc,aAAa,WAAW;AAC5C,QAAM,cAAc,aAAa,WAAW;AAE5C,MAAI,CAAC,aAAa;AACjB,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACrD;AAEA,MAAI,CAAC,aAAa;AACjB,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACrD;AAGA,QAAM,SAAS,UAAU,WAAW;AACpC,QAAM,SAAS,UAAU,WAAW;AAEpC,SAAO;AAAA,IACN;AAAA,IACA;AAAA,EACD;AACD;","names":[]}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@thyme-sh/sdk",
3
+ "version": "0.2.0",
4
+ "description": "SDK for authoring Web3 automation tasks",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "dev": "tsup --watch",
20
+ "test": "echo \"No tests yet\""
21
+ },
22
+ "keywords": [
23
+ "web3",
24
+ "automation",
25
+ "ethereum",
26
+ "tasks",
27
+ "thyme"
28
+ ],
29
+ "author": "",
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "fflate": "^0.8.2",
33
+ "viem": "^2.21.54",
34
+ "zod": "^3.24.1"
35
+ },
36
+ "devDependencies": {
37
+ "tsup": "^8.3.5",
38
+ "typescript": "^5.7.2"
39
+ }
40
+ }