windmill-ts 0.1.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.
Files changed (38) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +106 -0
  3. package/dist/package.json +39 -0
  4. package/dist/src/generator/common.js +68 -0
  5. package/dist/src/generator/common.js.map +1 -0
  6. package/dist/src/generator/context.js +13 -0
  7. package/dist/src/generator/context.js.map +1 -0
  8. package/dist/src/generator/flows.js +34 -0
  9. package/dist/src/generator/flows.js.map +1 -0
  10. package/dist/src/generator/index.js +18 -0
  11. package/dist/src/generator/index.js.map +1 -0
  12. package/dist/src/generator/preamble.js +25 -0
  13. package/dist/src/generator/preamble.js.map +1 -0
  14. package/dist/src/generator/resources.js +28 -0
  15. package/dist/src/generator/resources.js.map +1 -0
  16. package/dist/src/generator/scripts.js +34 -0
  17. package/dist/src/generator/scripts.js.map +1 -0
  18. package/dist/src/generator/types.js +2 -0
  19. package/dist/src/generator/types.js.map +1 -0
  20. package/dist/src/index.js +45 -0
  21. package/dist/src/index.js.map +1 -0
  22. package/dist/src/utils/inMemoryDuplex.js +39 -0
  23. package/dist/src/utils/inMemoryDuplex.js.map +1 -0
  24. package/dist/src/windmill/client.js +6 -0
  25. package/dist/src/windmill/client.js.map +1 -0
  26. package/dist/src/windmill/flows.js +23 -0
  27. package/dist/src/windmill/flows.js.map +1 -0
  28. package/dist/src/windmill/resourceTypes.js +12 -0
  29. package/dist/src/windmill/resourceTypes.js.map +1 -0
  30. package/dist/src/windmill/resources.js +18 -0
  31. package/dist/src/windmill/resources.js.map +1 -0
  32. package/dist/src/windmill/scripts.js +23 -0
  33. package/dist/src/windmill/scripts.js.map +1 -0
  34. package/dist/src/windmill/store.js +77 -0
  35. package/dist/src/windmill/store.js.map +1 -0
  36. package/dist/src/windmill/workspace.js +39 -0
  37. package/dist/src/windmill/workspace.js.map +1 -0
  38. package/package.json +41 -0
