@colixsystems/widget-sdk 0.136.0 → 0.137.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 +26 -1
- package/dist/contract.cjs +2 -2
- package/dist/contract.js +2 -2
- package/dist/index.d.ts +9 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,7 +70,32 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
|
|
|
70
70
|
|
|
71
71
|
## Status
|
|
72
72
|
|
|
73
|
-
`v0.
|
|
73
|
+
`v0.137.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**.
|
|
74
|
+
|
|
75
|
+
### What's new in 0.137.0 (contract 1.106.0)
|
|
76
|
+
|
|
77
|
+
**A `datastoreTemplate` column marked `encrypted` is now actually encrypted in the workspace that installs you (sc-7557).** The field was documented nowhere and honoured nowhere: install built its column rows one way, the republish/upgrade migration built them another way, and neither carried the flag — so a column you declared confidential was created as an ordinary plaintext column and nothing told you or your installer. Both paths now share one projection, so the flag lands on install and on upgrade alike.
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
datastoreTemplate: {
|
|
81
|
+
tables: [
|
|
82
|
+
{
|
|
83
|
+
suffix: "Patients",
|
|
84
|
+
columns: [
|
|
85
|
+
{ name: "Name", dataType: "STRING", required: true },
|
|
86
|
+
{ name: "Ssn", dataType: "STRING", required: true, encrypted: true },
|
|
87
|
+
],
|
|
88
|
+
rows: [{ Name: "Ada Lovelace", Ssn: "600101-1234" }],
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- **Your widget code does not change.** It reads and writes plaintext through `useDatastoreQuery` / `useDatastoreMutation` exactly as it does for any other column — the platform encrypts on write (AES-256-GCM under a per-workspace subkey) and decrypts for end users.
|
|
95
|
+
- **Studio users see `🔒`, not the value.** That is the point of the flag: the people authoring the app cannot read what their end users store. The column also cannot be searched, filtered or sorted on — ciphertext is opaque.
|
|
96
|
+
- **Sample `rows` are encrypted too.** They used to be written straight into the value table; a plaintext row under an encrypted column would have been read back as a corrupt envelope.
|
|
97
|
+
- **Not valid on `RELATION`.** Its value is a foreign key the backend has to resolve, so it can never be opaque — declaring it is now a publish error, as is a non-boolean `encrypted`.
|
|
98
|
+
- **An upgrade adds a new encrypted column, but never flips a live one.** Turning encryption on over existing plaintext (or off over existing ciphertext) would strand what is already stored, so a changed flag on a column that already exists is reported back to you rather than applied.
|
|
74
99
|
|
|
75
100
|
### What's new in 0.136.0 (contract 1.105.0)
|
|
76
101
|
|
package/dist/contract.cjs
CHANGED
|
@@ -2153,7 +2153,7 @@ const MANIFEST_SCHEMA = {
|
|
|
2153
2153
|
type: "object",
|
|
2154
2154
|
required: false,
|
|
2155
2155
|
description:
|
|
2156
|
-
"Optional. Tables the widget needs, seeded into the workspace at install time. Authors wire them into the widget's `tableRef` properties via the Properties Panel — the SDK does not auto-bind. Limits: 8 tables, 24 columns per table. RELATION columns address siblings by `targetSuffix` (must be declared earlier in the array). Tables persist across uninstalls. A `tableRef` property may also carry `sharedTable: true`, declaring that the table is the APP'S OWN — the author picks an existing table and the widget seeds nothing for it. That is the correct shape for a widget that reads data it does not own (a chart, a metric, a manager view over another widget's table). `sharedTable` exempts the property from needing a seeded table at publish (`manifest.requiredTableRefsHaveTemplate`) WITHOUT making it optional: the author must still bind one, and the host still refuses to place the widget unbound. Use it instead of dropping `required` — a widget that silently renders an empty tile is the defect it looks like a fix for. sc-7530: a table may also declare `roleGrants` — group-scoped access named SYMBOLICALLY, because a group id belongs to the workspace that installs the widget and could never travel in the manifest. Declare the audiences once at template level as `roles: [{ key, label, description? }]` (key is lowercase kebab, max 8 roles), then per table `roleGrants: [{ role, canRead?, canWrite?, canDelete? }]`. The installing workspace binds each role to one of its own user groups (or has one created) during the install consent step, so a permission model where an admin group does everything and signed-in users only read survives the trip between workspaces. Use `publicGrant` for the two id-less audiences (everyone / any signed-in user) and `roleGrants` for anything that names a group. A role nobody binds simply writes no grant — it never fails the install.",
|
|
2156
|
+
"Optional. Tables the widget needs, seeded into the workspace at install time. Authors wire them into the widget's `tableRef` properties via the Properties Panel — the SDK does not auto-bind. Limits: 8 tables, 24 columns per table. RELATION columns address siblings by `targetSuffix` (must be declared earlier in the array). Tables persist across uninstalls. A `tableRef` property may also carry `sharedTable: true`, declaring that the table is the APP'S OWN — the author picks an existing table and the widget seeds nothing for it. That is the correct shape for a widget that reads data it does not own (a chart, a metric, a manager view over another widget's table). `sharedTable` exempts the property from needing a seeded table at publish (`manifest.requiredTableRefsHaveTemplate`) WITHOUT making it optional: the author must still bind one, and the host still refuses to place the widget unbound. Use it instead of dropping `required` — a widget that silently renders an empty tile is the defect it looks like a fix for. sc-7530: a table may also declare `roleGrants` — group-scoped access named SYMBOLICALLY, because a group id belongs to the workspace that installs the widget and could never travel in the manifest. Declare the audiences once at template level as `roles: [{ key, label, description? }]` (key is lowercase kebab, max 8 roles), then per table `roleGrants: [{ role, canRead?, canWrite?, canDelete? }]`. The installing workspace binds each role to one of its own user groups (or has one created) during the install consent step, so a permission model where an admin group does everything and signed-in users only read survives the trip between workspaces. Use `publicGrant` for the two id-less audiences (everyone / any signed-in user) and `roleGrants` for anything that names a group. A role nobody binds simply writes no grant — it never fails the install. sc-7557: a column may declare `encrypted: true` — its values are stored AES-256-GCM encrypted at rest under a per-workspace subkey. The widget still reads and writes PLAINTEXT (the platform encrypts on write, decrypts for end users); studio users see `🔒` instead, and the column cannot be searched, filtered or sorted on. Sample `rows` you seed for it are encrypted the same way. Not valid on `RELATION` — its value is a foreign key the backend must resolve — and publishing one is rejected.",
|
|
2157
2157
|
},
|
|
2158
2158
|
translations: {
|
|
2159
2159
|
type: "object",
|
|
@@ -3926,7 +3926,7 @@ const CONTRACT = deepFreeze({
|
|
|
3926
3926
|
// template declaring neither behaves exactly as before, and a role nobody
|
|
3927
3927
|
// binds writes no grant rather than failing the install. Minor bump on the
|
|
3928
3928
|
// pre-1.0 channel.
|
|
3929
|
-
version: "1.
|
|
3929
|
+
version: "1.106.0",
|
|
3930
3930
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
3931
3931
|
hooks: HOOKS,
|
|
3932
3932
|
primitives: PRIMITIVES,
|
package/dist/contract.js
CHANGED
|
@@ -2153,7 +2153,7 @@ const MANIFEST_SCHEMA = {
|
|
|
2153
2153
|
type: "object",
|
|
2154
2154
|
required: false,
|
|
2155
2155
|
description:
|
|
2156
|
-
"Optional. Tables the widget needs, seeded into the workspace at install time. Authors wire them into the widget's `tableRef` properties via the Properties Panel — the SDK does not auto-bind. Limits: 8 tables, 24 columns per table. RELATION columns address siblings by `targetSuffix` (must be declared earlier in the array). Tables persist across uninstalls. A `tableRef` property may also carry `sharedTable: true`, declaring that the table is the APP'S OWN — the author picks an existing table and the widget seeds nothing for it. That is the correct shape for a widget that reads data it does not own (a chart, a metric, a manager view over another widget's table). `sharedTable` exempts the property from needing a seeded table at publish (`manifest.requiredTableRefsHaveTemplate`) WITHOUT making it optional: the author must still bind one, and the host still refuses to place the widget unbound. Use it instead of dropping `required` — a widget that silently renders an empty tile is the defect it looks like a fix for. sc-7530: a table may also declare `roleGrants` — group-scoped access named SYMBOLICALLY, because a group id belongs to the workspace that installs the widget and could never travel in the manifest. Declare the audiences once at template level as `roles: [{ key, label, description? }]` (key is lowercase kebab, max 8 roles), then per table `roleGrants: [{ role, canRead?, canWrite?, canDelete? }]`. The installing workspace binds each role to one of its own user groups (or has one created) during the install consent step, so a permission model where an admin group does everything and signed-in users only read survives the trip between workspaces. Use `publicGrant` for the two id-less audiences (everyone / any signed-in user) and `roleGrants` for anything that names a group. A role nobody binds simply writes no grant — it never fails the install.",
|
|
2156
|
+
"Optional. Tables the widget needs, seeded into the workspace at install time. Authors wire them into the widget's `tableRef` properties via the Properties Panel — the SDK does not auto-bind. Limits: 8 tables, 24 columns per table. RELATION columns address siblings by `targetSuffix` (must be declared earlier in the array). Tables persist across uninstalls. A `tableRef` property may also carry `sharedTable: true`, declaring that the table is the APP'S OWN — the author picks an existing table and the widget seeds nothing for it. That is the correct shape for a widget that reads data it does not own (a chart, a metric, a manager view over another widget's table). `sharedTable` exempts the property from needing a seeded table at publish (`manifest.requiredTableRefsHaveTemplate`) WITHOUT making it optional: the author must still bind one, and the host still refuses to place the widget unbound. Use it instead of dropping `required` — a widget that silently renders an empty tile is the defect it looks like a fix for. sc-7530: a table may also declare `roleGrants` — group-scoped access named SYMBOLICALLY, because a group id belongs to the workspace that installs the widget and could never travel in the manifest. Declare the audiences once at template level as `roles: [{ key, label, description? }]` (key is lowercase kebab, max 8 roles), then per table `roleGrants: [{ role, canRead?, canWrite?, canDelete? }]`. The installing workspace binds each role to one of its own user groups (or has one created) during the install consent step, so a permission model where an admin group does everything and signed-in users only read survives the trip between workspaces. Use `publicGrant` for the two id-less audiences (everyone / any signed-in user) and `roleGrants` for anything that names a group. A role nobody binds simply writes no grant — it never fails the install. sc-7557: a column may declare `encrypted: true` — its values are stored AES-256-GCM encrypted at rest under a per-workspace subkey. The widget still reads and writes PLAINTEXT (the platform encrypts on write, decrypts for end users); studio users see `🔒` instead, and the column cannot be searched, filtered or sorted on. Sample `rows` you seed for it are encrypted the same way. Not valid on `RELATION` — its value is a foreign key the backend must resolve — and publishing one is rejected.",
|
|
2157
2157
|
},
|
|
2158
2158
|
translations: {
|
|
2159
2159
|
type: "object",
|
|
@@ -3926,7 +3926,7 @@ const CONTRACT = deepFreeze({
|
|
|
3926
3926
|
// template declaring neither behaves exactly as before, and a role nobody
|
|
3927
3927
|
// binds writes no grant rather than failing the install. Minor bump on the
|
|
3928
3928
|
// pre-1.0 channel.
|
|
3929
|
-
version: "1.
|
|
3929
|
+
version: "1.106.0",
|
|
3930
3930
|
sharedTranslationKeys: SHARED_TRANSLATION_KEYS,
|
|
3931
3931
|
hooks: HOOKS,
|
|
3932
3932
|
primitives: PRIMITIVES,
|
package/dist/index.d.ts
CHANGED
|
@@ -186,6 +186,15 @@ export interface WidgetDatastoreTemplateColumn {
|
|
|
186
186
|
relationType?: "ONE_TO_ONE" | "ONE_TO_MANY" | "MANY_TO_MANY";
|
|
187
187
|
/** REQ-ACL-RELINHERIT: opt this RELATION column into row-level ACL inheritance. */
|
|
188
188
|
inheritAcl?: boolean;
|
|
189
|
+
/**
|
|
190
|
+
* REQ-DDL-ENCRYPT: store this column's values encrypted at rest (AES-256-GCM
|
|
191
|
+
* under a per-workspace subkey). The widget still reads and writes plaintext
|
|
192
|
+
* — the platform encrypts on write and decrypts for end users — but studio
|
|
193
|
+
* users see `🔒` instead of the value, and the column cannot be searched,
|
|
194
|
+
* filtered or sorted on. Not valid on `RELATION` (its value is a foreign key
|
|
195
|
+
* the backend must resolve); publishing one is rejected.
|
|
196
|
+
*/
|
|
197
|
+
encrypted?: boolean;
|
|
189
198
|
}
|
|
190
199
|
|
|
191
200
|
export interface WidgetDatastoreTemplateTable {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colixsystems/widget-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.137.0",
|
|
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",
|