Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/13440-objectstack-pin-e649c2d.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@object-ui/auth': patch
---

The `@objectstack/*` pin moves from `915e940499` to objectstack `e649c2d91e`, the 18.1.0 release commit (objectstack#25606), past objectstack#25483 and objectstack#25564, which ship together in that release (objectui#13440).

`@object-ui/auth` now takes `ORG_ROLE_EXTERNAL` from `@objectstack/spec`'s `MEMBERSHIP_ROLE_EXTERNAL` instead of spelling the literal. The exported name and its value (`'external'`) are unchanged, and `ORG_ROLE_LABELS` is typed by `OrgRole` alone again. The published module now imports that constant, so it needs an `@objectstack/spec` that exports it (18.1.0 or later); the publish step floors the `@objectstack/*` ranges at the release that contains the pin. With that spec the invite dialog lists `external` among the roles it offers, as objectui#13427 described for a spec that lists the role.
30 changes: 15 additions & 15 deletions .objectstack-pin/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@objectstack/client",
"version": "18.0.0",
"version": "18.1.0",
"license": "Apache-2.0",
"description": "Official Client SDK for ObjectStack Protocol",
"main": "dist/index.js",
Expand All @@ -13,23 +13,23 @@
}
},
"dependencies": {
"@objectstack/core": "18.0.0",
"@objectstack/spec": "18.0.0"
"@objectstack/core": "18.1.0",
"@objectstack/spec": "18.1.0"
},
"devDependencies": {
"@hono/node-server": "^2.1.1",
"@objectstack/driver-sqlite-wasm": "18.0.0",
"@objectstack/hono": "18.0.0",
"@objectstack/metadata-core": "18.0.0",
"@objectstack/metadata-protocol": "18.0.0",
"@objectstack/objectql": "18.0.0",
"@objectstack/platform-objects": "18.0.0",
"@objectstack/plugin-auth": "18.0.0",
"@objectstack/plugin-hono-server": "18.0.0",
"@objectstack/rest": "18.0.0",
"@objectstack/runtime": "18.0.0",
"@objectstack/service-analytics": "18.0.0",
"@objectstack/service-automation": "18.0.0",
"@objectstack/driver-sqlite-wasm": "18.1.0",
"@objectstack/hono": "18.1.0",
"@objectstack/metadata-core": "18.1.0",
"@objectstack/metadata-protocol": "18.1.0",
"@objectstack/objectql": "18.1.0",
"@objectstack/platform-objects": "18.1.0",
"@objectstack/plugin-auth": "18.1.0",
"@objectstack/plugin-hono-server": "18.1.0",
"@objectstack/rest": "18.1.0",
"@objectstack/runtime": "18.1.0",
"@objectstack/service-analytics": "18.1.0",
"@objectstack/service-automation": "18.1.0",
"tsx": "^4.23.15",
"typescript": "^6.0.3",
"vitest": "^4.1.11"
Expand Down
8 changes: 4 additions & 4 deletions .objectstack-pin/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@objectstack/core",
"version": "18.0.0",
"version": "18.1.0",
"license": "Apache-2.0",
"description": "Microkernel Core for ObjectStack",
"type": "module",
Expand All @@ -19,16 +19,16 @@
}
},
"devDependencies": {
"@objectstack/metadata-core": "18.0.0",
"@objectstack/metadata-core": "18.1.0",
"@objectstack/refd-timer-testkit": "0.1.0",
"@types/node": "^26.6.3",
"esbuild": "^0.28.2",
"typescript": "^6.0.3",
"vitest": "^4.1.11"
},
"dependencies": {
"@objectstack/spec": "18.0.0",
"@objectstack/types": "18.0.0",
"@objectstack/spec": "18.1.0",
"@objectstack/types": "18.1.0",
"zod": "^4.6.5"
},
"keywords": [
Expand Down
4 changes: 2 additions & 2 deletions .objectstack-pin/formula/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@objectstack/formula",
"version": "18.0.0",
"version": "18.1.0",
"license": "Apache-2.0",
"description": "ObjectStack canonical expression engine — CEL (cel-js) + ObjectStack stdlib + dialect registry",
"main": "dist/index.js",
Expand All @@ -14,7 +14,7 @@
},
"dependencies": {
"@marcbachmann/cel-js": "^8.0.0",
"@objectstack/spec": "18.0.0"
"@objectstack/spec": "18.1.0"
},
"devDependencies": {
"@types/node": "^26.6.3",
Expand Down
8 changes: 4 additions & 4 deletions .objectstack-pin/lint/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@objectstack/lint",
"version": "18.0.0",
"version": "18.1.0",
"license": "Apache-2.0",
"description": "Static, build-time validation for an ObjectStack metadata graph — dashboard widget bindings, CEL/predicate expressions, and more. Pure (stack) => Issue[] functions shared by the CLI's `os validate` and any other consumer (e.g. AI authoring). Depends on @objectstack/spec; never on a runtime.",
"type": "module",
Expand Down Expand Up @@ -39,9 +39,9 @@
}
},
"dependencies": {
"@objectstack/formula": "18.0.0",
"@objectstack/sdui-parser": "18.0.0",
"@objectstack/spec": "18.0.0",
"@objectstack/formula": "18.1.0",
"@objectstack/sdui-parser": "18.1.0",
"@objectstack/spec": "18.1.0",
"ajv": "^8.20.0",
"ajv-formats": "^3.0.1",
"sucrase": "^3.35.1",
Expand Down
2 changes: 1 addition & 1 deletion .objectstack-pin/sdui-parser/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@objectstack/sdui-parser",
"version": "18.0.0",
"version": "18.1.0",
"license": "Apache-2.0",
"description": "ObjectStack constrained JSX-source → SDUI SchemaNode tree compiler (parse, never execute). Isomorphic, zero React. ADR-0080.",
"main": "dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion .objectstack-pin/spec/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@objectstack/spec",
"version": "18.0.0",
"version": "18.1.0",
"description": "ObjectStack Protocol & Specification - TypeScript Interfaces, JSON Schemas, and Convention Configurations",
"license": "Apache-2.0",
"main": "dist/index.js",
Expand Down
4 changes: 2 additions & 2 deletions .objectstack-pin/types/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@objectstack/types",
"version": "18.0.0",
"version": "18.1.0",
"license": "Apache-2.0",
"description": "Shared interfaces describing the ObjectStack Runtime environment",
"main": "dist/index.js",
Expand All @@ -18,7 +18,7 @@
}
},
"dependencies": {
"@objectstack/spec": "18.0.0"
"@objectstack/spec": "18.1.0"
},
"devDependencies": {
"typescript": "^6.0.3",
Expand Down
2 changes: 1 addition & 1 deletion .objectstack-sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
915e9404992234a7cd0d2dd4701dfbadbe9cb2c7
e649c2d91e270e3da26820bcfe54a28445305a75
Original file line number Diff line number Diff line change
Expand Up @@ -3180,11 +3180,11 @@ const MEMBER_PINS: Record<string, MemberPin> = {
},
'object-grid.data': {
file: 'packages/plugin-grid/src/__tests__/gridDataInputContract.test.ts',
pins: 'The `object` arm is `ViewDataSchema` discriminated on `provider`: each of the three providers parses and the retired `api` one is refused (spec 18.0.0, objectui#12370, objectui#12971, objectui#13261), none of them is an array, the declaration is one shape across both registered tags so the alias cannot drift, and it is pinned at compile time too (objectui#5090).',
pins: 'The `object` arm is `ViewDataSchema` discriminated on `provider`: each of the three providers parses and the retired `api` one is refused (spec 18.1.0, objectui#12370, objectui#12971, objectui#13261, objectui#13440), none of them is an array, the declaration is one shape across both registered tags so the alias cannot drift, and it is pinned at compile time too (objectui#5090).',
},
'object-grid.conditionalFormatting': {
file: 'packages/plugin-grid/src/__tests__/gridRowDecorationMembers-8071.test.tsx',
pins: 'The members read inside ONE formatting rule, asserted on the `style` attribute of the `<tr>` the grid paints. THREE alternative predicate members with a PRECEDENCE between them — one rule carrying `condition`, `expression` and the native `field`/`operator`/`value` triple, each naming a DIFFERENT row, is decided by `condition`; drop it and `expression` decides; drop that and the triple does — so a renderer reading any two of them as equivalent is red in a specific direction rather than merely unpinned. FOUR style members, and the sharp one is a RENAME: `backgroundColor` and `borderColor` keep their authored names on the way to the DOM while `textColor` is read as the CSS `color`, so keeping the authored spelling hands React a key it silently drops — same rules, same background, the text colour gone with nothing thrown. `style` is pinned as the BASE the three colour members override rather than replace (a non-colour member of it survives alongside the override). Two rule-list facts complete it: FIRST-MATCH-WINS with no merge (the second matching rule\'s own `textColor` never lands) and a rule carrying NO predicate member is SKIPPED rather than read as always-true, with the rule after it still deciding. ⚠️ Since objectui#11533 the AUTHORED member is ONE dialect, `{ condition, style }`: `expression`, the native triple and the three top-level colour members are refused by name on `ObjectGridSchema` and the list view (`packages/types/src/__tests__/grid-list-view-conditional-formatting-11533.test.ts`), so the rows that write them pin STORED-rule reads, which the resolver keeps as compatibility arms; a last block pins the two facts side by side — the stored native rule refused at authoring and painted at render, with its respelling painting the same row. The registration is an `array` arm; the installed spec row (18.0.0, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971, objectui#13261) takes the list view\'s own `{ condition, style }` rule and refuses the native members and any other key, so the spec fixes the AUTHORED shape and the read site is the rest of the member contract, the stored-rule compatibility arms included (objectui#8071 slice 12).',
pins: 'The members read inside ONE formatting rule, asserted on the `style` attribute of the `<tr>` the grid paints. THREE alternative predicate members with a PRECEDENCE between them — one rule carrying `condition`, `expression` and the native `field`/`operator`/`value` triple, each naming a DIFFERENT row, is decided by `condition`; drop it and `expression` decides; drop that and the triple does — so a renderer reading any two of them as equivalent is red in a specific direction rather than merely unpinned. FOUR style members, and the sharp one is a RENAME: `backgroundColor` and `borderColor` keep their authored names on the way to the DOM while `textColor` is read as the CSS `color`, so keeping the authored spelling hands React a key it silently drops — same rules, same background, the text colour gone with nothing thrown. `style` is pinned as the BASE the three colour members override rather than replace (a non-colour member of it survives alongside the override). Two rule-list facts complete it: FIRST-MATCH-WINS with no merge (the second matching rule\'s own `textColor` never lands) and a rule carrying NO predicate member is SKIPPED rather than read as always-true, with the rule after it still deciding. ⚠️ Since objectui#11533 the AUTHORED member is ONE dialect, `{ condition, style }`: `expression`, the native triple and the three top-level colour members are refused by name on `ObjectGridSchema` and the list view (`packages/types/src/__tests__/grid-list-view-conditional-formatting-11533.test.ts`), so the rows that write them pin STORED-rule reads, which the resolver keeps as compatibility arms; a last block pins the two facts side by side — the stored native rule refused at authoring and painted at render, with its respelling painting the same row. The registration is an `array` arm; the installed spec row (18.1.0, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971, objectui#13261, objectui#13440) takes the list view\'s own `{ condition, style }` rule and refuses the native members and any other key, so the spec fixes the AUTHORED shape and the read site is the rest of the member contract, the stored-rule compatibility arms included (objectui#8071 slice 12).',
},
'object-grid.operations': {
file: 'packages/plugin-grid/src/__tests__/gridOperationsMembers-8071.test.tsx',
Expand Down Expand Up @@ -3260,7 +3260,7 @@ const MEMBER_PINS: Record<string, MemberPin> = {
},
'object-kanban.conditionalFormatting': {
file: 'packages/plugin-kanban/src/__tests__/ObjectKanban.structuredMembersReachTheirSinks-8313.test.tsx',
pins: 'Members are card STYLE RULES in ONE dialect since objectui#11522, the spec list view\'s `{ condition, style }`, and it reaches the sink: a rule colours the matching card and only it, a second rule aimed at the other card does the same, and the whole `style` map arrives, with the sibling card in the same render as the live non-matching control so a green cannot come from two unstyled cards agreeing. The retired native `{ field, operator, value }` and flat-colour dialects are refused by name on the types side (`packages/types/src/__tests__/kanban-conditional-formatting.test.ts`); these rows are their respellings, painting the same cards. ⛔ NOT an identity pin and not a wire pin: `ObjectKanban.tsx` never names this key at all (measured zero, against nine for `cardFields` in the same file) — it rides the `{ ...schema }` spread into `KanbanRenderer`, which forwards it to `KanbanImpl`\'s `getCardStyles`. That makes the pin load-bearing in a way the others are not: an edit replacing that spread with an explicit key list drops the key silently and nothing else in the repo would notice. The installed spec row (18.0.0, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971, objectui#13261) takes the list view\'s own `{ condition, style }` rule, so the spec fixes the authored shape and the read site is the rest of the member contract (objectui#8313).',
pins: 'Members are card STYLE RULES in ONE dialect since objectui#11522, the spec list view\'s `{ condition, style }`, and it reaches the sink: a rule colours the matching card and only it, a second rule aimed at the other card does the same, and the whole `style` map arrives, with the sibling card in the same render as the live non-matching control so a green cannot come from two unstyled cards agreeing. The retired native `{ field, operator, value }` and flat-colour dialects are refused by name on the types side (`packages/types/src/__tests__/kanban-conditional-formatting.test.ts`); these rows are their respellings, painting the same cards. ⛔ NOT an identity pin and not a wire pin: `ObjectKanban.tsx` never names this key at all (measured zero, against nine for `cardFields` in the same file) — it rides the `{ ...schema }` spread into `KanbanRenderer`, which forwards it to `KanbanImpl`\'s `getCardStyles`. That makes the pin load-bearing in a way the others are not: an edit replacing that spread with an explicit key list drops the key silently and nothing else in the repo would notice. The installed spec row (18.1.0, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971, objectui#13261, objectui#13440) takes the list view\'s own `{ condition, style }` rule, so the spec fixes the authored shape and the read site is the rest of the member contract (objectui#8313).',
},
'object-kanban.data': {
file: 'packages/plugin-kanban/src/__tests__/ObjectKanban.structuredMembersReachTheirSinks-8313.test.tsx',
Expand Down
2 changes: 1 addition & 1 deletion e2e/live/ci/backend.env
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#
# This file declares exactly ONE @objectstack pin, and that is the whole
# design: the commit is derived from it, see below.
OBJECTSTACK_VERSION=18.0.0
OBJECTSTACK_VERSION=18.1.0

# There is deliberately no OBJECTSTACK_REF key here. The objectstack-ai/objectstack
# commit the showcase app metadata is sparse-checked-out from is DERIVED at
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ beforeEach(() => {
describe('InviteMemberDialog — role cap (framework#3697)', () => {
it('an owner is offered every role, delegated_admin included', async () => {
await renderAs('owner');
expect(offered()).toEqual(['owner', 'admin', 'delegated_admin', 'member']);
expect(offered()).toEqual(['owner', 'admin', 'delegated_admin', 'member', 'external']);
});

it('an admin may provision a delegate but may not invite an owner', async () => {
Expand All @@ -112,18 +112,18 @@ describe('InviteMemberDialog — role cap (framework#3697)', () => {
expect(roles).not.toContain('owner');
});

it('a DELEGATE is offered member only — the escalation chain has no UI entry', async () => {
it('a DELEGATE is offered member and external only — the escalation chain has no UI entry', async () => {
// Picking "Admin" here would 403 on the server's role cap; the console must
// not propose it. This is the whole reason the select stopped being a
// hardcoded three-item list.
await renderAs('delegated_admin');
expect(offered()).toEqual(['member']);
expect(offered()).toEqual(['member', 'external']);
expect(screen.queryByTestId('invite-role-admin')).not.toBeInTheDocument();
});

it('an unloaded membership still allows the ordinary member invite', async () => {
await renderAs(null);
expect(offered()).toEqual(['member']);
expect(offered()).toEqual(['member', 'external']);
});

it('the narrowed default still submits a plain, unchanged invitation', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ describe('#4474 family 1 — role names come from ONE map and resolve in zh', ()
.filter((o) => o.getAttribute('value'))
.map((o) => o.textContent);
// Pre-fix this array was ['Owner', 'Admin', 'Delegated Admin', 'Member'].
expect(labels).toEqual(['所有者', '管理员', '受托管理员', '成员']);
expect(labels).toEqual(['所有者', '管理员', '受托管理员', '成员', '外部成员']);
});

it('zh: the members page role badges render Chinese — site 2', async () => {
Expand Down Expand Up @@ -301,7 +301,7 @@ describe('#4474 family 1 — role names come from ONE map and resolve in zh', ()
const labels = Array.from(screen.getByTestId('select').querySelectorAll('option'))
.filter((o) => o.getAttribute('value'))
.map((o) => o.textContent);
expect(labels).toEqual(['Owner', 'Admin', 'Delegated Admin', 'Member']);
expect(labels).toEqual(['Owner', 'Admin', 'Delegated Admin', 'Member', 'External']);
});

it('an external member\'s badge reads 外部成员 in zh and External in en (objectui#13427)', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,12 @@ describe('objectui#6238 · the schema oracle — both tombstone keys are refused
// `defaultRowScope` (objectstack#24398; measured against the next.3 pin: the
// one top-level key `ObjectSchema` gains between the two commits, none lost;
// objectui#12971). Re-pointed the same way.
// 47 at `@objectstack/spec` 18.1.0, which adopted `membershipKeys`
// (objectstack#25513; measured against the 915e9404 pin: the spec's own
// `authorable-surface/data.json` gains exactly `data/Object:membershipKeys`
// between the two commits, none lost; objectui#13440). Re-pointed the same way.
const accept = new Set(Object.keys(ObjectSchema.shape as Record<string, unknown>));
expect(accept.size).toBe(46);
expect(accept.size).toBe(47);
expect(accept.has('enable')).toBe(true);
expect(accept.has('enabled')).toBe(false);
expect(accept.has('_deleted')).toBe(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,12 @@ describe('the instrument', () => {
// `defaultRowScope` (objectstack#24398; measured against the next.3 pin: the
// one top-level key `ObjectSchema` gains between the two commits, none lost;
// objectui#12971). Re-pointed the same way.
// 47 at `@objectstack/spec` 18.1.0, which adopted `membershipKeys`
// (objectstack#25513; measured against the 915e9404 pin: the spec's own
// `authorable-surface/data.json` gains exactly `data/Object:membershipKeys`
// between the two commits, none lost; objectui#13440). Re-pointed the same way.
const accept = new Set(Object.keys(ObjectSchema.shape as Record<string, unknown>));
expect(accept.size).toBe(46);
expect(accept.size).toBe(47);
// `fieldGroups` is the only grouping key on the object, and it groups the
// FIELDS INSIDE one object — it is not a category for objects themselves,
// so `group` has no mapping target here.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ function loadRowCanon(): Promise<RowCanonModule | null> {
* not re-derived — and the engine's own message ships with it.
*
* ⚠️ The reason is NOT that the engine's message refuses a `record.<root>`
* rewrite. Measured against the installed 18.0.0 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971, objectui#13261), it mostly PRESCRIBES one: the
* rewrite. Measured against the installed 18.1.0 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971, objectui#13261, objectui#13440), it mostly PRESCRIBES one: the
* `current_user` text CONTAINS "To gate on record state, rewrite the predicate
* against `record`." — one of the three remedies it offers, and NOT where it
* ends (measured: `includes` true, `endsWith` false; every covered slot's text
Expand Down
Loading
Loading