@ptkl/toolkit 0.7.2 → 0.8.8
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/bin/toolkit.js +3 -2
- package/dist/builder/register.js +6 -6
- package/dist/builder/sdk6/lit.js +52 -0
- package/dist/builder/sdk6/react.js +56 -0
- package/dist/builder/sdk6/vue3.js +52 -0
- package/dist/builder/sdk6/webcomponents.js +41 -0
- package/dist/commands/apiUsers.js +1 -1
- package/dist/commands/apps.js +26 -2
- package/dist/commands/component.js +302 -19
- package/dist/commands/forge.js +284 -38
- package/dist/commands/functions.js +1 -1
- package/dist/commands/generate-types.js +38 -0
- package/dist/commands/index.js +4 -0
- package/dist/commands/profile.js +1 -1
- package/dist/commands/role.js +1 -1
- package/dist/commands/users.js +1 -1
- package/dist/commands/validate-idl.js +115 -0
- package/dist/lib/idlToDts.js +242 -0
- package/dist/lib/util.js +2 -2
- package/package.json +11 -2
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IDL → TypeScript module-augmentation generator.
|
|
3
|
+
*
|
|
4
|
+
* Mirror of the runtime idlToDts.js used by the Monaco editor, but output
|
|
5
|
+
* targets a `declare module "@ptkl/sdk"` block so the generated `.d.ts` file
|
|
6
|
+
* extends the SDK's open interfaces at build time.
|
|
7
|
+
*/
|
|
8
|
+
// ── Primitive type conversion ─────────────────────────────────────────────────
|
|
9
|
+
function idlTypeNodeToTs(node, indent = 0) {
|
|
10
|
+
if (!node)
|
|
11
|
+
return 'any';
|
|
12
|
+
switch (node.type) {
|
|
13
|
+
case 'string': return 'string';
|
|
14
|
+
case 'number': return 'number';
|
|
15
|
+
case 'boolean': return 'boolean';
|
|
16
|
+
case 'any': return 'any';
|
|
17
|
+
case 'array':
|
|
18
|
+
return node.items ? `Array<${idlTypeNodeToTs(node.items, indent)}>` : 'any[]';
|
|
19
|
+
case 'object':
|
|
20
|
+
if (node.fields && Object.keys(node.fields).length > 0) {
|
|
21
|
+
return objectShape(node.fields, indent);
|
|
22
|
+
}
|
|
23
|
+
return 'Record<string, any>';
|
|
24
|
+
case 'relation':
|
|
25
|
+
// When used as a standalone type (not as a field entry),
|
|
26
|
+
// a relation is a UUID string.
|
|
27
|
+
return 'string';
|
|
28
|
+
default:
|
|
29
|
+
// NamedRef or unknown — treat as any
|
|
30
|
+
return 'any';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const I = ' '; // indent unit
|
|
34
|
+
function objectShape(fields, indent = 0) {
|
|
35
|
+
const entries = Object.entries(fields);
|
|
36
|
+
// Keep short objects (≤3 simple fields) inline
|
|
37
|
+
if (entries.length <= 3 && entries.every(([, n]) => !n.fields && n.type !== 'object')) {
|
|
38
|
+
const props = entries.map(([key, node]) => {
|
|
39
|
+
const opt = node.required === false || node.required === undefined;
|
|
40
|
+
return `${key}${opt ? '?' : ''}: ${idlTypeNodeToTs(node, indent)}`;
|
|
41
|
+
});
|
|
42
|
+
return `{ ${props.join('; ')} }`;
|
|
43
|
+
}
|
|
44
|
+
const pad = I.repeat(indent + 1);
|
|
45
|
+
const closePad = I.repeat(indent);
|
|
46
|
+
const lines = entries.map(([key, node]) => {
|
|
47
|
+
const opt = node.required === false || node.required === undefined;
|
|
48
|
+
return `${pad}${key}${opt ? '?' : ''}: ${idlTypeNodeToTs(node, indent + 1)};`;
|
|
49
|
+
});
|
|
50
|
+
return `{\n${lines.join('\n')}\n${closePad}}`;
|
|
51
|
+
}
|
|
52
|
+
// ── Relation expansion ────────────────────────────────────────────────────────
|
|
53
|
+
/**
|
|
54
|
+
* Expands a field map into TypeScript property lines. Relation fields produce
|
|
55
|
+
* two entries: the UUID field (`field: string`) and the hydrated reference
|
|
56
|
+
* (`field_RefObj: T` or `field_RefObj: Array<T>`).
|
|
57
|
+
*/
|
|
58
|
+
function expandFieldLines(fields, pad, indent) {
|
|
59
|
+
const lines = [];
|
|
60
|
+
for (const [k, node] of Object.entries(fields)) {
|
|
61
|
+
const opt = node.required === false || node.required === undefined;
|
|
62
|
+
if (node.type === 'relation') {
|
|
63
|
+
// UUID string field
|
|
64
|
+
lines.push(`${pad}${k}${opt ? '?' : ''}: string;`);
|
|
65
|
+
// Hydrated _RefObj field
|
|
66
|
+
const itemTs = node.items ? idlTypeNodeToTs(node.items, indent) : 'any';
|
|
67
|
+
const refType = node.cardinality === 'many' ? `Array<${itemTs}>` : itemTs;
|
|
68
|
+
lines.push(`${pad}${k}_RefObj?: ${refType};`);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
lines.push(`${pad}${k}${opt ? '?' : ''}: ${idlTypeNodeToTs(node, indent)};`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return lines;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Like objectShape but expands relation fields into two properties.
|
|
78
|
+
*/
|
|
79
|
+
function objectShapeWithRelations(fields, indent = 0) {
|
|
80
|
+
const entries = Object.entries(fields);
|
|
81
|
+
const hasRelation = entries.some(([, n]) => n.type === 'relation');
|
|
82
|
+
if (!hasRelation)
|
|
83
|
+
return objectShape(fields, indent); // fast path
|
|
84
|
+
const pad = I.repeat(indent + 1);
|
|
85
|
+
const closePad = I.repeat(indent);
|
|
86
|
+
const lines = expandFieldLines(fields, pad, indent + 1);
|
|
87
|
+
return `{\n${lines.join('\n')}\n${closePad}}`;
|
|
88
|
+
}
|
|
89
|
+
// ── Top-level generators ──────────────────────────────────────────────────────
|
|
90
|
+
function buildComponentModels(components, baseIndent) {
|
|
91
|
+
const entries = [];
|
|
92
|
+
const d = baseIndent;
|
|
93
|
+
const pad = I.repeat(d);
|
|
94
|
+
for (const [ref, comp] of Object.entries(components)) {
|
|
95
|
+
if (!comp)
|
|
96
|
+
continue;
|
|
97
|
+
// Collect all schema names from base + extensions.
|
|
98
|
+
const schemaNames = new Set();
|
|
99
|
+
for (const s of Object.keys(comp.schemas ?? {}))
|
|
100
|
+
schemaNames.add(s);
|
|
101
|
+
for (const ext of Object.values(comp.extensions ?? {})) {
|
|
102
|
+
if (!ext)
|
|
103
|
+
continue;
|
|
104
|
+
for (const s of Object.keys(ext.schemas ?? {}))
|
|
105
|
+
schemaNames.add(s);
|
|
106
|
+
}
|
|
107
|
+
for (const schema of schemaNames) {
|
|
108
|
+
const key = schema === 'default' ? ref : `${ref}.${schema}`;
|
|
109
|
+
const baseFields = comp.schemas?.[schema]?.fields;
|
|
110
|
+
// Collect extension entries for this schema.
|
|
111
|
+
const extEntries = [];
|
|
112
|
+
for (const [extName, ext] of Object.entries(comp.extensions ?? {})) {
|
|
113
|
+
if (!ext)
|
|
114
|
+
continue;
|
|
115
|
+
const extSchemaFields = ext.schemas?.[schema]?.fields;
|
|
116
|
+
if (extSchemaFields && Object.keys(extSchemaFields).length > 0) {
|
|
117
|
+
extEntries.push([extName, extSchemaFields]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const hasBase = baseFields && Object.keys(baseFields).length > 0;
|
|
121
|
+
const hasExt = extEntries.length > 0;
|
|
122
|
+
if (!hasBase && !hasExt) {
|
|
123
|
+
entries.push(`${pad}${JSON.stringify(key)}: Record<string, any>;`);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const propLines = [];
|
|
127
|
+
if (hasBase) {
|
|
128
|
+
propLines.push(...expandFieldLines(baseFields, `${pad}${I}`, d + 1));
|
|
129
|
+
}
|
|
130
|
+
if (hasExt) {
|
|
131
|
+
const extInner = [];
|
|
132
|
+
for (const [extName, extFields] of extEntries) {
|
|
133
|
+
extInner.push(`${pad}${I}${I}${extName}: ${objectShapeWithRelations(extFields, d + 2)};`);
|
|
134
|
+
}
|
|
135
|
+
propLines.push(`${pad}${I}extensions: {\n${extInner.join('\n')}\n${pad}${I}};`);
|
|
136
|
+
}
|
|
137
|
+
entries.push(`${pad}${JSON.stringify(key)}: {\n${propLines.join('\n')}\n${pad}};`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (entries.length === 0)
|
|
141
|
+
return '';
|
|
142
|
+
return entries.join('\n');
|
|
143
|
+
}
|
|
144
|
+
function buildComponentFunctions(components, baseIndent) {
|
|
145
|
+
const entries = [];
|
|
146
|
+
const d = baseIndent;
|
|
147
|
+
const pad = I.repeat(d);
|
|
148
|
+
for (const [ref, comp] of Object.entries(components)) {
|
|
149
|
+
if (!comp)
|
|
150
|
+
continue;
|
|
151
|
+
const allFunctions = [
|
|
152
|
+
...(comp.functions ?? []),
|
|
153
|
+
...Object.values(comp.extensions ?? {}).flatMap(ext => ext?.functions ?? []),
|
|
154
|
+
];
|
|
155
|
+
if (allFunctions.length === 0)
|
|
156
|
+
continue;
|
|
157
|
+
const fnLines = [];
|
|
158
|
+
for (const fn of allFunctions) {
|
|
159
|
+
const parts = [];
|
|
160
|
+
if (fn.input && Object.keys(fn.input).length > 0)
|
|
161
|
+
parts.push(`input: ${objectShape(fn.input, d + 2)}`);
|
|
162
|
+
if (fn.output)
|
|
163
|
+
parts.push(`output: ${idlTypeNodeToTs(fn.output, d + 2)}`);
|
|
164
|
+
if (parts.length === 0)
|
|
165
|
+
continue;
|
|
166
|
+
fnLines.push(`${pad}${I}${JSON.stringify(fn.name)}: { ${parts.join('; ')} };`);
|
|
167
|
+
}
|
|
168
|
+
if (fnLines.length > 0)
|
|
169
|
+
entries.push(`${pad}${JSON.stringify(ref)}: {\n${fnLines.join('\n')}\n${pad}};`);
|
|
170
|
+
}
|
|
171
|
+
if (entries.length === 0)
|
|
172
|
+
return '';
|
|
173
|
+
return entries.join('\n');
|
|
174
|
+
}
|
|
175
|
+
function buildPlatformFunctions(functions, baseIndent) {
|
|
176
|
+
const entries = [];
|
|
177
|
+
const d = baseIndent;
|
|
178
|
+
const pad = I.repeat(d);
|
|
179
|
+
for (const [name, sig] of Object.entries(functions)) {
|
|
180
|
+
if (!sig)
|
|
181
|
+
continue;
|
|
182
|
+
const parts = [];
|
|
183
|
+
if (sig.input && Object.keys(sig.input).length > 0)
|
|
184
|
+
parts.push(`input: ${objectShape(sig.input, d + 1)}`);
|
|
185
|
+
if (sig.output)
|
|
186
|
+
parts.push(`output: ${idlTypeNodeToTs(sig.output, d + 1)}`);
|
|
187
|
+
if (parts.length === 0)
|
|
188
|
+
continue;
|
|
189
|
+
entries.push(`${pad}${JSON.stringify(name)}: { ${parts.join('; ')} };`);
|
|
190
|
+
}
|
|
191
|
+
if (entries.length === 0)
|
|
192
|
+
return '';
|
|
193
|
+
return entries.join('\n');
|
|
194
|
+
}
|
|
195
|
+
// ── Main export ───────────────────────────────────────────────────────────────
|
|
196
|
+
/**
|
|
197
|
+
* Converts an IDL response into a `declare module "@ptkl/sdk"` augmentation
|
|
198
|
+
* block. Write the output to a `.d.ts` file and include it in your project
|
|
199
|
+
* (e.g., via `tsconfig.json` `"include"` or a triple-slash reference).
|
|
200
|
+
*/
|
|
201
|
+
export function idlToModuleAugmentation(idl) {
|
|
202
|
+
const hasComponents = idl.components && Object.keys(idl.components).length > 0;
|
|
203
|
+
const hasFunctions = idl.functions && Object.keys(idl.functions).length > 0;
|
|
204
|
+
if (!hasComponents && !hasFunctions) {
|
|
205
|
+
return `// No IDL definitions found — nothing to generate.\n`;
|
|
206
|
+
}
|
|
207
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
208
|
+
const lines = [
|
|
209
|
+
`// Generated by ptkl generate-types on ${date}`,
|
|
210
|
+
`// Do not edit manually — re-run \`ptkl generate-types\` to refresh.`,
|
|
211
|
+
``,
|
|
212
|
+
`import "@ptkl/sdk";`,
|
|
213
|
+
`import "@ptkl/sdk/beta";`,
|
|
214
|
+
];
|
|
215
|
+
// Declare interfaces once globally, then extend into both modules.
|
|
216
|
+
const ifaceNames = [];
|
|
217
|
+
if (hasComponents) {
|
|
218
|
+
const models = buildComponentModels(idl.components, 1);
|
|
219
|
+
if (models) {
|
|
220
|
+
lines.push(``, `interface _CM {\n${models}\n}`);
|
|
221
|
+
ifaceNames.push('ComponentModels extends _CM');
|
|
222
|
+
}
|
|
223
|
+
const fns = buildComponentFunctions(idl.components, 1);
|
|
224
|
+
if (fns) {
|
|
225
|
+
lines.push(``, `interface _CF {\n${fns}\n}`);
|
|
226
|
+
ifaceNames.push('ComponentFunctions extends _CF');
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (hasFunctions) {
|
|
230
|
+
const platFns = buildPlatformFunctions(idl.functions, 1);
|
|
231
|
+
if (platFns) {
|
|
232
|
+
lines.push(``, `interface _PF {\n${platFns}\n}`);
|
|
233
|
+
ifaceNames.push('PlatformFunctions extends _PF');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (ifaceNames.length > 0) {
|
|
237
|
+
const augBody = ifaceNames.map(n => ` interface ${n} {}`).join('\n');
|
|
238
|
+
lines.push(``, `declare module "@ptkl/sdk" {\n${augBody}\n}`, ``, `declare module "@ptkl/sdk/beta" {\n${augBody}\n}`);
|
|
239
|
+
}
|
|
240
|
+
lines.push(``);
|
|
241
|
+
return lines.join('\n');
|
|
242
|
+
}
|
package/dist/lib/util.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
2
|
-
import
|
|
2
|
+
import { Platform } from '@ptkl/sdk';
|
|
3
3
|
export default class Util {
|
|
4
4
|
static profilePath = `${process.env.HOME}/.ptkl`;
|
|
5
5
|
static fileName = "profiles.json";
|
|
@@ -69,6 +69,6 @@ export default class Util {
|
|
|
69
69
|
}
|
|
70
70
|
static getClientForProfile() {
|
|
71
71
|
const profile = Util.getCurrentProfile();
|
|
72
|
-
return new
|
|
72
|
+
return new Platform({ project: profile.project, token: profile.token, host: profile.host });
|
|
73
73
|
}
|
|
74
74
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ptkl/toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.8",
|
|
4
4
|
"description": "A command-line toolkit for managing Protokol platform applications, profiles, functions, and components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"protokol",
|
|
@@ -28,9 +28,17 @@
|
|
|
28
28
|
"prepublishOnly": "npm run build"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
+
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
32
|
+
"@babel/plugin-proposal-decorators": "^7.28.0",
|
|
33
|
+
"@babel/plugin-transform-class-static-block": "^7.28.3",
|
|
34
|
+
"@babel/preset-react": "^7.28.5",
|
|
35
|
+
"@babel/preset-typescript": "^7.28.5",
|
|
31
36
|
"@babel/standalone": "^7.26.10",
|
|
32
37
|
"@inquirer/password": "^4.0.21",
|
|
33
|
-
"@ptkl/sdk": "^
|
|
38
|
+
"@ptkl/sdk": "^1.5.1",
|
|
39
|
+
"@rollup/plugin-babel": "^6.1.0",
|
|
40
|
+
"@rollup/plugin-commonjs": "^29.0.0",
|
|
41
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
34
42
|
"@types/axios": "^0.14.0",
|
|
35
43
|
"@types/commander": "^2.12.2",
|
|
36
44
|
"@types/js-yaml": "^4.0.9",
|
|
@@ -45,6 +53,7 @@
|
|
|
45
53
|
"lodash": "^4.17.21",
|
|
46
54
|
"open": "^10.1.2",
|
|
47
55
|
"rollup": "^4.34.6",
|
|
56
|
+
"sass": "^1.95.1",
|
|
48
57
|
"tar": "^7.4.3",
|
|
49
58
|
"vite": "^6.0.6",
|
|
50
59
|
"vue-template-compiler": "^2.7.16",
|