@managespace/sdk 0.1.158-extensions → 0.1.159

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 (55) hide show
  1. package/README.md +2 -723
  2. package/dist/extensibility/functions/project/billing.d.ts +7 -0
  3. package/dist/extensibility/functions/project/billing.d.ts.map +1 -1
  4. package/dist/extensibility/functions/project/billing.js +5 -0
  5. package/dist/extensibility/types/control.d.ts +1 -1
  6. package/dist/extensibility/types/control.d.ts.map +1 -1
  7. package/dist/generated/apis/default-api.d.ts +9 -1
  8. package/dist/generated/apis/default-api.d.ts.map +1 -1
  9. package/dist/generated/apis/default-api.js +28 -0
  10. package/dist/generated/apis/index.d.ts +0 -1
  11. package/dist/generated/apis/index.d.ts.map +1 -1
  12. package/dist/generated/apis/index.js +0 -1
  13. package/dist/generated/models/index.d.ts +1 -2
  14. package/dist/generated/models/index.d.ts.map +1 -1
  15. package/dist/generated/models/index.js +1 -2
  16. package/dist/generated/models/payment-gateway-client-token-response.d.ts +47 -0
  17. package/dist/generated/models/payment-gateway-client-token-response.d.ts.map +1 -0
  18. package/dist/generated/models/payment-gateway-client-token-response.js +63 -0
  19. package/dist/index.d.ts +0 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +0 -1
  22. package/package.deploy.json +7 -3
  23. package/package.json +2 -5
  24. package/src/extensibility/functions/project/billing.ts +6 -0
  25. package/src/extensibility/types/control.ts +1 -0
  26. package/src/generated/.openapi-generator/FILES +1 -3
  27. package/src/generated/apis/default-api.ts +37 -0
  28. package/src/generated/apis/index.ts +0 -1
  29. package/src/generated/models/index.ts +1 -2
  30. package/src/generated/models/payment-gateway-client-token-response.ts +87 -0
  31. package/src/index.ts +0 -1
  32. package/dist/extensions/host-bridge.d.ts +0 -166
  33. package/dist/extensions/host-bridge.d.ts.map +0 -1
  34. package/dist/extensions/host-bridge.js +0 -259
  35. package/dist/extensions/index.d.ts +0 -40
  36. package/dist/extensions/index.d.ts.map +0 -1
  37. package/dist/extensions/index.js +0 -55
  38. package/dist/extensions/types.d.ts +0 -111
  39. package/dist/extensions/types.d.ts.map +0 -1
  40. package/dist/extensions/types.js +0 -2
  41. package/dist/generated/apis/extensions-api.d.ts +0 -98
  42. package/dist/generated/apis/extensions-api.d.ts.map +0 -1
  43. package/dist/generated/apis/extensions-api.js +0 -295
  44. package/dist/generated/models/extension-org.d.ts +0 -64
  45. package/dist/generated/models/extension-org.d.ts.map +0 -1
  46. package/dist/generated/models/extension-org.js +0 -70
  47. package/dist/generated/models/extension.d.ts +0 -106
  48. package/dist/generated/models/extension.d.ts.map +0 -1
  49. package/dist/generated/models/extension.js +0 -98
  50. package/src/extensions/host-bridge.ts +0 -272
  51. package/src/extensions/index.ts +0 -40
  52. package/src/extensions/types.ts +0 -120
  53. package/src/generated/apis/extensions-api.ts +0 -362
  54. package/src/generated/models/extension-org.ts +0 -119
  55. package/src/generated/models/extension.ts +0 -182
package/README.md CHANGED
@@ -1,727 +1,6 @@
1
1
  # @managespace/sdk
2
2
 
