smoodly 0.0.51 → 0.0.53
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 +14 -13
- package/dist/admin/auth.d.ts +3 -11
- package/dist/admin/auth.js +1 -30
- package/dist/admin/client-ops.d.ts +5 -4
- package/dist/admin/client-ops.js +15 -12
- package/dist/admin/delivery-mode.d.ts +1 -1
- package/dist/admin/delivery-mode.js +2 -2
- package/dist/admin/drift.d.ts +0 -2
- package/dist/admin/drift.js +1 -1
- package/dist/admin/editor/EditorView.d.ts +0 -3
- package/dist/admin/editor/EditorView.js +11 -16
- package/dist/admin/editor/FloatingToolbar.d.ts +0 -1
- package/dist/admin/editor/FloatingToolbar.js +1 -1
- package/dist/admin/editor/SeoSettings.d.ts +0 -2
- package/dist/admin/editor/SeoSettings.js +2 -2
- package/dist/admin/editor/canvas-address.d.ts +8 -0
- package/dist/admin/editor/canvas-address.js +18 -2
- package/dist/admin/editor/canvas-diagnosis.d.ts +2 -0
- package/dist/admin/editor/canvas-diagnosis.js +3 -0
- package/dist/admin/editor/inline-dom.d.ts +0 -4
- package/dist/admin/editor/inline-dom.js +1 -1
- package/dist/admin/editor/preview-grant.d.ts +6 -0
- package/dist/admin/editor/preview-grant.js +25 -0
- package/dist/admin/editor/useCanvasDiagnosis.js +2 -2
- package/dist/admin/files.generated.js +1 -1
- package/dist/admin/fixed-nodes.d.ts +0 -6
- package/dist/admin/fixed-nodes.js +1 -81
- package/dist/admin/forms/CropEditor.d.ts +4 -2
- package/dist/admin/forms/CropEditor.js +58 -5
- package/dist/admin/forms/ImagePreview.d.ts +3 -1
- package/dist/admin/forms/ImagePreview.js +9 -3
- package/dist/admin/forms/MediaGrid.js +2 -1
- package/dist/admin/forms/MediaPicker.js +9 -6
- package/dist/admin/forms/MediaWidget.js +11 -9
- package/dist/admin/forms/assets-context.d.ts +7 -3
- package/dist/admin/forms/assets-context.js +5 -3
- package/dist/admin/forms/crop-editor.d.ts +24 -2
- package/dist/admin/forms/crop-editor.js +36 -2
- package/dist/admin/forms/date-picker.d.ts +0 -1
- package/dist/admin/forms/date-picker.js +1 -1
- package/dist/admin/forms/tabs.d.ts +0 -1
- package/dist/admin/forms/tabs.js +1 -1
- package/dist/admin/forms/upload.d.ts +18 -11
- package/dist/admin/forms/upload.js +62 -24
- package/dist/admin/global-items.d.ts +0 -3
- package/dist/admin/global-items.js +0 -54
- package/dist/admin/handler.d.ts +22 -28
- package/dist/admin/handler.js +146 -47
- package/dist/admin/health.d.ts +0 -4
- package/dist/admin/index.d.ts +6 -9
- package/dist/admin/index.js +3 -6
- package/dist/admin/ops.d.ts +40 -32
- package/dist/admin/page-data.d.ts +14 -6
- package/dist/admin/page-data.js +1 -1
- package/dist/admin/session-flow.d.ts +65 -0
- package/dist/admin/session-flow.js +121 -0
- package/dist/admin/shell/AdminApp.d.ts +8 -3
- package/dist/admin/shell/AdminApp.js +37 -58
- package/dist/admin/shell/ContentHealthPage.js +1 -3
- package/dist/admin/shell/GlobalFields.d.ts +0 -3
- package/dist/admin/shell/GlobalFields.js +1 -1
- package/dist/admin/shell/IconRail.js +10 -8
- package/dist/admin/shell/MediaScreen.js +9 -6
- package/dist/admin/shell/MembersPage.d.ts +1 -2
- package/dist/admin/shell/MembersPage.js +19 -90
- package/dist/admin/shell/SettingsView.d.ts +1 -2
- package/dist/admin/shell/SettingsView.js +2 -2
- package/dist/admin/shell/SignedOutView.d.ts +5 -0
- package/dist/admin/shell/SignedOutView.js +9 -0
- package/dist/admin/shell/console-links.d.ts +5 -0
- package/dist/admin/shell/console-links.js +11 -0
- package/dist/admin/shell/members-list.d.ts +1 -14
- package/dist/admin/shell/members-list.js +2 -23
- package/dist/admin/shell/pages-tree.d.ts +0 -2
- package/dist/admin/shell/pages-tree.js +1 -1
- package/dist/admin/shell/presence-socket.d.ts +10 -0
- package/dist/admin/shell/presence-socket.js +191 -0
- package/dist/admin/shell/presence.d.ts +6 -18
- package/dist/admin/shell/presence.js +4 -11
- package/dist/admin/shell/session.d.ts +19 -12
- package/dist/admin/shell/session.js +114 -47
- package/dist/admin/ui/LocaleSwitcher.d.ts +0 -4
- package/dist/admin/ui/LocaleSwitcher.js +2 -2
- package/dist/admin/ui/primitives.d.ts +4 -14
- package/dist/admin/ui/primitives.js +7 -9
- package/dist/admin/ui/theme.js +13 -2
- package/dist/admin/validate.js +10 -1
- package/dist/api-client.d.ts +26 -0
- package/dist/api-client.js +107 -0
- package/dist/assemble.d.ts +4 -41
- package/dist/assemble.js +5 -303
- package/dist/asset-store.d.ts +28 -30
- package/dist/asset-store.js +26 -121
- package/dist/astro/cache.d.ts +1 -1
- package/dist/astro/components/Head.astro +4 -1
- package/dist/astro/components/Image.astro +12 -17
- package/dist/astro/components/Video.astro +5 -2
- package/dist/astro/head.d.ts +3 -0
- package/dist/astro/head.js +24 -0
- package/dist/astro/index.js +61 -27
- package/dist/astro/locale-paths.d.ts +5 -2
- package/dist/astro/locale-paths.js +10 -2
- package/dist/astro/routes/admin.js +9 -7
- package/dist/astro/runtime.d.ts +3 -2
- package/dist/astro/runtime.js +5 -4
- package/dist/astro/server.d.ts +7 -11
- package/dist/astro/server.js +22 -28
- package/dist/astro/shell.d.ts +3 -3
- package/dist/astro/shell.js +1 -1
- package/dist/astro/static-media-node.d.ts +4 -0
- package/dist/astro/static-media-node.js +25 -0
- package/dist/astro/static-media.d.ts +17 -0
- package/dist/astro/static-media.js +55 -0
- package/dist/astro/static.d.ts +5 -10
- package/dist/astro/static.js +13 -29
- package/dist/canvas-marker.d.ts +14 -0
- package/dist/canvas-marker.js +36 -0
- package/dist/cli/api.d.ts +14 -0
- package/dist/cli/api.js +48 -0
- package/dist/cli/app-env.d.ts +2 -0
- package/dist/cli/app-env.js +20 -0
- package/dist/cli/export.d.ts +16 -2
- package/dist/cli/export.js +52 -35
- package/dist/cli/import.d.ts +7 -11
- package/dist/cli/import.js +50 -54
- package/dist/cli/load-config.d.ts +0 -1
- package/dist/cli/load-config.js +1 -1
- package/dist/cli/main.d.ts +4 -12
- package/dist/cli/main.js +26 -72
- package/dist/cli/push.d.ts +6 -0
- package/dist/cli/push.js +31 -0
- package/dist/collections.d.ts +0 -1
- package/dist/collections.js +1 -1
- package/dist/config.d.ts +20 -5
- package/dist/config.js +18 -1
- package/dist/content/content-api.d.ts +23 -23
- package/dist/content/content-api.js +48 -56
- package/dist/content/mime.d.ts +1 -0
- package/dist/content/mime.js +6 -0
- package/dist/css.js +1 -1
- package/dist/deploy-store.d.ts +19 -0
- package/dist/entry-store.d.ts +8 -94
- package/dist/entry-store.js +9 -557
- package/dist/env.d.ts +27 -20
- package/dist/env.js +38 -50
- package/dist/fields.d.ts +11 -3
- package/dist/fields.js +33 -2
- package/dist/global-id.d.ts +2 -0
- package/dist/global-id.js +4 -2
- package/dist/image/SmoodlyImage.d.ts +9 -5
- package/dist/image/SmoodlyImage.js +29 -15
- package/dist/image/SmoodlyVideo.d.ts +1 -1
- package/dist/image/SmoodlyVideo.js +3 -2
- package/dist/image/index.d.ts +2 -3
- package/dist/image/index.js +0 -2
- package/dist/image/markup.d.ts +53 -0
- package/dist/image/markup.js +111 -0
- package/dist/index.d.ts +13 -23
- package/dist/index.js +7 -20
- package/dist/media-cut.d.ts +44 -0
- package/dist/media-cut.js +70 -0
- package/dist/media.d.ts +58 -4
- package/dist/media.js +126 -16
- package/dist/member-store.d.ts +2 -50
- package/dist/member-store.js +0 -56
- package/dist/next/admin-route.d.ts +1 -1
- package/dist/next/admin-route.js +5 -3
- package/dist/next/meta.js +2 -3
- package/dist/next/page-renderer.d.ts +2 -2
- package/dist/next/page-renderer.js +22 -11
- package/dist/next/queries.d.ts +2 -2
- package/dist/path-index.d.ts +0 -24
- package/dist/path-index.js +0 -98
- package/dist/paths.d.ts +1 -1
- package/dist/paths.js +1 -1
- package/dist/push.d.ts +30 -0
- package/dist/push.js +52 -0
- package/dist/read-counter.d.ts +2 -0
- package/dist/read-counter.js +6 -0
- package/dist/reads.d.ts +7 -7
- package/dist/reads.js +3 -0
- package/dist/registry-json.d.ts +11 -0
- package/dist/registry-json.js +81 -0
- package/dist/render.d.ts +0 -1
- package/dist/render.js +1 -1
- package/dist/resolve.d.ts +12 -6
- package/dist/resolve.js +11 -8
- package/dist/revalidate.d.ts +8 -1
- package/dist/revalidate.js +8 -1
- package/dist/richtext/index.d.ts +1 -1
- package/dist/section-wrapper.d.ts +1 -1
- package/dist/section-wrapper.js +0 -9
- package/dist/signed-message.d.ts +26 -0
- package/dist/signed-message.js +103 -0
- package/dist/site.d.ts +59 -18
- package/dist/site.js +21 -252
- package/dist/space-transfer.d.ts +6 -3
- package/dist/space-transfer.js +18 -6
- package/dist/store.d.ts +2 -80
- package/dist/store.js +3 -489
- package/dist/toolset.d.ts +2 -1
- package/dist/toolset.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -15
- package/dist/admin/auth-config.d.ts +0 -6
- package/dist/admin/browser/fetch-op.d.ts +0 -10
- package/dist/admin/browser/fetch-op.js +0 -44
- package/dist/admin/browser/main.d.ts +0 -1
- package/dist/admin/browser/main.js +0 -23
- package/dist/admin/ops-impl.d.ts +0 -51
- package/dist/admin/ops-impl.js +0 -1403
- package/dist/admin/shell/InviteModal.d.ts +0 -6
- package/dist/admin/shell/InviteModal.js +0 -28
- package/dist/admin/shell/LoginView.d.ts +0 -5
- package/dist/admin/shell/LoginView.js +0 -80
- package/dist/admin/shell/SchemaNotice.d.ts +0 -4
- package/dist/admin/shell/SchemaNotice.js +0 -4
- package/dist/admin/shell/SetPasswordView.d.ts +0 -7
- package/dist/admin/shell/SetPasswordView.js +0 -41
- package/dist/admin/shell/presence-realtime.d.ts +0 -3
- package/dist/admin/shell/presence-realtime.js +0 -32
- package/dist/admin/supabase-auth.d.ts +0 -7
- package/dist/admin/supabase-auth.js +0 -30
- package/dist/astro/deploy-deps.d.ts +0 -10
- package/dist/astro/deploy-deps.js +0 -8
- package/dist/astro/image.d.ts +0 -27
- package/dist/astro/image.js +0 -29
- package/dist/bind.d.ts +0 -19
- package/dist/bind.js +0 -34
- package/dist/cli/add-admin.d.ts +0 -11
- package/dist/cli/add-admin.js +0 -25
- package/dist/cli/load-collections.d.ts +0 -2
- package/dist/cli/load-collections.js +0 -27
- package/dist/cli/migrate.d.ts +0 -43
- package/dist/cli/migrate.js +0 -138
- package/dist/cli/rebuild.d.ts +0 -23
- package/dist/cli/rebuild.js +0 -22
- package/dist/cli/space-io.d.ts +0 -41
- package/dist/cli/space-io.js +0 -84
- package/dist/client.d.ts +0 -11
- package/dist/client.js +0 -54
- package/dist/current-space.d.ts +0 -4
- package/dist/current-space.js +0 -9
- package/dist/document-stamp.d.ts +0 -7
- package/dist/document-stamp.js +0 -48
- package/dist/image/loaders.d.ts +0 -15
- package/dist/image/loaders.js +0 -5
- package/dist/image/next-config.d.ts +0 -18
- package/dist/image/next-config.js +0 -32
- package/dist/image/remote-pattern.d.ts +0 -1
- package/dist/image/remote-pattern.js +0 -5
- package/dist/migrations.d.ts +0 -37
- package/dist/migrations.js +0 -73
- package/dist/project.d.ts +0 -88
- package/dist/project.js +0 -231
- package/dist/published.d.ts +0 -142
- package/dist/published.js +0 -164
- package/dist/ref-index.d.ts +0 -19
- package/dist/ref-index.js +0 -0
- package/dist/schema-read.d.ts +0 -23
- package/dist/schema-read.js +0 -50
- package/dist/schema-version.d.ts +0 -19
- package/dist/schema-version.js +0 -34
- package/dist/sql-space.d.ts +0 -44
- package/dist/sql-space.js +0 -289
- package/dist/sql.d.ts +0 -15
- package/dist/sql.js +0 -556
- package/dist/supabase-asset-store.d.ts +0 -21
- package/dist/supabase-asset-store.js +0 -170
- package/dist/supabase-entry-store.d.ts +0 -92
- package/dist/supabase-entry-store.js +0 -824
- package/dist/supabase-member-store.d.ts +0 -21
- package/dist/supabase-member-store.js +0 -96
- package/dist/supabase-path-index.d.ts +0 -30
- package/dist/supabase-path-index.js +0 -138
- package/dist/supabase-published-store.d.ts +0 -56
- package/dist/supabase-published-store.js +0 -314
- package/dist/supabase-store.d.ts +0 -103
- package/dist/supabase-store.js +0 -678
- package/migrations/20260926120000_smoodly_v1.sql +0 -535
- package/migrations/20260926130000_smoodly_v2.sql +0 -26
- package/migrations/20260926140000_smoodly_v3.sql +0 -38
- package/migrations/20260926150000_smoodly_v4.sql +0 -41
- package/migrations/20260929120000_smoodly_v5.sql +0 -56
- package/migrations/20260929135523_smoodly_v6.sql +0 -200
- package/migrations/20260930040956_smoodly_v7.sql +0 -84
- package/migrations/20261007120000_smoodly_v8.sql +0 -154
- package/migrations/20261007200000_smoodly_v9.sql +0 -30
- package/migrations/20261008120000_smoodly_v10.sql +0 -47
- package/migrations/20261009120000_smoodly_v11.sql +0 -49
- /package/dist/{admin/auth-config.js → deploy-store.js} +0 -0
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { InviteInput } from "../../member-store.ts";
|
|
2
|
-
export declare function InviteModal({ onClose, onInvite }: {
|
|
3
|
-
onClose(): void;
|
|
4
|
-
/** Resolves to an error message, or null when the invite landed (the caller closes). */
|
|
5
|
-
onInvite(input: Omit<InviteInput, "redirectTo">): Promise<string | null>;
|
|
6
|
-
}): import("react").JSX.Element;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
// packages/smoodly/src/admin/shell/InviteModal.tsx
|
|
4
|
-
// Invite a member (spec 2026-09-25 members management §4): an email, a
|
|
5
|
-
// role, Send. The role is a radio list with a line under each option
|
|
6
|
-
// saying what it may do — the one place the difference is explained in
|
|
7
|
-
// the admin (the Roles page was dropped 2026-09-25). The op's error
|
|
8
|
-
// shows inside; success closes it and the page reports what happened.
|
|
9
|
-
import { useState } from "react";
|
|
10
|
-
import { MEMBER_ROLES } from "../../permissions.js";
|
|
11
|
-
import { Modal } from "../ui/Modal.js";
|
|
12
|
-
import { Banner, Button, Field } from "../ui/primitives.js";
|
|
13
|
-
import { ROLE_DESCRIPTION, roleLabel } from "./members-list.js";
|
|
14
|
-
export function InviteModal({ onClose, onInvite }) {
|
|
15
|
-
const [email, setEmail] = useState("");
|
|
16
|
-
const [role, setRole] = useState("editor");
|
|
17
|
-
const [error, setError] = useState(null);
|
|
18
|
-
const [busy, setBusy] = useState(false);
|
|
19
|
-
const submit = async (e) => {
|
|
20
|
-
e.preventDefault();
|
|
21
|
-
setBusy(true);
|
|
22
|
-
setError(await onInvite({ email: email.trim(), role }));
|
|
23
|
-
setBusy(false);
|
|
24
|
-
};
|
|
25
|
-
// Editor first: the default, and the one most invites want.
|
|
26
|
-
const roles = [...MEMBER_ROLES].reverse();
|
|
27
|
-
return (_jsx(Modal, { title: "Invite a member", width: 420, onClose: onClose, children: _jsxs("form", { onSubmit: submit, style: { display: "flex", flexDirection: "column", gap: 14 }, children: [_jsx(Field, { label: "Email", children: _jsx("input", { className: "sm-input", type: "email", required: true, autoFocus: true, value: email, onChange: (e) => setEmail(e.target.value) }) }), _jsx(Field, { label: "Role", asDiv: true, children: _jsx("div", { className: "sm-choices", role: "radiogroup", children: roles.map((r) => (_jsxs("label", { className: "sm-choice sm-choice--desc", children: [_jsx("input", { type: "radio", name: "role", value: r, checked: role === r, onChange: () => setRole(r) }), _jsxs("span", { children: [_jsx("span", { className: "sm-choice__label", children: roleLabel(r) }), _jsx("span", { className: "sm-choice__desc", children: ROLE_DESCRIPTION[r] })] })] }, r))) }) }), error && _jsx(Banner, { tone: "error", children: error }), _jsxs("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: [_jsx(Button, { variant: "secondary", onClick: onClose, children: "Cancel" }), _jsx("button", { type: "submit", className: "sm-btn sm-btn--primary", disabled: busy, children: busy ? "Sending…" : "Send invite" })] })] }) }));
|
|
28
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
// The admin's front door (spec 2026-09-04 §5): email+password always;
|
|
4
|
-
// Google/GitHub when the auth project has them. Errors come from
|
|
5
|
-
// Supabase Auth verbatim. Being an editor is checked by the server on
|
|
6
|
-
// the first op — a signed-in non-editor sees that message in the shell.
|
|
7
|
-
// Forgot password (members management §6) mails a reset link; the reply
|
|
8
|
-
// is the same whatever the email, so the form reveals no membership.
|
|
9
|
-
import { useState } from "react";
|
|
10
|
-
import { Banner, Button, Field, Logo } from "../ui/primitives.js";
|
|
11
|
-
const LABELS = { google: "Continue with Google", github: "Continue with GitHub" };
|
|
12
|
-
const CARD = {
|
|
13
|
-
width: 320, display: "flex", flexDirection: "column", gap: 14,
|
|
14
|
-
background: "var(--surface)", padding: 28, borderRadius: "var(--radius-card-lg)",
|
|
15
|
-
border: "var(--menu-border)", boxShadow: "var(--shadow-page)",
|
|
16
|
-
};
|
|
17
|
-
export function LoginView({ client, providers = [] }) {
|
|
18
|
-
const [mode, setMode] = useState("signin");
|
|
19
|
-
const [email, setEmail] = useState("");
|
|
20
|
-
const [password, setPassword] = useState("");
|
|
21
|
-
const [error, setError] = useState(null);
|
|
22
|
-
const [busy, setBusy] = useState(false);
|
|
23
|
-
const submit = async (e) => {
|
|
24
|
-
e.preventDefault();
|
|
25
|
-
setBusy(true);
|
|
26
|
-
setError(null);
|
|
27
|
-
try {
|
|
28
|
-
const res = await client.auth.signInWithPassword({ email, password });
|
|
29
|
-
if (res.error)
|
|
30
|
-
setError(res.error.message);
|
|
31
|
-
}
|
|
32
|
-
catch (e) {
|
|
33
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
34
|
-
}
|
|
35
|
-
finally {
|
|
36
|
-
setBusy(false);
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
const forgot = async (e) => {
|
|
40
|
-
e.preventDefault();
|
|
41
|
-
setBusy(true);
|
|
42
|
-
setError(null);
|
|
43
|
-
try {
|
|
44
|
-
// The answer is not shown: the form must not reveal whether an email is registered.
|
|
45
|
-
await client.auth.resetPasswordForEmail(email, { redirectTo: window.location.origin + window.location.pathname });
|
|
46
|
-
}
|
|
47
|
-
catch { /* same */ }
|
|
48
|
-
finally {
|
|
49
|
-
setBusy(false);
|
|
50
|
-
setMode("sent");
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
const oauth = async (provider) => {
|
|
54
|
-
setBusy(true);
|
|
55
|
-
setError(null);
|
|
56
|
-
try {
|
|
57
|
-
const res = await client.auth.signInWithOAuth({ provider, options: { redirectTo: window.location.href } });
|
|
58
|
-
if (res.error)
|
|
59
|
-
setError(res.error.message);
|
|
60
|
-
}
|
|
61
|
-
catch (e) {
|
|
62
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
63
|
-
}
|
|
64
|
-
finally {
|
|
65
|
-
setBusy(false);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
const back = (_jsx(Button, { variant: "secondary", size: "lg", disabled: busy, onClick: () => { setError(null); setMode("signin"); }, children: "Back to sign in" }));
|
|
69
|
-
let card;
|
|
70
|
-
if (mode === "sent") {
|
|
71
|
-
card = (_jsxs("div", { style: CARD, children: [_jsx(Logo, { height: 20 }), _jsx("span", { children: "Check your email for a link to choose a new password." }), back] }));
|
|
72
|
-
}
|
|
73
|
-
else if (mode === "forgot") {
|
|
74
|
-
card = (_jsxs("form", { onSubmit: forgot, style: CARD, children: [_jsx(Logo, { height: 20 }), _jsx(Field, { label: "Email", children: _jsx("input", { className: "sm-input", type: "email", value: email, required: true, autoComplete: "email", autoFocus: true, onChange: (e) => setEmail(e.target.value) }) }), error && _jsx(Banner, { tone: "error", children: error }), _jsx("button", { type: "submit", disabled: busy, className: "sm-btn sm-btn--primary sm-btn--lg", children: busy ? "Sending…" : "Send reset link" }), back] }));
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
card = (_jsxs("form", { onSubmit: submit, style: CARD, children: [_jsx(Logo, { height: 20 }), _jsx(Field, { label: "Email", children: _jsx("input", { className: "sm-input", type: "email", value: email, required: true, autoComplete: "email", onChange: (e) => setEmail(e.target.value) }) }), _jsx(Field, { label: "Password", children: _jsx("input", { className: "sm-input", type: "password", value: password, required: true, autoComplete: "current-password", onChange: (e) => setPassword(e.target.value) }) }), error && _jsx(Banner, { tone: "error", children: error }), _jsx("button", { type: "submit", disabled: busy, className: "sm-btn sm-btn--primary sm-btn--lg", children: busy ? "Signing in…" : "Sign in" }), providers.map((p) => (_jsx(Button, { variant: "secondary", size: "lg", disabled: busy, onClick: () => oauth(p), children: LABELS[p] }, p))), _jsx("button", { type: "button", className: "sm-link", disabled: busy, onClick: () => { setError(null); setMode("forgot"); }, style: { background: "transparent", border: 0, color: "var(--text-muted)", cursor: "pointer", font: "inherit", padding: 0 }, children: "Forgot password?" })] }));
|
|
78
|
-
}
|
|
79
|
-
return (_jsx("div", { style: { minHeight: "100vh", display: "grid", placeItems: "center", background: "var(--bg)" }, children: card }));
|
|
80
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
export function SchemaNotice({ status }) {
|
|
3
|
-
return (_jsx("div", { style: { height: "100vh", display: "grid", placeItems: "center", padding: 24, color: "var(--text)" }, children: _jsxs("div", { style: { maxWidth: 520, display: "grid", gap: 12 }, children: [_jsx("h1", { className: "sm-title", style: { fontSize: 22, margin: 0 }, children: "The database needs an update" }), _jsxs("p", { style: { margin: 0 }, children: ["The database schema is at version ", status.database ?? "none", ". This version of Smoodly needs version ", status.required, "."] }), _jsx("p", { style: { margin: 0 }, children: "From the site's folder:" }), _jsx("pre", { className: "sm-code", children: _jsx("code", { children: "npx smoodly migrate" }) }), _jsx("p", { style: { margin: 0 }, children: "then apply it:" }), _jsx("pre", { className: "sm-code", children: _jsx("code", { children: "supabase db push" }) }), _jsxs("p", { style: { margin: 0, color: "var(--text-muted)" }, children: ["That is for a hosted project; for the local stack run ", _jsx("code", { children: "supabase migration up" }), ", which keeps the content. Reload this page afterwards."] })] }) }));
|
|
4
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
-
import type { Arrival } from "./session.ts";
|
|
3
|
-
export declare function SetPasswordView({ client, mode, onDone }: {
|
|
4
|
-
client: SupabaseClient;
|
|
5
|
-
mode: Arrival;
|
|
6
|
-
onDone(): void;
|
|
7
|
-
}): import("react").JSX.Element;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
// packages/smoodly/src/admin/shell/SetPasswordView.tsx
|
|
4
|
-
// The arrival screen (spec 2026-09-25 members management §6): an invite
|
|
5
|
-
// link or a reset link signed the person in; now they choose a password.
|
|
6
|
-
// An invite cannot skip it (the account has none yet); a recovery may.
|
|
7
|
-
import { useState } from "react";
|
|
8
|
-
import { Banner, Button, Field, Logo } from "../ui/primitives.js";
|
|
9
|
-
export function SetPasswordView({ client, mode, onDone }) {
|
|
10
|
-
const [password, setPassword] = useState("");
|
|
11
|
-
const [again, setAgain] = useState("");
|
|
12
|
-
const [error, setError] = useState(null);
|
|
13
|
-
const [busy, setBusy] = useState(false);
|
|
14
|
-
const submit = async (e) => {
|
|
15
|
-
e.preventDefault();
|
|
16
|
-
if (password !== again) {
|
|
17
|
-
setError("The two passwords differ.");
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
setBusy(true);
|
|
21
|
-
setError(null);
|
|
22
|
-
try {
|
|
23
|
-
const res = await client.auth.updateUser({ password });
|
|
24
|
-
if (res.error)
|
|
25
|
-
setError(res.error.message);
|
|
26
|
-
else
|
|
27
|
-
onDone();
|
|
28
|
-
}
|
|
29
|
-
catch (e) {
|
|
30
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
31
|
-
}
|
|
32
|
-
finally {
|
|
33
|
-
setBusy(false);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
return (_jsx("div", { style: { minHeight: "100vh", display: "grid", placeItems: "center", background: "var(--bg)" }, children: _jsxs("form", { onSubmit: submit, style: {
|
|
37
|
-
width: 320, display: "flex", flexDirection: "column", gap: 14,
|
|
38
|
-
background: "var(--surface)", padding: 28, borderRadius: "var(--radius-card-lg)",
|
|
39
|
-
border: "var(--menu-border)", boxShadow: "var(--shadow-page)",
|
|
40
|
-
}, children: [_jsx(Logo, { height: 20 }), _jsx("span", { className: "sm-title", children: mode === "invite" ? "Set your password" : "Choose a new password" }), _jsx(Field, { label: "Password", children: _jsx("input", { className: "sm-input", type: "password", required: true, minLength: 8, autoComplete: "new-password", value: password, onChange: (e) => setPassword(e.target.value) }) }), _jsx(Field, { label: "Again", children: _jsx("input", { className: "sm-input", type: "password", required: true, autoComplete: "new-password", value: again, onChange: (e) => setAgain(e.target.value) }) }), error && _jsx(Banner, { tone: "error", children: error }), _jsx("button", { type: "submit", disabled: busy, className: "sm-btn sm-btn--primary sm-btn--lg", children: busy ? "Saving…" : "Save" }), mode === "recovery" && _jsx(Button, { variant: "secondary", size: "lg", onClick: onDone, children: "Skip" })] }) }));
|
|
41
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
// The real channel behind `createPresence` (spec 2026-09-26 concurrency §5–§6;
|
|
3
|
-
// gated 2026-09-26 security pass §1): one supabase-js client on the CONTENT
|
|
4
|
-
// project whose public key (the anon key in self-host, the read key in the
|
|
5
|
-
// cloud) is only the gateway apikey — the socket authenticates with the
|
|
6
|
-
// editor's SESSION token, which the policies read auth.uid() from. A
|
|
7
|
-
// private channel named after the space, presence keyed by the email.
|
|
8
|
-
//
|
|
9
|
-
// The token rides the client's `accessToken` callback, not a bare
|
|
10
|
-
// `realtime.setAuth(token)`: realtime-js treats the callback as the source
|
|
11
|
-
// of truth and re-asks it after every join and reconnect — with the
|
|
12
|
-
// default callback that answer is the public key, which the server then
|
|
13
|
-
// refuses ("no permissions to read"). The join itself waits for the first
|
|
14
|
-
// setAuth, so it never goes out with the apikey alone.
|
|
15
|
-
import { createClient } from "@supabase/supabase-js";
|
|
16
|
-
export function connectRealtime(config, email, token) {
|
|
17
|
-
let current = token;
|
|
18
|
-
const client = createClient(config.url, config.key, { accessToken: async () => current });
|
|
19
|
-
const ready = client.realtime.setAuth(token).catch(() => { });
|
|
20
|
-
const channel = client.channel(`space:${config.spaceId}`, { config: { private: true, presence: { key: email } } });
|
|
21
|
-
return {
|
|
22
|
-
subscribe: (onStatus) => { void ready.then(() => { channel.subscribe((status) => onStatus(status)); }); },
|
|
23
|
-
setAuth: (fresh) => { current = fresh; return client.realtime.setAuth(fresh); },
|
|
24
|
-
track: (state) => channel.track(state),
|
|
25
|
-
untrack: () => channel.untrack(),
|
|
26
|
-
send: (message) => channel.send(message),
|
|
27
|
-
onSync: (listener) => { channel.on("presence", { event: "sync" }, listener); },
|
|
28
|
-
presenceState: () => channel.presenceState(),
|
|
29
|
-
onBroadcast: (event, listener) => { channel.on("broadcast", { event }, (m) => listener(m.payload)); },
|
|
30
|
-
unsubscribe: async () => { await channel.unsubscribe(); await client.removeAllChannels(); },
|
|
31
|
-
};
|
|
32
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// The Supabase-backed AdminAuth: the session is verified against the
|
|
2
|
-
// AUTH project (smoodly.io's in the cloud, the customer's own in self-
|
|
3
|
-
// host — same code, different SMOODLY_AUTH_URL), the members row is read
|
|
4
|
-
// from the CONTENT project with the write key, its role onto the session.
|
|
5
|
-
// No space filter: the policy set scopes the write key, and self-host
|
|
6
|
-
// has one space.
|
|
7
|
-
import { createClient } from "@supabase/supabase-js";
|
|
8
|
-
export function supabaseAdminAuth(input) {
|
|
9
|
-
// Built on the first sign-in check, not here: a live page constructs the glue with no publishable
|
|
10
|
-
// key and never verifies anyone (spec 2026-09-30 tester findings §4).
|
|
11
|
-
let client = null;
|
|
12
|
-
const auth = () => {
|
|
13
|
-
if (!input.authKey) {
|
|
14
|
-
throw new Error("smoodly: set SMOODLY_PUBLISHABLE_KEY in .env (Astro) or .env.local (Next.js), or in your host's environment variables — the admin signs in with it (Deploying: https://smoodly.io/docs/getting-started/deploying).");
|
|
15
|
-
}
|
|
16
|
-
return (client ?? (client = createClient(input.authUrl, input.authKey, { auth: { persistSession: false, autoRefreshToken: false } })));
|
|
17
|
-
};
|
|
18
|
-
return {
|
|
19
|
-
async verify(token) {
|
|
20
|
-
const res = await auth().auth.getUser(token);
|
|
21
|
-
return res.data.user ? { userId: res.data.user.id, email: res.data.user.email ?? null } : null;
|
|
22
|
-
},
|
|
23
|
-
async memberOf(userId) {
|
|
24
|
-
const res = await input.db.from("members").select("role").eq("user_id", userId).limit(1);
|
|
25
|
-
if (res.error)
|
|
26
|
-
throw new Error(`smoodly: ${res.error.message}`);
|
|
27
|
-
return res.data.length > 0 ? String(res.data[0].role) : null;
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { DeployDeps } from "../admin/ops-impl.ts";
|
|
2
|
-
export declare function deployDepsOf(input: {
|
|
3
|
-
output: "static" | "server";
|
|
4
|
-
/** astro.config's `site` (SITE_URL), the live address the marker is read from. */
|
|
5
|
-
site: string | undefined;
|
|
6
|
-
env: Record<string, string | undefined>;
|
|
7
|
-
store: DeployDeps["store"];
|
|
8
|
-
}): (DeployDeps & {
|
|
9
|
-
mode: "live" | "static";
|
|
10
|
-
}) | undefined;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export function deployDepsOf(input) {
|
|
2
|
-
if (input.output !== "static")
|
|
3
|
-
return undefined;
|
|
4
|
-
if (!input.site)
|
|
5
|
-
throw new Error("smoodly: static output needs `site` (SITE_URL) — the Deploy tile reads the build marker from the live address.");
|
|
6
|
-
const hook = input.env.SMOODLY_DEPLOY_HOOK?.trim() || undefined;
|
|
7
|
-
return { mode: "static", siteUrl: input.site.replace(/\/$/, ""), hook, store: input.store };
|
|
8
|
-
}
|
package/dist/astro/image.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { ResolvedImage } from "../media.ts";
|
|
2
|
-
/** The srcset candidates, up to the original's width: Astro ignores any wider than the image anyway. */
|
|
3
|
-
export declare const IMAGE_WIDTHS: number[];
|
|
4
|
-
export declare function imageWidths(width: number): number[];
|
|
5
|
-
export type ImagePlacement = {
|
|
6
|
-
box: string;
|
|
7
|
-
frame: string;
|
|
8
|
-
svg: boolean;
|
|
9
|
-
};
|
|
10
|
-
export declare function placeImage(image: ResolvedImage, options?: {
|
|
11
|
-
aspect?: string;
|
|
12
|
-
handlesCrop?: boolean;
|
|
13
|
-
}): ImagePlacement;
|
|
14
|
-
export type ImageRequest = {
|
|
15
|
-
src: string;
|
|
16
|
-
width: number;
|
|
17
|
-
height: number;
|
|
18
|
-
format: "webp";
|
|
19
|
-
widths?: number[];
|
|
20
|
-
sizes?: string;
|
|
21
|
-
};
|
|
22
|
-
/** What to ask Astro's image service for, or null when the original URL is served as it is: an SVG (a vector
|
|
23
|
-
* has no sizes) or `unoptimized`. Widths, and so a srcset, only when the page says its `sizes`. */
|
|
24
|
-
export declare function imageRequest(image: ResolvedImage, options?: {
|
|
25
|
-
sizes?: string;
|
|
26
|
-
unoptimized?: boolean;
|
|
27
|
-
}): ImageRequest | null;
|
package/dist/astro/image.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// What <Image> renders in Astro (spec 2026-09-08 media §9; the React one is image/SmoodlyImage.tsx): a box at
|
|
2
|
-
// the aspect, the picture inside placed by crop and hotspot, as inline style strings; and the candidate widths
|
|
3
|
-
// Astro's image service is asked for. Pure, so Image.astro is only markup around `getImage`.
|
|
4
|
-
import { boxAspectOf, frameFor } from "../image/crop-math.js";
|
|
5
|
-
/** The srcset candidates, up to the original's width: Astro ignores any wider than the image anyway. */
|
|
6
|
-
export const IMAGE_WIDTHS = [320, 640, 960, 1280, 1920, 2560];
|
|
7
|
-
export function imageWidths(width) {
|
|
8
|
-
return [...IMAGE_WIDTHS.filter((w) => w < width), width];
|
|
9
|
-
}
|
|
10
|
-
const pct = (n) => `${Math.round(n * 1000) / 1000}%`;
|
|
11
|
-
export function placeImage(image, options = {}) {
|
|
12
|
-
const box = boxAspectOf(image, options.aspect);
|
|
13
|
-
const frame = options.handlesCrop ? { left: 0, top: 0, width: 100, height: 100 } : frameFor(image, box);
|
|
14
|
-
return {
|
|
15
|
-
box: `display:block;position:relative;overflow:hidden;aspect-ratio:${box}`,
|
|
16
|
-
frame: `position:absolute;left:${pct(frame.left)};top:${pct(frame.top)};width:${pct(frame.width)};height:${pct(frame.height)};max-width:none`,
|
|
17
|
-
svg: image.mime === "image/svg+xml",
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
/** What to ask Astro's image service for, or null when the original URL is served as it is: an SVG (a vector
|
|
21
|
-
* has no sizes) or `unoptimized`. Widths, and so a srcset, only when the page says its `sizes`. */
|
|
22
|
-
export function imageRequest(image, options = {}) {
|
|
23
|
-
if (options.unoptimized || image.mime === "image/svg+xml")
|
|
24
|
-
return null;
|
|
25
|
-
return {
|
|
26
|
-
src: image.url, width: image.width, height: image.height, format: "webp",
|
|
27
|
-
...(options.sizes ? { widths: imageWidths(image.width), sizes: options.sizes } : {}),
|
|
28
|
-
};
|
|
29
|
-
}
|
package/dist/bind.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
-
import type { ResolvedConfig } from "./config.ts";
|
|
3
|
-
import type { SiteOptions } from "./site.ts";
|
|
4
|
-
import { SupabaseAssetStore } from "./supabase-asset-store.ts";
|
|
5
|
-
import { SupabaseEntryStore } from "./supabase-entry-store.ts";
|
|
6
|
-
import { SupabaseMemberStore } from "./supabase-member-store.ts";
|
|
7
|
-
import { SupabasePathIndex } from "./supabase-path-index.ts";
|
|
8
|
-
import { SupabasePublishedStore } from "./supabase-published-store.ts";
|
|
9
|
-
import { SupabasePageStore } from "./supabase-store.ts";
|
|
10
|
-
export declare function createSupabaseStores(db: SupabaseClient, config: ResolvedConfig): {
|
|
11
|
-
paths: SupabasePathIndex;
|
|
12
|
-
pages: SupabasePageStore;
|
|
13
|
-
entries: SupabaseEntryStore;
|
|
14
|
-
assets: SupabaseAssetStore;
|
|
15
|
-
members: SupabaseMemberStore;
|
|
16
|
-
published: SupabasePublishedStore;
|
|
17
|
-
};
|
|
18
|
-
/** What createSmoodlySite takes, read off the config. */
|
|
19
|
-
export declare function siteOptions(config: ResolvedConfig, stores: SiteOptions["stores"]): SiteOptions;
|
package/dist/bind.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { SupabaseAssetStore } from "./supabase-asset-store.js";
|
|
2
|
-
import { SupabaseEntryStore } from "./supabase-entry-store.js";
|
|
3
|
-
import { SupabaseMemberStore } from "./supabase-member-store.js";
|
|
4
|
-
import { SupabasePathIndex } from "./supabase-path-index.js";
|
|
5
|
-
import { SupabasePublishedStore } from "./supabase-published-store.js";
|
|
6
|
-
import { SupabasePageStore } from "./supabase-store.js";
|
|
7
|
-
export function createSupabaseStores(db, config) {
|
|
8
|
-
const { sections, elements, collections, globals } = config.registry;
|
|
9
|
-
const locales = config.locales;
|
|
10
|
-
// ONE path index for both stores: pages and entries share the URL space.
|
|
11
|
-
const paths = new SupabasePathIndex(db, config.anchors);
|
|
12
|
-
const entries = new SupabaseEntryStore(db, collections, { paths, locales, globals, elements: elements });
|
|
13
|
-
const pages = new SupabasePageStore(db, {
|
|
14
|
-
sections: sections, elements: elements, entries, paths, locales,
|
|
15
|
-
custom: config.custom,
|
|
16
|
-
homePageSlug: config.homePageSlug,
|
|
17
|
-
addresses: config.addresses,
|
|
18
|
-
tree: config.pages?.tree,
|
|
19
|
-
});
|
|
20
|
-
return {
|
|
21
|
-
paths, pages, entries, assets: new SupabaseAssetStore(db), members: new SupabaseMemberStore(db),
|
|
22
|
-
published: new SupabasePublishedStore(db, collections),
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
/** What createSmoodlySite takes, read off the config. */
|
|
26
|
-
export function siteOptions(config, stores) {
|
|
27
|
-
const { sections, elements, collections, globals, pages } = config.registry;
|
|
28
|
-
return {
|
|
29
|
-
stores, collections, globals,
|
|
30
|
-
// defineConfig's checks guarantee a section and an element carry `fields`.
|
|
31
|
-
sections: sections, elements: elements,
|
|
32
|
-
locales: config.locales, homePageSlug: config.homePageSlug, styles: config.styles, custom: config.custom, pages,
|
|
33
|
-
};
|
|
34
|
-
}
|
package/dist/cli/add-admin.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { MemberStore } from "../member-store.ts";
|
|
2
|
-
/** `adminUrl`: where an invite link lands — the site's admin address. */
|
|
3
|
-
export type AddAdminArgs = {
|
|
4
|
-
email: string;
|
|
5
|
-
adminUrl?: string;
|
|
6
|
-
};
|
|
7
|
-
export declare function runAddAdmin(args: AddAdminArgs, out: (line: string) => void, deps?: {
|
|
8
|
-
cwd?: string;
|
|
9
|
-
members?: MemberStore;
|
|
10
|
-
env?: Record<string, string | undefined>;
|
|
11
|
-
}): Promise<number>;
|
package/dist/cli/add-admin.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// `smoodly add-admin <email>` (spec 2026-09-30 tester findings §1): the first
|
|
2
|
-
// admin of a project the installer did not make — after an import, say.
|
|
3
|
-
import { SupabaseMemberStore } from "../supabase-member-store.js";
|
|
4
|
-
import { addAdmin } from "../content/content-api.js";
|
|
5
|
-
import { connectFromEnv } from "./space-io.js";
|
|
6
|
-
export async function runAddAdmin(args, out, deps = {}) {
|
|
7
|
-
const members = deps.members ?? new SupabaseMemberStore(connectFromEnv(deps.cwd ?? process.cwd()).db);
|
|
8
|
-
// Read after connectFromEnv: it loads the app's .env files.
|
|
9
|
-
const password = (deps.env ?? process.env).SMOODLY_ADMIN_PASSWORD;
|
|
10
|
-
// An invite link has to land on the admin, which finishes the sign-in: --admin-url, else SITE_URL's /admin.
|
|
11
|
-
const siteUrl = (deps.env ?? process.env).SITE_URL;
|
|
12
|
-
const redirectTo = args.adminUrl ?? (siteUrl ? `${siteUrl.replace(/\/+$/, "")}/admin` : undefined);
|
|
13
|
-
const { invited } = await addAdmin(members, args.email, password !== undefined ? { password } : { redirectTo });
|
|
14
|
-
if (password !== undefined)
|
|
15
|
-
out(`${args.email} is an admin. Sign in at your admin address with that password (an account that already existed keeps its own).`);
|
|
16
|
-
else if (invited) {
|
|
17
|
-
out(`Invited ${args.email} as an admin: the mail has the sign-in link.`);
|
|
18
|
-
out(redirectTo
|
|
19
|
-
? `The link lands on ${redirectTo}, which must be in the Auth project's redirect URLs.`
|
|
20
|
-
: "No --admin-url and no SITE_URL: the link lands on the Auth project's Site URL. If that is not the admin, run it again with --admin-url <the admin's address>, or set SMOODLY_ADMIN_PASSWORD.");
|
|
21
|
-
}
|
|
22
|
-
else
|
|
23
|
-
out(`${args.email} already had an account and is now an admin.`);
|
|
24
|
-
return 0;
|
|
25
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// packages/smoodly/src/cli/load-collections.ts
|
|
2
|
-
// Loads the app's `smoodly/collections.ts` — TypeScript, through tsx's
|
|
3
|
-
// import API, under the app's own tsconfig so its `@/` alias resolves.
|
|
4
|
-
// The barrel and not `smoodly/config.ts`: the collections are all a
|
|
5
|
-
// migration needs, and the barrel is what the config registers in both
|
|
6
|
-
// starters. (Since the registration split the config imports no
|
|
7
|
-
// component either; a command that needs the whole registry may load it.)
|
|
8
|
-
import { existsSync } from "node:fs";
|
|
9
|
-
import { join } from "node:path";
|
|
10
|
-
import { pathToFileURL } from "node:url";
|
|
11
|
-
import { tsImport } from "tsx/esm/api";
|
|
12
|
-
export async function loadCollections(file, cwd) {
|
|
13
|
-
if (!existsSync(file)) {
|
|
14
|
-
throw new Error(`smoodly: ${file} does not exist — pass --collections <file> for the module that exports \`collections\`.`);
|
|
15
|
-
}
|
|
16
|
-
const tsconfig = join(cwd, "tsconfig.json");
|
|
17
|
-
const mod = (await tsImport(pathToFileURL(file).href, {
|
|
18
|
-
parentURL: import.meta.url,
|
|
19
|
-
...(existsSync(tsconfig) ? { tsconfig } : {}),
|
|
20
|
-
}));
|
|
21
|
-
const list = mod.collections;
|
|
22
|
-
const isCollection = (c) => typeof c === "object" && c !== null && typeof c.name === "string";
|
|
23
|
-
if (!Array.isArray(list) || !list.every(isCollection)) {
|
|
24
|
-
throw new Error(`smoodly: ${file} must export \`collections\`, the list of smoodly.collection() definitions the config registers.`);
|
|
25
|
-
}
|
|
26
|
-
return list;
|
|
27
|
-
}
|
package/dist/cli/migrate.d.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { CollectionSchema } from "../collections.ts";
|
|
2
|
-
import { type SchemaRead } from "../schema-read.ts";
|
|
3
|
-
import { type MigrationFile, type MigratePlan } from "../migrations.ts";
|
|
4
|
-
export type MigrateArgs = {
|
|
5
|
-
check: boolean;
|
|
6
|
-
collections: string;
|
|
7
|
-
migrations: string;
|
|
8
|
-
};
|
|
9
|
-
export declare const DEFAULT_COLLECTIONS = "smoodly/collections.ts";
|
|
10
|
-
/** The Astro starter keeps the setup under src/ (plan 2026-10-06 astro adapter 3); the default follows it when the Next path is absent. */
|
|
11
|
-
export declare function collectionsFile(cwd: string, given: string, exists?: (p: string) => boolean): string;
|
|
12
|
-
/** The folder shipped in the package: `../../migrations/` from dist/cli/ and from src/cli/ alike. */
|
|
13
|
-
export declare const PACKAGE_MIGRATIONS_DIR: string;
|
|
14
|
-
export declare const NO_FOLDER: (dir: string) => string;
|
|
15
|
-
export declare const NEXT_STEP = "Next: apply it \u2014 `supabase db push` (hosted) or `supabase migration up` (local).";
|
|
16
|
-
export declare const upToDate: (version: number, n: number) => string;
|
|
17
|
-
export declare const KEY_NOT_CHECKED = "Key not checked: SMOODLY_URL and SMOODLY_SECRET_KEY are not both set here.";
|
|
18
|
-
export declare const keyChecked: (version: number) => string;
|
|
19
|
-
export declare const modifiedMessage: (name: string) => string;
|
|
20
|
-
export declare function readSqlFiles(dir: string): Promise<MigrationFile[]>;
|
|
21
|
-
/** One line per thing the plan does; "Pending" wording under --check. */
|
|
22
|
-
export declare function describePlan(plan: MigratePlan, check: boolean): string[];
|
|
23
|
-
export type MigrateDeps = {
|
|
24
|
-
cwd?: string;
|
|
25
|
-
/** Test seam: replaces the tsx loader. */
|
|
26
|
-
load?: (file: string, cwd: string) => Promise<CollectionSchema<any>[]>;
|
|
27
|
-
now?: () => Date;
|
|
28
|
-
/** The env the key check reads; `.env.local` and `.env` fill what it lacks, as Next does. */
|
|
29
|
-
env?: Record<string, string | undefined>;
|
|
30
|
-
/** Test seam: replaces the database read behind the key check. */
|
|
31
|
-
readKey?: (env: Record<string, string | undefined>) => Promise<SchemaRead>;
|
|
32
|
-
/** Test seam: the delivery rows behind the site's document stamp (DESIGN §3); default: the app's config, loaded, against the key's space. */
|
|
33
|
-
delivery?: (env: Record<string, string | undefined>, cwd: string) => Promise<{
|
|
34
|
-
behind: number;
|
|
35
|
-
total: number;
|
|
36
|
-
}>;
|
|
37
|
-
};
|
|
38
|
-
/** The delivery line of `--check` (DESIGN §3, the document stamp): a count with the one command to run, never a verdict. */
|
|
39
|
-
export declare const deliveryLine: (d: {
|
|
40
|
-
behind: number;
|
|
41
|
-
total: number;
|
|
42
|
-
}) => string;
|
|
43
|
-
export declare function runMigrate(args: MigrateArgs, out: (line: string) => void, deps?: MigrateDeps): Promise<number>;
|