@softr/sdk 0.0.97-alpha.2 → 0.0.98-anonsession.0
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/action.d.ts +1 -45
- package/dist/action.js +1 -37
- package/dist/auth/context.d.ts +4 -1
- package/dist/auth/isomorphic.d.ts +1 -1
- package/dist/auth/isomorphic.js +2 -1
- package/dist/auth/methods/authenticator.js +3 -12
- package/dist/auth/methods/code.js +1 -4
- package/dist/auth/methods/emailCode2fa.js +1 -4
- package/dist/auth/methods/magicLink.js +1 -4
- package/dist/auth/methods/password.js +1 -4
- package/dist/auth/methods/passwordLink.js +1 -4
- package/dist/auth/methods/signup.js +1 -4
- package/dist/auth/methods/social.js +1 -4
- package/dist/auth/permissions.d.ts +0 -9
- package/dist/auth/platform.js +12 -27
- package/dist/default-error-overlay.d.ts +2 -2
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2 -2
- package/dist/package.js +1 -1
- package/dist/pwa.d.ts +2 -2
- package/dist/server.d.ts +1 -2
- package/dist/server.js +1 -2
- package/package.json +1 -1
- package/skills/softr-sdk/SKILL.md +4 -10
- package/skills/softr-sdk/ai/SKILL.md +3 -1
- package/skills/softr-sdk/auth/SKILL.md +1 -1
- package/skills/softr-sdk/charts-and-metrics/SKILL.md +21 -4
- package/skills/softr-sdk/current-user/SKILL.md +16 -3
- package/skills/softr-sdk/file-uploads/SKILL.md +1 -1
- package/skills/softr-sdk/formatting/SKILL.md +1 -1
- package/skills/softr-sdk/integrations/SKILL.md +1 -3
- package/skills/softr-sdk/mcp/SKILL.md +1 -1
- package/skills/softr-sdk/pwa/SKILL.md +1 -1
- package/skills/softr-sdk/record-mutations/SKILL.md +41 -4
- package/skills/softr-sdk/record-queries/SKILL.md +132 -36
- package/skills/softr-sdk/region-visibility/SKILL.md +1 -1
- package/skills/softr-sdk/routes-and-visibility/SKILL.md +2 -2
- package/skills/softr-sdk/workflows/SKILL.md +8 -10
- package/dist/auth/permissions.js +0 -13
- package/dist/core/email.d.ts +0 -48
- package/dist/core/email.js +0 -100
- package/skills/softr-sdk/email/SKILL.md +0 -136
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: email
|
|
3
|
-
description: >-
|
|
4
|
-
Send an email from the app itself, with nothing to connect and no workflow:
|
|
5
|
-
defineEmailAction from @softr/sdk declares who may send it and the fields it
|
|
6
|
-
fixes (to, cc, bcc, replyTo, and an optional senderId); email.send from
|
|
7
|
-
@softr/sdk/server sends one with a subject and a text or HTML body, and throws
|
|
8
|
-
an EmailError with a code when Softr does not send it. Load this for a contact
|
|
9
|
-
form that emails the owner, a confirmation to the signed-in user, staff
|
|
10
|
-
emailing a client, or any email the app sends while handling what a person
|
|
11
|
-
does in it.
|
|
12
|
-
metadata:
|
|
13
|
-
type: sub-skill
|
|
14
|
-
library: softr-sdk
|
|
15
|
-
library_version: 0.0.97-alpha.2
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
**Boundary.** `email` and `EmailError` live on `@softr/sdk/server` and run only inside a `createServerFn` handler — importing them into a component fails the build. `defineEmailAction` and every type come from `@softr/sdk` and can be imported anywhere.
|
|
19
|
-
|
|
20
|
-
# Email
|
|
21
|
-
|
|
22
|
-
An app sends an email through an email action. Softr sends it and bills the workspace's **workflow credits**, so there is no mail service to connect and no workflow to build. Use it for every email the app sends while it handles something a person does in it: a form submitted, a button pressed, a record saved through the app.
|
|
23
|
-
|
|
24
|
-
A workflow is still the answer for an email on a schedule ("every Monday") or on a change made outside the app (a record edited in the table): load `automate-with-workflows` for those. A connected Gmail or Outlook is the answer only when the user wants the email to come from their own mailbox, through the `integrations` sub-skill.
|
|
25
|
-
|
|
26
|
-
`defineEmailAction` missing from `@softr/sdk`? The app was built on an older version. Upgrade `@softr/sdk` to the latest version first, then write the action.
|
|
27
|
-
|
|
28
|
-
## Who can send it, and to whom
|
|
29
|
-
|
|
30
|
-
The action's `permissions` is its audience: everyone in it can send an email through it, directly, without the app's own code. The app's code is not a guard. Only what the declaration fixes holds whatever the caller sends.
|
|
31
|
-
|
|
32
|
-
- **Fix the recipients whenever the use case allows.** A contact form that emails the owner fixes `to` to the owner. "Email me this report" fixes `to` to `{LOGGED_IN_USER:EMAIL}`. Then nobody can send the app's email to anyone else.
|
|
33
|
-
- **When people pick the recipients, narrow the audience.** "Staff email a client" leaves `to` open and keeps the action to the staff group with `customGroups`. An action with open recipients for all signed-in users lets anyone who signs up send any email to anyone from the app's address, up to the workspace's credits. Build that only when the user asks for it, and tell them so in one line. An action open to visitors must fix `to`: one that fixes only `cc` or `bcc` is not stored.
|
|
34
|
-
- **Recipients the person picks need the workspace's own sender.** An action that leaves `to` open must send from a confirmed sender, as its `senderId` or as the app's sender. From Softr's address every send fails with `SENDER_UNAVAILABLE`. Set the sender up before you write such an action, or ask the user which one to use.
|
|
35
|
-
|
|
36
|
-
## The sender
|
|
37
|
-
|
|
38
|
-
An email comes from the action's `senderId`, else from the app's email sender. With neither, it comes from Softr's own address, `"<workspace name>" <workspaceId@softr-email.com>`, the one workflows' "Send email with Softr" uses. That address is for testing: at most 30 emails a day per workspace, and the next one fails with `DAILY_LIMIT_REACHED`. The app's default `@softr.app` address sends only its sign-in emails.
|
|
39
|
-
|
|
40
|
-
A chosen sender that is missing or not confirmed fails every send with `SENDER_UNAVAILABLE`. Softr never falls back to its own address.
|
|
41
|
-
|
|
42
|
-
- While you build, list the workspace's senders with `workspace_list_email_senders`, and say which are confirmed, or that there are none.
|
|
43
|
-
- With confirmed senders, and a plan that allows custom senders, ask the user which one the email comes from and set it as the action's `senderId`, copied exactly. Nothing else changes, sign-in emails included. Never pick one yourself.
|
|
44
|
-
- With none, say the emails come from Softr's address, for testing and at most 30 a day. To send from their own address, they add one under the workspace's email senders and confirm the email it receives. Custom senders need the Professional or Business plan.
|
|
45
|
-
- Read the app's sender with `application_get` before you say where the emails come from. Your closing message names the actual From address: the `senderId`'s, else the app's, else `<workspaceId>@softr-email.com` with the real id. Never write "if no sender is set": read it.
|
|
46
|
-
- Changing the app's sender also changes the address its sign-in emails come from. Call `application_configure_email_sender` only when the user wants the app's sender changed, after naming both effects.
|
|
47
|
-
- Confirming the email is all an email action needs. The domain's DNS records (DKIM, Return-Path) are needed only before Studio lets the app pick the address as its own sender, and they help the emails stay out of spam.
|
|
48
|
-
|
|
49
|
-
## What it costs
|
|
50
|
-
|
|
51
|
-
Every email costs **5 workflow credits per recipient**, from the workspace's monthly workflow credits, which its workflows spend too. You do not know the workspace's plan, so never name one or count how many emails it covers. The plan and the closing message give the cost and where to watch it, for example: "Each submission emails you, at 5 workflow credits per email. Track them in Settings → Billing → Workflow usage, where this app has its own row."
|
|
52
|
-
|
|
53
|
-
Emails sent from the preview are real and charged, and the actions in the code reach the live app as soon as they are saved. Send at most one test email, and only when the user asks for one. Never send emails in a loop to try something out.
|
|
54
|
-
|
|
55
|
-
## Declare the action
|
|
56
|
-
|
|
57
|
-
```ts
|
|
58
|
-
const notifyOwner = defineEmailAction({
|
|
59
|
-
id: 'notifyOwner',
|
|
60
|
-
to: ['owner@acme.com'],
|
|
61
|
-
permissions: { userGroupTypes: ['NON_LOGGED_IN_USERS', 'LOGGED_IN_USERS'] },
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
const emailClient = defineEmailAction({
|
|
65
|
-
id: 'emailClient',
|
|
66
|
-
replyTo: '{LOGGED_IN_USER:EMAIL}',
|
|
67
|
-
permissions: { userGroupTypes: ['LOGGED_IN_USERS'], customGroups: ['<the staff group id>'] },
|
|
68
|
-
})
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
- `id` is a name you choose, unique across the app.
|
|
72
|
-
- `to`, `cc`, `bcc`: arrays of addresses. Each one declared here replaces the call's, and declaring `to` also ignores the call's `cc` and `bcc`. An element may be a whole placeholder for the signed-in sender: `{LOGGED_IN_USER:EMAIL}`, or `{LOGGED_IN_USER:<field>}` for an email field of their user record. Never part of a string, never in the call.
|
|
73
|
-
- `replyTo`: an address or one such placeholder.
|
|
74
|
-
- `senderId`: one of the workspace's senders, as above. The call can never set the sender.
|
|
75
|
-
- `permissions`: who may send it, as for queries and mutations.
|
|
76
|
-
|
|
77
|
-
Write the object inline in `defineEmailAction`, every value a literal. A declaration that cannot be read is not stored, and the check reports it.
|
|
78
|
-
|
|
79
|
-
Declare one action per kind of email: the owner's notification and the client's confirmation are two actions, each with its own recipients and audience.
|
|
80
|
-
|
|
81
|
-
## Core pattern
|
|
82
|
-
|
|
83
|
-
```ts
|
|
84
|
-
const submit = createServerFn({ method: 'POST' })
|
|
85
|
-
.validator(contactSchema)
|
|
86
|
-
.handler(async ({ data }) => {
|
|
87
|
-
const saved = await ds.create(saveSubmission, { data })
|
|
88
|
-
try {
|
|
89
|
-
await email.send(notifyOwner, {
|
|
90
|
-
subject: `New message from ${data.name}`,
|
|
91
|
-
body: renderSubmission(data), // the app's own HTML, with what the visitor typed escaped
|
|
92
|
-
replyTo: data.email,
|
|
93
|
-
})
|
|
94
|
-
} catch (error) {
|
|
95
|
-
if (error instanceof EmailError) return { saved: true, emailed: false, reason: error.message }
|
|
96
|
-
throw error
|
|
97
|
-
}
|
|
98
|
-
return { saved: true, emailed: true }
|
|
99
|
-
})
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
`email.send(action, init)` takes:
|
|
103
|
-
|
|
104
|
-
- `subject` and `body`. Required. `body` is plain text or HTML. Escape what visitors typed before you put it into HTML.
|
|
105
|
-
- `to`, `cc`, `bcc`, `replyTo`: each used only where the action does not fix it, and `cc` and `bcc` never when it fixes `to`. Each entry is one address. At most 50 recipients per email.
|
|
106
|
-
|
|
107
|
-
It answers `{ messageId }` once the email is sent. The answer never lists the recipients. An email carries no attachments: link to the file instead.
|
|
108
|
-
|
|
109
|
-
Every call is a new email. Disable the button while the request runs, so a double click does not send twice.
|
|
110
|
-
|
|
111
|
-
## Failure modes
|
|
112
|
-
|
|
113
|
-
**Not handling `EmailError`.** `email.send` throws an `EmailError` from `@softr/sdk/server`, with `status`, `code` and `message` when the email was not sent, and never retries by itself. Catch it, keep what the request already saved, and show the person a line they can act on: "Saved, but the email could not be sent." The codes:
|
|
114
|
-
|
|
115
|
-
| `code` | Meaning |
|
|
116
|
-
| --- | --- |
|
|
117
|
-
| `NOT_FOUND` | No such action, or the caller is not in its audience |
|
|
118
|
-
| `INVALID_INPUT` | No subject or body, an entry or placeholder that is not exactly one address, or more than 50 recipients |
|
|
119
|
-
| `PLAN_RESTRICTED` | The workspace's plan does not allow this email |
|
|
120
|
-
| `CREDITS_EXHAUSTED` | The workspace has no workflow credits left |
|
|
121
|
-
| `RATE_LIMITED` | The app sent too often lately. Tell the person to try again later |
|
|
122
|
-
| `DAILY_LIMIT_REACHED` | Softr's own address sent its 30 emails for today. Tell the person the email could not be sent today; the owner fixes it by choosing their own sender |
|
|
123
|
-
| `SENDER_UNAVAILABLE` | The chosen sender is missing or not confirmed, or the action leaves `to` open and has no sender of the workspace's own. Tell the person the email could not be sent; the owner fixes the sender |
|
|
124
|
-
| `PROVIDER_REJECTED` | The mail provider refused the email |
|
|
125
|
-
| `UNAVAILABLE` | Softr could not send it right now or could not be reached |
|
|
126
|
-
| `TIMEOUT` | No answer in time. It may still have been sent, so never send it again by yourself |
|
|
127
|
-
|
|
128
|
-
**Letting a mistyped address reach Softr.** An address the person typed (the reply-to of a contact form, a client's email) that is not one address is refused with `INVALID_INPUT`, which reads as a vague failure. Check its format in the validator and tell them which field is wrong.
|
|
129
|
-
|
|
130
|
-
**Calling from client code.** `email` is server-only. Wrap the send in a `createServerFn` and call that from the form or the button.
|
|
131
|
-
|
|
132
|
-
**Taking recipients from the request when they could be fixed.** A `to` the browser sends is a `to` any caller can change. Fix it in the declaration, or read it on the server from the record the email is about.
|
|
133
|
-
|
|
134
|
-
**Placeholders in the call.** `{LOGGED_IN_USER:EMAIL}` is filled only in the declaration. In the call it is sent as written and fails.
|
|
135
|
-
|
|
136
|
-
**Building a workflow for an email the app sends itself.** A "Run custom workflow" trigger plus a "Send email" step does the same at more cost to the user: a workflow to keep published. Use the email action; keep workflows for schedules and table events.
|