@colixsystems/widget-sdk 0.34.0 → 0.35.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.
- package/README.md +9 -1
- package/dist/contract.cjs +55 -2
- package/dist/contract.js +55 -2
- package/dist/hooks.js +187 -0
- package/dist/index.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,7 +47,15 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
47
47
|
|
|
48
48
|
## Status
|
|
49
49
|
|
|
50
|
-
`v0.
|
|
50
|
+
`v0.35.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
|
|
51
|
+
|
|
52
|
+
### What's new in 0.35.0
|
|
53
|
+
|
|
54
|
+
**Folder-ACL + signer-roster hooks (REQ-FSH / REQ-SIGN).** Two admin/MANAGE-gated hooks reading the existing `ctx.filestore`:
|
|
55
|
+
- `useFileRoster(fileId, { limit?, offset?, enabled? })` → `{ roster, total, signedCount, loading, error, refetch }` — the signer roster for one file: the folder audience (every member of an open project folder, or the granted users/groups of a restricted one), each annotated `signed` with `signer_name` / `signed_at`. Reads `ctx.filestore.signatures.roster` (new `@colixsystems/filestore-client` **0.5.0** method); the host 403s a non-manager, so use `error` to hide the panel for non-admins.
|
|
56
|
+
- `useFolderPermissions(folderId, { enabled? })` → `{ grants, loading, busy, error, refetch, grant, revoke, setVisibility }` — manage a folder's permissions (the Filestore ACL): `grant(subjectType, subjectId, 'VIEW'|'DOWNLOAD'|'MANAGE')`, `revoke(shareId)`, `setVisibility('INHERIT'|'RESTRICTED')`. Pair the user/group picker with `useUsers` / `useGroups`.
|
|
57
|
+
|
|
58
|
+
Also: `useFileSignatures(fileIds)` is now **self-scoped** (the caller's own signatures only) — the backend tightened; the hook's shape is unchanged. **`CONTRACT.version` → `1.25.0`** (additive: two new hooks; the underlying `filestore-client` → `0.5.0`, shares folder-scoped).
|
|
51
59
|
|
|
52
60
|
### What's new in 0.34.0
|
|
53
61
|
|
package/dist/contract.cjs
CHANGED
|
@@ -236,6 +236,51 @@ const HOOKS = [
|
|
|
236
236
|
requiredContextSlice: ["filestore.signatures"],
|
|
237
237
|
scopes: ["files.read:*"],
|
|
238
238
|
},
|
|
239
|
+
{
|
|
240
|
+
name: "useFileRoster",
|
|
241
|
+
signature: "useFileRoster(fileId, { limit?, offset?, enabled? }?)",
|
|
242
|
+
description:
|
|
243
|
+
"MANAGE-gated signer roster for one Filestore file: the people expected " +
|
|
244
|
+
"to be able to sign it (the file's folder audience) each annotated " +
|
|
245
|
+
"signed/not-signed, plus a distinct signed_count. Reads " +
|
|
246
|
+
"ctx.filestore.signatures.roster and unwraps { data, meta }. The host 403s " +
|
|
247
|
+
"a caller who can see the file but does not MANAGE its folder — surface " +
|
|
248
|
+
"that as 'not an admin here' via `error`.",
|
|
249
|
+
returnShape: {
|
|
250
|
+
roster:
|
|
251
|
+
"{ app_user_id, name, signed, signature_id, signer_name, signed_at }[]",
|
|
252
|
+
total: "number",
|
|
253
|
+
signedCount: "number",
|
|
254
|
+
loading: "boolean",
|
|
255
|
+
error: "Error | null",
|
|
256
|
+
refetch: "() => Promise<void>",
|
|
257
|
+
},
|
|
258
|
+
requiredContextSlice: ["filestore.signatures"],
|
|
259
|
+
scopes: ["files.read:*"],
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "useFolderPermissions",
|
|
263
|
+
signature: "useFolderPermissions(folderId, { enabled? }?)",
|
|
264
|
+
description:
|
|
265
|
+
"Manage a folder's permissions (the Filestore ACL — folder-scoped). Lists " +
|
|
266
|
+
"the folder's grants and exposes grant(subjectType, subjectId, permission) " +
|
|
267
|
+
"/ revoke(shareId) / setVisibility('INHERIT' | 'RESTRICTED') — all MANAGE " +
|
|
268
|
+
"actions the host enforces. Reads ctx.filestore.shares + ctx.filestore." +
|
|
269
|
+
"folders; pair the user/group picker with useUsers / useGroups.",
|
|
270
|
+
returnShape: {
|
|
271
|
+
grants:
|
|
272
|
+
"{ id, folder_id, subject_type, subject_id, permission, created_at }[]",
|
|
273
|
+
loading: "boolean",
|
|
274
|
+
busy: "boolean",
|
|
275
|
+
error: "Error | null",
|
|
276
|
+
refetch: "() => Promise<void>",
|
|
277
|
+
grant: "(subjectType, subjectId, permission) => Promise<share>",
|
|
278
|
+
revoke: "(shareId) => Promise<void>",
|
|
279
|
+
setVisibility: "(visibility) => Promise<folder>",
|
|
280
|
+
},
|
|
281
|
+
requiredContextSlice: ["filestore.shares", "filestore.folders"],
|
|
282
|
+
scopes: ["files.read:*", "files.write:*"],
|
|
283
|
+
},
|
|
239
284
|
{
|
|
240
285
|
name: "useDatastoreQuery",
|
|
241
286
|
signature: "useDatastoreQuery(tableId, options?)",
|
|
@@ -867,7 +912,7 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
867
912
|
"signatures: { initiate(fileId), status(id), cancel(id), verify(id) }, objectUrl(token), fetchObject(token) }. " +
|
|
868
913
|
"Backs useFilestoreFiles() + useFilestoreFolders() + useFileSignature(). Optional — a host without an end-user filestore omits it and those hooks throw a clear error.",
|
|
869
914
|
required: false,
|
|
870
|
-
fields: { files: "object", folders: "object", signatures: "object" },
|
|
915
|
+
fields: { files: "object", folders: "object", shares: "object", signatures: "object" },
|
|
871
916
|
},
|
|
872
917
|
renderer: {
|
|
873
918
|
description:
|
|
@@ -1394,7 +1439,15 @@ const CONTRACT = deepFreeze({
|
|
|
1394
1439
|
// (animated-QR poll). Self-service + JWT-gated — no requestedScopes entry.
|
|
1395
1440
|
// No existing hook, primitive, or field changed shape — minor bump on the
|
|
1396
1441
|
// pre-1.0 channel.
|
|
1397
|
-
|
|
1442
|
+
//
|
|
1443
|
+
// 1.25.0: additive (REQ-FSH / REQ-SIGN) — new `useFileRoster(fileId)`
|
|
1444
|
+
// (MANAGE-gated signer roster: the folder audience annotated
|
|
1445
|
+
// signed/not-signed) and `useFolderPermissions(folderId)` (manage the
|
|
1446
|
+
// folder ACL: list grants + grant/revoke a VIEW/DOWNLOAD/MANAGE tier +
|
|
1447
|
+
// setVisibility). Both read the existing `ctx.filestore`; the underlying
|
|
1448
|
+
// `filestore-client` 0.5.0 made shares folder-scoped + added
|
|
1449
|
+
// `signatures.roster`. No existing hook changed.
|
|
1450
|
+
version: "1.25.0",
|
|
1398
1451
|
hooks: HOOKS,
|
|
1399
1452
|
primitives: PRIMITIVES,
|
|
1400
1453
|
manifestSchema: MANIFEST_SCHEMA,
|
package/dist/contract.js
CHANGED
|
@@ -236,6 +236,51 @@ const HOOKS = [
|
|
|
236
236
|
requiredContextSlice: ["filestore.signatures"],
|
|
237
237
|
scopes: ["files.read:*"],
|
|
238
238
|
},
|
|
239
|
+
{
|
|
240
|
+
name: "useFileRoster",
|
|
241
|
+
signature: "useFileRoster(fileId, { limit?, offset?, enabled? }?)",
|
|
242
|
+
description:
|
|
243
|
+
"MANAGE-gated signer roster for one Filestore file: the people expected " +
|
|
244
|
+
"to be able to sign it (the file's folder audience) each annotated " +
|
|
245
|
+
"signed/not-signed, plus a distinct signed_count. Reads " +
|
|
246
|
+
"ctx.filestore.signatures.roster and unwraps { data, meta }. The host 403s " +
|
|
247
|
+
"a caller who can see the file but does not MANAGE its folder — surface " +
|
|
248
|
+
"that as 'not an admin here' via `error`.",
|
|
249
|
+
returnShape: {
|
|
250
|
+
roster:
|
|
251
|
+
"{ app_user_id, name, signed, signature_id, signer_name, signed_at }[]",
|
|
252
|
+
total: "number",
|
|
253
|
+
signedCount: "number",
|
|
254
|
+
loading: "boolean",
|
|
255
|
+
error: "Error | null",
|
|
256
|
+
refetch: "() => Promise<void>",
|
|
257
|
+
},
|
|
258
|
+
requiredContextSlice: ["filestore.signatures"],
|
|
259
|
+
scopes: ["files.read:*"],
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "useFolderPermissions",
|
|
263
|
+
signature: "useFolderPermissions(folderId, { enabled? }?)",
|
|
264
|
+
description:
|
|
265
|
+
"Manage a folder's permissions (the Filestore ACL — folder-scoped). Lists " +
|
|
266
|
+
"the folder's grants and exposes grant(subjectType, subjectId, permission) " +
|
|
267
|
+
"/ revoke(shareId) / setVisibility('INHERIT' | 'RESTRICTED') — all MANAGE " +
|
|
268
|
+
"actions the host enforces. Reads ctx.filestore.shares + ctx.filestore." +
|
|
269
|
+
"folders; pair the user/group picker with useUsers / useGroups.",
|
|
270
|
+
returnShape: {
|
|
271
|
+
grants:
|
|
272
|
+
"{ id, folder_id, subject_type, subject_id, permission, created_at }[]",
|
|
273
|
+
loading: "boolean",
|
|
274
|
+
busy: "boolean",
|
|
275
|
+
error: "Error | null",
|
|
276
|
+
refetch: "() => Promise<void>",
|
|
277
|
+
grant: "(subjectType, subjectId, permission) => Promise<share>",
|
|
278
|
+
revoke: "(shareId) => Promise<void>",
|
|
279
|
+
setVisibility: "(visibility) => Promise<folder>",
|
|
280
|
+
},
|
|
281
|
+
requiredContextSlice: ["filestore.shares", "filestore.folders"],
|
|
282
|
+
scopes: ["files.read:*", "files.write:*"],
|
|
283
|
+
},
|
|
239
284
|
{
|
|
240
285
|
name: "useDatastoreQuery",
|
|
241
286
|
signature: "useDatastoreQuery(tableId, options?)",
|
|
@@ -867,7 +912,7 @@ const WIDGET_CONTEXT_SHAPE = {
|
|
|
867
912
|
"signatures: { initiate(fileId), status(id), cancel(id), verify(id) }, objectUrl(token), fetchObject(token) }. " +
|
|
868
913
|
"Backs useFilestoreFiles() + useFilestoreFolders() + useFileSignature(). Optional — a host without an end-user filestore omits it and those hooks throw a clear error.",
|
|
869
914
|
required: false,
|
|
870
|
-
fields: { files: "object", folders: "object", signatures: "object" },
|
|
915
|
+
fields: { files: "object", folders: "object", shares: "object", signatures: "object" },
|
|
871
916
|
},
|
|
872
917
|
renderer: {
|
|
873
918
|
description:
|
|
@@ -1394,7 +1439,15 @@ const CONTRACT = deepFreeze({
|
|
|
1394
1439
|
// (animated-QR poll). Self-service + JWT-gated — no requestedScopes entry.
|
|
1395
1440
|
// No existing hook, primitive, or field changed shape — minor bump on the
|
|
1396
1441
|
// pre-1.0 channel.
|
|
1397
|
-
|
|
1442
|
+
//
|
|
1443
|
+
// 1.25.0: additive (REQ-FSH / REQ-SIGN) — new `useFileRoster(fileId)`
|
|
1444
|
+
// (MANAGE-gated signer roster: the folder audience annotated
|
|
1445
|
+
// signed/not-signed) and `useFolderPermissions(folderId)` (manage the
|
|
1446
|
+
// folder ACL: list grants + grant/revoke a VIEW/DOWNLOAD/MANAGE tier +
|
|
1447
|
+
// setVisibility). Both read the existing `ctx.filestore`; the underlying
|
|
1448
|
+
// `filestore-client` 0.5.0 made shares folder-scoped + added
|
|
1449
|
+
// `signatures.roster`. No existing hook changed.
|
|
1450
|
+
version: "1.25.0",
|
|
1398
1451
|
hooks: HOOKS,
|
|
1399
1452
|
primitives: PRIMITIVES,
|
|
1400
1453
|
manifestSchema: MANIFEST_SCHEMA,
|
package/dist/hooks.js
CHANGED
|
@@ -1503,6 +1503,193 @@ export function useFileSignatures(fileIds) {
|
|
|
1503
1503
|
return { signaturesByFileId, loading, error, refetch };
|
|
1504
1504
|
}
|
|
1505
1505
|
|
|
1506
|
+
/**
|
|
1507
|
+
* REQ-SIGN: MANAGE-gated signer roster for one file — the people expected to be
|
|
1508
|
+
* able to sign it (the file's folder audience) each annotated signed/not-signed.
|
|
1509
|
+
* Reads ctx.filestore.signatures.roster. The host backend 403s a caller who can
|
|
1510
|
+
* see the file but doesn't manage its folder, so `error` (a ForbiddenError) is
|
|
1511
|
+
* the "you're not an admin here" signal the widget hides on. Returns
|
|
1512
|
+
* { roster, total, signedCount, loading, error, refetch }. `roster` items are
|
|
1513
|
+
* { app_user_id, name, signed, signature_id, signer_name, signed_at }.
|
|
1514
|
+
*/
|
|
1515
|
+
export function useFileRoster(fileId, options = {}) {
|
|
1516
|
+
const ctx = useWidgetContextOrThrow("useFileRoster");
|
|
1517
|
+
if (
|
|
1518
|
+
!ctx.filestore ||
|
|
1519
|
+
!ctx.filestore.signatures ||
|
|
1520
|
+
typeof ctx.filestore.signatures.roster !== "function"
|
|
1521
|
+
) {
|
|
1522
|
+
throw new Error(
|
|
1523
|
+
"useFileRoster: host did not inject a filestore client (ctx.filestore.signatures.roster)",
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
const { limit = 50, offset = 0, enabled = true } = options;
|
|
1527
|
+
const [roster, setRoster] = useState([]);
|
|
1528
|
+
const [total, setTotal] = useState(0);
|
|
1529
|
+
const [signedCount, setSignedCount] = useState(0);
|
|
1530
|
+
const [loading, setLoading] = useState(Boolean(fileId) && enabled);
|
|
1531
|
+
const [error, setError] = useState(null);
|
|
1532
|
+
|
|
1533
|
+
const sigRef = useRef(ctx.filestore.signatures);
|
|
1534
|
+
sigRef.current = ctx.filestore.signatures;
|
|
1535
|
+
const argsRef = useRef({ fileId, limit, offset, enabled });
|
|
1536
|
+
argsRef.current = { fileId, limit, offset, enabled };
|
|
1537
|
+
const runRef = useRef(0);
|
|
1538
|
+
|
|
1539
|
+
const doFetch = useCallback(async () => {
|
|
1540
|
+
const myRun = ++runRef.current;
|
|
1541
|
+
const { fileId: fid, limit: lim, offset: off, enabled: en } = argsRef.current;
|
|
1542
|
+
if (!fid || !en) {
|
|
1543
|
+
setLoading(false);
|
|
1544
|
+
setError(null);
|
|
1545
|
+
setRoster([]);
|
|
1546
|
+
setTotal(0);
|
|
1547
|
+
setSignedCount(0);
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
setLoading(true);
|
|
1551
|
+
setError(null);
|
|
1552
|
+
try {
|
|
1553
|
+
const res = await sigRef.current.roster(fid, { limit: lim, offset: off });
|
|
1554
|
+
if (runRef.current !== myRun) return;
|
|
1555
|
+
const rows = res && Array.isArray(res.data) ? res.data : [];
|
|
1556
|
+
const meta = (res && res.meta) || {};
|
|
1557
|
+
setRoster(rows);
|
|
1558
|
+
setTotal(typeof meta.total === "number" ? meta.total : rows.length);
|
|
1559
|
+
setSignedCount(typeof meta.signed_count === "number" ? meta.signed_count : 0);
|
|
1560
|
+
setLoading(false);
|
|
1561
|
+
} catch (err) {
|
|
1562
|
+
if (runRef.current !== myRun) return;
|
|
1563
|
+
setError(err);
|
|
1564
|
+
setLoading(false);
|
|
1565
|
+
}
|
|
1566
|
+
}, []);
|
|
1567
|
+
|
|
1568
|
+
useEffect(() => {
|
|
1569
|
+
doFetch();
|
|
1570
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1571
|
+
}, [fileId, limit, offset, enabled]);
|
|
1572
|
+
|
|
1573
|
+
const refetch = useCallback(async () => {
|
|
1574
|
+
await doFetch();
|
|
1575
|
+
}, [doFetch]);
|
|
1576
|
+
|
|
1577
|
+
return { roster, total, signedCount, loading, error, refetch };
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
/**
|
|
1581
|
+
* REQ-FSH: folder-permission management for one folder (the Filestore ACL).
|
|
1582
|
+
* Reads ctx.filestore.shares + ctx.filestore.folders. Lists the folder's grants
|
|
1583
|
+
* and exposes grant / revoke / setVisibility mutations — all MANAGE actions the
|
|
1584
|
+
* host backend enforces (a non-manager's mutation rejects). Pair the user/group
|
|
1585
|
+
* picker with useUsers / useGroups. Returns { grants, loading, busy, error,
|
|
1586
|
+
* refetch, grant, revoke, setVisibility }.
|
|
1587
|
+
*/
|
|
1588
|
+
export function useFolderPermissions(folderId, options = {}) {
|
|
1589
|
+
const ctx = useWidgetContextOrThrow("useFolderPermissions");
|
|
1590
|
+
if (
|
|
1591
|
+
!ctx.filestore ||
|
|
1592
|
+
!ctx.filestore.shares ||
|
|
1593
|
+
typeof ctx.filestore.shares.list !== "function" ||
|
|
1594
|
+
!ctx.filestore.folders ||
|
|
1595
|
+
typeof ctx.filestore.folders.update !== "function"
|
|
1596
|
+
) {
|
|
1597
|
+
throw new Error(
|
|
1598
|
+
"useFolderPermissions: host did not inject a filestore client (ctx.filestore.shares / ctx.filestore.folders)",
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
const { enabled = true } = options;
|
|
1602
|
+
const [grants, setGrants] = useState([]);
|
|
1603
|
+
const [loading, setLoading] = useState(Boolean(folderId) && enabled);
|
|
1604
|
+
const [busy, setBusy] = useState(false);
|
|
1605
|
+
const [error, setError] = useState(null);
|
|
1606
|
+
|
|
1607
|
+
const sharesRef = useRef(ctx.filestore.shares);
|
|
1608
|
+
sharesRef.current = ctx.filestore.shares;
|
|
1609
|
+
const foldersRef = useRef(ctx.filestore.folders);
|
|
1610
|
+
foldersRef.current = ctx.filestore.folders;
|
|
1611
|
+
const idRef = useRef({ folderId, enabled });
|
|
1612
|
+
idRef.current = { folderId, enabled };
|
|
1613
|
+
const runRef = useRef(0);
|
|
1614
|
+
|
|
1615
|
+
const doFetch = useCallback(async () => {
|
|
1616
|
+
const myRun = ++runRef.current;
|
|
1617
|
+
const { folderId: fid, enabled: en } = idRef.current;
|
|
1618
|
+
if (!fid || !en) {
|
|
1619
|
+
setLoading(false);
|
|
1620
|
+
setError(null);
|
|
1621
|
+
setGrants([]);
|
|
1622
|
+
return;
|
|
1623
|
+
}
|
|
1624
|
+
setLoading(true);
|
|
1625
|
+
setError(null);
|
|
1626
|
+
try {
|
|
1627
|
+
const res = await sharesRef.current.list({ folder_id: fid });
|
|
1628
|
+
if (runRef.current !== myRun) return;
|
|
1629
|
+
setGrants(res && Array.isArray(res.data) ? res.data : []);
|
|
1630
|
+
setLoading(false);
|
|
1631
|
+
} catch (err) {
|
|
1632
|
+
if (runRef.current !== myRun) return;
|
|
1633
|
+
setError(err);
|
|
1634
|
+
setLoading(false);
|
|
1635
|
+
}
|
|
1636
|
+
}, []);
|
|
1637
|
+
|
|
1638
|
+
useEffect(() => {
|
|
1639
|
+
doFetch();
|
|
1640
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1641
|
+
}, [folderId, enabled]);
|
|
1642
|
+
|
|
1643
|
+
const refetch = useCallback(async () => {
|
|
1644
|
+
await doFetch();
|
|
1645
|
+
}, [doFetch]);
|
|
1646
|
+
|
|
1647
|
+
const grant = useCallback(
|
|
1648
|
+
async (subjectType, subjectId, permission) => {
|
|
1649
|
+
const { folderId: fid } = idRef.current;
|
|
1650
|
+
setBusy(true);
|
|
1651
|
+
try {
|
|
1652
|
+
const row = await sharesRef.current.create({
|
|
1653
|
+
folder_id: fid,
|
|
1654
|
+
subject_type: subjectType,
|
|
1655
|
+
subject_id: subjectId,
|
|
1656
|
+
permission,
|
|
1657
|
+
});
|
|
1658
|
+
await doFetch();
|
|
1659
|
+
return row;
|
|
1660
|
+
} finally {
|
|
1661
|
+
setBusy(false);
|
|
1662
|
+
}
|
|
1663
|
+
},
|
|
1664
|
+
[doFetch],
|
|
1665
|
+
);
|
|
1666
|
+
|
|
1667
|
+
const revoke = useCallback(
|
|
1668
|
+
async (shareId) => {
|
|
1669
|
+
setBusy(true);
|
|
1670
|
+
try {
|
|
1671
|
+
await sharesRef.current.remove(shareId);
|
|
1672
|
+
await doFetch();
|
|
1673
|
+
} finally {
|
|
1674
|
+
setBusy(false);
|
|
1675
|
+
}
|
|
1676
|
+
},
|
|
1677
|
+
[doFetch],
|
|
1678
|
+
);
|
|
1679
|
+
|
|
1680
|
+
const setVisibility = useCallback(async (visibility) => {
|
|
1681
|
+
const { folderId: fid } = idRef.current;
|
|
1682
|
+
setBusy(true);
|
|
1683
|
+
try {
|
|
1684
|
+
return await foldersRef.current.update(fid, { visibility });
|
|
1685
|
+
} finally {
|
|
1686
|
+
setBusy(false);
|
|
1687
|
+
}
|
|
1688
|
+
}, []);
|
|
1689
|
+
|
|
1690
|
+
return { grants, loading, busy, error, refetch, grant, revoke, setVisibility };
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1506
1693
|
/* ============================================================================
|
|
1507
1694
|
* DIRECTORY CLIENT — ctx.directory (@colixsystems/directory-client)
|
|
1508
1695
|
*
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|