@everystack/cli 0.4.3 → 0.4.4
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/package.json
CHANGED
package/src/cli/authz-compile.ts
CHANGED
|
@@ -267,9 +267,12 @@ export function compileTableContract(model: ModelDescriptor, opts: CompileOption
|
|
|
267
267
|
const anonUsing = sdGuard ?? 'true';
|
|
268
268
|
policy(`${t}_select_anon`, 'SELECT', ['anon'], anonUsing, null);
|
|
269
269
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
270
|
+
// The owner predicate may only ever WIDEN a public read (the soft-delete OR:
|
|
271
|
+
// owners also see their own deleted rows). It must never REPLACE it — an owner
|
|
272
|
+
// condition on a WRITE ability used to narrow the authenticated SELECT to
|
|
273
|
+
// own-rows-only, so anon saw the whole table and a signed-in user lost it.
|
|
274
|
+
// Without a soft-delete guard, `true OR owner` is just `true`.
|
|
275
|
+
const authedUsing = sdGuard && rowPred ? `(${sdGuard} OR ${rowPred})` : anonUsing;
|
|
273
276
|
policy(`${t}_select_authenticated`, 'SELECT', ['authenticated'], authedUsing, null);
|
|
274
277
|
} else if (hasOwnerRead && rowPred) {
|
|
275
278
|
// owner-scoped read — no anon visibility; you see only the rows you own
|
|
@@ -319,11 +319,13 @@ export function compileDerived(models: readonly ModelDescriptor[], derived: read
|
|
|
319
319
|
|
|
320
320
|
// Triggers declared on models and on views — the deps come free (execute fn; the
|
|
321
321
|
// declaration-site view when it is itself derived). The function MUST be declared.
|
|
322
|
+
// `?? []` mirrors the first trigger walk above: a descriptor built by an older
|
|
323
|
+
// @everystack/model arrives without the key, and this walk crashed "not iterable".
|
|
322
324
|
const triggerOwners: Array<{ schema: string; name: string; ownerIdentity: string | null; triggers: TriggerSpec[] }> = [
|
|
323
|
-
...models.map((m) => ({ schema: m.schema, name: m.table, ownerIdentity: null, triggers: m.triggers })),
|
|
325
|
+
...models.map((m) => ({ schema: m.schema, name: m.table, ownerIdentity: null, triggers: m.triggers ?? [] })),
|
|
324
326
|
...derived.filter((d): d is ViewDescriptor => d.kind === 'view').map((v) => {
|
|
325
327
|
const q = parseQualified(v.name);
|
|
326
|
-
return { schema: q.schema, name: q.name, ownerIdentity: `${q.schema}.${q.name}`, triggers: v.triggers };
|
|
328
|
+
return { schema: q.schema, name: q.name, ownerIdentity: `${q.schema}.${q.name}`, triggers: v.triggers ?? [] };
|
|
327
329
|
}),
|
|
328
330
|
];
|
|
329
331
|
for (const owner of triggerOwners) {
|