@guard-rail/core 0.9.0 → 0.9.1
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 -2
- package/dist/email/console.d.ts +24 -0
- package/dist/email/console.js +30 -0
- package/dist/email/console.js.map +1 -0
- package/dist/index.client.d.ts +2 -1
- package/dist/index.client.js +5 -0
- package/dist/index.client.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/scripts/postinstall.mjs +2 -2
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ pnpm add @guard-rail/core @supabase/ssr @supabase/supabase-js
|
|
|
25
25
|
|
|
26
26
|
Set up the database:
|
|
27
27
|
|
|
28
|
-
1. Run `
|
|
28
|
+
1. Run `pnpm exec guardrail-init-db --push`. It copies the package's migration(s)
|
|
29
29
|
into your own project's `supabase/migrations/` (skipping any already
|
|
30
30
|
there — safe to re-run after upgrading), runs `supabase init` if needed,
|
|
31
31
|
adds `guardrail` to `config.toml`'s exposed schemas for local dev, and
|
|
@@ -273,6 +273,18 @@ accounts and links, and to check membership for "Forgot password?". The Resend
|
|
|
273
273
|
key belongs in the site's server environment too; a *sending-only* key limited
|
|
274
274
|
to your domain is plenty.
|
|
275
275
|
|
|
276
|
+
**While developing,** you don't need a mail provider: `consoleEmails()` prints
|
|
277
|
+
each invite and reset link to your terminal instead of sending it, so the whole
|
|
278
|
+
flow can be tried locally. It refuses in production — a link is as good as a
|
|
279
|
+
password for choosing one, so it doesn't belong in a log — and tells the admin
|
|
280
|
+
what to configure instead:
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
...(process.env.GUARDRAIL_EMAIL_FROM
|
|
284
|
+
? resendEmails({ from: process.env.GUARDRAIL_EMAIL_FROM, siteName: "My Site" })
|
|
285
|
+
: consoleEmails()),
|
|
286
|
+
```
|
|
287
|
+
|
|
276
288
|
**Your own wording or provider.** `render` and `renderReset` replace the default
|
|
277
289
|
emails; any other provider just needs an `onInvite` and `onPasswordReset` — each
|
|
278
290
|
receives the same event, including the `link`:
|
|
@@ -302,7 +314,7 @@ as letting anyone make themselves an admin. Seed the first admin with the
|
|
|
302
314
|
bundled command instead of hand-writing SQL:
|
|
303
315
|
|
|
304
316
|
```bash
|
|
305
|
-
SERVICE_KEY=...
|
|
317
|
+
SERVICE_KEY=... pnpm exec guardrail-seed-user --email=you@example.com --password=...
|
|
306
318
|
```
|
|
307
319
|
|
|
308
320
|
`--site-id` defaults to `GUARDRAIL_SITE_ID` from your `.env.local` (and
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { GRInviteEvent, GRPasswordResetEvent } from '../core/adapter-types.js';
|
|
2
|
+
import 'react';
|
|
3
|
+
import '../core/types.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A stand-in for resendEmails() while you're developing: nothing is sent, and
|
|
7
|
+
* each invite or password-reset link is printed to the server's terminal
|
|
8
|
+
* instead, so the whole flow can be tried locally with no mail provider.
|
|
9
|
+
*
|
|
10
|
+
* ...(process.env.GUARDRAIL_EMAIL_FROM
|
|
11
|
+
* ? resendEmails({ from: process.env.GUARDRAIL_EMAIL_FROM, siteName: "My Site" })
|
|
12
|
+
* : consoleEmails()),
|
|
13
|
+
*
|
|
14
|
+
* Refuses in production, with an error that reaches the admin who sent the
|
|
15
|
+
* invite. A link is as good as a password for choosing one, so it doesn't
|
|
16
|
+
* belong in a production log — a deployed site without email configured should
|
|
17
|
+
* say so rather than quietly writing them there.
|
|
18
|
+
*/
|
|
19
|
+
declare function consoleEmails(): {
|
|
20
|
+
onInvite: (event: GRInviteEvent) => void;
|
|
21
|
+
onPasswordReset: (event: GRPasswordResetEvent) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export { consoleEmails };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function consoleEmails() {
|
|
2
|
+
const refuseInProduction = () => {
|
|
3
|
+
if (process.env.NODE_ENV === "production") {
|
|
4
|
+
throw new Error(
|
|
5
|
+
`no email provider is configured, so this can't be sent \u2014 set GUARDRAIL_EMAIL_FROM and RESEND_API_KEY (see the README's "Passwords, invites and resets").`
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
return {
|
|
10
|
+
onInvite: (event) => {
|
|
11
|
+
refuseInProduction();
|
|
12
|
+
const what = event.isNewUser === false ? `${event.email} already has an account \u2014 they'd be told they've been added` : `Invite for ${event.email} (${event.role})`;
|
|
13
|
+
console.log(`
|
|
14
|
+
[guardrail] ${what}. Nothing was emailed (development only):
|
|
15
|
+
${event.link ?? "(no link: this auth adapter can't create one)"}
|
|
16
|
+
`);
|
|
17
|
+
},
|
|
18
|
+
onPasswordReset: (event) => {
|
|
19
|
+
refuseInProduction();
|
|
20
|
+
console.log(`
|
|
21
|
+
[guardrail] Password reset for ${event.email}. Nothing was emailed (development only):
|
|
22
|
+
${event.link}
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
consoleEmails
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=console.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/email/console.ts"],"sourcesContent":["import type { GRInviteEvent, GRPasswordResetEvent } from \"../core/adapter-types\";\n\n/**\n * A stand-in for resendEmails() while you're developing: nothing is sent, and\n * each invite or password-reset link is printed to the server's terminal\n * instead, so the whole flow can be tried locally with no mail provider.\n *\n * ...(process.env.GUARDRAIL_EMAIL_FROM\n * ? resendEmails({ from: process.env.GUARDRAIL_EMAIL_FROM, siteName: \"My Site\" })\n * : consoleEmails()),\n *\n * Refuses in production, with an error that reaches the admin who sent the\n * invite. A link is as good as a password for choosing one, so it doesn't\n * belong in a production log — a deployed site without email configured should\n * say so rather than quietly writing them there.\n */\nexport function consoleEmails() {\n const refuseInProduction = () => {\n if (process.env.NODE_ENV === \"production\") {\n throw new Error(\n \"no email provider is configured, so this can't be sent — set GUARDRAIL_EMAIL_FROM and RESEND_API_KEY (see the README's \\\"Passwords, invites and resets\\\").\",\n );\n }\n };\n\n return {\n onInvite: (event: GRInviteEvent): void => {\n refuseInProduction();\n const what =\n event.isNewUser === false\n ? `${event.email} already has an account — they'd be told they've been added`\n : `Invite for ${event.email} (${event.role})`;\n console.log(`\\n[guardrail] ${what}. Nothing was emailed (development only):\\n ${event.link ?? \"(no link: this auth adapter can't create one)\"}\\n`);\n },\n onPasswordReset: (event: GRPasswordResetEvent): void => {\n refuseInProduction();\n console.log(`\\n[guardrail] Password reset for ${event.email}. Nothing was emailed (development only):\\n ${event.link}\\n`);\n },\n };\n}\n"],"mappings":"AAgBO,SAAS,gBAAgB;AAC9B,QAAM,qBAAqB,MAAM;AAC/B,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,CAAC,UAA+B;AACxC,yBAAmB;AACnB,YAAM,OACJ,MAAM,cAAc,QAChB,GAAG,MAAM,KAAK,qEACd,cAAc,MAAM,KAAK,KAAK,MAAM,IAAI;AAC9C,cAAQ,IAAI;AAAA,cAAiB,IAAI;AAAA,IAAgD,MAAM,QAAQ,+CAA+C;AAAA,CAAI;AAAA,IACpJ;AAAA,IACA,iBAAiB,CAAC,UAAsC;AACtD,yBAAmB;AACnB,cAAQ,IAAI;AAAA,iCAAoC,MAAM,KAAK;AAAA,IAAgD,MAAM,IAAI;AAAA,CAAI;AAAA,IAC3H;AAAA,EACF;AACF;","names":[]}
|
package/dist/index.client.d.ts
CHANGED
|
@@ -20,5 +20,6 @@ declare const isEditor: (..._args: unknown[]) => never;
|
|
|
20
20
|
declare const canEdit: (..._args: unknown[]) => never;
|
|
21
21
|
declare const resendInvite: (..._args: unknown[]) => never;
|
|
22
22
|
declare const resendEmails: (..._args: unknown[]) => never;
|
|
23
|
+
declare const consoleEmails: (..._args: unknown[]) => never;
|
|
23
24
|
|
|
24
|
-
export { GRepeater, canEdit, configureGuardrail, getFieldValue, getRepeaterItemBySlug, isAdmin, isEditor, listRepeaterItems, resendEmails, resendInvite, withGuardrail };
|
|
25
|
+
export { GRepeater, canEdit, configureGuardrail, consoleEmails, getFieldValue, getRepeaterItemBySlug, isAdmin, isEditor, listRepeaterItems, resendEmails, resendInvite, withGuardrail };
|
package/dist/index.client.js
CHANGED
|
@@ -69,12 +69,17 @@ const resendEmails = serverOnly(
|
|
|
69
69
|
"resendEmails()",
|
|
70
70
|
"Spread it into withGuardrail(), which runs in your root layout."
|
|
71
71
|
);
|
|
72
|
+
const consoleEmails = serverOnly(
|
|
73
|
+
"consoleEmails()",
|
|
74
|
+
"Spread it into withGuardrail(), which runs in your root layout."
|
|
75
|
+
);
|
|
72
76
|
export {
|
|
73
77
|
GRail,
|
|
74
78
|
GRepeater,
|
|
75
79
|
addRepeaterItem,
|
|
76
80
|
canEdit,
|
|
77
81
|
configureGuardrail,
|
|
82
|
+
consoleEmails,
|
|
78
83
|
createAssetUpload,
|
|
79
84
|
forgotPasswordAction,
|
|
80
85
|
getFieldValue,
|
package/dist/index.client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.client.ts"],"sourcesContent":["// Client-graph entry. `import ... from \"@guard-rail/core\"` resolves here from a\n// Client Component (see \"exports\" in package.json) and to ./index from a\n// Server Component, so an app uses one import path everywhere.\n//\n// Nothing server-only may be imported here — this is bundled for the browser.\n// Server Actions are fine: a \"use server\" module is replaced by references in\n// the client bundle, which is what lets an app build its own team/repeater UI\n// in a Client Component.\n\nexport { GRail } from \"./react/GRail/universal\";\nexport { useGRail } from \"./react/Provider\";\n\nexport {\n listTeam,\n inviteMember,\n updateMemberRole,\n removeMember,\n createAssetUpload,\n listAssets,\n setPasswordAction,\n skipSetPasswordAction,\n forgotPasswordAction,\n sendPasswordResetAction,\n setFieldValue,\n} from \"./server/actions\";\nexport {\n addRepeaterItem,\n removeRepeaterItem,\n reorderRepeaterItems,\n} from \"./server/repeaterActions\";\n\n/**\n * Stand-ins for the server-only exports, so importing one from a Client\n * Component fails with an explanation instead of an undefined-is-not-a-function\n * deep in a render. Also what a tool that doesn't set the \"react-server\"\n * condition (a test runner, a plain Node script) gets from the package root —\n * `@guard-rail/core/server` is the explicit path to the real ones there.\n */\nfunction serverOnly(name: string, hint: string) {\n return (..._args: unknown[]): never => {\n throw new Error(\n `Guardrail: ${name} only works in a Server Component. ${hint} ` +\n `(If this isn't a Client Component, your tooling may not set the ` +\n `\"react-server\" condition — import from \"@guard-rail/core/server\" instead.)`,\n );\n };\n}\n\nexport const withGuardrail = serverOnly(\n \"withGuardrail()\",\n \"Call it in your root layout, which is a Server Component.\",\n);\nexport const configureGuardrail = serverOnly(\n \"configureGuardrail()\",\n \"Configuration is applied by withGuardrail() in your root layout.\",\n);\nexport const GRepeater = serverOnly(\n \"<GRepeater>\",\n \"Render it in a Server Component and pass it into this one as children or a prop.\",\n);\nexport const listRepeaterItems = serverOnly(\n \"listRepeaterItems()\",\n \"Read repeater items in a Server Component and pass them down.\",\n);\nexport const getRepeaterItemBySlug = serverOnly(\n \"getRepeaterItemBySlug()\",\n \"Resolve the item in a Server Component (your [slug]/page.tsx) and pass it down.\",\n);\nexport const getFieldValue = serverOnly(\n \"getFieldValue()\",\n \"Read the value in a Server Component and pass it down as a prop.\",\n);\nexport const isAdmin = serverOnly(\n \"isAdmin()\",\n \"Call it inside your own Server Action to authorize it; in a Client Component, read useGRail().role to decide what to show.\",\n);\nexport const isEditor = serverOnly(\n \"isEditor()\",\n \"Call it inside your own Server Action to authorize it; in a Client Component, read useGRail().role to decide what to show.\",\n);\nexport const canEdit = serverOnly(\n \"canEdit()\",\n \"Call it in a Server Component; in a Client Component, read `canEdit` from useGRail().\",\n);\nexport const resendInvite = serverOnly(\n \"resendInvite()\",\n \"Pass it as onInvite in withGuardrail(), which runs in your root layout.\",\n);\nexport const resendEmails = serverOnly(\n \"resendEmails()\",\n \"Spread it into withGuardrail(), which runs in your root layout.\",\n);\n\nexport type { GRepeaterProps, RepeaterItemProps } from \"./react/Repeater\";\nexport type {\n ResendInviteOptions,\n ResendEmailOptions,\n ResendInviteContent,\n ResendInviteTemplateEvent,\n ResendResetTemplateEvent,\n} from \"./email/resend\";\nexport type {\n GRState,\n GRRole,\n GRMember,\n GRViewer,\n GRAsset,\n GRRepeaterItem,\n ActionState,\n SetPasswordState,\n OverrideRow,\n OverrideValue,\n OverrideType,\n PolymorphicProps,\n HTMLKeys,\n} from \"./core/types\";\nexport type {\n GRConfig,\n GRPrefetch,\n GRMembershipAdapter,\n GRInviteEvent,\n GRStorageAdapter,\n GRUploadTarget,\n GRRepeaterAdapter,\n GRDBAdapter,\n GRAuthAdapter,\n GRSession,\n GRStorageRow,\n AuthResult,\n AuthRedirectParams,\n GRPasswordResetEvent,\n} from \"./core/adapter-types\";\n"],"mappings":"AASA,SAAS,aAAa;AACtB,SAAS,gBAAgB;AAEzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AASP,SAAS,WAAW,MAAc,MAAc;AAC9C,SAAO,IAAI,UAA4B;AACrC,UAAM,IAAI;AAAA,MACR,cAAc,IAAI,sCAAsC,IAAI;AAAA,IAG9D;AAAA,EACF;AACF;AAEO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AACF;AACO,MAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AACF;AACO,MAAM,YAAY;AAAA,EACvB;AAAA,EACA;AACF;AACO,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AACF;AACO,MAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AACF;AACO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AACF;AACO,MAAM,UAAU;AAAA,EACrB;AAAA,EACA;AACF;AACO,MAAM,WAAW;AAAA,EACtB;AAAA,EACA;AACF;AACO,MAAM,UAAU;AAAA,EACrB;AAAA,EACA;AACF;AACO,MAAM,eAAe;AAAA,EAC1B;AAAA,EACA;AACF;AACO,MAAM,eAAe;AAAA,EAC1B;AAAA,EACA;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.client.ts"],"sourcesContent":["// Client-graph entry. `import ... from \"@guard-rail/core\"` resolves here from a\n// Client Component (see \"exports\" in package.json) and to ./index from a\n// Server Component, so an app uses one import path everywhere.\n//\n// Nothing server-only may be imported here — this is bundled for the browser.\n// Server Actions are fine: a \"use server\" module is replaced by references in\n// the client bundle, which is what lets an app build its own team/repeater UI\n// in a Client Component.\n\nexport { GRail } from \"./react/GRail/universal\";\nexport { useGRail } from \"./react/Provider\";\n\nexport {\n listTeam,\n inviteMember,\n updateMemberRole,\n removeMember,\n createAssetUpload,\n listAssets,\n setPasswordAction,\n skipSetPasswordAction,\n forgotPasswordAction,\n sendPasswordResetAction,\n setFieldValue,\n} from \"./server/actions\";\nexport {\n addRepeaterItem,\n removeRepeaterItem,\n reorderRepeaterItems,\n} from \"./server/repeaterActions\";\n\n/**\n * Stand-ins for the server-only exports, so importing one from a Client\n * Component fails with an explanation instead of an undefined-is-not-a-function\n * deep in a render. Also what a tool that doesn't set the \"react-server\"\n * condition (a test runner, a plain Node script) gets from the package root —\n * `@guard-rail/core/server` is the explicit path to the real ones there.\n */\nfunction serverOnly(name: string, hint: string) {\n return (..._args: unknown[]): never => {\n throw new Error(\n `Guardrail: ${name} only works in a Server Component. ${hint} ` +\n `(If this isn't a Client Component, your tooling may not set the ` +\n `\"react-server\" condition — import from \"@guard-rail/core/server\" instead.)`,\n );\n };\n}\n\nexport const withGuardrail = serverOnly(\n \"withGuardrail()\",\n \"Call it in your root layout, which is a Server Component.\",\n);\nexport const configureGuardrail = serverOnly(\n \"configureGuardrail()\",\n \"Configuration is applied by withGuardrail() in your root layout.\",\n);\nexport const GRepeater = serverOnly(\n \"<GRepeater>\",\n \"Render it in a Server Component and pass it into this one as children or a prop.\",\n);\nexport const listRepeaterItems = serverOnly(\n \"listRepeaterItems()\",\n \"Read repeater items in a Server Component and pass them down.\",\n);\nexport const getRepeaterItemBySlug = serverOnly(\n \"getRepeaterItemBySlug()\",\n \"Resolve the item in a Server Component (your [slug]/page.tsx) and pass it down.\",\n);\nexport const getFieldValue = serverOnly(\n \"getFieldValue()\",\n \"Read the value in a Server Component and pass it down as a prop.\",\n);\nexport const isAdmin = serverOnly(\n \"isAdmin()\",\n \"Call it inside your own Server Action to authorize it; in a Client Component, read useGRail().role to decide what to show.\",\n);\nexport const isEditor = serverOnly(\n \"isEditor()\",\n \"Call it inside your own Server Action to authorize it; in a Client Component, read useGRail().role to decide what to show.\",\n);\nexport const canEdit = serverOnly(\n \"canEdit()\",\n \"Call it in a Server Component; in a Client Component, read `canEdit` from useGRail().\",\n);\nexport const resendInvite = serverOnly(\n \"resendInvite()\",\n \"Pass it as onInvite in withGuardrail(), which runs in your root layout.\",\n);\nexport const resendEmails = serverOnly(\n \"resendEmails()\",\n \"Spread it into withGuardrail(), which runs in your root layout.\",\n);\nexport const consoleEmails = serverOnly(\n \"consoleEmails()\",\n \"Spread it into withGuardrail(), which runs in your root layout.\",\n);\n\nexport type { GRepeaterProps, RepeaterItemProps } from \"./react/Repeater\";\nexport type {\n ResendInviteOptions,\n ResendEmailOptions,\n ResendInviteContent,\n ResendInviteTemplateEvent,\n ResendResetTemplateEvent,\n} from \"./email/resend\";\nexport type {\n GRState,\n GRRole,\n GRMember,\n GRViewer,\n GRAsset,\n GRRepeaterItem,\n ActionState,\n SetPasswordState,\n OverrideRow,\n OverrideValue,\n OverrideType,\n PolymorphicProps,\n HTMLKeys,\n} from \"./core/types\";\nexport type {\n GRConfig,\n GRPrefetch,\n GRMembershipAdapter,\n GRInviteEvent,\n GRStorageAdapter,\n GRUploadTarget,\n GRRepeaterAdapter,\n GRDBAdapter,\n GRAuthAdapter,\n GRSession,\n GRStorageRow,\n AuthResult,\n AuthRedirectParams,\n GRPasswordResetEvent,\n} from \"./core/adapter-types\";\n"],"mappings":"AASA,SAAS,aAAa;AACtB,SAAS,gBAAgB;AAEzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AASP,SAAS,WAAW,MAAc,MAAc;AAC9C,SAAO,IAAI,UAA4B;AACrC,UAAM,IAAI;AAAA,MACR,cAAc,IAAI,sCAAsC,IAAI;AAAA,IAG9D;AAAA,EACF;AACF;AAEO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AACF;AACO,MAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AACF;AACO,MAAM,YAAY;AAAA,EACvB;AAAA,EACA;AACF;AACO,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AACF;AACO,MAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AACF;AACO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AACF;AACO,MAAM,UAAU;AAAA,EACrB;AAAA,EACA;AACF;AACO,MAAM,WAAW;AAAA,EACtB;AAAA,EACA;AACF;AACO,MAAM,UAAU;AAAA,EACrB;AAAA,EACA;AACF;AACO,MAAM,eAAe;AAAA,EAC1B;AAAA,EACA;AACF;AACO,MAAM,eAAe;AAAA,EAC1B;AAAA,EACA;AACF;AACO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AACF;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { getRepeaterItemBySlug, listRepeaterItems } from './server/repeaterData.
|
|
|
7
7
|
export { getFieldValue } from './server/fieldData.js';
|
|
8
8
|
export { canEdit, isAdmin, isEditor } from './server/access.js';
|
|
9
9
|
export { ResendEmailOptions, ResendInviteContent, ResendInviteOptions, ResendInviteTemplateEvent, ResendResetTemplateEvent, resendEmails, resendInvite } from './email/resend.js';
|
|
10
|
+
export { consoleEmails } from './email/console.js';
|
|
10
11
|
export { addRepeaterItem, removeRepeaterItem, reorderRepeaterItems } from './server/repeaterActions.js';
|
|
11
12
|
export { useGRail } from './react/Provider.js';
|
|
12
13
|
export { ActionState, GRAsset, GRMember, GRRepeaterItem, GRRole, GRState, GRViewer, HTMLKeys, OverrideRow, OverrideType, OverrideValue, PolymorphicProps, SetPasswordState } from './core/types.js';
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import { getFieldValue } from "./server/fieldData";
|
|
23
23
|
import { isAdmin, isEditor, canEdit } from "./server/access";
|
|
24
24
|
import { resendInvite, resendEmails } from "./email/resend";
|
|
25
|
+
import { consoleEmails } from "./email/console";
|
|
25
26
|
import {
|
|
26
27
|
addRepeaterItem,
|
|
27
28
|
removeRepeaterItem,
|
|
@@ -34,6 +35,7 @@ export {
|
|
|
34
35
|
addRepeaterItem,
|
|
35
36
|
canEdit,
|
|
36
37
|
configureGuardrail,
|
|
38
|
+
consoleEmails,
|
|
37
39
|
createAssetUpload,
|
|
38
40
|
forgotPasswordAction,
|
|
39
41
|
getFieldValue,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Server-safe entry. Client components are reached through the files that\n// carry their own \"use client\" directive, so importing this from a Server\n// Component does not pull the editor into the client bundle.\nexport { withGuardrail } from \"./server/wrapper\";\n\n// Team management and the set-password step, exported so an app can build\n// its own UI instead of using the bundled drawer / sign-in bar.\nexport {\n listTeam,\n inviteMember,\n updateMemberRole,\n removeMember,\n createAssetUpload,\n listAssets,\n setPasswordAction,\n skipSetPasswordAction,\n forgotPasswordAction,\n sendPasswordResetAction,\n setFieldValue,\n} from \"./server/actions\";\nexport { GRail } from \"./react/GRail\";\nexport { GRepeater } from \"./react/Repeater\";\nexport type { GRepeaterProps, RepeaterItemProps } from \"./react/Repeater\";\nexport { configureGuardrail } from \"./core/config\";\nexport {\n listRepeaterItems,\n getRepeaterItemBySlug,\n} from \"./server/repeaterData\";\nexport { getFieldValue } from \"./server/fieldData\";\n// Role / edit-mode checks for a custom admin UI and the Server Actions behind\n// it. Plain server functions, not actions — see access.ts for why.\nexport { isAdmin, isEditor, canEdit } from \"./server/access\";\n// Invite delivery through Resend, as an onInvite handler — see email/resend.ts.\nexport { resendInvite, resendEmails } from \"./email/resend\";\nexport type {\n ResendInviteOptions,\n ResendEmailOptions,\n ResendInviteContent,\n ResendInviteTemplateEvent,\n ResendResetTemplateEvent,\n} from \"./email/resend\";\n// Mutations, exported so an app can build its own add/remove/reorder UI\n// instead of the bundled chrome — same rationale as the team actions above.\nexport {\n addRepeaterItem,\n removeRepeaterItem,\n reorderRepeaterItems,\n} from \"./server/repeaterActions\";\nexport { useGRail } from \"./react/Provider\";\n\nexport type {\n GRState,\n GRRole,\n GRMember,\n GRViewer,\n GRAsset,\n GRRepeaterItem,\n ActionState,\n SetPasswordState,\n OverrideRow,\n OverrideValue,\n OverrideType,\n PolymorphicProps,\n HTMLKeys,\n} from \"./core/types\";\nexport type {\n GRConfig,\n GRPrefetch,\n GRMembershipAdapter,\n GRInviteEvent,\n GRStorageAdapter,\n GRUploadTarget,\n GRRepeaterAdapter,\n GRDBAdapter,\n GRAuthAdapter,\n GRSession,\n GRStorageRow,\n AuthResult,\n AuthRedirectParams,\n GRPasswordResetEvent,\n} from \"./core/adapter-types\";\n"],"mappings":"AAGA,SAAS,qBAAqB;AAI9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,iBAAiB;AAE1B,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB;AAG9B,SAAS,SAAS,UAAU,eAAe;AAE3C,SAAS,cAAc,oBAAoB;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Server-safe entry. Client components are reached through the files that\n// carry their own \"use client\" directive, so importing this from a Server\n// Component does not pull the editor into the client bundle.\nexport { withGuardrail } from \"./server/wrapper\";\n\n// Team management and the set-password step, exported so an app can build\n// its own UI instead of using the bundled drawer / sign-in bar.\nexport {\n listTeam,\n inviteMember,\n updateMemberRole,\n removeMember,\n createAssetUpload,\n listAssets,\n setPasswordAction,\n skipSetPasswordAction,\n forgotPasswordAction,\n sendPasswordResetAction,\n setFieldValue,\n} from \"./server/actions\";\nexport { GRail } from \"./react/GRail\";\nexport { GRepeater } from \"./react/Repeater\";\nexport type { GRepeaterProps, RepeaterItemProps } from \"./react/Repeater\";\nexport { configureGuardrail } from \"./core/config\";\nexport {\n listRepeaterItems,\n getRepeaterItemBySlug,\n} from \"./server/repeaterData\";\nexport { getFieldValue } from \"./server/fieldData\";\n// Role / edit-mode checks for a custom admin UI and the Server Actions behind\n// it. Plain server functions, not actions — see access.ts for why.\nexport { isAdmin, isEditor, canEdit } from \"./server/access\";\n// Invite delivery through Resend, as an onInvite handler — see email/resend.ts.\nexport { resendInvite, resendEmails } from \"./email/resend\";\nexport { consoleEmails } from \"./email/console\";\nexport type {\n ResendInviteOptions,\n ResendEmailOptions,\n ResendInviteContent,\n ResendInviteTemplateEvent,\n ResendResetTemplateEvent,\n} from \"./email/resend\";\n// Mutations, exported so an app can build its own add/remove/reorder UI\n// instead of the bundled chrome — same rationale as the team actions above.\nexport {\n addRepeaterItem,\n removeRepeaterItem,\n reorderRepeaterItems,\n} from \"./server/repeaterActions\";\nexport { useGRail } from \"./react/Provider\";\n\nexport type {\n GRState,\n GRRole,\n GRMember,\n GRViewer,\n GRAsset,\n GRRepeaterItem,\n ActionState,\n SetPasswordState,\n OverrideRow,\n OverrideValue,\n OverrideType,\n PolymorphicProps,\n HTMLKeys,\n} from \"./core/types\";\nexport type {\n GRConfig,\n GRPrefetch,\n GRMembershipAdapter,\n GRInviteEvent,\n GRStorageAdapter,\n GRUploadTarget,\n GRRepeaterAdapter,\n GRDBAdapter,\n GRAuthAdapter,\n GRSession,\n GRStorageRow,\n AuthResult,\n AuthRedirectParams,\n GRPasswordResetEvent,\n} from \"./core/adapter-types\";\n"],"mappings":"AAGA,SAAS,qBAAqB;AAI9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,iBAAiB;AAE1B,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB;AAG9B,SAAS,SAAS,UAAU,eAAe;AAE3C,SAAS,cAAc,oBAAoB;AAC3C,SAAS,qBAAqB;AAU9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gBAAgB;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guard-rail/core",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Lightweight inline content editing for developer-owned Next.js sites.",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"type": "module",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@supabase/ssr": "
|
|
42
|
+
"@supabase/ssr": ">=0.8.0 <1",
|
|
43
43
|
"@supabase/supabase-js": "^2.0.0",
|
|
44
44
|
"next": ">=15",
|
|
45
45
|
"react": ">=19"
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -30,7 +30,7 @@ Guardrail installed. Next steps:
|
|
|
30
30
|
1. Set up the database (skip both if this Supabase project already has
|
|
31
31
|
Guardrail applied for another site — see "Many sites, one Supabase
|
|
32
32
|
project" in the README):
|
|
33
|
-
-
|
|
33
|
+
- pnpm exec guardrail-init-db --push
|
|
34
34
|
- If that project is hosted (not local Docker), also add "guardrail"
|
|
35
35
|
under Settings > API > Exposed schemas in the Supabase dashboard —
|
|
36
36
|
config.toml only covers local dev.
|
|
@@ -42,7 +42,7 @@ Guardrail installed. Next steps:
|
|
|
42
42
|
first admin on a site (needs the service_role key, not the anon key —
|
|
43
43
|
Settings > API in the dashboard; pass it inline, don't store it):
|
|
44
44
|
|
|
45
|
-
SERVICE_KEY=...
|
|
45
|
+
SERVICE_KEY=... pnpm exec guardrail-seed-user \\
|
|
46
46
|
--email=you@example.com --password=... --site-id=my-site
|
|
47
47
|
`);
|
|
48
48
|
}
|