create-pylon 0.0.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/dist/index.js ADDED
@@ -0,0 +1,305 @@
1
+ #!/usr/bin/env node
2
+ // @bun
3
+
4
+ // src/index.ts
5
+ import {Option, program} from "commander";
6
+ // package.json
7
+ var version = "0.0.1";
8
+
9
+ // src/index.ts
10
+ import consola from "consola";
11
+ import {input, select, confirm} from "@inquirer/prompts";
12
+ import path from "path";
13
+ import * as fs from "fs";
14
+ function mkdirp(dir) {
15
+ try {
16
+ fs.mkdirSync(dir, { recursive: true });
17
+ } catch (e) {
18
+ if (e instanceof Error) {
19
+ if ("code" in e && e.code === "EEXIST")
20
+ return;
21
+ }
22
+ throw e;
23
+ }
24
+ }
25
+ import {detect} from "detect-package-manager";
26
+ import {spawnSync} from "child_process";
27
+ async function main(targetDir, options, command) {
28
+ try {
29
+ consola.log(`${command.name()} version ${command.version()}`);
30
+ const {
31
+ install: installArg,
32
+ runtime: runtimeArg,
33
+ template: templateArg,
34
+ packageManager: packageManagerArg,
35
+ client: clientArg,
36
+ clientPath: clientPathArg,
37
+ clientPort: clientPortArg
38
+ } = options;
39
+ let target = "";
40
+ if (targetDir) {
41
+ target = targetDir;
42
+ consola.success(`Using target directory \u2026 ${target}`);
43
+ } else {
44
+ const answer = await input({
45
+ message: "Target directory",
46
+ default: "my-pylon"
47
+ });
48
+ target = answer;
49
+ }
50
+ let projectName = "";
51
+ if (target === ".") {
52
+ projectName = path.basename(process.cwd());
53
+ } else {
54
+ projectName = path.basename(target);
55
+ }
56
+ const runtimeName = runtimeArg || await select({
57
+ message: "Which runtime would you like to use?",
58
+ choices: runtimes.map((runtime2) => ({
59
+ name: `${runtime2.name} (${runtime2.website})`,
60
+ value: runtime2.key
61
+ })),
62
+ default: 0
63
+ });
64
+ if (!runtimeName) {
65
+ throw new Error("No runtime selected");
66
+ }
67
+ const runtime = runtimes.find(({ key }) => key === runtimeName);
68
+ if (!runtime) {
69
+ throw new Error(`Invalid runtime selected: ${runtimeName}`);
70
+ }
71
+ const templateName = templateArg || await select({
72
+ message: "Which template would you like to use?",
73
+ choices: templates.filter((template) => runtime.templates?.includes(template.key)).map((template) => ({
74
+ name: template.name,
75
+ value: template.key
76
+ })),
77
+ default: 0
78
+ });
79
+ if (!templateName) {
80
+ throw new Error("No template selected");
81
+ }
82
+ if (fs.existsSync(target)) {
83
+ if (fs.readdirSync(target).length > 0) {
84
+ const response = await confirm({
85
+ message: "Directory not empty. Continue?",
86
+ default: false
87
+ });
88
+ if (!response) {
89
+ process.exit(1);
90
+ }
91
+ }
92
+ } else {
93
+ mkdirp(target);
94
+ }
95
+ const install = installArg || await confirm({ message: "Would you like to install dependencies?" });
96
+ await createTemplate({
97
+ name: projectName,
98
+ runtime: runtimeName,
99
+ template: templateName,
100
+ target
101
+ });
102
+ let packageManager = packageManagerArg;
103
+ if (runtimeName === "bun" && !packageManager) {
104
+ packageManager = "bun";
105
+ }
106
+ if (install) {
107
+ await installDependencies({ target, packageManager });
108
+ }
109
+ const client = clientArg || await confirm({
110
+ message: "Would you like to enable client generation? (https://pylon.cronit.io/docs/integrations/gqty)",
111
+ default: false
112
+ });
113
+ if (client) {
114
+ let clientRoot = "";
115
+ let clientPath = "";
116
+ if (!clientPathArg) {
117
+ clientRoot = await input({
118
+ message: "Path to the root where the client should be generated",
119
+ default: "."
120
+ });
121
+ clientPath = await input({
122
+ message: "Path to generate the client to",
123
+ default: path.join(clientRoot, "gqty/index.ts"),
124
+ validate: (value) => {
125
+ if (!value.startsWith(clientRoot === "." ? "" : clientRoot)) {
126
+ return "Path must start with the client root";
127
+ }
128
+ return true;
129
+ }
130
+ });
131
+ }
132
+ const clientPort = clientPortArg || await input({
133
+ message: "Port of the pylon server to generate the client from",
134
+ default: "3000"
135
+ });
136
+ consola.start(`Updating pylon dev script to generate client`);
137
+ const devScriptPath = path.join(target, "package.json");
138
+ const devScript = JSON.parse(fs.readFileSync(devScriptPath, "utf-8"));
139
+ devScript.scripts = {
140
+ ...devScript.scripts,
141
+ dev: devScript.scripts.dev + ` --client --client-port ${clientPort} --client-path ${clientPath}`
142
+ };
143
+ fs.writeFileSync(devScriptPath, JSON.stringify(devScript, null, 2));
144
+ consola.success(`Pylon dev script updated`);
145
+ }
146
+ consola.box(`Pylon successfully created in ${target}.\n\nHappy coding!`);
147
+ } catch (e) {
148
+ consola.error(e);
149
+ }
150
+ }
151
+ var __dirname = "/Users/schettn/Documents/pylon/packages/create-pylon/src";
152
+ var runtimes = [
153
+ {
154
+ key: "bun",
155
+ name: "Bun.js",
156
+ website: "https://bunjs.dev",
157
+ templates: ["default"]
158
+ },
159
+ {
160
+ key: "node",
161
+ name: "Node.js",
162
+ website: "https://nodejs.org",
163
+ templates: ["default"]
164
+ },
165
+ {
166
+ key: "cf-workers",
167
+ name: "Cloudflare Workers",
168
+ website: "https://workers.cloudflare.com",
169
+ templates: ["default"]
170
+ }
171
+ ];
172
+ var templates = [
173
+ {
174
+ key: "default",
175
+ name: "Default",
176
+ description: "Default template"
177
+ },
178
+ {
179
+ key: "database",
180
+ name: "Database (Prisma)",
181
+ description: "Template with Prisma ORM"
182
+ }
183
+ ];
184
+ var injectVariablesInContent = (content, variables) => {
185
+ let result = content;
186
+ Object.entries(variables).forEach(([key, value]) => {
187
+ result = result.replaceAll(key, value);
188
+ });
189
+ return result;
190
+ };
191
+ var readdirFilesSyncRecursive = (dir) => {
192
+ const run = (dir2) => {
193
+ const result = [];
194
+ const files = fs.readdirSync(dir2);
195
+ files.forEach((file) => {
196
+ const filePath = path.join(dir2, file);
197
+ if (fs.statSync(filePath).isDirectory() && !filePath.includes("node_modules")) {
198
+ result.push(...run(filePath));
199
+ }
200
+ if (fs.statSync(filePath).isFile()) {
201
+ result.push(filePath);
202
+ }
203
+ });
204
+ return result;
205
+ };
206
+ return run(dir).map((file) => {
207
+ return file.replace(dir, ".");
208
+ });
209
+ };
210
+ var createTemplate = async (options) => {
211
+ const { runtime, template, target } = options;
212
+ const runtimeName = runtimes.find(({ key }) => key === runtime)?.name;
213
+ const templateName = templates.find(({ key }) => key === template)?.name;
214
+ if (!runtimeName) {
215
+ throw new Error(`Invalid runtime: ${runtime}`);
216
+ }
217
+ if (!templateName) {
218
+ throw new Error(`Invalid template: ${template}`);
219
+ }
220
+ const sharedTemplateDir = path.join(__dirname, "..", "templates", "shared");
221
+ if (!fs.existsSync(sharedTemplateDir)) {
222
+ throw new Error(`Shared templates not found: ${sharedTemplateDir}`);
223
+ }
224
+ const templateDir = path.join(__dirname, "..", "templates", runtime, template);
225
+ if (!fs.existsSync(templateDir)) {
226
+ throw new Error(`Template not found: ${templateDir}`);
227
+ }
228
+ const targetDirectoryPath = path.join(process.cwd(), target);
229
+ consola.start(`Creating pylon in ${targetDirectoryPath}`);
230
+ const inject = (content) => {
231
+ return injectVariablesInContent(content, {
232
+ __PYLON_NAME__: options.name
233
+ });
234
+ };
235
+ readdirFilesSyncRecursive(sharedTemplateDir).forEach((file) => {
236
+ const source = path.join(sharedTemplateDir, file);
237
+ const target2 = path.join(targetDirectoryPath, file);
238
+ const targetDir = path.dirname(target2);
239
+ if (runtime === "cf-workers" && source.includes(".github/workflows/publish.yaml")) {
240
+ return;
241
+ }
242
+ if (!fs.existsSync(targetDir)) {
243
+ fs.mkdirSync(targetDir, { recursive: true });
244
+ }
245
+ const injectedContent = inject(fs.readFileSync(source, "utf-8"));
246
+ fs.writeFileSync(target2, injectedContent);
247
+ });
248
+ readdirFilesSyncRecursive(templateDir).forEach((file) => {
249
+ const source = path.join(templateDir, file);
250
+ const target2 = path.join(targetDirectoryPath, file);
251
+ const targetDir = path.dirname(target2);
252
+ if (!fs.existsSync(targetDir)) {
253
+ fs.mkdirSync(targetDir, { recursive: true });
254
+ }
255
+ const injectedContent = inject(fs.readFileSync(source, "utf-8"));
256
+ fs.writeFileSync(target2, injectedContent);
257
+ });
258
+ consola.success(`Pylon created`);
259
+ };
260
+ var installDependencies = async (args) => {
261
+ const target = path.resolve(args.target);
262
+ console.log("target", target);
263
+ if (!args.packageManager) {
264
+ args.packageManager = await detect({
265
+ cwd: target,
266
+ includeGlobalBun: true
267
+ });
268
+ }
269
+ if (!args.packageManager) {
270
+ throw new Error("No package manager found");
271
+ }
272
+ const { packageManager } = args;
273
+ let command = "";
274
+ switch (packageManager) {
275
+ case "yarn":
276
+ command = "yarn";
277
+ break;
278
+ case "npm":
279
+ command = "npm install";
280
+ break;
281
+ case "pnpm":
282
+ command = "pnpm install";
283
+ break;
284
+ case "bun":
285
+ command = "bun install";
286
+ break;
287
+ default:
288
+ throw new Error(`Invalid package manager: ${packageManager}`);
289
+ }
290
+ consola.start(`Installing dependencies using ${packageManager}`);
291
+ const proc = spawnSync(command, {
292
+ cwd: target,
293
+ shell: true,
294
+ stdio: "inherit"
295
+ });
296
+ if (proc.status !== 0) {
297
+ throw new Error(`Failed to install dependencies`);
298
+ }
299
+ consola.success(`Dependencies installed`);
300
+ };
301
+ program.name("create-pylon").version(version).arguments("[target]").addOption(new Option("-i, --install", "Install dependencies")).addOption(new Option("-r, --runtime <runtime>", "Runtime").choices(runtimes.map(({ key }) => key))).addOption(new Option("-t, --template <template>", "Template")).addOption(new Option("-pm, --package-manager <packageManager>", "Package manager")).addOption(new Option("--client", "Enable client generation (https://pylon.cronit.io/docs/integrations/gqty)")).addOption(new Option("--client-path <clientPath>", "Client path")).addOption(new Option("--client-port <clientPort>", "Client port")).action(main);
302
+ program.parse();
303
+
304
+ //# debugId=DACB758B74278AF064756E2164756E21
305
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL2luZGV4LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWwogICAgIiMhL3Vzci9iaW4vZW52IG5vZGVcblxuaW1wb3J0IHtPcHRpb24sIHByb2dyYW0sIHR5cGUgQ29tbWFuZH0gZnJvbSAnY29tbWFuZGVyJ1xuaW1wb3J0IHt2ZXJzaW9ufSBmcm9tICcuLi9wYWNrYWdlLmpzb24nXG5pbXBvcnQgY29uc29sYSBmcm9tICdjb25zb2xhJ1xuaW1wb3J0IHtpbnB1dCwgc2VsZWN0LCBjb25maXJtfSBmcm9tICdAaW5xdWlyZXIvcHJvbXB0cydcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcydcblxuZnVuY3Rpb24gbWtkaXJwKGRpcjogc3RyaW5nKSB7XG4gIHRyeSB7XG4gICAgZnMubWtkaXJTeW5jKGRpciwge3JlY3Vyc2l2ZTogdHJ1ZX0pXG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBpZiAoZSBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICBpZiAoJ2NvZGUnIGluIGUgJiYgZS5jb2RlID09PSAnRUVYSVNUJykgcmV0dXJuXG4gICAgfVxuICAgIHRocm93IGVcbiAgfVxufVxuXG5jb25zdCBydW50aW1lczoge1xuICBrZXk6IHN0cmluZ1xuICBuYW1lOiBzdHJpbmdcbiAgd2Vic2l0ZTogc3RyaW5nXG4gIHRlbXBsYXRlcz86IHN0cmluZ1tdXG59W10gPSBbXG4gIHtcbiAgICBrZXk6ICdidW4nLFxuICAgIG5hbWU6ICdCdW4uanMnLFxuICAgIHdlYnNpdGU6ICdodHRwczovL2J1bmpzLmRldicsXG4gICAgdGVtcGxhdGVzOiBbJ2RlZmF1bHQnXVxuICB9LFxuICB7XG4gICAga2V5OiAnbm9kZScsXG4gICAgbmFtZTogJ05vZGUuanMnLFxuICAgIHdlYnNpdGU6ICdodHRwczovL25vZGVqcy5vcmcnLFxuICAgIHRlbXBsYXRlczogWydkZWZhdWx0J11cbiAgfSxcbiAge1xuICAgIGtleTogJ2NmLXdvcmtlcnMnLFxuICAgIG5hbWU6ICdDbG91ZGZsYXJlIFdvcmtlcnMnLFxuICAgIHdlYnNpdGU6ICdodHRwczovL3dvcmtlcnMuY2xvdWRmbGFyZS5jb20nLFxuICAgIHRlbXBsYXRlczogWydkZWZhdWx0J11cbiAgfVxuXVxuXG5jb25zdCB0ZW1wbGF0ZXM6IHtcbiAga2V5OiBzdHJpbmdcbiAgbmFtZTogc3RyaW5nXG4gIGRlc2NyaXB0aW9uOiBzdHJpbmdcbn1bXSA9IFtcbiAge1xuICAgIGtleTogJ2RlZmF1bHQnLFxuICAgIG5hbWU6ICdEZWZhdWx0JyxcbiAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgdGVtcGxhdGUnXG4gIH0sXG4gIHtcbiAgICBrZXk6ICdkYXRhYmFzZScsXG4gICAgbmFtZTogJ0RhdGFiYXNlIChQcmlzbWEpJyxcbiAgICBkZXNjcmlwdGlvbjogJ1RlbXBsYXRlIHdpdGggUHJpc21hIE9STSdcbiAgfVxuXVxuXG5jb25zdCBpbmplY3RWYXJpYWJsZXNJbkNvbnRlbnQgPSAoXG4gIGNvbnRlbnQ6IHN0cmluZyxcbiAgdmFyaWFibGVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+XG4pID0+IHtcbiAgbGV0IHJlc3VsdCA9IGNvbnRlbnRcblxuICBPYmplY3QuZW50cmllcyh2YXJpYWJsZXMpLmZvckVhY2goKFtrZXksIHZhbHVlXSkgPT4ge1xuICAgIHJlc3VsdCA9IHJlc3VsdC5yZXBsYWNlQWxsKGtleSwgdmFsdWUpXG4gIH0pXG5cbiAgcmV0dXJuIHJlc3VsdFxufVxuY29uc3QgcmVhZGRpckZpbGVzU3luY1JlY3Vyc2l2ZSA9IChkaXI6IHN0cmluZyk6IHN0cmluZ1tdID0+IHtcbiAgY29uc3QgcnVuID0gKGRpcjogc3RyaW5nKTogc3RyaW5nW10gPT4ge1xuICAgIGNvbnN0IHJlc3VsdDogc3RyaW5nW10gPSBbXVxuXG4gICAgY29uc3QgZmlsZXMgPSBmcy5yZWFkZGlyU3luYyhkaXIpXG5cbiAgICBmaWxlcy5mb3JFYWNoKGZpbGUgPT4ge1xuICAgICAgY29uc3QgZmlsZVBhdGggPSBwYXRoLmpvaW4oZGlyLCBmaWxlKVxuXG4gICAgICBpZiAoXG4gICAgICAgIGZzLnN0YXRTeW5jKGZpbGVQYXRoKS5pc0RpcmVjdG9yeSgpICYmXG4gICAgICAgICFmaWxlUGF0aC5pbmNsdWRlcygnbm9kZV9tb2R1bGVzJylcbiAgICAgICkge1xuICAgICAgICByZXN1bHQucHVzaCguLi5ydW4oZmlsZVBhdGgpKVxuICAgICAgfVxuXG4gICAgICAvLyBPbmx5IGFkZCBmaWxlc1xuICAgICAgaWYgKGZzLnN0YXRTeW5jKGZpbGVQYXRoKS5pc0ZpbGUoKSkge1xuICAgICAgICByZXN1bHQucHVzaChmaWxlUGF0aClcbiAgICAgIH1cbiAgICB9KVxuXG4gICAgcmV0dXJuIHJlc3VsdFxuICB9XG5cbiAgcmV0dXJuIHJ1bihkaXIpLm1hcChmaWxlID0+IHtcbiAgICByZXR1cm4gZmlsZS5yZXBsYWNlKGRpciwgJy4nKVxuICB9KVxufVxuXG5jb25zdCBjcmVhdGVUZW1wbGF0ZSA9IGFzeW5jIChvcHRpb25zOiB7XG4gIG5hbWU6IHN0cmluZ1xuICBydW50aW1lOiBzdHJpbmdcbiAgdGVtcGxhdGU6IHN0cmluZ1xuICB0YXJnZXQ6IHN0cmluZ1xufSkgPT4ge1xuICBjb25zdCB7cnVudGltZSwgdGVtcGxhdGUsIHRhcmdldH0gPSBvcHRpb25zXG5cbiAgY29uc3QgcnVudGltZU5hbWUgPSBydW50aW1lcy5maW5kKCh7a2V5fSkgPT4ga2V5ID09PSBydW50aW1lKT8ubmFtZVxuICBjb25zdCB0ZW1wbGF0ZU5hbWUgPSB0ZW1wbGF0ZXMuZmluZCgoe2tleX0pID0+IGtleSA9PT0gdGVtcGxhdGUpPy5uYW1lXG5cbiAgaWYgKCFydW50aW1lTmFtZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBydW50aW1lOiAke3J1bnRpbWV9YClcbiAgfVxuXG4gIGlmICghdGVtcGxhdGVOYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHRlbXBsYXRlOiAke3RlbXBsYXRlfWApXG4gIH1cblxuICAvLyBUaGUgdGVtcGxhdGVzIGFyZSBzdG9yZWQgaW4gdGhlIGB0ZW1wbGF0ZXNgIGRpcmVjdG9yeVxuICBjb25zdCBzaGFyZWRUZW1wbGF0ZURpciA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICd0ZW1wbGF0ZXMnLCAnc2hhcmVkJylcblxuICBpZiAoIWZzLmV4aXN0c1N5bmMoc2hhcmVkVGVtcGxhdGVEaXIpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBTaGFyZWQgdGVtcGxhdGVzIG5vdCBmb3VuZDogJHtzaGFyZWRUZW1wbGF0ZURpcn1gKVxuICB9XG5cbiAgY29uc3QgdGVtcGxhdGVEaXIgPSBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAndGVtcGxhdGVzJywgcnVudGltZSwgdGVtcGxhdGUpXG5cbiAgaWYgKCFmcy5leGlzdHNTeW5jKHRlbXBsYXRlRGlyKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgVGVtcGxhdGUgbm90IGZvdW5kOiAke3RlbXBsYXRlRGlyfWApXG4gIH1cblxuICAvLyBUaGUgdGFyZ2V0IGRpcmVjdG9yeSBpcyBhbHJlYWR5IGNyZWF0ZWRcbiAgY29uc3QgdGFyZ2V0RGlyZWN0b3J5UGF0aCA9IHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCB0YXJnZXQpXG5cbiAgY29uc29sYS5zdGFydChgQ3JlYXRpbmcgcHlsb24gaW4gJHt0YXJnZXREaXJlY3RvcnlQYXRofWApXG5cbiAgY29uc3QgaW5qZWN0ID0gKGNvbnRlbnQ6IHN0cmluZykgPT4ge1xuICAgIHJldHVybiBpbmplY3RWYXJpYWJsZXNJbkNvbnRlbnQoY29udGVudCwge1xuICAgICAgX19QWUxPTl9OQU1FX186IG9wdGlvbnMubmFtZVxuICAgIH0pXG4gIH1cblxuICAvLyBDb3B5IHRoZSBzaGFyZWQgdGVtcGxhdGUgZmlsZXNcbiAgcmVhZGRpckZpbGVzU3luY1JlY3Vyc2l2ZShzaGFyZWRUZW1wbGF0ZURpcikuZm9yRWFjaChmaWxlID0+IHtcbiAgICBjb25zdCBzb3VyY2UgPSBwYXRoLmpvaW4oc2hhcmVkVGVtcGxhdGVEaXIsIGZpbGUpXG4gICAgY29uc3QgdGFyZ2V0ID0gcGF0aC5qb2luKHRhcmdldERpcmVjdG9yeVBhdGgsIGZpbGUpXG5cbiAgICAvLyBDcmVhdGUgZm9sZGVyIHJlY3Vyc2l2ZWx5IGFuZCBjb3B5IGZpbGVcblxuICAgIGNvbnN0IHRhcmdldERpciA9IHBhdGguZGlybmFtZSh0YXJnZXQpXG5cbiAgICAvLyBTa2lwIHRoZSAuZ2l0aHViL3dvcmtmbG93cyBkaXJlY3RvcnkgZm9yIGNmLXdvcmtlcnMgcnVudGltZVxuICAgIGlmIChcbiAgICAgIHJ1bnRpbWUgPT09ICdjZi13b3JrZXJzJyAmJlxuICAgICAgc291cmNlLmluY2x1ZGVzKCcuZ2l0aHViL3dvcmtmbG93cy9wdWJsaXNoLnlhbWwnKVxuICAgICkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKHRhcmdldERpcikpIHtcbiAgICAgIGZzLm1rZGlyU3luYyh0YXJnZXREaXIsIHtyZWN1cnNpdmU6IHRydWV9KVxuICAgIH1cblxuICAgIGNvbnN0IGluamVjdGVkQ29udGVudCA9IGluamVjdChmcy5yZWFkRmlsZVN5bmMoc291cmNlLCAndXRmLTgnKSlcblxuICAgIGZzLndyaXRlRmlsZVN5bmModGFyZ2V0LCBpbmplY3RlZENvbnRlbnQpXG4gIH0pXG5cbiAgLy8gQ29weSB0aGUgcnVudGltZSBzcGVjaWZpYyB0ZW1wbGF0ZSBmaWxlc1xuICByZWFkZGlyRmlsZXNTeW5jUmVjdXJzaXZlKHRlbXBsYXRlRGlyKS5mb3JFYWNoKGZpbGUgPT4ge1xuICAgIGNvbnN0IHNvdXJjZSA9IHBhdGguam9pbih0ZW1wbGF0ZURpciwgZmlsZSlcbiAgICBjb25zdCB0YXJnZXQgPSBwYXRoLmpvaW4odGFyZ2V0RGlyZWN0b3J5UGF0aCwgZmlsZSlcblxuICAgIC8vIENyZWF0ZSBmb2xkZXIgcmVjdXJzaXZlbHkgYW5kIGNvcHkgZmlsZVxuICAgIGNvbnN0IHRhcmdldERpciA9IHBhdGguZGlybmFtZSh0YXJnZXQpXG5cbiAgICBpZiAoIWZzLmV4aXN0c1N5bmModGFyZ2V0RGlyKSkge1xuICAgICAgZnMubWtkaXJTeW5jKHRhcmdldERpciwge3JlY3Vyc2l2ZTogdHJ1ZX0pXG4gICAgfVxuXG4gICAgY29uc3QgaW5qZWN0ZWRDb250ZW50ID0gaW5qZWN0KGZzLnJlYWRGaWxlU3luYyhzb3VyY2UsICd1dGYtOCcpKVxuXG4gICAgZnMud3JpdGVGaWxlU3luYyh0YXJnZXQsIGluamVjdGVkQ29udGVudClcbiAgfSlcblxuICBjb25zb2xhLnN1Y2Nlc3MoYFB5bG9uIGNyZWF0ZWRgKVxufVxuXG5pbXBvcnQge2RldGVjdH0gZnJvbSAnZGV0ZWN0LXBhY2thZ2UtbWFuYWdlcidcbmltcG9ydCB7c3Bhd25TeW5jfSBmcm9tICdjaGlsZF9wcm9jZXNzJ1xuXG5jb25zdCBpbnN0YWxsRGVwZW5kZW5jaWVzID0gYXN5bmMgKGFyZ3M6IHtcbiAgdGFyZ2V0OiBzdHJpbmdcbiAgcGFja2FnZU1hbmFnZXI/OiBzdHJpbmdcbn0pID0+IHtcbiAgY29uc3QgdGFyZ2V0ID0gcGF0aC5yZXNvbHZlKGFyZ3MudGFyZ2V0KVxuXG4gIGNvbnNvbGUubG9nKCd0YXJnZXQnLCB0YXJnZXQpXG5cbiAgaWYgKCFhcmdzLnBhY2thZ2VNYW5hZ2VyKSB7XG4gICAgYXJncy5wYWNrYWdlTWFuYWdlciA9IGF3YWl0IGRldGVjdCh7XG4gICAgICBjd2Q6IHRhcmdldCxcbiAgICAgIGluY2x1ZGVHbG9iYWxCdW46IHRydWVcbiAgICB9KVxuICB9XG5cbiAgaWYgKCFhcmdzLnBhY2thZ2VNYW5hZ2VyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdObyBwYWNrYWdlIG1hbmFnZXIgZm91bmQnKVxuICB9XG5cbiAgLy8geWFybicsICducG0nLCBvciAncG5wbScsICdidW4nXG4gIGNvbnN0IHtwYWNrYWdlTWFuYWdlcn0gPSBhcmdzXG5cbiAgbGV0IGNvbW1hbmQgPSAnJ1xuXG4gIHN3aXRjaCAocGFja2FnZU1hbmFnZXIpIHtcbiAgICBjYXNlICd5YXJuJzpcbiAgICAgIGNvbW1hbmQgPSAneWFybidcbiAgICAgIGJyZWFrXG4gICAgY2FzZSAnbnBtJzpcbiAgICAgIGNvbW1hbmQgPSAnbnBtIGluc3RhbGwnXG4gICAgICBicmVha1xuICAgIGNhc2UgJ3BucG0nOlxuICAgICAgY29tbWFuZCA9ICdwbnBtIGluc3RhbGwnXG4gICAgICBicmVha1xuICAgIGNhc2UgJ2J1bic6XG4gICAgICBjb21tYW5kID0gJ2J1biBpbnN0YWxsJ1xuICAgICAgYnJlYWtcbiAgICBkZWZhdWx0OlxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBhY2thZ2UgbWFuYWdlcjogJHtwYWNrYWdlTWFuYWdlcn1gKVxuICB9XG5cbiAgY29uc29sYS5zdGFydChgSW5zdGFsbGluZyBkZXBlbmRlbmNpZXMgdXNpbmcgJHtwYWNrYWdlTWFuYWdlcn1gKVxuXG4gIGNvbnN0IHByb2MgPSBzcGF3blN5bmMoY29tbWFuZCwge1xuICAgIGN3ZDogdGFyZ2V0LFxuICAgIHNoZWxsOiB0cnVlLFxuICAgIHN0ZGlvOiAnaW5oZXJpdCdcbiAgfSlcblxuICBpZiAocHJvYy5zdGF0dXMgIT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBpbnN0YWxsIGRlcGVuZGVuY2llc2ApXG4gIH1cblxuICBjb25zb2xhLnN1Y2Nlc3MoYERlcGVuZGVuY2llcyBpbnN0YWxsZWRgKVxufVxuXG5wcm9ncmFtXG4gIC5uYW1lKCdjcmVhdGUtcHlsb24nKVxuICAudmVyc2lvbih2ZXJzaW9uKVxuICAuYXJndW1lbnRzKCdbdGFyZ2V0XScpXG4gIC5hZGRPcHRpb24obmV3IE9wdGlvbignLWksIC0taW5zdGFsbCcsICdJbnN0YWxsIGRlcGVuZGVuY2llcycpKVxuICAuYWRkT3B0aW9uKFxuICAgIG5ldyBPcHRpb24oJy1yLCAtLXJ1bnRpbWUgPHJ1bnRpbWU+JywgJ1J1bnRpbWUnKS5jaG9pY2VzKFxuICAgICAgcnVudGltZXMubWFwKCh7a2V5fSkgPT4ga2V5KVxuICAgIClcbiAgKVxuICAuYWRkT3B0aW9uKG5ldyBPcHRpb24oJy10LCAtLXRlbXBsYXRlIDx0ZW1wbGF0ZT4nLCAnVGVtcGxhdGUnKSlcbiAgLmFkZE9wdGlvbihcbiAgICBuZXcgT3B0aW9uKCctcG0sIC0tcGFja2FnZS1tYW5hZ2VyIDxwYWNrYWdlTWFuYWdlcj4nLCAnUGFja2FnZSBtYW5hZ2VyJylcbiAgKVxuICAuYWRkT3B0aW9uKFxuICAgIG5ldyBPcHRpb24oXG4gICAgICAnLS1jbGllbnQnLFxuICAgICAgJ0VuYWJsZSBjbGllbnQgZ2VuZXJhdGlvbiAoaHR0cHM6Ly9weWxvbi5jcm9uaXQuaW8vZG9jcy9pbnRlZ3JhdGlvbnMvZ3F0eSknXG4gICAgKVxuICApXG4gIC5hZGRPcHRpb24obmV3IE9wdGlvbignLS1jbGllbnQtcGF0aCA8Y2xpZW50UGF0aD4nLCAnQ2xpZW50IHBhdGgnKSlcbiAgLmFkZE9wdGlvbihuZXcgT3B0aW9uKCctLWNsaWVudC1wb3J0IDxjbGllbnRQb3J0PicsICdDbGllbnQgcG9ydCcpKVxuICAuYWN0aW9uKG1haW4pXG5cbnR5cGUgQXJnT3B0aW9ucyA9IHtcbiAgaW5zdGFsbDogYm9vbGVhblxuICBydW50aW1lOiBzdHJpbmdcbiAgdGVtcGxhdGU6IHN0cmluZ1xuICBwYWNrYWdlTWFuYWdlcj86IHN0cmluZ1xuICBjbGllbnQ/OiBib29sZWFuXG4gIGNsaWVudFBhdGg/OiBzdHJpbmdcbiAgY2xpZW50UG9ydD86IHN0cmluZ1xufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKFxuICB0YXJnZXREaXI6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgb3B0aW9uczogQXJnT3B0aW9ucyxcbiAgY29tbWFuZDogQ29tbWFuZFxuKSB7XG4gIHRyeSB7XG4gICAgY29uc29sYS5sb2coYCR7Y29tbWFuZC5uYW1lKCl9IHZlcnNpb24gJHtjb21tYW5kLnZlcnNpb24oKX1gKVxuXG4gICAgY29uc3Qge1xuICAgICAgaW5zdGFsbDogaW5zdGFsbEFyZyxcbiAgICAgIHJ1bnRpbWU6IHJ1bnRpbWVBcmcsXG4gICAgICB0ZW1wbGF0ZTogdGVtcGxhdGVBcmcsXG4gICAgICBwYWNrYWdlTWFuYWdlcjogcGFja2FnZU1hbmFnZXJBcmcsXG4gICAgICBjbGllbnQ6IGNsaWVudEFyZyxcbiAgICAgIGNsaWVudFBhdGg6IGNsaWVudFBhdGhBcmcsXG4gICAgICBjbGllbnRQb3J0OiBjbGllbnRQb3J0QXJnXG4gICAgfSA9IG9wdGlvbnNcblxuICAgIGxldCB0YXJnZXQgPSAnJ1xuXG4gICAgaWYgKHRhcmdldERpcikge1xuICAgICAgdGFyZ2V0ID0gdGFyZ2V0RGlyXG5cbiAgICAgIGNvbnNvbGEuc3VjY2VzcyhgVXNpbmcgdGFyZ2V0IGRpcmVjdG9yeSDigKYgJHt0YXJnZXR9YClcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgYW5zd2VyID0gYXdhaXQgaW5wdXQoe1xuICAgICAgICBtZXNzYWdlOiAnVGFyZ2V0IGRpcmVjdG9yeScsXG4gICAgICAgIGRlZmF1bHQ6ICdteS1weWxvbidcbiAgICAgIH0pXG4gICAgICB0YXJnZXQgPSBhbnN3ZXJcbiAgICB9XG5cbiAgICBsZXQgcHJvamVjdE5hbWUgPSAnJ1xuXG4gICAgaWYgKHRhcmdldCA9PT0gJy4nKSB7XG4gICAgICBwcm9qZWN0TmFtZSA9IHBhdGguYmFzZW5hbWUocHJvY2Vzcy5jd2QoKSlcbiAgICB9IGVsc2Uge1xuICAgICAgcHJvamVjdE5hbWUgPSBwYXRoLmJhc2VuYW1lKHRhcmdldClcbiAgICB9XG5cbiAgICBjb25zdCBydW50aW1lTmFtZSA9XG4gICAgICBydW50aW1lQXJnIHx8XG4gICAgICAoYXdhaXQgc2VsZWN0KHtcbiAgICAgICAgbWVzc2FnZTogJ1doaWNoIHJ1bnRpbWUgd291bGQgeW91IGxpa2UgdG8gdXNlPycsXG4gICAgICAgIGNob2ljZXM6IHJ1bnRpbWVzLm1hcChydW50aW1lID0+ICh7XG4gICAgICAgICAgbmFtZTogYCR7cnVudGltZS5uYW1lfSAoJHtydW50aW1lLndlYnNpdGV9KWAsXG4gICAgICAgICAgdmFsdWU6IHJ1bnRpbWUua2V5XG4gICAgICAgIH0pKSxcbiAgICAgICAgZGVmYXVsdDogMFxuICAgICAgfSkpXG5cbiAgICBpZiAoIXJ1bnRpbWVOYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHJ1bnRpbWUgc2VsZWN0ZWQnKVxuICAgIH1cblxuICAgIGNvbnN0IHJ1bnRpbWUgPSBydW50aW1lcy5maW5kKCh7a2V5fSkgPT4ga2V5ID09PSBydW50aW1lTmFtZSlcblxuICAgIGlmICghcnVudGltZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHJ1bnRpbWUgc2VsZWN0ZWQ6ICR7cnVudGltZU5hbWV9YClcbiAgICB9XG5cbiAgICBjb25zdCB0ZW1wbGF0ZU5hbWUgPVxuICAgICAgdGVtcGxhdGVBcmcgfHxcbiAgICAgIChhd2FpdCBzZWxlY3Qoe1xuICAgICAgICBtZXNzYWdlOiAnV2hpY2ggdGVtcGxhdGUgd291bGQgeW91IGxpa2UgdG8gdXNlPycsXG4gICAgICAgIGNob2ljZXM6IHRlbXBsYXRlc1xuICAgICAgICAgIC5maWx0ZXIodGVtcGxhdGUgPT4gcnVudGltZS50ZW1wbGF0ZXM/LmluY2x1ZGVzKHRlbXBsYXRlLmtleSkpXG4gICAgICAgICAgLm1hcCh0ZW1wbGF0ZSA9PiAoe1xuICAgICAgICAgICAgbmFtZTogdGVtcGxhdGUubmFtZSxcbiAgICAgICAgICAgIHZhbHVlOiB0ZW1wbGF0ZS5rZXlcbiAgICAgICAgICB9KSksXG4gICAgICAgIGRlZmF1bHQ6IDBcbiAgICAgIH0pKVxuXG4gICAgaWYgKCF0ZW1wbGF0ZU5hbWUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdGVtcGxhdGUgc2VsZWN0ZWQnKVxuICAgIH1cblxuICAgIGlmIChmcy5leGlzdHNTeW5jKHRhcmdldCkpIHtcbiAgICAgIGlmIChmcy5yZWFkZGlyU3luYyh0YXJnZXQpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjb25maXJtKHtcbiAgICAgICAgICBtZXNzYWdlOiAnRGlyZWN0b3J5IG5vdCBlbXB0eS4gQ29udGludWU/JyxcbiAgICAgICAgICBkZWZhdWx0OiBmYWxzZVxuICAgICAgICB9KVxuICAgICAgICBpZiAoIXJlc3BvbnNlKSB7XG4gICAgICAgICAgcHJvY2Vzcy5leGl0KDEpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgbWtkaXJwKHRhcmdldClcbiAgICB9XG5cbiAgICBjb25zdCBpbnN0YWxsID1cbiAgICAgIGluc3RhbGxBcmcgfHxcbiAgICAgIChhd2FpdCBjb25maXJtKHttZXNzYWdlOiAnV291bGQgeW91IGxpa2UgdG8gaW5zdGFsbCBkZXBlbmRlbmNpZXM/J30pKVxuXG4gICAgYXdhaXQgY3JlYXRlVGVtcGxhdGUoe1xuICAgICAgbmFtZTogcHJvamVjdE5hbWUsXG4gICAgICBydW50aW1lOiBydW50aW1lTmFtZSxcbiAgICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZU5hbWUsXG4gICAgICB0YXJnZXRcbiAgICB9KVxuXG4gICAgbGV0IHBhY2thZ2VNYW5hZ2VyID0gcGFja2FnZU1hbmFnZXJBcmdcblxuICAgIGlmIChydW50aW1lTmFtZSA9PT0gJ2J1bicgJiYgIXBhY2thZ2VNYW5hZ2VyKSB7XG4gICAgICBwYWNrYWdlTWFuYWdlciA9ICdidW4nXG4gICAgfVxuXG4gICAgaWYgKGluc3RhbGwpIHtcbiAgICAgIGF3YWl0IGluc3RhbGxEZXBlbmRlbmNpZXMoe3RhcmdldCwgcGFja2FnZU1hbmFnZXJ9KVxuICAgIH1cblxuICAgIGNvbnN0IGNsaWVudCA9XG4gICAgICBjbGllbnRBcmcgfHxcbiAgICAgIChhd2FpdCBjb25maXJtKHtcbiAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAnV291bGQgeW91IGxpa2UgdG8gZW5hYmxlIGNsaWVudCBnZW5lcmF0aW9uPyAoaHR0cHM6Ly9weWxvbi5jcm9uaXQuaW8vZG9jcy9pbnRlZ3JhdGlvbnMvZ3F0eSknLFxuICAgICAgICBkZWZhdWx0OiBmYWxzZVxuICAgICAgfSkpXG5cbiAgICBpZiAoY2xpZW50KSB7XG4gICAgICBsZXQgY2xpZW50Um9vdDogc3RyaW5nID0gJydcbiAgICAgIGxldCBjbGllbnRQYXRoOiBzdHJpbmcgPSAnJ1xuICAgICAgaWYgKCFjbGllbnRQYXRoQXJnKSB7XG4gICAgICAgIGNsaWVudFJvb3QgPSBhd2FpdCBpbnB1dCh7XG4gICAgICAgICAgbWVzc2FnZTogJ1BhdGggdG8gdGhlIHJvb3Qgd2hlcmUgdGhlIGNsaWVudCBzaG91bGQgYmUgZ2VuZXJhdGVkJyxcbiAgICAgICAgICBkZWZhdWx0OiAnLidcbiAgICAgICAgfSlcblxuICAgICAgICBjbGllbnRQYXRoID0gYXdhaXQgaW5wdXQoe1xuICAgICAgICAgIG1lc3NhZ2U6ICdQYXRoIHRvIGdlbmVyYXRlIHRoZSBjbGllbnQgdG8nLFxuICAgICAgICAgIGRlZmF1bHQ6IHBhdGguam9pbihjbGllbnRSb290LCAnZ3F0eS9pbmRleC50cycpLFxuICAgICAgICAgIHZhbGlkYXRlOiB2YWx1ZSA9PiB7XG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgcGF0aCBzdGFydHMgd2l0aCB0aGUgY2xpZW50IHJvb3QgKHRha2UgY2FyZSBvZiAuKVxuICAgICAgICAgICAgaWYgKCF2YWx1ZS5zdGFydHNXaXRoKGNsaWVudFJvb3QgPT09ICcuJyA/ICcnIDogY2xpZW50Um9vdCkpIHtcbiAgICAgICAgICAgICAgcmV0dXJuICdQYXRoIG11c3Qgc3RhcnQgd2l0aCB0aGUgY2xpZW50IHJvb3QnXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0cnVlXG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgfVxuXG4gICAgICBjb25zdCBjbGllbnRQb3J0ID1cbiAgICAgICAgY2xpZW50UG9ydEFyZyB8fFxuICAgICAgICAoYXdhaXQgaW5wdXQoe1xuICAgICAgICAgIG1lc3NhZ2U6ICdQb3J0IG9mIHRoZSBweWxvbiBzZXJ2ZXIgdG8gZ2VuZXJhdGUgdGhlIGNsaWVudCBmcm9tJyxcbiAgICAgICAgICBkZWZhdWx0OiAnMzAwMCdcbiAgICAgICAgfSkpXG5cbiAgICAgIGNvbnNvbGEuc3RhcnQoYFVwZGF0aW5nIHB5bG9uIGRldiBzY3JpcHQgdG8gZ2VuZXJhdGUgY2xpZW50YClcblxuICAgICAgY29uc3QgZGV2U2NyaXB0UGF0aCA9IHBhdGguam9pbih0YXJnZXQsICdwYWNrYWdlLmpzb24nKVxuXG4gICAgICBjb25zdCBkZXZTY3JpcHQgPSBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhkZXZTY3JpcHRQYXRoLCAndXRmLTgnKSlcblxuICAgICAgZGV2U2NyaXB0LnNjcmlwdHMgPSB7XG4gICAgICAgIC4uLmRldlNjcmlwdC5zY3JpcHRzLFxuICAgICAgICBkZXY6XG4gICAgICAgICAgZGV2U2NyaXB0LnNjcmlwdHMuZGV2ICtcbiAgICAgICAgICBgIC0tY2xpZW50IC0tY2xpZW50LXBvcnQgJHtjbGllbnRQb3J0fSAtLWNsaWVudC1wYXRoICR7Y2xpZW50UGF0aH1gXG4gICAgICB9XG5cbiAgICAgIGZzLndyaXRlRmlsZVN5bmMoZGV2U2NyaXB0UGF0aCwgSlNPTi5zdHJpbmdpZnkoZGV2U2NyaXB0LCBudWxsLCAyKSlcblxuICAgICAgY29uc29sYS5zdWNjZXNzKGBQeWxvbiBkZXYgc2NyaXB0IHVwZGF0ZWRgKVxuICAgIH1cblxuICAgIGNvbnNvbGEuYm94KGBQeWxvbiBzdWNjZXNzZnVsbHkgY3JlYXRlZCBpbiAke3RhcmdldH0uXFxuXFxuSGFwcHkgY29kaW5nIWApXG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBjb25zb2xhLmVycm9yKGUpXG4gIH1cbn1cblxucHJvZ3JhbS5wYXJzZSgpXG4iCiAgXSwKICAibWFwcGluZ3MiOiAiOzs7O0FBRUE7Ozs7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQSxTQUFTLE1BQU0sQ0FBQyxLQUFhO0FBQzNCLE1BQUk7QUFDRixJQUFHLGFBQVUsS0FBSyxFQUFDLFdBQVcsS0FB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LE1BQU0sNEJBQTRCLGdCQUFnQjtBQUFBO0FBR2hFLFVBQVEsTUFBTSxpQ0FBaUMsZ0JBQWdCO0FBRS9ELFFBQU0sT0FBTyxVQUFVLFNBQVM7QUFBQSxJQUM5QixLQUFLO0FBQUEsSUFDTCxPQUFPO0FBQUEsSUFDUCxPQUFPO0FBQUEsRUFDVCxDQUFDO0FBRUQsTUFBSSxLQUFLLFdBQVcsR0FBRztBQUNyQixVQUFNLElBQUksTUFBTSxnQ0FBZ0M7QUFBQSxFQUNsRDtBQUVBLFVBQVEsUUFBUSx3QkFBd0I7QUFBQTtBQUcxQyxRQUNHLEtBQUssY0FBYyxFQUNuQixRQUFRLE9BQU8sRUFDZixVQUFVLFVBQVUsRUFDcEIsVUFBVSxJQUFJLE9BQU8saUJBQWlCLHNCQUFzQixDQUFDLEVBQzdELFVBQ0MsSUFBSSxPQUFPLDJCQUEyQixTQUFTLEVBQUUsUUFDL0MsU0FBUyxJQUFJLEdBQUUsVUFBUyxHQUFHLENBQzdCLENBQ0YsRUFDQyxVQUFVLElBQUksT0FBTyw2QkFBNkIsVUFBVSxDQUFDLEVBQzdELFVBQ0MsSUFBSSxPQUFPLDJDQUEyQyxpQkFBaUIsQ0FDekUsRUFDQyxVQUNDLElBQUksT0FDRixZQUNBLDJFQUNGLENBQ0YsRUFDQyxVQUFVLElBQUksT0FBTyw4QkFBOEIsYUFBYSxDQUFDLEVBQ2pFLFVBQVUsSUFBSSxPQUFPLDhCQUE4QixhQUFhLENBQUMsRUFDakUsT0FBTyxJQUFJO0FBMkxkLFFBQVEsTUFBTTsiLAogICJkZWJ1Z0lkIjogIkRBQ0I3NThCNzQyNzhBRjA2NDc1NkUyMTY0NzU2RTIxIiwKICAibmFtZXMiOiBbXQp9
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "create-pylon",
3
+ "version": "0.0.1",
4
+ "description": "CLI for creating a Pylon",
5
+ "scripts": {
6
+ "build": "bun build ./src/index.ts --target=bun --outdir=./dist --sourcemap=inline --packages external"
7
+ },
8
+ "bin": "./dist/index.js",
9
+ "files": [
10
+ "dist",
11
+ "templates"
12
+ ],
13
+ "author": "Nico Schett <nico.schett@cronit.io>",
14
+ "license": "Apache-2.0",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/getcronit/pylon.git",
18
+ "directory": "packages/create-pylon"
19
+ },
20
+ "homepage": "https://pylon.cronit.io",
21
+ "dependencies": {
22
+ "@inquirer/prompts": "^5.4.0",
23
+ "commander": "^12.1.0",
24
+ "consola": "^3.2.3",
25
+ "detect-package-manager": "^3.0.2"
26
+ }
27
+ }
@@ -0,0 +1,47 @@
1
+ # use the official Bun image
2
+ # see all versions at https://hub.docker.com/r/oven/bun/tags
3
+ FROM oven/bun:1 as base
4
+
5
+ LABEL description="Offical docker image for Pylon services (Bun)"
6
+ LABEL org.opencontainers.image.source="https://github.com/getcronit/pylon"
7
+ LABEL maintainer="office@cronit.io"
8
+
9
+ WORKDIR /usr/src/pylon
10
+
11
+
12
+ # install dependencies into temp directory
13
+ # this will cache them and speed up future builds
14
+ FROM base AS install
15
+ RUN mkdir -p /temp/dev
16
+ COPY package.json bun.lockb /temp/dev/
17
+ RUN cd /temp/dev && bun install --frozen-lockfile
18
+
19
+ # install with --production (exclude devDependencies)
20
+ RUN mkdir -p /temp/prod
21
+ COPY package.json bun.lockb /temp/prod/
22
+ RUN cd /temp/prod && bun install --frozen-lockfile --production
23
+
24
+ # copy node_modules from temp directory
25
+ # then copy all (non-ignored) project files into the image
26
+ FROM install AS prerelease
27
+ COPY --from=install /temp/dev/node_modules node_modules
28
+ COPY . .
29
+
30
+ # [optional] tests & build
31
+ ENV NODE_ENV=production
32
+
33
+ # Create .pylon folder (mkdir)
34
+ RUN mkdir -p .pylon
35
+ # RUN bun test
36
+ RUN bun run pylon build
37
+
38
+ # copy production dependencies and source code into final image
39
+ FROM base AS release
40
+ COPY --from=install /temp/prod/node_modules node_modules
41
+ COPY --from=prerelease /usr/src/pylon/.pylon .pylon
42
+ COPY --from=prerelease /usr/src/pylon/package.json .
43
+
44
+ # run the app
45
+ USER bun
46
+ EXPOSE 3000/tcp
47
+ ENTRYPOINT [ "bun", "run", "/usr/src/pylon/.pylon/index.js" ]
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "__PYLON_NAME__",
3
+ "private": true,
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "description": "Generated with `npm create pylon`",
7
+ "scripts": {
8
+ "dev": "pylon dev -c 'node --enable-source-maps .pylon/index.js'",
9
+ "build": "pylon build"
10
+ },
11
+ "dependencies": {
12
+ "@getcronit/pylon": "*",
13
+ "bun-types": "^1.1.18"
14
+ },
15
+ "devDependencies": {
16
+ "@getcronit/pylon-dev": "*"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/getcronit/pylon.git"
21
+ },
22
+ "homepage": "https://pylon.cronit.io"
23
+ }
@@ -0,0 +1,12 @@
1
+ import {app} from '@getcronit/pylon'
2
+
3
+ export const graphql = {
4
+ Query: {
5
+ hello: () => {
6
+ return 'Hello, world!'
7
+ }
8
+ },
9
+ Mutation: {}
10
+ }
11
+
12
+ export default app
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "@getcronit/pylon/tsconfig.pylon.json",
3
+ "compilerOptions": {
4
+ // add Bun type definitions
5
+ "types": ["bun-types"]
6
+ }
7
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "__PYLON_NAME__",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "deploy": "pylon build && wrangler deploy",
7
+ "dev": "pylon dev -c 'wrangler dev'",
8
+ "cf-typegen": "wrangler types"
9
+ },
10
+ "dependencies": {
11
+ "@getcronit/pylon": "*"
12
+ },
13
+ "devDependencies": {
14
+ "@getcronit/pylon-dev": "*",
15
+ "@cloudflare/vitest-pool-workers": "^0.4.5",
16
+ "@cloudflare/workers-types": "^4.20240903.0",
17
+ "typescript": "^5.5.2",
18
+ "wrangler": "^3.60.3"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/getcronit/pylon.git"
23
+ },
24
+ "homepage": "https://pylon.cronit.io"
25
+ }
@@ -0,0 +1,12 @@
1
+ import {app} from '@getcronit/pylon'
2
+
3
+ export const graphql = {
4
+ Query: {
5
+ hello: () => {
6
+ return 'Hello, world!'
7
+ }
8
+ },
9
+ Mutation: {}
10
+ }
11
+
12
+ export default app
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "@getcronit/pylon/tsconfig.pylon.json",
3
+ "include": ["worker-configuration.d.ts", "src/**/*.ts"]
4
+ }
@@ -0,0 +1,3 @@
1
+ // Generated by Wrangler
2
+ // After adding bindings to `wrangler.toml`, regenerate this interface via `npm run cf-typegen`
3
+ interface Env {}
@@ -0,0 +1,108 @@
1
+ #:schema node_modules/wrangler/config-schema.json
2
+ name = "__PYLON_NAME__"
3
+ main = ".pylon/index.js"
4
+ compatibility_date = "2024-09-03"
5
+ compatibility_flags = ["nodejs_compat_v2"]
6
+
7
+ # Automatically place your workloads in an optimal location to minimize latency.
8
+ # If you are running back-end logic in a Worker, running it closer to your back-end infrastructure
9
+ # rather than the end user may result in better performance.
10
+ # Docs: https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement
11
+ # [placement]
12
+ # mode = "smart"
13
+
14
+ # Variable bindings. These are arbitrary, plaintext strings (similar to environment variables)
15
+ # Docs:
16
+ # - https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables
17
+ # Note: Use secrets to store sensitive data.
18
+ # - https://developers.cloudflare.com/workers/configuration/secrets/
19
+ # [vars]
20
+ # MY_VARIABLE = "production_value"
21
+
22
+ # Bind the Workers AI model catalog. Run machine learning models, powered by serverless GPUs, on Cloudflare’s global network
23
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#workers-ai
24
+ # [ai]
25
+ # binding = "AI"
26
+
27
+ # Bind an Analytics Engine dataset. Use Analytics Engine to write analytics within your Pages Function.
28
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#analytics-engine-datasets
29
+ # [[analytics_engine_datasets]]
30
+ # binding = "MY_DATASET"
31
+
32
+ # Bind a headless browser instance running on Cloudflare's global network.
33
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#browser-rendering
34
+ # [browser]
35
+ # binding = "MY_BROWSER"
36
+
37
+ # Bind a D1 database. D1 is Cloudflare’s native serverless SQL database.
38
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#d1-databases
39
+ # [[d1_databases]]
40
+ # binding = "MY_DB"
41
+ # database_name = "my-database"
42
+ # database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
43
+
44
+ # Bind a dispatch namespace. Use Workers for Platforms to deploy serverless functions programmatically on behalf of your customers.
45
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#dispatch-namespace-bindings-workers-for-platforms
46
+ # [[dispatch_namespaces]]
47
+ # binding = "MY_DISPATCHER"
48
+ # namespace = "my-namespace"
49
+
50
+ # Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model.
51
+ # Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps.
52
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects
53
+ # [[durable_objects.bindings]]
54
+ # name = "MY_DURABLE_OBJECT"
55
+ # class_name = "MyDurableObject"
56
+
57
+ # Durable Object migrations.
58
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations
59
+ # [[migrations]]
60
+ # tag = "v1"
61
+ # new_classes = ["MyDurableObject"]
62
+
63
+ # Bind a Hyperdrive configuration. Use to accelerate access to your existing databases from Cloudflare Workers.
64
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#hyperdrive
65
+ # [[hyperdrive]]
66
+ # binding = "MY_HYPERDRIVE"
67
+ # id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
68
+
69
+ # Bind a KV Namespace. Use KV as persistent storage for small key-value pairs.
70
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#kv-namespaces
71
+ # [[kv_namespaces]]
72
+ # binding = "MY_KV_NAMESPACE"
73
+ # id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
74
+
75
+ # Bind an mTLS certificate. Use to present a client certificate when communicating with another service.
76
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#mtls-certificates
77
+ # [[mtls_certificates]]
78
+ # binding = "MY_CERTIFICATE"
79
+ # certificate_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
80
+
81
+ # Bind a Queue producer. Use this binding to schedule an arbitrary task that may be processed later by a Queue consumer.
82
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#queues
83
+ # [[queues.producers]]
84
+ # binding = "MY_QUEUE"
85
+ # queue = "my-queue"
86
+
87
+ # Bind a Queue consumer. Queue Consumers can retrieve tasks scheduled by Producers to act on them.
88
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#queues
89
+ # [[queues.consumers]]
90
+ # queue = "my-queue"
91
+
92
+ # Bind an R2 Bucket. Use R2 to store arbitrarily large blobs of data, such as files.
93
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#r2-buckets
94
+ # [[r2_buckets]]
95
+ # binding = "MY_BUCKET"
96
+ # bucket_name = "my-bucket"
97
+
98
+ # Bind another Worker service. Use this binding to call another Worker without network overhead.
99
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings
100
+ # [[services]]
101
+ # binding = "MY_SERVICE"
102
+ # service = "my-service"
103
+
104
+ # Bind a Vectorize index. Use to store and query vector embeddings for semantic search, classification and other vector search use-cases.
105
+ # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#vectorize-indexes
106
+ # [[vectorize]]
107
+ # binding = "MY_INDEX"
108
+ # index_name = "my-index"
@@ -0,0 +1,45 @@
1
+ # Use the official Node.js 20 image as the base
2
+ FROM node:20-alpine as base
3
+
4
+ LABEL description="Offical docker image for Pylon services (Node.js)"
5
+ LABEL org.opencontainers.image.source="https://github.com/getcronit/pylon"
6
+ LABEL maintainer="office@cronit.io"
7
+
8
+ WORKDIR /usr/src/pylon
9
+
10
+ # install dependencies into a temp directory
11
+ # this will cache them and speed up future builds
12
+ FROM base AS install
13
+ RUN mkdir -p /temp/dev
14
+ COPY package.json package-lock.json /temp/dev/
15
+ RUN cd /temp/dev && npm ci
16
+
17
+ # install with --production (exclude devDependencies)
18
+ RUN mkdir -p /temp/prod
19
+ COPY package.json package-lock.json /temp/prod/
20
+ RUN cd /temp/prod && npm ci --only=production
21
+
22
+ # copy node_modules from temp directory
23
+ # then copy all (non-ignored) project files into the image
24
+ FROM install AS prerelease
25
+ COPY --from=install /temp/dev/node_modules node_modules
26
+ COPY . .
27
+
28
+ # [optional] tests & build
29
+ ENV NODE_ENV=production
30
+
31
+ # Create .pylon folder (mkdir)
32
+ RUN mkdir -p .pylon
33
+ # RUN npm test
34
+ RUN npm run pylon build
35
+
36
+ # copy production dependencies and source code into final image
37
+ FROM base AS release
38
+ COPY --from=install /temp/prod/node_modules node_modules
39
+ COPY --from=prerelease /usr/src/pylon/.pylon .pylon
40
+ COPY --from=prerelease /usr/src/pylon/package.json .
41
+
42
+ # run the app
43
+ USER node
44
+ EXPOSE 3000/tcp
45
+ ENTRYPOINT [ "node", "/usr/src/pylon/.pylon/index.js" ]
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "__PYLON_NAME__",
3
+ "private": true,
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "description": "Generated with `npm create pylon`",
7
+ "scripts": {
8
+ "dev": "pylon dev -c 'node --enable-source-maps .pylon/index.js'",
9
+ "build": "pylon build"
10
+ },
11
+ "dependencies": {
12
+ "@getcronit/pylon": "*"
13
+ },
14
+ "devDependencies": {
15
+ "@getcronit/pylon-dev": "*"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/getcronit/pylon.git"
20
+ },
21
+ "homepage": "https://pylon.cronit.io"
22
+ }
@@ -0,0 +1,15 @@
1
+ import {app} from '@getcronit/pylon'
2
+ import {serve} from '@hono/node-server'
3
+
4
+ export const graphql = {
5
+ Query: {
6
+ hello: () => {
7
+ return 'Hello, world!'
8
+ }
9
+ },
10
+ Mutation: {}
11
+ }
12
+
13
+ serve(app, info => {
14
+ console.log(`Server running at ${info.port}`)
15
+ })
@@ -0,0 +1,15 @@
1
+ node_modules
2
+ Dockerfile*
3
+ docker-compose*
4
+ .dockerignore
5
+ .git
6
+ .gitignore
7
+ README.md
8
+ LICENSE
9
+ .vscode
10
+ Makefile
11
+ helm-charts
12
+ .env
13
+ .editorconfig
14
+ .idea
15
+ coverage*
@@ -0,0 +1,43 @@
1
+ name: publish
2
+
3
+ on: [push]
4
+ env:
5
+ IMAGE_NAME: __PYLON_NAME__
6
+
7
+ jobs:
8
+ # Push image to GitHub Packages.
9
+ # See also https://docs.docker.com/docker-hub/builds/
10
+ publish-container:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ packages: write
14
+ contents: read
15
+
16
+ steps:
17
+ - uses: actions/checkout@v2
18
+
19
+ - name: Build image
20
+ run: docker build . --file Dockerfile --tag $IMAGE_NAME
21
+
22
+ - name: Log into registry
23
+ run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
24
+
25
+ - name: Push image
26
+ run: |
27
+ IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
28
+
29
+ # Change all uppercase to lowercase
30
+ IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
31
+ # Strip git ref prefix from version
32
+ VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
33
+ # Strip "v" prefix from tag name
34
+ [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
35
+ # Use Docker `latest` tag convention
36
+ [ "$VERSION" == "main" ] && VERSION=latest
37
+ echo IMAGE_ID=$IMAGE_ID
38
+ echo VERSION=$VERSION
39
+ docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
40
+ docker push $IMAGE_ID:$VERSION
41
+
42
+ # SPDX-License-Identifier: (EUPL-1.2)
43
+ # Copyright © 2024 cronit KG
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "@getcronit/pylon/tsconfig.pylon.json"
3
+ }