infaira-canvas 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,264 @@
1
+ # infaira-canvas
2
+
3
+ CLI toolkit for building and publishing widgets for the **InfAIra Canvas (ICan)**.
4
+
5
+ ---
6
+
7
+ ## What is this?
8
+
9
+ `infaira-canvas` is a command-line tool that helps widget developers:
10
+
11
+ 1. **Scaffold** a new widget project with all required files
12
+ 2. **Upload** a built widget bundle to an ICan portal
13
+
14
+ ---
15
+
16
+ ## Installation
17
+
18
+ No installation needed. Use `npx` to always get the latest version:
19
+
20
+ ```bash
21
+ npx infaira-canvas <command>
22
+ ```
23
+
24
+ Or install globally:
25
+
26
+ ```bash
27
+ npm install -g infaira-canvas
28
+ infaira-canvas <command>
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Commands
34
+
35
+ ### `init` — Scaffold a new widget
36
+
37
+ ```bash
38
+ npx infaira-canvas init <widget-name>
39
+ ```
40
+
41
+ **Example:**
42
+
43
+ ```bash
44
+ npx infaira-canvas init my-sales-widget
45
+ ```
46
+
47
+ **What it does:**
48
+
49
+ - Creates a new folder `my-sales-widget/`
50
+ - Fetches the latest `ican.d.ts` type definitions from `https://infaira.ai/dist/client/ican.d.ts`
51
+ - Generates all files needed to build and run a widget
52
+
53
+ **Files generated:**
54
+
55
+ | File | Purpose |
56
+ |------|---------|
57
+ | `bundle.json` | Widget identity — unique ID, name, version |
58
+ | `src/index.tsx` | Main widget React component |
59
+ | `src/ican.ts` | ICan bridge — `registerWidget()` and other registration functions |
60
+ | `src/styles.scss` | Widget styles |
61
+ | `ican.d.ts` | TypeScript type definitions for ICan components |
62
+ | `designer.d.ts` | TypeScript type definitions for the widget designer |
63
+ | `webpack.config.js` | Build config — ensures React and ICan are NOT bundled |
64
+ | `tsconfig.json` | TypeScript config |
65
+ | `package.json` | npm dependencies |
66
+ | `index.html` | Dev harness to preview the widget locally |
67
+ | `ui.html` | UI harness for testing UIs |
68
+ | `localization.json` | Localization strings |
69
+ | `.gitignore` | Ignores `node_modules/`, `dist/` |
70
+
71
+ ---
72
+
73
+ ### `upload` — Upload a built widget to the portal
74
+
75
+ ```bash
76
+ infaira-canvas upload \
77
+ --url <portal-url> \
78
+ --token <auth-token> \
79
+ --bundle <path-to-bundle.json> \
80
+ --script <path-to-main.js>
81
+ ```
82
+
83
+ **Example:**
84
+
85
+ ```bash
86
+ infaira-canvas upload \
87
+ --url https://infaira.ai \
88
+ --token eyJhbGciOiJIUzI1NiJ9... \
89
+ --bundle ./bundle.json \
90
+ --script ./dist/main.js
91
+ ```
92
+
93
+ **Options:**
94
+
95
+ | Flag | Required | Description |
96
+ |------|----------|-------------|
97
+ | `--url` | Yes | Base URL of the ICan portal |
98
+ | `--token` | Yes | Your JWT auth token from the portal |
99
+ | `--bundle` | Yes | Path to `bundle.json` |
100
+ | `--script` | Yes | Path to compiled `main.js` (from `npm run build`) |
101
+
102
+ **What it does:**
103
+
104
+ - Sends `bundle.json` and `main.js` to the portal's `/api/bundles/upload` endpoint
105
+ - The portal stores widget metadata in the database
106
+ - The widget becomes available in the portal's widget library
107
+ - Admins can then add it to any dashboard
108
+
109
+ ---
110
+
111
+ ## Full Developer Workflow
112
+
113
+ ```bash
114
+ # 1. Scaffold a new widget
115
+ npx infaira-canvas init my-widget
116
+
117
+ # 2. Install dependencies
118
+ cd my-widget
119
+ npm install
120
+
121
+ # 3. Start dev server (preview at http://localhost:8080)
122
+ npm run dev
123
+
124
+ # 4. Build for production
125
+ npm run build
126
+
127
+ # 5. Upload to the ICan portal
128
+ infaira-canvas upload \
129
+ --url https://infaira.ai \
130
+ --token <your-token> \
131
+ --bundle ./bundle.json \
132
+ --script ./dist/main.js
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Widget Structure
138
+
139
+ Every widget scaffolded by `infaira-canvas init` follows this structure:
140
+
141
+ ```
142
+ my-widget/
143
+ ├── bundle.json ← Widget metadata (edit this to configure your widget)
144
+ ├── localization.json ← Localization strings
145
+ ├── src/
146
+ │ ├── index.tsx ← Your widget component (main file to edit)
147
+ │ ├── ican.ts ← ICan bridge (do not edit)
148
+ │ └── styles.scss ← Widget styles
149
+ ├── resources/
150
+ │ ├── ican-components.js ← ICan component library (for dev mode)
151
+ │ ├── infaira-logo.png
152
+ │ └── infaira-icon.png
153
+ ├── ican.d.ts ← ICan type definitions
154
+ ├── designer.d.ts ← Designer type definitions
155
+ ├── index.html ← Dev harness
156
+ ├── ui.html ← UI harness
157
+ ├── webpack.config.js ← Build config
158
+ ├── tsconfig.json
159
+ └── package.json
160
+ ```
161
+
162
+ ---
163
+
164
+ ## How Widgets Work
165
+
166
+ ```
167
+ Developer builds → main.js + bundle.json
168
+
169
+ Upload via infaira-canvas upload
170
+
171
+ Portal stores main.js + metadata in DB
172
+
173
+ Portal loads main.js as <script> tag at runtime
174
+
175
+ Script calls window.registerWidget() → widget appears in grid
176
+
177
+ Widget receives icanContext → calls executeAction() → renders data
178
+ ```
179
+
180
+ ---
181
+
182
+ ## `bundle.json` Reference
183
+
184
+ ```json
185
+ {
186
+ "id": "your-bundle-uuid",
187
+ "name": "My Widget",
188
+ "version": "1.0.0",
189
+ "author": "Your Name",
190
+ "widgets": [
191
+ {
192
+ "id": "my-widget",
193
+ "name": "My Widget",
194
+ "description": "What this widget does",
195
+ "icon": "",
196
+ "tags": [],
197
+ "category": "",
198
+ "isTemplate": false
199
+ }
200
+ ],
201
+ "sidebarLinks": [],
202
+ "uis": [],
203
+ "menuItems": []
204
+ }
205
+ ```
206
+
207
+ ---
208
+
209
+ ## Using `icanContext` in your widget
210
+
211
+ The portal passes an `icanContext` prop to every widget. Use it to fetch data from Orch:
212
+
213
+ ```tsx
214
+ const MyWidget: React.FC<IWidgetProps> = ({ icanContext }) => {
215
+ const [data, setData] = React.useState(null);
216
+
217
+ React.useEffect(() => {
218
+ if (!icanContext) return;
219
+
220
+ icanContext
221
+ .executeAction('MyModel', 'GetAll', {}, { json: true })
222
+ .then((result) => setData(result));
223
+ }, [icanContext]);
224
+
225
+ return <div>{JSON.stringify(data)}</div>;
226
+ };
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Important Rules
232
+
233
+ - **Never bundle React** — it comes from the portal at runtime. The `webpack.config.js` externals handle this automatically.
234
+ - **Always call `registerWidget()`** at the bottom of `src/index.tsx` — this is how the portal discovers your widget.
235
+ - **Widget ID must match `bundle.json`** — the ID you pass to `registerWidget()` must exist in the `widgets` array in `bundle.json`.
236
+ - **Grid is 30 columns** — design your widget layout accordingly.
237
+
238
+ ---
239
+
240
+ ## Updating `ican.d.ts`
241
+
242
+ The type definitions are served from `https://infaira.ai/dist/client/ican.d.ts`. When you run `npx infaira-canvas init`, it always fetches the latest version. If the server is unreachable, it falls back to the version bundled inside the npm package.
243
+
244
+ ---
245
+
246
+ ## Publishing a New CLI Version (Maintainers Only)
247
+
248
+ ```bash
249
+ # Make your changes in src/ or templates/
250
+ # then bump version and publish:
251
+
252
+ npm version patch # bug fix → 0.1.1
253
+ npm version minor # new feature → 0.2.0
254
+ npm version major # breaking change → 1.0.0
255
+
256
+ npm publish --access public
257
+ ```
258
+
259
+ ---
260
+
261
+ ## Requirements
262
+
263
+ - Node.js >= 18
264
+ - npm >= 7
@@ -0,0 +1,17 @@
1
+ export interface IBundleJson {
2
+ id: string;
3
+ name?: string;
4
+ version?: string;
5
+ widgets: Array<{
6
+ id: string;
7
+ name: string;
8
+ }>;
9
+ }
10
+ export declare function validateBundleJson(raw: string): {
11
+ valid: true;
12
+ data: IBundleJson;
13
+ } | {
14
+ valid: false;
15
+ error: string;
16
+ };
17
+ export declare function handleInit(name: string): Promise<void>;