3
- ManageSpace SDK for building integrations and extensions.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @managespace/sdk
9
- ```
10
-
11
- ---
12
-
13
- # Extension Development Guide
14
-
15
- This guide explains how to build extensions that run within the ManageSpace platform.
16
-
17
- ## Overview
18
-
19
- ManageSpace extensions are standalone web applications that run in an iframe within the ManageSpace UI. They have access to:
20
-
21
- - **Authentication context** - User's auth token, org/site IDs
22
- - **ManageSpace APIs** - Full access to the REST API
23
- - **Host navigation** - Ability to navigate the main application
24
- - **Toast notifications** - Display feedback to users
25
- - **Entity events** - React to changes in ManageSpace data
26
-
27
- ## Quick Start
28
-
29
- ### 1. Create Project Structure
30
-
31
- ```
32
- my-extension/
33
- ├── package.json
34
- ├── tsconfig.json
35
- ├── vite.config.ts
36
- ├── manifest.json
37
- ├── index.html
38
- └── src/
39
- ├── main.tsx
40
- ├── App.tsx
41
- └── styles.css
42
- ```
43
-
44
- ### 2. package.json
45
-
46
- ```json
47
- {
48
- "name": "my-extension",
49
- "version": "1.0.0",
50
- "private": true,
51
- "type": "module",
52
- "scripts": {
53
- "dev": "vite",
54
- "build": "tsc && vite build",
55
- "bundle": "bun run build && cp manifest.json dist/ && cd dist && zip -r ../bundle.zip ."
56
- },
57
- "dependencies": {
58
- "@managespace/sdk": "^0.1.0",
59
- "react": "^18.3.0",
60
- "react-dom": "^18.3.0"
61
- },
62
- "devDependencies": {
63
- "@types/react": "^18.3.0",
64
- "@types/react-dom": "^18.3.0",
65
- "@vitejs/plugin-react": "^4.3.0",
66
- "typescript": "^5.6.0",
67
- "vite": "^5.4.0"
68
- }
69
- }
70
- ```
71
-
72
- ### 3. tsconfig.json
73
-
74
- ```json
75
- {
76
- "compilerOptions": {
77
- "target": "ES2020",
78
- "useDefineForClassFields": true,
79
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
80
- "module": "ESNext",
81
- "skipLibCheck": true,
82
- "moduleResolution": "bundler",
83
- "allowImportingTsExtensions": true,
84
- "resolveJsonModule": true,
85
- "isolatedModules": true,
86
- "noEmit": true,
87
- "jsx": "react-jsx",
88
- "strict": true,
89
- "noUnusedLocals": true,
90
- "noUnusedParameters": true,
91
- "noFallthroughCasesInSwitch": true
92
- },
93
- "include": ["src"]
94
- }
95
- ```
96
-
97
- ### 4. vite.config.ts
98
-
99
- ```typescript
100
- import react from '@vitejs/plugin-react';
101
- import { defineConfig } from 'vite';
102
-
103
- export default defineConfig({
104
- plugins: [react()],
105
- build: {
106
- outDir: 'dist',
107
- assetsDir: 'assets',
108
- rollupOptions: {
109
- output: {
110
- entryFileNames: 'assets/[name].js',
111
- chunkFileNames: 'assets/[name].js',
112
- assetFileNames: 'assets/[name].[ext]',
113
- },
114
- },
115
- },
116
- });
117
- ```
118
-
119
- ### 5. manifest.json
120
-
121
- ```json
122
- {
123
- "name": "My Extension",
124
- "version": "1.0.0",
125
- "author": "Your Name",
126
- "description": "Description of what your extension does",
127
- "navLabel": "My Extension",
128
- "navIcon": "Layout",
129
- "navRoute": "/extensions/my-extension",
130
- "entryPoint": "index.html"
131
- }
132
- ```
133
-
134
- **Manifest Fields:**
135
-
136
- | Field | Required | Description |
137
- |-------|----------|-------------|
138
- | `name` | Yes | Display name of the extension |
139
- | `version` | Yes | Semantic version (e.g., "1.0.0") |
140
- | `author` | Yes | Author or company name |
141
- | `description` | No | Short description |
142
- | `navLabel` | Yes | Label shown in navigation menu |
143
- | `navIcon` | Yes | Lucide icon name (e.g., "Users", "Settings", "BarChart") |
144
- | `navRoute` | Yes | Route path, must start with "/extensions/" |
145
- | `entryPoint` | Yes | Entry HTML file (usually "index.html") |
146
- | `bff.url` | No | URL of your Backend for Frontend server |
147
-
148
- ### 6. index.html
149
-
150
- ```html
151
- <!DOCTYPE html>
152
- <html lang="en">
153
- <head>
154
- <meta charset="UTF-8" />
155
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
156
- <title>My Extension</title>
157
- </head>
158
- <body>
159
- <div id="root"></div>
160
- <script type="module" src="/src/main.tsx"></script>
161
- </body>
162
- </html>
163
- ```
164
-
165
- ### 7. src/main.tsx
166
-
167
- ```typescript
168
- import React from 'react';
169
- import ReactDOM from 'react-dom/client';
170
- import App from './App';
171
- import { signalReady } from '@managespace/sdk/extensions';
172
- import './styles.css';
173
-
174
- // Signal to host that extension is ready to receive context
175
- signalReady();
176
-
177
- ReactDOM.createRoot(document.getElementById('root')!).render(
178
- <React.StrictMode>
179
- <App />
180
- </React.StrictMode>
181
- );
182
- ```
183
-
184
- ### 8. src/App.tsx
185
-
186
- ```typescript
187
- import { useEffect, useState } from 'react';
188
- import {
189
- getContext,
190
- createApiFetch,
191
- navigate,
192
- showToast,
193
- type ExtensionContext,
194
- } from '@managespace/sdk/extensions';
195
-
196
- export default function App() {
197
- const [context, setContext] = useState<ExtensionContext | null>(null);
198
- const [loading, setLoading] = useState(true);
199
-
200
- useEffect(() => {
201
- getContext()
202
- .then(setContext)
203
- .finally(() => setLoading(false));
204
- }, []);
205
-
206
- if (loading) {
207
- return <div>Loading...</div>;
208
- }
209
-
210
- if (!context) {
211
- return <div>Failed to receive context from host</div>;
212
- }
213
-
214
- return (
215
- <div>
216
- <h1>My Extension</h1>
217
- <p>Organisation: {context.orgId}</p>
218
- <p>User: {context.userId}</p>
219
- {/* Your extension UI here */}
220
- </div>
221
- );
222
- }
223
- ```
224
-
225
- ---
226
-
227
- ## Extension SDK API
228
-
229
- Import from `@managespace/sdk/extensions`:
230
-
231
- ### getContext()
232
-
233
- Get the extension context from the ManageSpace host.
234
-
235
- ```typescript
236
- import { getContext } from '@managespace/sdk/extensions';
237
-
238
- const context = await getContext();
239
- // context.orgId - Current organisation ID
240
- // context.userId - Current user ID
241
- // context.siteId - Current site ID
242
- // context.apiBaseUrl - Base URL for API calls
243
- // context.bffUrl - Your BFF URL (if configured)
244
- ```
245
-
246
- ### signalReady()
247
-
248
- Signal to the host that your extension is ready to receive context. Call this early in your extension's lifecycle.
249
-
250
- ```typescript
251
- import { signalReady } from '@managespace/sdk/extensions';
252
-
253
- signalReady();
254
- ```
255
-
256
- ### navigate(path)
257
-
258
- Navigate the ManageSpace host to a specific path.
259
-
260
- ```typescript
261
- import { navigate } from '@managespace/sdk/extensions';
262
-
263
- // Navigate to a customer profile
264
- navigate('/customer/abc-123');
265
-
266
- // Navigate to the assets page
267
- navigate('/assets');
268
- ```
269
-
270
- ### showToast(message, variant?)
271
-
272
- Show a toast notification in the host application.
273
-
274
- ```typescript
275
- import { showToast } from '@managespace/sdk/extensions';
276
-
277
- showToast('Operation successful');
278
- showToast('Something went wrong', 'error');
279
- ```
280
-
281
- ### createApiFetch(context)
282
-
283
- Create a fetch function configured for ManageSpace API calls.
284
-
285
- ```typescript
286
- import { getContext, createApiFetch } from '@managespace/sdk/extensions';
287
-
288
- const context = await getContext();
289
- const apiFetch = createApiFetch(context);
290
-
291
- const response = await apiFetch('/api/crm/customers/queries', {
292
- method: 'POST',
293
- body: JSON.stringify({
294
- pageOptions: { offset: 0, limit: 20 }
295
- })
296
- });
297
- const data = await response.json();
298
- ```
299
-
300
- ### createBffFetch(context)
301
-
302
- Create a fetch function for calling your extension's Backend for Frontend.
303
-
304
- ```typescript
305
- import { getContext, createBffFetch } from '@managespace/sdk/extensions';
306
-
307
- const context = await getContext();
308
- const bffFetch = createBffFetch(context);
309
-
310
- if (bffFetch) {
311
- const response = await bffFetch('/api/my-endpoint');
312
- const data = await response.json();
313
- }
314
- ```
315
-
316
- ### onEntityEvent(handler)
317
-
318
- Subscribe to entity events from the ManageSpace host.
319
-
320
- ```typescript
321
- import { onEntityEvent } from '@managespace/sdk/extensions';
322
-
323
- const unsubscribe = onEntityEvent((event) => {
324
- console.log(`${event.entityType} ${event.entityId} was ${event.action}`);
325
- // event.entityType: 'customer', 'asset', 'subscription', etc.
326
- // event.action: 'created', 'updated', 'deleted'
327
- });
328
-
329
- // To stop listening:
330
- unsubscribe();
331
- ```
332
-
333
- ---
334
-
335
- ## ManageSpace API Reference
336
-
337
- Use `createApiFetch(context)` to call these endpoints. All requests include authentication automatically.
338
-
339
- ### Customers
340
-
341
- #### List/Query Customers
342
-
343
- ```typescript
344
- const response = await apiFetch('/api/crm/customers/queries', {
345
- method: 'POST',
346
- body: JSON.stringify({
347
- pageOptions: { offset: 0, limit: 20 },
348
- filters: [
349
- { field: 'name', operator: 'contains', value: 'Smith' }
350
- ]
351
- })
352
- });
353
-
354
- // Response: { results: Customer[], total: number }
355
- ```
356
-
357
- **Customer Type:**
358
- ```typescript
359
- interface Customer {
360
- id: string;
361
- name: string;
362
- description: string | null;
363
- orgId: string;
364
- createdAt: Date;
365
- updatedAt: Date | null;
366
- customerStatusId: string;
367
- commercial: boolean;
368
- contacts?: Contact[];
369
- // ... additional fields
370
- }
371
- ```
372
-
373
- #### Get Customer by ID
374
-
375
- ```typescript
376
- const response = await apiFetch(`/api/crm/customers/${customerId}`);
377
- const customer = await response.json();
378
- ```
379
-
380
- ### Assets
381
-
382
- #### List Assets
383
-
384
- ```typescript
385
- const response = await apiFetch('/api/assets');
386
- // Response: { results: Asset[], total: number }
387
- ```
388
-
389
- #### Get Asset by ID
390
-
391
- ```typescript
392
- const response = await apiFetch(`/api/assets/${assetId}`);
393
- const asset = await response.json();
394
- ```
395
-
396
- **Asset Type:**
397
- ```typescript
398
- interface Asset {
399
- id: string;
400
- name: string;
401
- siteId: string;
402
- assetClassId: string;
403
- status: string;
404
- width: number | null;
405
- height: number | null;
406
- depth: number | null;
407
- // ... additional fields
408
- }
409
- ```
410
-
411
- ### Subscriptions
412
-
413
- #### List Subscriptions
414
-
415
- ```typescript
416
- const response = await apiFetch('/api/subscriptions/queries', {
417
- method: 'POST',
418
- body: JSON.stringify({
419
- pageOptions: { offset: 0, limit: 20 }
420
- })
421
- });
422
- // Response: { results: Subscription[], total: number }
423
- ```
424
-
425
- **Subscription Type:**
426
- ```typescript
427
- interface Subscription {
428
- id: string;
429
- customerId: string;
430
- assetId: string;
431
- planId: string;
432
- status: string;
433
- startDate: Date;
434
- endDate: Date | null;
435
- // ... additional fields
436
- }
437
- ```
438
-
439
- ### Sites
440
-
441
- #### List Sites
442
-
443
- ```typescript
444
- const response = await apiFetch('/api/sites');
445
- // Response: { results: Site[], total: number }
446
- ```
447
-
448
- ### Invoices
449
-
450
- #### List Invoices
451
-
452
- ```typescript
453
- const response = await apiFetch('/api/billing/invoices/queries', {
454
- method: 'POST',
455
- body: JSON.stringify({
456
- pageOptions: { offset: 0, limit: 20 }
457
- })
458
- });
459
- // Response: { results: Invoice[], total: number }
460
- ```
461
-
462
- ### Payments
463
-
464
- #### List Payments
465
-
466
- ```typescript
467
- const response = await apiFetch('/api/billing/payments/queries', {
468
- method: 'POST',
469
- body: JSON.stringify({
470
- pageOptions: { offset: 0, limit: 20 }
471
- })
472
- });
473
- // Response: { results: Payment[], total: number }
474
- ```
475
-
476
- ---
477
-
478
- ## Building a Backend for Frontend (BFF)
479
-
480
- If your extension needs to call external APIs, perform complex data processing, or keep secrets secure, you can create a BFF.
481
-
482
- ### 1. Update manifest.json
483
-
484
- ```json
485
- {
486
- "name": "My Extension",
487
- "version": "1.0.0",
488
- "author": "Your Name",
489
- "navLabel": "My Extension",
490
- "navIcon": "Layout",
491
- "navRoute": "/extensions/my-extension",
492
- "entryPoint": "index.html",
493
- "bff": {
494
- "url": "https://my-bff.example.com"
495
- }
496
- }
497
- ```
498
-
499
- ### 2. Create BFF Server
500
-
501
- Using Hono (recommended):
502
-
503
- ```typescript
504
- // server.ts
505
- import { Hono } from 'hono';
506
- import { cors } from 'hono/cors';
507
-
508
- const app = new Hono();
509
-
510
- // Enable CORS for your ManageSpace instance
511
- app.use('*', cors({
512
- origin: ['https://your-managespace-instance.com'],
513
- credentials: true,
514
- }));
515
-
516
- app.get('/api/my-endpoint', async (c) => {
517
- // Get auth cookie forwarded from extension
518
- const cookie = c.req.header('Cookie');
519
-
520
- if (!cookie) {
521
- return c.json({ error: 'Not authenticated' }, 401);
522
- }
523
-
524
- // Call ManageSpace API with forwarded credentials
525
- const response = await fetch('https://your-instance/gateway/api/crm/customers/queries', {
526
- method: 'POST',
527
- headers: {
528
- Cookie: cookie,
529
- 'Content-Type': 'application/json',
530
- },
531
- body: JSON.stringify({ pageOptions: { offset: 0, limit: 20 } }),
532
- });
533
-
534
- const data = await response.json();
535
-
536
- // Enrich or transform data
537
- const enrichedData = data.results.map(customer => ({
538
- ...customer,
539
- customField: 'added by BFF',
540
- }));
541
-
542
- return c.json({ customers: enrichedData });
543
- });
544
-
545
- export default {
546
- port: 4000,
547
- fetch: app.fetch,
548
- };
549
- ```
550
-
551
- ### 3. Call BFF from Extension
552
-
553
- ```typescript
554
- import { getContext, createBffFetch } from '@managespace/sdk/extensions';
555
-
556
- const context = await getContext();
557
- const bffFetch = createBffFetch(context);
558
-
559
- if (bffFetch) {
560
- const response = await bffFetch('/api/my-endpoint');
561
- const data = await response.json();
562
- }
563
- ```
564
-
565
- ---
566
-
567
- ## Building and Packaging
568
-
569
- ### Development
570
-
571
- ```bash
572
- npm run dev
573
- ```
574
-
575
- This starts a local dev server. During development, the extension runs standalone and waits for context from the host.
576
-
577
- ### Build
578
-
579
- ```bash
580
- npm run build
581
- ```
582
-
583
- Creates a production build in `dist/`.
584
-
585
- ### Package for Upload
586
-
587
- ```bash
588
- npm run bundle
589
- ```
590
-
591
- Creates `bundle.zip` containing:
592
- - `index.html`
593
- - `assets/` (JS, CSS)
594
- - `manifest.json`
595
-
596
- Upload this ZIP file through the ManageSpace Admin > Extensions page.
597
-
598
- ---
599
-
600
- ## Available Lucide Icons
601
-
602
- For `navIcon` in manifest.json, use any Lucide icon name:
603
-
604
- **Common icons:**
605
- - `Users` - People/customers
606
- - `Building` - Properties/sites
607
- - `Box` - Assets/inventory
608
- - `CreditCard` - Payments/billing
609
- - `FileText` - Documents/invoices
610
- - `Settings` - Configuration
611
- - `BarChart` - Analytics/reports
612
- - `Calendar` - Scheduling
613
- - `Bell` - Notifications
614
- - `Search` - Search functionality
615
- - `Layout` - Dashboard/overview
616
- - `Truck` - Delivery/logistics
617
- - `Key` - Access/security
618
- - `Mail` - Communications
619
-
620
- See https://lucide.dev/icons for the full list.
621
-
622
- ---
623
-
624
- ## TypeScript Types
625
-
626
- All types are exported from `@managespace/sdk/extensions`:
627
-
628
- ```typescript
629
- import type {
630
- ExtensionContext,
631
- ExtensionManifest,
632
- HostMessage,
633
- ExtensionMessage,
634
- EntityEvent,
635
- EntityEventHandler,
636
- } from '@managespace/sdk/extensions';
637
- ```
638
-
639
- Entity types are available from the main SDK:
640
-
641
- ```typescript
642
- import type {
643
- Customer,
644
- Asset,
645
- Subscription,
646
- Site,
647
- Invoice,
648
- Payment,
649
- Contact,
650
- } from '@managespace/sdk';
651
- ```
652
-
653
- ---
654
-
655
- ## Example: Customer List Extension
656
-
657
- Complete example showing customers with click-to-navigate:
658
-
659
- ```typescript
660
- // src/App.tsx
661
- import { useEffect, useState } from 'react';
662
- import {
663
- getContext,
664
- createApiFetch,
665
- navigate,
666
- showToast,
667
- type ExtensionContext,
668
- } from '@managespace/sdk/extensions';
669
- import type { Customer } from '@managespace/sdk';
670
-
671
- export default function App() {
672
- const [context, setContext] = useState<ExtensionContext | null>(null);
673
- const [customers, setCustomers] = useState<Customer[]>([]);
674
- const [loading, setLoading] = useState(true);
675
-
676
- useEffect(() => {
677
- getContext().then(setContext);
678
- }, []);
679
-
680
- useEffect(() => {
681
- if (!context) return;
682
-
683
- const apiFetch = createApiFetch(context);
684
-
685
- apiFetch('/api/crm/customers/queries', {
686
- method: 'POST',
687
- body: JSON.stringify({
688
- pageOptions: { offset: 0, limit: 20 }
689
- })
690
- })
691
- .then(res => res.json())
692
- .then(data => setCustomers(data.results || []))
693
- .catch(() => showToast('Failed to load customers', 'error'))
694
- .finally(() => setLoading(false));
695
- }, [context]);
696
-
697
- if (loading) return <div>Loading...</div>;
698
-
699
- return (
700
- <div>
701
- <h1>Customers</h1>
702
- <ul>
703
- {customers.map(customer => (
704
- <li
705
- key={customer.id}
706
- onClick={() => navigate(`/customer/${customer.id}`)}
707
- style={{ cursor: 'pointer' }}
708
- >
709
- {customer.name}
710
- </li>
711
- ))}
712
- </ul>
713
- </div>
714
- );
715
- }
716
- ```
717
-
718
- ---
719
-
720
- ## Publishing the SDK
721
-
722
- ```bash
723
- # Update version in package.json
724
- npm install
3
+ update version number in package.json
4
+ npm i
725
5
  npm run build
726
6
  npm publish
727
- ```