@colixsystems/widget-sdk 0.277.2 → 0.277.3
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 +7 -2
- package/dist/linter.cjs +27 -0
- package/dist/linter.js +27 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,7 +63,8 @@ The data layer lives in **four separate domain-client packages**, each instantia
|
|
|
63
63
|
| **DATASTORE** | `useTyping(tableId, recordId)` | `{ typingUserIds, setTyping, status }` — status `"connecting" \| "live" \| "unavailable"` | `records(table).typing` — `datastore.read:<table>`. Who else is typing in one record, over the same socket as `useDatastoreSubscription`. Call `setTyping(true)` on every keystroke (throttled to one signal per 3 s; `false` is sent after 5 s idle) and `setTyping(false)` on send, clear or blur. `typingUserIds` lists the OTHER users' ids; each drops out 6 s after their last signal. Needs a signed-in user who can read the record. Never throws: an anonymous visitor, a refused subscription or a host whose client lacks `typing` reads `{ typingUserIds: [], status: "unavailable" }`. Re-subscribes when either id changes. |
|
|
64
64
|
| **DATASTORE** | `useRecordPermissions(tableId, recordId)` | `{ permissions, loading, error, grant, revoke, update, refetch }` | `records(table).permissions(record).{ list, grant, update, revoke }` — `acl.write:records` (+ `can_grant` on the record) |
|
|
65
65
|
| **DATASTORE** | `useCanWrite(tableId, options)` (optional: options) | `{ canWrite, loading, error, refetch }` | `myPermissions(tableId, { recordId? })` — scope `datastore.read:<table>`. A FLOOR, not a full replacement for domain-specific write rules: answers "may this caller write", reading the same table-ACL answer the write endpoint enforces — so a table granting Create to Everyone answers `true` for a logged-out visitor, and this hook alone is the right gate for a widget meant to work without signing in. Pass `{ recordId }` for a per-row check. A widget whose own rule is MORE SPECIFIC than the table ACL (e.g. "only the assigned user may edit this row") must still hand-check that in addition. Pair with `useUser()` to also tell "not signed in" apart from "signed in but forbidden" — both resolve `canWrite: false` here. Falsy `tableId`, or a host that hasn't injected `myPermissions` (an older host), collapses to `{ canWrite: false, loading: false, error: null, refetch: async () => undefined }` rather than throwing. |
|
|
66
|
-
| **FILES** (`ctx.
|
|
66
|
+
| **FILES** (`ctx.filestore`) | `useFilestoreFile(fileId)` | `{ file, url, urls, loading, error, refetch }` | `ctx.filestore.files.get` — `files.read:*`. **A FILE column's value is a filestore file id.** Draw it with `<FileImage fileId={row.photo} variant="card" />`, or read `useFilestoreFile(row.photo).url` (`urls.thumbnail` / `.card` / `.large` for a smaller render); `url` and `urls` are `null` until the fetch resolves and for an empty cell. Never pass a column value to `useAsset`: it resolves no file id, so the picture renders blank. |
|
|
67
|
+
| **FILES** (`ctx.assets`) | `useAsset(id)` | `{ url, asset, loading, error, refetch }` | `ctx.assets.get` — no scope. Takes an asset-library id: an `asset` property's value, or the `asset_id` an image import (`import_image`, `import_stock_image`) answers. Never a FILE column's value, which is a filestore file id (see `useFilestoreFile`). |
|
|
67
68
|
| **FILES** | `useAssetsByTag(tag, { type })` (optional: the whole argument, and `type` within it) | `{ assets, loading, error, refetch }` | `ctx.assets.list` (unwraps `{ data, meta }` to `assets`) — no scope. `type` defaults to `"image"`; pass `"all"` / `"audio"` / `"video"` / `"document"` to widen. Falsy `tag` collapses to `assets: []` without a round-trip. |
|
|
68
69
|
| **FILES** (`ctx.widget`) | `useBundledAsset(fileName)` | `string \| null` | `ctx.widget.assets` — no scope. The URL of an image or sound the widget package ships in its `assets/` directory, or `null` when it has no file with that name. See [Bundled images and sounds](#bundled-images-and-sounds). |
|
|
69
70
|
| **DIRECTORY** (`ctx.directory`) | `useDirectory(query)` (optional: query) | `{ users, loading, error, refetch }` | `directory.users.list` — `directory.read:users` |
|
|
@@ -86,7 +87,11 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
86
87
|
|
|
87
88
|
## Status
|
|
88
89
|
|
|
89
|
-
`v0.277.
|
|
90
|
+
`v0.277.3` — 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**.
|
|
91
|
+
|
|
92
|
+
### What's new in 0.277.3
|
|
93
|
+
|
|
94
|
+
**A FILE column's value goes to `<FileImage fileId>` or `useFilestoreFile`, never `useAsset`.** The hook table's FILES group now leads with the filestore file id a FILE column holds and says that `useAsset(id)` takes an asset-library id. A new linter warning, `useAsset-on-file-column`, flags `useAsset(row.photo)` (a value read from a datastore row) in a widget that reads records: the hook resolves no URL for a file id, so the picture renders blank.
|
|
90
95
|
|
|
91
96
|
### What's new in 0.277.2
|
|
92
97
|
|
package/dist/linter.cjs
CHANGED
|
@@ -1584,6 +1584,32 @@ function _rawUseMemoIntoDatastoreQueryRules(source) {
|
|
|
1584
1584
|
return findings;
|
|
1585
1585
|
}
|
|
1586
1586
|
|
|
1587
|
+
// A FILE column holds a filestore file id; useAsset resolves asset-library
|
|
1588
|
+
// ids only, so a row value passed to it renders a blank picture.
|
|
1589
|
+
function _useAssetOnFileColumnRules(source) {
|
|
1590
|
+
const code = _stripNonCode(source);
|
|
1591
|
+
if (!/\buseDatastore(?:Query|Record)\w*\s*\(/.test(code)) return [];
|
|
1592
|
+
const callRe = /\buseAsset\s*\(\s*(?:row|record|item)\s*\??\s*[.[]/g;
|
|
1593
|
+
const sourceLines = source.split(/\r?\n/);
|
|
1594
|
+
const lineAt = _lineCounter(code);
|
|
1595
|
+
const findings = [];
|
|
1596
|
+
let m;
|
|
1597
|
+
while ((m = callRe.exec(code))) {
|
|
1598
|
+
const line = lineAt(m.index);
|
|
1599
|
+
findings.push({
|
|
1600
|
+
rule: "useAsset-on-file-column",
|
|
1601
|
+
severity: "warning",
|
|
1602
|
+
label:
|
|
1603
|
+
"useAsset() resolves an asset-library id, never a FILE column's value: " +
|
|
1604
|
+
"that is a filestore file id, so draw it with <FileImage fileId={…}> " +
|
|
1605
|
+
"or read useFilestoreFile(id).url.",
|
|
1606
|
+
line,
|
|
1607
|
+
snippet: (sourceLines[line - 1] || "").trim().slice(0, 200),
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1610
|
+
return findings;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1587
1613
|
// sc-5206 — soft warning, the write-gate twin of `write-not-gated-on-user`.
|
|
1588
1614
|
// A widget that hand-derives write permission from `useUser().groupIds` /
|
|
1589
1615
|
// `.roles` re-implements the table ACL client-side and drifts from it the
|
|
@@ -2874,6 +2900,7 @@ function lintSource(source, options) {
|
|
|
2874
2900
|
// sc-5206 — soft warnings steering a widget toward the two new hooks.
|
|
2875
2901
|
findings.push(..._rawUseMemoIntoDatastoreQueryRules(source));
|
|
2876
2902
|
findings.push(..._handRolledWriteGateRules(source));
|
|
2903
|
+
findings.push(..._useAssetOnFileColumnRules(source));
|
|
2877
2904
|
findings.push(..._rowActionGatingRules(source));
|
|
2878
2905
|
// REQ-USERMGMT / REQ-ACL-SYS M3 — scope-aware rules. Run after the
|
|
2879
2906
|
// line-by-line scan so banned-identifier findings stay first in the
|
package/dist/linter.js
CHANGED
|
@@ -1579,6 +1579,32 @@ function _rawUseMemoIntoDatastoreQueryRules(source) {
|
|
|
1579
1579
|
return findings;
|
|
1580
1580
|
}
|
|
1581
1581
|
|
|
1582
|
+
// A FILE column holds a filestore file id; useAsset resolves asset-library
|
|
1583
|
+
// ids only, so a row value passed to it renders a blank picture.
|
|
1584
|
+
function _useAssetOnFileColumnRules(source) {
|
|
1585
|
+
const code = _stripNonCode(source);
|
|
1586
|
+
if (!/\buseDatastore(?:Query|Record)\w*\s*\(/.test(code)) return [];
|
|
1587
|
+
const callRe = /\buseAsset\s*\(\s*(?:row|record|item)\s*\??\s*[.[]/g;
|
|
1588
|
+
const sourceLines = source.split(/\r?\n/);
|
|
1589
|
+
const lineAt = _lineCounter(code);
|
|
1590
|
+
const findings = [];
|
|
1591
|
+
let m;
|
|
1592
|
+
while ((m = callRe.exec(code))) {
|
|
1593
|
+
const line = lineAt(m.index);
|
|
1594
|
+
findings.push({
|
|
1595
|
+
rule: "useAsset-on-file-column",
|
|
1596
|
+
severity: "warning",
|
|
1597
|
+
label:
|
|
1598
|
+
"useAsset() resolves an asset-library id, never a FILE column's value: " +
|
|
1599
|
+
"that is a filestore file id, so draw it with <FileImage fileId={…}> " +
|
|
1600
|
+
"or read useFilestoreFile(id).url.",
|
|
1601
|
+
line,
|
|
1602
|
+
snippet: (sourceLines[line - 1] || "").trim().slice(0, 200),
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
return findings;
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1582
1608
|
// sc-5206 — soft warning, the write-gate twin of `write-not-gated-on-user`.
|
|
1583
1609
|
// A widget that hand-derives write permission from `useUser().groupIds` /
|
|
1584
1610
|
// `.roles` re-implements the table ACL client-side and drifts from it the
|
|
@@ -2869,6 +2895,7 @@ export function lintSource(source, options) {
|
|
|
2869
2895
|
// sc-5206 — soft warnings steering a widget toward the two new hooks.
|
|
2870
2896
|
findings.push(..._rawUseMemoIntoDatastoreQueryRules(source));
|
|
2871
2897
|
findings.push(..._handRolledWriteGateRules(source));
|
|
2898
|
+
findings.push(..._useAssetOnFileColumnRules(source));
|
|
2872
2899
|
findings.push(..._rowActionGatingRules(source));
|
|
2873
2900
|
// REQ-USERMGMT / REQ-ACL-SYS M3 — scope-aware rules. Run after the
|
|
2874
2901
|
// line-by-line scan so banned-identifier findings stay first in the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.277.
|
|
3
|
+
"version": "0.277.3",
|
|
4
4
|
"description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
|
|
5
5
|
"homepage": "https://github.com/Colix-AB/AppStudio",
|
|
6
6
|
"type": "module",
|