package/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org>
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # windmill-ts
2
+
3
+ A TypeScript code generator for creating type-safe clients for
4
+ [Windmill](https://www.windmill.dev/).
5
+
6
+ https://github.com/user-attachments/assets/b6bc15a0-3e17-4d93-8b7f-cf10505e14c9
7
+
8
+ Under the hood, it uses the official
9
+ [windmill-client](http://npm.im/windmill-client) library to interact with
10
+ Windmill, and exposes a similar interface.
11
+
12
+ The output is a single file that could be used from Windmill itself (by creating
13
+ a script from the output and importing it from other TypeScript files), and from
14
+ your own codebase (by setting up `windmill-client` in it).
15
+
16
+ ## Features
17
+
18
+ - Generates fully typed TypeScript client code for your Windmill workspace
19
+ - Type-safe access to scripts, flows and resources
20
+ - Automatic schema generation from Windmill's JSON schemas
21
+ - Integration with the Windmill CLI configuration
22
+
23
+ ## Requirements
24
+
25
+ - A configured Windmill CLI environment
26
+
27
+ Refer to the
28
+ [Windmill docs](https://www.windmill.dev/docs/advanced/cli/installation) for
29
+ instructions on how to set up the Windmill CLI.
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install windmill-ts
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ The simplest way to use windmill-ts is to run it with no arguments, which will
40
+ use your active Windmill CLI workspace:
41
+
42
+ ```bash
43
+ npx windmill-ts ./generated-client.ts
44
+ ```
45
+
46
+ You can also specify a specific workspace:
47
+
48
+ ```bash
49
+ npx windmill-ts -w my-workspace ./generated-client.ts
50
+ ```
51
+
52
+ To output to stdout instead of a file, use `-` as the output path:
53
+
54
+ ```bash
55
+ npx windmill-ts -
56
+ ```
57
+
58
+ ## Generated Client Usage
59
+
60
+ The generated client provides type-safe functions for running scripts and flows:
61
+
62
+ ```typescript
63
+ import {
64
+ runScript,
65
+ runScriptAsync,
66
+ runFlow,
67
+ runFlowAsync,
68
+ } from "./generated-client";
69
+
70
+ // Run a script synchronously
71
+ const result = await runScript("my/script/path", {
72
+ // TypeScript will enforce the correct argument types here
73
+ arg1: "value",
74
+ arg2: 42,
75
+ });
76
+
77
+ // Run a script asynchronously
78
+ const jobId = await runScriptAsync("my/script/path", {
79
+ arg1: "value",
80
+ arg2: 42,
81
+ });
82
+
83
+ // Run a flow
84
+ const flowResult = await runFlow("my/flow/path", {
85
+ input1: "value",
86
+ input2: true,
87
+ });
88
+ ```
89
+
90
+ ## How It Works
91
+
92
+ The generator:
93
+
94
+ 1. Connects to your configured Windmill workspace
95
+ 2. Fetches all available scripts, flows and resource types
96
+ 3. Generates Zod schemas for validating inputs
97
+ 4. Creates type-safe wrapper functions for running scripts and flows
98
+ 5. Handles resource type references and validations
99
+
100
+ ## License
101
+
102
+ This project is licensed under the Unlicense - see the LICENSE file for details.
103
+
104
+ ## Contributing
105
+
106
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "windmill-ts",
3
+ "version": "0.1.0",
4
+ "description": "Type-safe client for Windmill",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "build": "rimraf dist/ && tsc",
9
+ "prepublishOnly": "npm run build"
10
+ },
11
+ "keywords": [],
12
+ "author": "Tsvetomir Bonev <me@invak.id>",
13
+ "license": "Unlicense",
14
+ "devDependencies": {
15
+ "@types/node": "^22.9.0",
16
+ "rimraf": "^6.0.1",
17
+ "typescript": "^5.6.3"
18
+ },
19
+ "dependencies": {
20
+ "chalk": "^5.3.0",
21
+ "commander": "^12.1.0",
22
+ "dedent": "^1.5.3",
23
+ "json-schema-to-zod": "^2.4.1",
24
+ "ora": "^8.1.1",
25
+ "p-queue": "^8.0.1",
26
+ "to-valid-identifier": "^0.1.1",
27
+ "windmill-client": "^1.422.0",
28
+ "zod": "^3.23.8"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/invakid404/windmill-ts.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/invakid404/windmill-ts/issues"
36
+ },
37
+ "homepage": "https://github.com/invakid404/windmill-ts#readme",
38
+ "files": ["dist", "README.md"]
39
+ }
@@ -0,0 +1,68 @@
1
+ import toValidIdentifier from "to-valid-identifier";
2
+ import { jsonSchemaToZod } from "json-schema-to-zod";
3
+ import { getContext, run } from "./context.js";
4
+ import { InMemoryDuplex } from "../utils/inMemoryDuplex.js";
5
+ export const runWithBuffer = async (cb) => {
6
+ const buffer = new InMemoryDuplex();
7
+ const result = await run(buffer, cb);
8
+ return { buffer, result };
9
+ };
10
+ export const generateSchemas = async ({ allResourceTypes, generator, mapName, }) => {
11
+ const { write } = getContext();
12
+ const pathToSchemaMap = new Map();
13
+ const referencedResourceTypes = new Set();
14
+ for await (const { path, schema } of generator) {
15
+ if (schema == null) {
16
+ continue;
17
+ }
18
+ const schemaName = toValidIdentifier(`${mapName}_${path}`);
19
+ const zodSchema = jsonSchemaToZod(schema, {
20
+ parserOverride: (schema, _refs) => {
21
+ // NOTE: Windmill sometimes has `default: null` on required fields,
22
+ // which is incorrect for obvious reasons, so as a rule of thumb,
23
+ // we remove null default values as a whole
24
+ if ("default" in schema && schema.default == null) {
25
+ delete schema.default;
26
+ }
27
+ // NOTE: Windmill sometimes has `enum: null` on string fields, and the
28
+ // library doesn't like that, so we need to delete it
29
+ if (schema.type === "string" && schema.enum == null) {
30
+ delete schema.enum;
31
+ return;
32
+ }
33
+ const resourceTypeOrFalse = extractResourceTypeFromSchema(schema);
34
+ if (resourceTypeOrFalse) {
35
+ const { resourceType } = resourceTypeOrFalse;
36
+ // NOTE: we could do a best-effort attempt to resolve non-resource
37
+ // argument types by parsing the script sources (for TS only),
38
+ // but handling things like types imported from elsewhere would
39
+ // not be easy
40
+ if (!(resourceType in allResourceTypes)) {
41
+ return `z.any()`;
42
+ }
43
+ referencedResourceTypes.add(resourceType);
44
+ return toValidIdentifier(resourceType);
45
+ }
46
+ },
47
+ });
48
+ write(`const ${schemaName} = lazyObject(() => ${zodSchema});`);
49
+ pathToSchemaMap.set(path, schemaName);
50
+ }
51
+ write(`const ${mapName} = lazyObject(() => ({`);
52
+ for (const [scriptPath, schemaName] of pathToSchemaMap) {
53
+ write(`${JSON.stringify(scriptPath)}: ${schemaName},`);
54
+ }
55
+ write("} as const))");
56
+ return referencedResourceTypes;
57
+ };
58
+ const RESOURCE_TYPE_PREFIX = "resource-";
59
+ const extractResourceTypeFromSchema = (schema) => {
60
+ if (schema.type !== "object" ||
61
+ !schema.format?.startsWith(RESOURCE_TYPE_PREFIX)) {
62
+ return false;
63
+ }
64
+ return {
65
+ resourceType: schema.format.slice(RESOURCE_TYPE_PREFIX.length),
66
+ };
67
+ };
68
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../../src/generator/common.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const generateStore = new AsyncLocalStorage();
3
+ export const run = (output, cb) => {
4
+ const write = (content) => new Promise((resolve, reject) => output.write(content + "\n", (err) => {
5
+ if (err != null) {
6
+ return void reject(err);
7
+ }
8
+ resolve();
9
+ }));
10
+ return generateStore.run({ write }, cb);
11
+ };
12
+ export const getContext = () => generateStore.getStore();
13
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/generator/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAOrD,MAAM,aAAa,GAAG,IAAI,iBAAiB,EAAmB,CAAC;AAE/D,MAAM,CAAC,MAAM,GAAG,GAAG,CAAK,MAAgB,EAAE,EAAW,EAAE,EAAE;IACvD,MAAM,KAAK,GAAG,CAAC,OAAe,EAAE,EAAE,CAChC,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CACpC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;QACnC,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;YAChB,OAAO,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CACH,CAAC;IAEJ,OAAO,aAAa,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;AAC1C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,34 @@
1
+ import dedent from "dedent";
2
+ import { listFlows } from "../windmill/flows.js";
3
+ import { getContext } from "./context.js";
4
+ import { generateSchemas } from "./common.js";
5
+ const mapName = "flows";
6
+ const preamble = dedent `
7
+ export const runFlow = <Path extends keyof typeof ${mapName}>(
8
+ flowPath: Path,
9
+ args: z.input<(typeof ${mapName})[Path]>,
10
+ ) => {
11
+ const schema = ${mapName}[flowPath];
12
+
13
+ return wmill.runFlow(flowPath, schema.parse(args));
14
+ };
15
+
16
+ export const runFlowAsync = <Path extends keyof typeof ${mapName}>(
17
+ flowPath: Path,
18
+ args: z.input<(typeof ${mapName})[Path]>,
19
+ ) => {
20
+ const schema = ${mapName}[flowPath];
21
+
22
+ return wmill.runFlowAsync(flowPath, schema.parse(args));
23
+ };
24
+ `;
25
+ export const generateFlows = async (allResourceTypes) => {
26
+ const { write } = getContext();
27
+ await write(preamble);
28
+ return generateSchemas({
29
+ allResourceTypes,
30
+ generator: listFlows(),
31
+ mapName,
32
+ });
33
+ };
34
+ //# sourceMappingURL=flows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flows.js","sourceRoot":"","sources":["../../../src/generator/flows.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,MAAM,QAAQ,GAAG,MAAM,CAAA;sDAC+B,OAAO;;4BAEjC,OAAO;;qBAEd,OAAO;;;;;2DAK+B,OAAO;;4BAEtC,OAAO;;qBAEd,OAAO;;;;CAI3B,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,gBAA+B,EAAE,EAAE;IACrE,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,EAAG,CAAC;IAEhC,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEtB,OAAO,eAAe,CAAC;QACrB,gBAAgB;QAChB,SAAS,EAAE,SAAS,EAAE;QACtB,OAAO;KACR,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { writePreamble } from "./preamble.js";
2
+ import { run } from "./context.js";
3
+ import { listResourceTypes } from "../windmill/resourceTypes.js";
4
+ import { generateScripts } from "./scripts.js";
5
+ import { generateResources } from "./resources.js";
6
+ import { generateFlows } from "./flows.js";
7
+ import { runWithBuffer } from "./common.js";
8
+ export const generate = async (output) => run(output, async () => {
9
+ writePreamble();
10
+ const allResourceTypes = await listResourceTypes();
11
+ const results = await Promise.all([generateScripts, generateFlows].map((fn) => runWithBuffer(() => fn(allResourceTypes))));
12
+ const referencedResourceTypes = results.reduce((acc, { buffer, result }) => {
13
+ buffer.pipe(output);
14
+ return acc.union(result);
15
+ }, new Set());
16
+ await generateResources([...referencedResourceTypes]);
17
+ });
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/generator/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAgB,EAAE,EAAE,CACjD,GAAG,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;IACrB,aAAa,EAAE,CAAC;IAEhB,MAAM,gBAAgB,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAC1C,aAAa,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAC1C,CACF,CAAC;IAEF,MAAM,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAC5C,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;QAC1B,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEpB,OAAO,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC,EACD,IAAI,GAAG,EAAU,CAClB,CAAC;IAEF,MAAM,iBAAiB,CAAC,CAAC,GAAG,uBAAuB,CAAC,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import dedent from "dedent";
2
+ import { getContext } from "./context.js";
3
+ const preamble = dedent `
4
+ // This file is auto-generated by windmill-ts, do not modify it manually
5
+ import { z } from 'zod';
6
+ import * as wmill from 'windmill-client';
7
+
8
+ const lazyObject = <T,>(fn: () => T) => {
9
+ let instance: T | null = null;
10
+ return new Proxy({}, {
11
+ get(_target, prop) {
12
+ if (instance == null) {
13
+ instance = fn();
14
+ }
15
+
16
+ return (instance as never)[prop];
17
+ }
18
+ }) as T;
19
+ }
20
+ `;
21
+ export const writePreamble = () => {
22
+ const { write } = getContext();
23
+ write(preamble);
24
+ };
25
+ //# sourceMappingURL=preamble.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preamble.js","sourceRoot":"","sources":["../../../src/generator/preamble.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,QAAQ,GAAG,MAAM,CAAA;;;;;;;;;;;;;;;;;CAiBtB,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE;IAChC,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,EAAG,CAAC;IAEhC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAClB,CAAC,CAAC"}
@@ -0,0 +1,28 @@
1
+ import toValidIdentifier from "to-valid-identifier";
2
+ import { jsonSchemaToZod } from "json-schema-to-zod";
3
+ import PQueue from "p-queue";
4
+ import { listResourcesByType } from "../windmill/resources.js";
5
+ import { getContext } from "./context.js";
6
+ export const generateResources = async (resourceTypes) => {
7
+ const { write } = getContext();
8
+ const resourceQueue = new PQueue({ concurrency: 5 });
9
+ const resources = resourceTypes.map((resourceType) => resourceQueue.add(async () => ({
10
+ resourceType,
11
+ paths: await Array.fromAsync(listResourcesByType(resourceType), ({ path }) => path),
12
+ }), { throwOnTimeout: true }));
13
+ for await (const { resourceType, paths } of resources) {
14
+ const resourceSchema = makeResourceSchema(paths);
15
+ const schemaName = toValidIdentifier(resourceType);
16
+ const zodSchema = jsonSchemaToZod(resourceSchema);
17
+ write(`const ${schemaName} = lazyObject(() => ${zodSchema});`);
18
+ }
19
+ };
20
+ const makeResourceSchema = (paths) => {
21
+ const refs = paths.map((path) => `$res:${path}`);
22
+ return {
23
+ type: "string",
24
+ enum: refs,
25
+ ...(refs.length === 1 && { default: refs[0] }),
26
+ };
27
+ };
28
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../src/generator/resources.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,MAAM,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EAAE,aAAuB,EAAE,EAAE;IACjE,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,EAAG,CAAC;IAEhC,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;IAErD,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CACnD,aAAa,CAAC,GAAG,CACf,KAAK,IAAI,EAAE,CAAC,CAAC;QACX,YAAY;QACZ,KAAK,EAAE,MAAM,KAAK,CAAC,SAAS,CAC1B,mBAAmB,CAAC,YAAY,CAAC,EACjC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CACnB;KACF,CAAC,EACF,EAAE,cAAc,EAAE,IAAI,EAAE,CACzB,CACF,CAAC;IAEF,IAAI,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,IAAI,SAAS,EAAE,CAAC;QACtD,MAAM,cAAc,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAEjD,MAAM,UAAU,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,eAAe,CAAC,cAAc,CAAC,CAAC;QAElD,KAAK,CAAC,SAAS,UAAU,uBAAuB,SAAS,IAAI,CAAC,CAAC;IACjE,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,KAAe,EAAE,EAAE;IAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAEjD,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,IAAI;QACV,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1B,CAAC;AACzB,CAAC,CAAC"}
@@ -0,0 +1,34 @@
1
+ import dedent from "dedent";
2
+ import { listScripts } from "../windmill/scripts.js";
3
+ import { getContext } from "./context.js";
4
+ import { generateSchemas } from "./common.js";
5
+ const mapName = "scripts";
6
+ const preamble = dedent `
7
+ export const runScript = <Path extends keyof typeof ${mapName}>(
8
+ scriptPath: Path,
9
+ args: z.input<(typeof ${mapName})[Path]>,
10
+ ) => {
11
+ const schema = ${mapName}[scriptPath];
12
+
13
+ return wmill.runScript(scriptPath, null, schema.parse(args));
14
+ };
15
+
16
+ export const runScriptAsync = <Path extends keyof typeof ${mapName}>(
17
+ scriptPath: Path,
18
+ args: z.input<(typeof ${mapName})[Path]>,
19
+ ) => {
20
+ const schema = ${mapName}[scriptPath];
21
+
22
+ return wmill.runScriptAsync(scriptPath, null, schema.parse(args));
23
+ };
24
+ `;
25
+ export const generateScripts = async (allResourceTypes) => {
26
+ const { write } = getContext();
27
+ await write(preamble);
28
+ return generateSchemas({
29
+ allResourceTypes,
30
+ generator: listScripts(),
31
+ mapName,
32
+ });
33
+ };
34
+ //# sourceMappingURL=scripts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scripts.js","sourceRoot":"","sources":["../../../src/generator/scripts.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,OAAO,GAAG,SAAS,CAAC;AAE1B,MAAM,QAAQ,GAAG,MAAM,CAAA;wDACiC,OAAO;;4BAEnC,OAAO;;qBAEd,OAAO;;;;;6DAKiC,OAAO;;4BAExC,OAAO;;qBAEd,OAAO;;;;CAI3B,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,gBAA+B,EAAE,EAAE;IACvE,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,EAAG,CAAC;IAEhC,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEtB,OAAO,eAAe,CAAC;QACrB,gBAAgB;QAChB,SAAS,EAAE,WAAW,EAAE;QACxB,OAAO;KACR,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/generator/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,45 @@
1
+ import packageJSON from "../package.json" with { type: "json" };
2
+ import { Command } from "commander";
3
+ import { setup } from "./windmill/client.js";
4
+ import { getActiveWorkspaceName, getWorkspace } from "./windmill/workspace.js";
5
+ import { generate } from "./generator/index.js";
6
+ import * as fs from "node:fs";
7
+ import ora from "ora";
8
+ import chalk from "chalk";
9
+ const program = new Command();
10
+ program
11
+ .name("windmill-ts")
12
+ .description("Type-safe Windmill client for TypeScript")
13
+ .version(packageJSON.version);
14
+ program
15
+ .command("generate", { isDefault: true })
16
+ .description("Generate client")
17
+ .argument("<output>", "output path; provide - to output to stdout")
18
+ .option("-w, --workspace <name>", "target Windmill workspace, defaults to the active Windmill CLI workspace")
19
+ .action(async (output, options) => {
20
+ const isStdout = output === "-";
21
+ let workspaceName = options.workspace;
22
+ if (!workspaceName) {
23
+ workspaceName = await getActiveWorkspaceName();
24
+ if (!isStdout) {
25
+ console.error(chalk.yellow(`⚠️ Workspace name not provided, defaulting to "${workspaceName}"`));
26
+ }
27
+ }
28
+ const workspace = await getWorkspace(workspaceName);
29
+ if (workspace == null) {
30
+ throw new Error(`Workspace with name ${workspace} not found in Windmill CLI config`);
31
+ }
32
+ setup(workspace);
33
+ const stream = isStdout ? process.stdout : fs.createWriteStream(output);
34
+ let spinner = null;
35
+ if (!isStdout) {
36
+ spinner = ora("Generating...").start();
37
+ }
38
+ await generate(stream);
39
+ spinner?.stop();
40
+ if (!isStdout) {
41
+ console.error(chalk.green("🚀 Done!"));
42
+ }
43
+ });
44
+ program.parse();
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,GAAY,MAAM,KAAK,CAAC;AAC/B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,0CAA0C,CAAC;KACvD,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAEhC,OAAO;KACJ,OAAO,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACxC,WAAW,CAAC,iBAAiB,CAAC;KAC9B,QAAQ,CAAC,UAAU,EAAE,4CAA4C,CAAC;KAClE,MAAM,CACL,wBAAwB,EACxB,0EAA0E,CAC3E;KACA,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,OAA+B,EAAE,EAAE;IAChE,MAAM,QAAQ,GAAG,MAAM,KAAK,GAAG,CAAC;IAEhC,IAAI,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC;IACtC,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,aAAa,GAAG,MAAM,sBAAsB,EAAE,CAAC;QAE/C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,MAAM,CACV,kDAAkD,aAAa,GAAG,CACnE,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,CAAC;IACpD,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,uBAAuB,SAAS,mCAAmC,CACpE,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,CAAC;IAEjB,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAExE,IAAI,OAAO,GAAe,IAAI,CAAC;IAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC,KAAK,EAAE,CAAC;IACzC,CAAC;IAED,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEvB,OAAO,EAAE,IAAI,EAAE,CAAC;IAEhB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IACzC,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { Duplex } from "stream";
2
+ export class InMemoryDuplex extends Duplex {
3
+ chunks;
4
+ readIndex;
5
+ constructor(options) {
6
+ super({ ...options, readableObjectMode: true, writableObjectMode: true });
7
+ this.chunks = [];
8
+ this.readIndex = 0;
9
+ }
10
+ _write(chunk, encoding, callback) {
11
+ const buffer = Buffer.isBuffer(chunk)
12
+ ? chunk
13
+ : Buffer.from(chunk, encoding);
14
+ this.chunks.push(buffer);
15
+ callback();
16
+ }
17
+ _read(size) {
18
+ while (this.readIndex < this.chunks.length) {
19
+ const chunk = this.chunks[this.readIndex];
20
+ this.readIndex++;
21
+ if (!this.push(chunk)) {
22
+ return;
23
+ }
24
+ }
25
+ if (this.writableFinished) {
26
+ this.push(null);
27
+ }
28
+ }
29
+ end(chunk, encoding, cb) {
30
+ return super.end(chunk, encoding, cb);
31
+ }
32
+ toString(encoding = "utf8") {
33
+ return Buffer.concat(this.chunks).toString(encoding);
34
+ }
35
+ toBuffer() {
36
+ return Buffer.concat(this.chunks);
37
+ }
38
+ }
39
+ //# sourceMappingURL=inMemoryDuplex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inMemoryDuplex.js","sourceRoot":"","sources":["../../../src/utils/inMemoryDuplex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,OAAO,cAAe,SAAQ,MAAM;IAChC,MAAM,CAAW;IACjB,SAAS,CAAS;IAE1B,YAAY,OAAa;QACvB,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,MAAM,CACJ,KAAU,EACV,QAAwB,EACxB,QAAwC;QAExC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YACnC,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAEjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,KAAK,CAAC,IAAY;QAChB,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC1C,IAAI,CAAC,SAAS,EAAE,CAAC;YAEjB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO;YACT,CAAC;QACH,CAAC;QAED,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAMD,GAAG,CAAC,KAAW,EAAE,QAAc,EAAE,EAAQ;QACvC,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,QAAQ,CAAC,WAA2B,MAAM;QACxC,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;IAED,QAAQ;QACN,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ import * as wmill from "windmill-client";
2
+ export const setup = (workspace) => {
3
+ process.env["WM_WORKSPACE"] = workspace.workspaceId;
4
+ wmill.setClient(workspace.token, new URL(workspace.remote).origin);
5
+ };
6
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/windmill/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAC;AAGzC,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,SAAoB,EAAE,EAAE;IAC5C,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC;IACpD,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AACrE,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import PQueue from "p-queue";
2
+ import * as wmill from "windmill-client";
3
+ const PER_PAGE = 20;
4
+ export async function* listFlows(concurrency) {
5
+ const queue = new PQueue({ concurrency: concurrency ?? 5 });
6
+ const workspace = process.env["WM_WORKSPACE"];
7
+ for (let page = 1;; ++page) {
8
+ const pageData = await wmill.FlowService.listFlows({
9
+ workspace,
10
+ page,
11
+ perPage: PER_PAGE,
12
+ });
13
+ if (pageData.length === 0) {
14
+ break;
15
+ }
16
+ const promises = pageData.map(({ path }) => queue.add(() => wmill.FlowService.getFlowByPath({
17
+ workspace,
18
+ path,
19
+ }), { throwOnTimeout: true }));
20
+ yield* promises;
21
+ }
22
+ }
23
+ //# sourceMappingURL=flows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flows.js","sourceRoot":"","sources":["../../../src/windmill/flows.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAC7B,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAC;AAEzC,MAAM,QAAQ,GAAG,EAAE,CAAC;AAEpB,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,SAAS,CAAC,WAAoB;IACnD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,EAAE,WAAW,EAAE,WAAW,IAAI,CAAC,EAAE,CAAC,CAAC;IAE5D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAE,CAAC;IAE/C,KAAK,IAAI,IAAI,GAAG,CAAC,GAAI,EAAE,IAAI,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC;YACjD,SAAS;YACT,IAAI;YACJ,OAAO,EAAE,QAAQ;SAClB,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CACzC,KAAK,CAAC,GAAG,CACP,GAAG,EAAE,CACH,KAAK,CAAC,WAAW,CAAC,aAAa,CAAC;YAC9B,SAAS;YACT,IAAI;SACL,CAAC,EACJ,EAAE,cAAc,EAAE,IAAI,EAAE,CACzB,CACF,CAAC;QAEF,KAAK,CAAC,CAAC,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ import * as wmill from "windmill-client";
2
+ export const listResourceTypes = async () => {
3
+ const workspace = process.env["WM_WORKSPACE"];
4
+ const resourceTypes = await wmill.ResourceService.listResourceType({
5
+ workspace,
6
+ });
7
+ return resourceTypes.reduce((acc, resourceType) => ({
8
+ ...acc,
9
+ [resourceType.name]: resourceType,
10
+ }), {});
11
+ };
12
+ //# sourceMappingURL=resourceTypes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resourceTypes.js","sourceRoot":"","sources":["../../../src/windmill/resourceTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAC;AAEzC,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,IAAI,EAAE;IAC1C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAE,CAAC;IAE/C,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,gBAAgB,CAAC;QACjE,SAAS;KACV,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC,MAAM,CACzB,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;QACtB,GAAG,GAAG;QACN,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,YAAY;KAClC,CAAC,EACF,EAAiD,CAClD,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import * as wmill from "windmill-client";
2
+ const PER_PAGE = 20;
3
+ export async function* listResourcesByType(resourceType) {
4
+ const workspace = process.env["WM_WORKSPACE"];
5
+ for (let page = 1;; ++page) {
6
+ const pageData = await wmill.ResourceService.listResource({
7
+ workspace,
8
+ page,
9
+ perPage: PER_PAGE,
10
+ resourceType,
11
+ });
12
+ if (pageData.length === 0) {
13
+ break;
14
+ }
15
+ yield* pageData;
16
+ }
17
+ }
18
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../src/windmill/resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAC;AAEzC,MAAM,QAAQ,GAAG,EAAE,CAAC;AAEpB,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,mBAAmB,CAAC,YAAoB;IAC7D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAE,CAAC;IAE/C,KAAK,IAAI,IAAI,GAAG,CAAC,GAAI,EAAE,IAAI,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,YAAY,CAAC;YACxD,SAAS;YACT,IAAI;YACJ,OAAO,EAAE,QAAQ;YACjB,YAAY;SACb,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM;QACR,CAAC;QAED,KAAK,CAAC,CAAC,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ import PQueue from "p-queue";
2
+ import * as wmill from "windmill-client";
3
+ const PER_PAGE = 20;
4
+ export async function* listScripts(concurrency) {
5
+ const queue = new PQueue({ concurrency: concurrency ?? 5 });
6
+ const workspace = process.env["WM_WORKSPACE"];
7
+ for (let page = 1;; ++page) {
8
+ const pageData = await wmill.ScriptService.listScripts({
9
+ workspace,
10
+ page,
11
+ perPage: PER_PAGE,
12
+ });
13
+ if (pageData.length === 0) {
14
+ break;
15
+ }
16
+ const promises = pageData.map(({ path }) => queue.add(() => wmill.ScriptService.getScriptByPath({
17
+ workspace,
18
+ path,
19
+ }), { throwOnTimeout: true }));
20
+ yield* promises;
21
+ }
22
+ }
23
+ //# sourceMappingURL=scripts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scripts.js","sourceRoot":"","sources":["../../../src/windmill/scripts.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAC7B,OAAO,KAAK,KAAK,MAAM,iBAAiB,CAAC;AAEzC,MAAM,QAAQ,GAAG,EAAE,CAAC;AAEpB,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,WAAW,CAAC,WAAoB;IACrD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,EAAE,WAAW,EAAE,WAAW,IAAI,CAAC,EAAE,CAAC,CAAC;IAE5D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAE,CAAC;IAE/C,KAAK,IAAI,IAAI,GAAG,CAAC,GAAI,EAAE,IAAI,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC;YACrD,SAAS;YACT,IAAI;YACJ,OAAO,EAAE,QAAQ;SAClB,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CACzC,KAAK,CAAC,GAAG,CACP,GAAG,EAAE,CACH,KAAK,CAAC,aAAa,CAAC,eAAe,CAAC;YAClC,SAAS;YACT,IAAI;SACL,CAAC,EACJ,EAAE,cAAc,EAAE,IAAI,EAAE,CACzB,CACF,CAAC;QAEF,KAAK,CAAC,CAAC,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,77 @@
1
+ // Lifted from https://github.com/windmill-labs/windmill/blob/main/cli/store.ts
2
+ // with the Deno cruft removed
3
+ import * as fs from "node:fs/promises";
4
+ import * as os from "node:os";
5
+ function ensureDir(dir) {
6
+ return fs.mkdir(dir, { recursive: true });
7
+ }
8
+ function hash_string(str) {
9
+ let hash = 0, i, chr;
10
+ if (str.length === 0)
11
+ return hash;
12
+ for (i = 0; i < str.length; i++) {
13
+ chr = str.charCodeAt(i);
14
+ hash = (hash << 5) - hash + chr;
15
+ hash |= 0; // Convert to 32bit integer
16
+ }
17
+ return hash;
18
+ }
19
+ export async function getRootStore() {
20
+ const store = (config_dir() ?? tmp_dir() ?? "/tmp/") + "/windmill/";
21
+ await ensureDir(store);
22
+ return store;
23
+ }
24
+ export async function getStore(baseUrl) {
25
+ const baseHash = Math.abs(hash_string(baseUrl)).toString(16);
26
+ const baseStore = (await getRootStore()) + baseHash + "/";
27
+ await ensureDir(baseStore);
28
+ return baseStore;
29
+ }
30
+ //inlined import dir from "https://deno.land/x/dir/mod.ts";
31
+ function tmp_dir() {
32
+ switch (os.platform()) {
33
+ case "linux": {
34
+ const xdg = process.env["XDG_RUNTIME_DIR"];
35
+ if (xdg)
36
+ return `${xdg}-/tmp`;
37
+ const tmpDir = process.env["TMPDIR"];
38
+ if (tmpDir)
39
+ return tmpDir;
40
+ const tempDir = process.env["TEMP"];
41
+ if (tempDir)
42
+ return tempDir;
43
+ const tmp = process.env["TMP"];
44
+ if (tmp)
45
+ return tmp;
46
+ return "/var/tmp";
47
+ }
48
+ case "darwin":
49
+ return process.env["TMPDIR"] ?? null;
50
+ case "win32":
51
+ return process.env["TMP"] ?? process.env["TEMP"] ?? null;
52
+ }
53
+ return null;
54
+ }
55
+ function config_dir() {
56
+ switch (os.platform()) {
57
+ case "linux": {
58
+ const xdg = process.env["XDG_CONFIG_HOME"];
59
+ if (xdg)
60
+ return xdg;
61
+ const home = process.env["HOME"];
62
+ if (home)
63
+ return `${home}/.config`;
64
+ break;
65
+ }
66
+ case "darwin": {
67
+ const home = process.env["HOME"];
68
+ if (home)
69
+ return `${home}/Library/Preferences`;
70
+ break;
71
+ }
72
+ case "win32":
73
+ return process.env["APPDATA"] ?? null;
74
+ }
75
+ return null;
76
+ }
77
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/windmill/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ import * as path from "node:path";
3
+ import * as fs from "node:fs/promises";
4
+ import { getRootStore } from "./store.js";
5
+ export const WorkspaceSchema = z.object({
6
+ remote: z.string().url(),
7
+ workspaceId: z.string(),
8
+ name: z.string(),
9
+ token: z.string(),
10
+ });
11
+ export const getAllWorkspaces = async () => {
12
+ const rootStore = await getRootStore();
13
+ const workspacesPath = path.join(rootStore, "remotes.ndjson");
14
+ const content = await fs.readFile(workspacesPath, "utf-8");
15
+ const workspaces = content
16
+ .split("\n")
17
+ .map((line) => {
18
+ if (line.length <= 2) {
19
+ return;
20
+ }
21
+ return WorkspaceSchema.parse(JSON.parse(line));
22
+ })
23
+ .filter((value) => value != null);
24
+ return workspaces.reduce((acc, workspace) => ({
25
+ ...acc,
26
+ [workspace.name]: workspace,
27
+ }), {});
28
+ };
29
+ export const getWorkspace = async (name) => {
30
+ const workspaces = await getAllWorkspaces();
31
+ return workspaces[name];
32
+ };
33
+ export const getActiveWorkspaceName = async () => {
34
+ const rootStore = await getRootStore();
35
+ const activeWorkspacePath = path.join(rootStore, "activeWorkspace");
36
+ const activeWorkspaceName = await fs.readFile(activeWorkspacePath, "utf-8");
37
+ return activeWorkspaceName;
38
+ };
39
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/windmill/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACxB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;CAClB,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,IAAI,EAAE;IACzC,MAAM,SAAS,GAAG,MAAM,YAAY,EAAE,CAAC;IACvC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAE9D,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAE3D,MAAM,UAAU,GAAG,OAAO;SACvB,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,OAAO,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;IAEpC,OAAO,UAAU,CAAC,MAAM,CACtB,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QACnB,GAAG,GAAG;QACN,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS;KAC5B,CAAC,EACF,EAAwC,CACzC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,IAAY,EAAE,EAAE;IACjD,MAAM,UAAU,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAE5C,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,IAAI,EAAE;IAC/C,MAAM,SAAS,GAAG,MAAM,YAAY,EAAE,CAAC;IAEvC,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IACpE,MAAM,mBAAmB,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;IAE5E,OAAO,mBAAmB,CAAC;AAC7B,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "windmill-ts",
3
+ "version": "0.1.0",
4
+ "description": "Type-safe client for Windmill",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "keywords": [],
8
+ "author": "Tsvetomir Bonev <me@invak.id>",
9
+ "license": "Unlicense",
10
+ "devDependencies": {
11
+ "@types/node": "^22.9.0",
12
+ "rimraf": "^6.0.1",
13
+ "typescript": "^5.6.3"
14
+ },
15
+ "dependencies": {
16
+ "chalk": "^5.3.0",
17
+ "commander": "^12.1.0",
18
+ "dedent": "^1.5.3",
19
+ "json-schema-to-zod": "^2.4.1",
20
+ "ora": "^8.1.1",
21
+ "p-queue": "^8.0.1",
22
+ "to-valid-identifier": "^0.1.1",
23
+ "windmill-client": "^1.422.0",
24
+ "zod": "^3.23.8"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/invakid404/windmill-ts.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/invakid404/windmill-ts/issues"
32
+ },
33
+ "homepage": "https://github.com/invakid404/windmill-ts#readme",
34
+ "files": [
35
+ "dist",
36
+ "README.md"
37
+ ],
38
+ "scripts": {
39
+ "build": "rimraf dist/ && tsc"
40
+ }
41
+ }