smoodly 0.0.46 → 0.0.48
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/dist/admin/browser/main.js +2 -0
- package/dist/admin/client-ops.js +1 -0
- package/dist/admin/delivery-mode.d.ts +5 -0
- package/dist/admin/delivery-mode.js +20 -0
- package/dist/admin/editor/EditorView.js +3 -0
- package/dist/admin/files.generated.js +1 -1
- package/dist/admin/handler.d.ts +5 -1
- package/dist/admin/handler.js +2 -1
- package/dist/admin/health.d.ts +4 -0
- package/dist/admin/ops-impl.d.ts +13 -0
- package/dist/admin/ops-impl.js +48 -2
- package/dist/admin/ops.d.ts +11 -0
- package/dist/admin/page-data.d.ts +2 -0
- package/dist/admin/shell/AdminApp.js +47 -1
- package/dist/admin/shell/ContentHealthPage.js +3 -1
- package/dist/admin/shell/EntryForm.js +3 -0
- package/dist/admin/shell/GlobalForm.js +5 -1
- package/dist/admin/shell/IconRail.d.ts +8 -1
- package/dist/admin/shell/IconRail.js +8 -3
- package/dist/admin/shell/deploy-tile.d.ts +20 -0
- package/dist/admin/shell/deploy-tile.js +35 -0
- package/dist/admin/ui/PublishControl.js +3 -1
- package/dist/admin/ui/theme.js +12 -0
- package/dist/astro/deploy-deps.d.ts +10 -0
- package/dist/astro/deploy-deps.js +8 -0
- package/dist/astro/index.d.ts +9 -4
- package/dist/astro/index.js +75 -15
- package/dist/astro/middleware.js +4 -0
- package/dist/astro/routes/admin.js +2 -1
- package/dist/astro/routes/preview.astro +17 -5
- package/dist/astro/routes/static-page.astro +21 -0
- package/dist/astro/runtime.d.ts +6 -0
- package/dist/astro/runtime.js +4 -1
- package/dist/astro/server.d.ts +6 -0
- package/dist/astro/server.js +7 -1
- package/dist/astro/static.d.ts +36 -0
- package/dist/astro/static.js +59 -0
- package/dist/cli/load-config.d.ts +3 -0
- package/dist/cli/load-config.js +8 -1
- package/dist/cli/migrate.d.ts +10 -0
- package/dist/cli/migrate.js +22 -1
- package/dist/cli/space-io.js +3 -3
- package/dist/deploy-state.d.ts +28 -0
- package/dist/deploy-state.js +31 -0
- package/dist/document-stamp.d.ts +7 -0
- package/dist/document-stamp.js +48 -0
- package/dist/project.d.ts +22 -3
- package/dist/project.js +33 -12
- package/dist/published.d.ts +50 -4
- package/dist/published.js +46 -7
- package/dist/schema-version.d.ts +1 -1
- package/dist/schema-version.js +1 -1
- package/dist/site.d.ts +2 -0
- package/dist/site.js +53 -11
- package/dist/sql-space.d.ts +4 -2
- package/dist/sql-space.js +4 -2
- package/dist/sql.js +20 -1
- package/dist/supabase-published-store.d.ts +24 -3
- package/dist/supabase-published-store.js +104 -5
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/migrations/20261008120000_smoodly_v10.sql +47 -0
- package/migrations/20261009120000_smoodly_v11.sql +49 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
2
|
import type { CollectionSchema } from "./collections.ts";
|
|
3
|
-
import type { PublishedEntryRow, PublishedKey, PublishedPageRow, PublishedQuery, PublishedRoute, PublishedStore, PublishedTreeRow } from "./published.ts";
|
|
3
|
+
import type { PublishedEntryRow, PublishedKey, PublishedPageRow, PublishedQuery, PublishedRoute, PublishedStore, PublishedTreeRow, PutOptions } from "./published.ts";
|
|
4
4
|
export declare class SupabasePublishedStore implements PublishedStore {
|
|
5
5
|
private db;
|
|
6
6
|
private schemas;
|
|
@@ -8,8 +8,8 @@ export declare class SupabasePublishedStore implements PublishedStore {
|
|
|
8
8
|
/** `collections` encode a `where` on an array field as containment, as SupabaseEntryStore.query does. */
|
|
9
9
|
constructor(db: SupabaseClient, collections?: CollectionSchema<any>[]);
|
|
10
10
|
private fail;
|
|
11
|
-
putPages(rows: PublishedPageRow[]): Promise<void>;
|
|
12
|
-
putEntries(rows: PublishedEntryRow[]): Promise<void>;
|
|
11
|
+
putPages(rows: PublishedPageRow[], options?: PutOptions): Promise<void>;
|
|
12
|
+
putEntries(rows: PublishedEntryRow[], options?: PutOptions): Promise<void>;
|
|
13
13
|
/** The space this client writes in (the service role's is the default): a path delete must not reach past it,
|
|
14
14
|
* since the service role passes every policy. Cached for the life of the client; a failed lookup is not. */
|
|
15
15
|
private space;
|
|
@@ -20,6 +20,27 @@ export declare class SupabasePublishedStore implements PublishedStore {
|
|
|
20
20
|
/** One request per kind and locale filter: the keys without a locale go in one in(). */
|
|
21
21
|
private eachGroup;
|
|
22
22
|
remove(keys: PublishedKey[]): Promise<void>;
|
|
23
|
+
lastRemovalAt(): Promise<number | null>;
|
|
24
|
+
/** The space's recorded stamp (DESIGN §3): one row per space in published_models; the key's space, or the
|
|
25
|
+
* service role's default one. */
|
|
26
|
+
recordedModel(): Promise<string | null>;
|
|
27
|
+
recordModel(model: string): Promise<void>;
|
|
28
|
+
/** Four head counts (no rows travel): each table's rows, and its rows at another stamp. The policies scope a
|
|
29
|
+
* write key to its space; the service role counts the default space's rows by the explicit filter. */
|
|
30
|
+
countBehind(model: string): Promise<{
|
|
31
|
+
behind: number;
|
|
32
|
+
total: number;
|
|
33
|
+
}>;
|
|
34
|
+
/** The static build's watermark (spec 2026-10-09 static mode §5): the newest published_at over both tables. */
|
|
35
|
+
newestPublishedAt(): Promise<number | null>;
|
|
36
|
+
/** Rows published strictly after `since`: the Deploy tile's "changes waiting". Two head counts. */
|
|
37
|
+
countPublishedAfter(since: number): Promise<number>;
|
|
38
|
+
/** The space's last Deploy press, one row in space_deploys (schema v11). */
|
|
39
|
+
deployRequest(): Promise<{
|
|
40
|
+
at: number;
|
|
41
|
+
by: string | null;
|
|
42
|
+
} | null>;
|
|
43
|
+
requestDeploy(by: string | null, at?: number): Promise<void>;
|
|
23
44
|
markStale(keys: PublishedKey[]): Promise<void>;
|
|
24
45
|
/** A route row is for serving, not for the tree: a page route carries the
|
|
25
46
|
* document, model, stale flag and tags; its tree columns are empty, and an
|
|
@@ -13,6 +13,13 @@ const fromPage = (r) => ({
|
|
|
13
13
|
id: r.page_id, locale: r.locale, parentId: r.parent_id, sort: num(r.sort), path: r.path, title: r.title, hasPage: r.has_page,
|
|
14
14
|
linkFields: r.link_fields, document: r.document, tags: r.tags, model: r.model, stale: r.stale, publishedAt: Date.parse(r.published_at),
|
|
15
15
|
});
|
|
16
|
+
/** `keep` strips published_at from an upsert's payload (PutOptions): the row keeps its own, a new row is dated by the default. */
|
|
17
|
+
function keeping(row, options) {
|
|
18
|
+
if (!options?.keep)
|
|
19
|
+
return row;
|
|
20
|
+
const { published_at: _at, ...rest } = row;
|
|
21
|
+
return rest;
|
|
22
|
+
}
|
|
16
23
|
const toPage = (r) => ({
|
|
17
24
|
page_id: r.id, locale: r.locale, parent_id: r.parentId, sort: r.sort, path: r.path, title: r.title, has_page: r.hasPage,
|
|
18
25
|
link_fields: r.linkFields, document: r.document, tags: r.tags, model: r.model, stale: r.stale, published_at: iso(r.publishedAt),
|
|
@@ -36,20 +43,21 @@ export class SupabasePublishedStore {
|
|
|
36
43
|
fail(message) {
|
|
37
44
|
throw new Error(`smoodly: published store: ${message}`);
|
|
38
45
|
}
|
|
39
|
-
async putPages(rows) {
|
|
46
|
+
async putPages(rows, options) {
|
|
40
47
|
for (let i = 0; i < rows.length; i += CHUNK) {
|
|
41
48
|
const chunk = rows.slice(i, i + CHUNK);
|
|
42
49
|
await this.vacate("published_pages", "page_id", chunk);
|
|
43
|
-
|
|
50
|
+
// `keep`: published_at leaves the payload, so an updated row keeps its own and an inserted one takes the default (now).
|
|
51
|
+
const res = await this.db.from("published_pages").upsert(chunk.map((r) => keeping(toPage(r), options)), { onConflict: "page_id,locale" });
|
|
44
52
|
if (res.error)
|
|
45
53
|
this.fail(res.error.message);
|
|
46
54
|
}
|
|
47
55
|
}
|
|
48
|
-
async putEntries(rows) {
|
|
56
|
+
async putEntries(rows, options) {
|
|
49
57
|
for (let i = 0; i < rows.length; i += CHUNK) {
|
|
50
58
|
const chunk = rows.slice(i, i + CHUNK);
|
|
51
59
|
await this.vacate("published_entries", "entry_id", chunk);
|
|
52
|
-
const res = await this.db.from("published_entries").upsert(chunk.map(toEntry), { onConflict: "entry_id,locale" });
|
|
60
|
+
const res = await this.db.from("published_entries").upsert(chunk.map((r) => keeping(toEntry(r), options)), { onConflict: "entry_id,locale" });
|
|
53
61
|
if (res.error)
|
|
54
62
|
this.fail(res.error.message);
|
|
55
63
|
}
|
|
@@ -108,14 +116,105 @@ export class SupabasePublishedStore {
|
|
|
108
116
|
}
|
|
109
117
|
}
|
|
110
118
|
async remove(keys) {
|
|
119
|
+
if (keys.length === 0)
|
|
120
|
+
return;
|
|
121
|
+
let deleted = 0;
|
|
111
122
|
await this.eachGroup(keys, async (table, column, ids, locale) => {
|
|
112
|
-
let q = this.db.from(table).delete().in(column, ids);
|
|
123
|
+
let q = this.db.from(table).delete({ count: "exact" }).in(column, ids);
|
|
113
124
|
if (locale !== undefined)
|
|
114
125
|
q = q.eq("locale", locale);
|
|
115
126
|
const res = await q;
|
|
116
127
|
if (res.error)
|
|
117
128
|
this.fail(res.error.message);
|
|
129
|
+
deleted += res.count ?? 0;
|
|
118
130
|
});
|
|
131
|
+
// A row that went is a change the count of newer rows cannot see (spec 2026-10-09 static mode §5): the space's
|
|
132
|
+
// row keeps when one last happened. A key with no row (a publish vacating a locale that never had one) is no
|
|
133
|
+
// change. The press's columns are absent from the payload, so they stay as they are.
|
|
134
|
+
if (deleted === 0)
|
|
135
|
+
return;
|
|
136
|
+
const res = await this.db.from("space_deploys").upsert({ space_id: await this.space(), removed_at: new Date().toISOString() }, { onConflict: "space_id" });
|
|
137
|
+
if (res.error)
|
|
138
|
+
this.fail(res.error.message);
|
|
139
|
+
}
|
|
140
|
+
async lastRemovalAt() {
|
|
141
|
+
const res = await this.db.from("space_deploys").select("removed_at").eq("space_id", await this.space()).maybeSingle();
|
|
142
|
+
if (res.error)
|
|
143
|
+
this.fail(res.error.message);
|
|
144
|
+
const at = res.data?.removed_at;
|
|
145
|
+
return at ? Date.parse(at) : null;
|
|
146
|
+
}
|
|
147
|
+
/** The space's recorded stamp (DESIGN §3): one row per space in published_models; the key's space, or the
|
|
148
|
+
* service role's default one. */
|
|
149
|
+
async recordedModel() {
|
|
150
|
+
const res = await this.db.from("published_models").select("model").eq("space_id", await this.space()).maybeSingle();
|
|
151
|
+
if (res.error)
|
|
152
|
+
this.fail(res.error.message);
|
|
153
|
+
return res.data?.model ?? null;
|
|
154
|
+
}
|
|
155
|
+
async recordModel(model) {
|
|
156
|
+
const res = await this.db.from("published_models")
|
|
157
|
+
.upsert({ space_id: await this.space(), model, recorded_at: new Date().toISOString() }, { onConflict: "space_id" });
|
|
158
|
+
if (res.error)
|
|
159
|
+
this.fail(res.error.message);
|
|
160
|
+
}
|
|
161
|
+
/** Four head counts (no rows travel): each table's rows, and its rows at another stamp. The policies scope a
|
|
162
|
+
* write key to its space; the service role counts the default space's rows by the explicit filter. */
|
|
163
|
+
async countBehind(model) {
|
|
164
|
+
const space = await this.space();
|
|
165
|
+
const count = async (table, behind) => {
|
|
166
|
+
let q = this.db.from(table).select("*", { count: "exact", head: true }).eq("space_id", space);
|
|
167
|
+
if (behind)
|
|
168
|
+
q = q.neq("model", model);
|
|
169
|
+
const res = await q;
|
|
170
|
+
if (res.error)
|
|
171
|
+
this.fail(res.error.message);
|
|
172
|
+
return res.count ?? 0;
|
|
173
|
+
};
|
|
174
|
+
const [pages, entries, pagesBehind, entriesBehind] = await Promise.all([
|
|
175
|
+
count("published_pages", false), count("published_entries", false), count("published_pages", true), count("published_entries", true),
|
|
176
|
+
]);
|
|
177
|
+
return { behind: pagesBehind + entriesBehind, total: pages + entries };
|
|
178
|
+
}
|
|
179
|
+
/** The static build's watermark (spec 2026-10-09 static mode §5): the newest published_at over both tables. */
|
|
180
|
+
async newestPublishedAt() {
|
|
181
|
+
const space = await this.space();
|
|
182
|
+
const latest = async (table) => {
|
|
183
|
+
const res = await this.db.from(table).select("published_at").eq("space_id", space).order("published_at", { ascending: false }).limit(1).maybeSingle();
|
|
184
|
+
if (res.error)
|
|
185
|
+
this.fail(res.error.message);
|
|
186
|
+
const at = res.data?.published_at;
|
|
187
|
+
return at ? Date.parse(at) : null;
|
|
188
|
+
};
|
|
189
|
+
const [p, e] = await Promise.all([latest("published_pages"), latest("published_entries")]);
|
|
190
|
+
return p === null && e === null ? null : Math.max(p ?? 0, e ?? 0);
|
|
191
|
+
}
|
|
192
|
+
/** Rows published strictly after `since`: the Deploy tile's "changes waiting". Two head counts. */
|
|
193
|
+
async countPublishedAfter(since) {
|
|
194
|
+
const space = await this.space();
|
|
195
|
+
const count = async (table) => {
|
|
196
|
+
const res = await this.db.from(table).select("*", { count: "exact", head: true }).eq("space_id", space).gt("published_at", new Date(since).toISOString());
|
|
197
|
+
if (res.error)
|
|
198
|
+
this.fail(res.error.message);
|
|
199
|
+
return res.count ?? 0;
|
|
200
|
+
};
|
|
201
|
+
const [p, e] = await Promise.all([count("published_pages"), count("published_entries")]);
|
|
202
|
+
return p + e;
|
|
203
|
+
}
|
|
204
|
+
/** The space's last Deploy press, one row in space_deploys (schema v11). */
|
|
205
|
+
async deployRequest() {
|
|
206
|
+
const res = await this.db.from("space_deploys").select("requested_at, requested_by").eq("space_id", await this.space()).maybeSingle();
|
|
207
|
+
if (res.error)
|
|
208
|
+
this.fail(res.error.message);
|
|
209
|
+
// A removal may have made the row before any press: no requested_at is no press.
|
|
210
|
+
const row = res.data;
|
|
211
|
+
return row?.requested_at ? { at: Date.parse(row.requested_at), by: row.requested_by } : null;
|
|
212
|
+
}
|
|
213
|
+
async requestDeploy(by, at = Date.now()) {
|
|
214
|
+
const res = await this.db.from("space_deploys")
|
|
215
|
+
.upsert({ space_id: await this.space(), requested_at: new Date(at).toISOString(), requested_by: by }, { onConflict: "space_id" });
|
|
216
|
+
if (res.error)
|
|
217
|
+
this.fail(res.error.message);
|
|
119
218
|
}
|
|
120
219
|
async markStale(keys) {
|
|
121
220
|
await this.eachGroup(keys, async (table, column, ids, locale) => {
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SMOODLY_VERSION = "0.0.
|
|
1
|
+
export declare const SMOODLY_VERSION = "0.0.48";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by scripts/write-version.mjs from package.json — do not edit.
|
|
2
|
-
export const SMOODLY_VERSION = "0.0.
|
|
2
|
+
export const SMOODLY_VERSION = "0.0.48";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
-- Smoodly core schema, version 10 (DESIGN §3, the document stamp, decided 2026-10-08).
|
|
2
|
+
-- Shipped in the smoodly package; `npx smoodly migrate` copies it into supabase/migrations/.
|
|
3
|
+
-- Never edit a published file: the next change is the next file.
|
|
4
|
+
-- The delta over version 9: published_models, one row per space holding the
|
|
5
|
+
-- document stamp the space recorded as current, so only the deployment at that
|
|
6
|
+
-- stamp rewrites delivery rows (a preview deployment on a newer package serves
|
|
7
|
+
-- assembled documents and writes nothing). Additive: no function changes.
|
|
8
|
+
|
|
9
|
+
set client_min_messages = warning;
|
|
10
|
+
|
|
11
|
+
-- The document stamp a space recorded as current: set by `npx smoodly rebuild` and by the first writer
|
|
12
|
+
-- into an empty record; only a reader at this stamp rewrites published_pages and published_entries.
|
|
13
|
+
create table if not exists "published_models" (
|
|
14
|
+
"space_id" uuid primary key default '00000000-0000-0000-0000-000000000000',
|
|
15
|
+
"model" text not null,
|
|
16
|
+
"recorded_at" timestamptz not null default now()
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
alter table "published_models" enable row level security;
|
|
20
|
+
|
|
21
|
+
-- Stamped with the caller's space on insert, as every content table.
|
|
22
|
+
drop trigger if exists "smoodly_a_set_space" on "published_models";
|
|
23
|
+
create trigger "smoodly_a_set_space" before insert on "published_models"
|
|
24
|
+
for each row execute function "smoodly_set_space"();
|
|
25
|
+
|
|
26
|
+
-- A write key reads and writes its own space's record; no other key reads (spec 2026-09-29 content API contract §8).
|
|
27
|
+
drop policy if exists "smoodly_write" on "published_models";
|
|
28
|
+
|
|
29
|
+
drop policy if exists "smoodly_insert" on "published_models";
|
|
30
|
+
create policy "smoodly_insert" on "published_models" for insert
|
|
31
|
+
with check ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
32
|
+
|
|
33
|
+
drop policy if exists "smoodly_update" on "published_models";
|
|
34
|
+
create policy "smoodly_update" on "published_models" for update
|
|
35
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write')
|
|
36
|
+
with check ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
37
|
+
|
|
38
|
+
drop policy if exists "smoodly_delete" on "published_models";
|
|
39
|
+
create policy "smoodly_delete" on "published_models" for delete
|
|
40
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
41
|
+
|
|
42
|
+
drop policy if exists "smoodly_read" on "published_models";
|
|
43
|
+
create policy "smoodly_read" on "published_models" for select
|
|
44
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
45
|
+
|
|
46
|
+
insert into "smoodly_meta" ("key", "value") values ('schema_version', '10')
|
|
47
|
+
on conflict ("key") do update set "value" = excluded."value";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
-- Smoodly core schema, version 11 (DESIGN §3, static mode, decided 2026-10-09).
|
|
2
|
+
-- Shipped in the smoodly package; `npx smoodly migrate` copies it into supabase/migrations/.
|
|
3
|
+
-- Never edit a published file: the next change is the next file.
|
|
4
|
+
-- The delta over version 10: space_deploys, one row per space holding the last
|
|
5
|
+
-- Deploy press (static mode's button), so a serverless function can tell a
|
|
6
|
+
-- build in flight from one that landed. Additive: no function changes.
|
|
7
|
+
|
|
8
|
+
set client_min_messages = warning;
|
|
9
|
+
|
|
10
|
+
-- The last Deploy press of a space (spec 2026-10-09 static mode §7): who pressed and when; the admin
|
|
11
|
+
-- compares it with the build marker the live site serves to show building, landed or not landed.
|
|
12
|
+
create table if not exists "space_deploys" (
|
|
13
|
+
"space_id" uuid primary key default '00000000-0000-0000-0000-000000000000',
|
|
14
|
+
-- Null until the first press: a removal may make the row first.
|
|
15
|
+
"requested_at" timestamptz,
|
|
16
|
+
"requested_by" text,
|
|
17
|
+
-- When a delivery row last went (an unpublish, a delete): a change the count of newer rows cannot see.
|
|
18
|
+
"removed_at" timestamptz
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
alter table "space_deploys" enable row level security;
|
|
22
|
+
|
|
23
|
+
-- Stamped with the caller's space on insert, as every content table.
|
|
24
|
+
drop trigger if exists "smoodly_a_set_space" on "space_deploys";
|
|
25
|
+
create trigger "smoodly_a_set_space" before insert on "space_deploys"
|
|
26
|
+
for each row execute function "smoodly_set_space"();
|
|
27
|
+
|
|
28
|
+
-- A write key reads and writes its own space's row; no other key reads (spec 2026-09-29 content API contract §8).
|
|
29
|
+
drop policy if exists "smoodly_write" on "space_deploys";
|
|
30
|
+
|
|
31
|
+
drop policy if exists "smoodly_insert" on "space_deploys";
|
|
32
|
+
create policy "smoodly_insert" on "space_deploys" for insert
|
|
33
|
+
with check ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
34
|
+
|
|
35
|
+
drop policy if exists "smoodly_update" on "space_deploys";
|
|
36
|
+
create policy "smoodly_update" on "space_deploys" for update
|
|
37
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write')
|
|
38
|
+
with check ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
39
|
+
|
|
40
|
+
drop policy if exists "smoodly_delete" on "space_deploys";
|
|
41
|
+
create policy "smoodly_delete" on "space_deploys" for delete
|
|
42
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
43
|
+
|
|
44
|
+
drop policy if exists "smoodly_read" on "space_deploys";
|
|
45
|
+
create policy "smoodly_read" on "space_deploys" for select
|
|
46
|
+
using ("space_id" = (select "smoodly_current_space"()) and not (select "smoodly_space_key_revoked"()) and (select "smoodly_key_kind"()) = 'write');
|
|
47
|
+
|
|
48
|
+
insert into "smoodly_meta" ("key", "value") values ('schema_version', '11')
|
|
49
|
+
on conflict ("key") do update set "value" = excluded."value";
|
package/package.json
CHANGED