@ptkl/toolkit 0.3.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.
@@ -0,0 +1,171 @@
1
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from "fs";
2
+ import chokidar from "chokidar";
3
+ import { join, relative } from "path";
4
+ import Builder, { BuildError } from "./builder/index.js";
5
+ import { WebSocketServer } from "ws";
6
+ export default class Playground {
7
+ apptype;
8
+ basePath;
9
+ sdkVersion;
10
+ engine;
11
+ profile;
12
+ watcher;
13
+ wss;
14
+ srcPath;
15
+ connectedClient;
16
+ constructor(apptype, basePath, sdkVersion, engine, port, profile) {
17
+ this.apptype = apptype;
18
+ this.basePath = basePath;
19
+ this.sdkVersion = sdkVersion;
20
+ this.engine = engine;
21
+ this.profile = profile;
22
+ this.wss = new WebSocketServer({ port });
23
+ console.log(`Starting playground at ${port}`);
24
+ console.log(`SDK Version: ${this.sdkVersion}`);
25
+ console.log(`Engine: ${this.engine}`);
26
+ this.watcher = chokidar.watch([], { persistent: true, ignoreInitial: true });
27
+ this.srcPath = "";
28
+ }
29
+ async build(files) {
30
+ console.log("Building app...");
31
+ const builder = new Builder(this.sdkVersion, this.engine);
32
+ let dist = await builder.build(files);
33
+ return dist;
34
+ }
35
+ setBuildDetails(manifestFile) {
36
+ try {
37
+ const manifest = JSON.parse(readFileSync(manifestFile, "utf-8"));
38
+ const sdkVersion = manifest?.sdkVersion ? Number(manifest.sdkVersion) : undefined;
39
+ this.sdkVersion = Number.isInteger(sdkVersion) ? sdkVersion : undefined;
40
+ this.engine = manifest?.engine;
41
+ }
42
+ catch {
43
+ throw new Error("Unable to read the manifest file, it may be invalid or malformed.");
44
+ }
45
+ }
46
+ setManifestDetails(manifestFile) {
47
+ try {
48
+ const manifest = JSON.parse(readFileSync(manifestFile, "utf-8"));
49
+ const sdkVersion = Number(this.sdkVersion) ? this.sdkVersion : false;
50
+ const engine = this.engine ? this.engine : false;
51
+ manifest.sdkVersion = sdkVersion;
52
+ manifest.engine = engine;
53
+ writeFileSync(manifestFile, JSON.stringify(manifest, null, 4));
54
+ }
55
+ catch (err) {
56
+ throw new Error(`Unable to set (sdkVersion/engine) in the manifest file: ${err.message}`);
57
+ }
58
+ }
59
+ // Method to validate a given path
60
+ validatePath(path, createIfNotExist) {
61
+ if (!existsSync(path)) {
62
+ if (createIfNotExist) {
63
+ writeFileSync(path, "{}");
64
+ this.setManifestDetails(path);
65
+ }
66
+ else {
67
+ throw new Error(`Path does not exist: ${path}`);
68
+ }
69
+ }
70
+ console.log(`Validated path: ${path}`);
71
+ }
72
+ async getFilesContents(dir) {
73
+ const files = readdirSync(dir, { recursive: true, withFileTypes: true });
74
+ let filesData = {};
75
+ const ps = files.map(async (file) => {
76
+ let filePath = join(file.path, file.name);
77
+ if (file.isFile()) {
78
+ const p = relative(dir, filePath).replaceAll("\\", "/");
79
+ filesData[p] = readFileSync(filePath, "utf8");
80
+ }
81
+ });
82
+ await Promise.all(ps);
83
+ return filesData;
84
+ }
85
+ async auth(ws) {
86
+ ws.send(JSON.stringify({ action: "auth", profile: this.profile }));
87
+ }
88
+ async initalWsSend(ws) {
89
+ try {
90
+ let initialFilesContents = await this.getFilesContents(this.srcPath);
91
+ let dist = await this.build(initialFilesContents);
92
+ if (dist) {
93
+ ws.send(JSON.stringify({ action: "update", sdkVersion: this.sdkVersion, engine: this.engine, dist }));
94
+ console.log(`Full build for engine ${this.engine} sdkVersion ${this.sdkVersion}`);
95
+ }
96
+ }
97
+ catch (error) {
98
+ if (error instanceof BuildError) {
99
+ error.errors.forEach(err => {
100
+ console.error(err);
101
+ });
102
+ }
103
+ else {
104
+ throw error;
105
+ }
106
+ }
107
+ }
108
+ // Method to validate paths and initialize the watcher
109
+ init() {
110
+ const srcDir = join(this.basePath, "src");
111
+ const manifestFile = join(this.basePath, "manifest.json");
112
+ this.validatePath(srcDir, false);
113
+ this.validatePath(manifestFile, true);
114
+ this.srcPath = srcDir;
115
+ if (this.engine || this.sdkVersion) {
116
+ this.setManifestDetails(manifestFile);
117
+ }
118
+ this.setBuildDetails(manifestFile);
119
+ }
120
+ // Start watching and listen for events
121
+ start() {
122
+ this.watcher.add(this.srcPath);
123
+ this.wss.on("connection", async (ws) => {
124
+ this.connectedClient = ws;
125
+ if (this.apptype == 'public-app') {
126
+ await this.auth(this.connectedClient);
127
+ }
128
+ this.initalWsSend(this.connectedClient);
129
+ console.log("Playground connected");
130
+ });
131
+ const handleUpdate = async (filePath) => {
132
+ try {
133
+ const fileData = readFileSync(filePath, "utf-8");
134
+ const relativeFilePath = relative(this.srcPath, filePath);
135
+ let dist = await this.build({ [relativeFilePath]: fileData });
136
+ if (dist) {
137
+ this.connectedClient.send(JSON.stringify({ action: "update", dist }));
138
+ console.log(`Updating ${relativeFilePath}`);
139
+ }
140
+ this.watcher.on("add", this.debounce(handleUpdate, 300, false));
141
+ this.watcher.on("change", this.debounce(handleUpdate, 300, false));
142
+ this.watcher.on("unlink", this.debounce((filePath) => {
143
+ const relativeFilePath = relative(this.srcPath, filePath);
144
+ this.connectedClient.send(JSON.stringify({ action: "delete", files: [relativeFilePath] }));
145
+ console.log(`Deleting ${relativeFilePath}`);
146
+ }, 300, false));
147
+ }
148
+ catch (err) {
149
+ console.log(err.message);
150
+ }
151
+ };
152
+ }
153
+ close() {
154
+ this.watcher.close();
155
+ console.log("Watcher closed.");
156
+ }
157
+ debounce(func, wait, immediate) {
158
+ let timeout;
159
+ return function (...args) {
160
+ const callNow = immediate && !timeout;
161
+ clearTimeout(timeout);
162
+ timeout = setTimeout(() => {
163
+ timeout = null;
164
+ if (!immediate)
165
+ func.apply(null, args);
166
+ }, wait);
167
+ if (callNow)
168
+ func.apply(null, args);
169
+ };
170
+ }
171
+ }
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@ptkl/toolkit",
3
+ "version": "0.3.0",
4
+ "scripts": {
5
+ "test": "echo \"Error: no test specified\" && exit 1",
6
+ "build": "npx tsc",
7
+ "toolkit": "tsc --build && node dist/bin/toolkit"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "MIT",
12
+ "description": "",
13
+ "dependencies": {
14
+ "@types/axios": "^0.14.0",
15
+ "@types/commander": "^2.12.2",
16
+ "@types/js-yaml": "^4.0.9",
17
+ "axios": "^1.7.4",
18
+ "chalk": "^4.1.2",
19
+ "chokidar": "^4.0.1",
20
+ "circular-json": "^0.5.9",
21
+ "commander": "^12.1.0",
22
+ "js-yaml": "^4.1.0",
23
+ "protokol-sdk": "file:../protokol-sdk",
24
+ "tar": "^7.4.3",
25
+ "ws": "^8.18.0",
26
+ "yaml": "^2.5.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^22.3.0",
30
+ "@types/ws": "^8.5.12",
31
+ "typescript": "^5.5.4"
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "bin": {
37
+ "pkit": "dist/bin/toolkit"
38
+ }
39
+ }