frontpage-host 0.2.5 → 0.2.7
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/AGENTS.md +3 -1
- package/CUSTOMER-INBOX.md +102 -7
- package/README.md +9 -0
- package/dist/commands/customer-inbox.js +1 -1
- package/dist/commands/shop.js +7 -1
- package/dist/registry.js +1 -0
- package/llms.txt +3 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -129,7 +129,7 @@ Sites are Astro 6 + Tailwind v4. More detail: `frontpage help site-building` or
|
|
|
129
129
|
- Analytics: bare `frontpage analytics` = dashboard; also `summary|query|funnel|timeseries|compare|sql` for structured reads (SQL is guard + RLS site-scoped).
|
|
130
130
|
- People CRM: `frontpage people list|get|add|set|note|rm-note|follow-up|hide|unhide|tag|export`. Site-scoped person graph (email or phone). Inbox stays the raw ledger. Hide is not forget. List export is CSV (not a one-person legal dump). Full guide: https://frontpage.host/developers/people
|
|
131
131
|
- Routines: `frontpage routines list|get|add|set|pause|resume|rm|run|runs`. One routine can hold several hours and several days. `8am,12pm,4pm` on `tue,thu,fri` stores hours `[8, 12, 16]` and weekdays `[2, 4, 5]`. Ask for an IANA timezone. Do not guess UTC. Full guide: https://frontpage.host/developers/routines
|
|
132
|
-
- Store catalog: `frontpage store items|variants|categories|settings|orders|import`. Integer cents only (`$49.99` is `4999`). `--price-cents` is the usual cost. Optional `--discount-cents` is the sale the buyer pays (must be lower). Create a category before assigning it. Photos are a site path `/__media/uploads/<this-slug>/…` or an HTTPS URL already saved on this site. `frontpage payments connect [--no-open]` opens Frontpage then Stripe. Store always uses Add to cart. Use Payments for standalone Pay now and invoices. Service fee is `settings set-checkout-fee`. The cart starts hidden. Product pages are the default: unless they said they do not want product pages, write one `src/pages/products/item.astro` (or shop) with `data-fp-store-product`. If they said no, skip that file and do not bind `href` or `url`. Description is a small markdown subset; product-page bind is `<div data-fp-store-bind="description">`. Every store control carries `data-fp-requires="store"`. Do not bake titles or prices. Full guide: https://frontpage.host/developers/store
|
|
132
|
+
- Store catalog: `frontpage store items|variants|categories|settings|orders|import`. Integer cents only (`$49.99` is `4999`). `--price-cents` is the usual cost. Optional `--discount-cents` is the sale the buyer pays (must be lower). End a sale with `frontpage store variants update <itemId> --id <variantId> --clear-discount`. This sends discountPriceCents: null and keeps the regular price. Omit both sale flags on update to preserve the current sale. Do not combine --clear-discount with --discount-cents; 0 means free, not removal. Read the item back to verify. Create a category before assigning it. Photos are a site path `/__media/uploads/<this-slug>/…` or an HTTPS URL already saved on this site. `frontpage payments connect [--no-open]` opens Frontpage then Stripe. Store always uses Add to cart. Use Payments for standalone Pay now and invoices. Service fee is `settings set-checkout-fee`. The cart starts hidden. Product pages are the default: unless they said they do not want product pages, write one `src/pages/products/item.astro` (or shop) with `data-fp-store-product`. If they said no, skip that file and do not bind `href` or `url`. Description is a small markdown subset; product-page bind is `<div data-fp-store-bind="description">`. Every store control carries `data-fp-requires="store"`. Do not bake titles or prices. Full guide: https://frontpage.host/developers/store
|
|
133
133
|
|
|
134
134
|
## Agent prompt loop
|
|
135
135
|
|
|
@@ -269,3 +269,5 @@ Payments, invoices and recurring billing: see packaged [PAYMENTS.md](./PAYMENTS.
|
|
|
269
269
|
Offerings own every standalone Pay now payment. Use `frontpage payments buttons list|get|create|update|archive|restore`; create the saved offering before adding its returned `data-fp-pay` markup. Supports `--receipt-template-id UUID`, `--default-receipt`, `--active true|false`, combined price/details updates and JSON payloads. Archive deletes from active checkout but preserves history. The website agent uses the same service automatically for ordinary payment-button requests. Store stays cart-only; invoices stay saved customer-addressed records. Full instructions: PAYMENTS.md and https://frontpage.host/developers/payments.
|
|
270
270
|
|
|
271
271
|
Currency is owned by Payments and read by Store, Offerings and invoices. Offering create/get/update responses include exact receiptVariables. For custom confirmations, declare those names with existing mail template commands, attach receiptTemplateId, and verify both records. Only include expressly selected answers; keep private answers excluded. Forms still use input-name tokens and confirmTemplateId.
|
|
272
|
+
|
|
273
|
+
Customer Inbox setup: enable website chat through Inbox settings; Frontpage public sites load it without a file edit or publish. Other websites use the explicit widget snippet. `get website` reports managed addresses/public availability. Website knowledge is default-on, read-only public retrieval; `websiteKnowledge.enabled:false` disables it. Source toggles, attention filtering and receipt cursors use the documented versioned resources.
|
package/CUSTOMER-INBOX.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Customer Inbox
|
|
2
2
|
|
|
3
|
-
Customer Inbox uses the site's existing AI credits and storage allowance. It is available on Scale and internal plans after owner activation. Other public plans do not include Inbox. No pilot allowlist is required. The support agent uses fixed GPT-6 Luna and bills AI usage at 10× raw provider cost. During human handling, customer messages use ordinary routing.
|
|
3
|
+
Customer Inbox uses the site's existing AI credits and storage allowance. It is available on Scale and internal plans after owner activation. Other public plans do not include Inbox. No pilot allowlist is required. The support agent uses fixed GPT-6 Luna and bills AI usage at 10× raw provider cost. During human handling, customer messages use ordinary routing. Normal owner-control email uses a small metered Luna Decisions call to keep private guidance, ownership controls and customer-facing replies distinct; the full support agent stays paused. UI and CLI controls need no intent call.
|
|
4
4
|
|
|
5
5
|
Run `frontpage help customer-inbox`. Use the site's normal CLI key:
|
|
6
6
|
|
|
@@ -45,9 +45,24 @@ Aliases use 3–48 ASCII letters, numbers and single hyphens. The service normal
|
|
|
45
45
|
| `knowledge/<id>/history` | GET | Immutable revisions for that note |
|
|
46
46
|
| `knowledge` | PUT | `{"title":"Evening visits","body":"Ask the owner before promising an evening visit.","expectedVersion":0,"reason":"Owner policy"}` |
|
|
47
47
|
| `knowledge/<id>` | PUT | Current title/body, `expectedVersion`, `reason`, optional `locked` or `restoreVersion` |
|
|
48
|
-
| `sources` | GET | Approved source records |
|
|
48
|
+
| `sources` | GET | Approved source records; `?overview=true` also includes the latest learning job status |
|
|
49
49
|
| `sources` | PUT | `{"url":"https://example.com/help","enabled":true,"expectedVersion":0}`; fetches public text |
|
|
50
50
|
|
|
51
|
+
The workspace’s **Knowledge** tab separates reusable internal facts from approved webpages. Adding a webpage fetches only that public page’s text; it does not crawl a website or edit an article. Expand **View saved webpage text** to see the snapshot the agent can use. Learning status reports the existing background job; queued does not mean the knowledge update has finished. Open a knowledge note to see its revisions, lock agent changes or restore a version.
|
|
52
|
+
|
|
53
|
+
To enable or disable a saved source without fetching it again, use the owner API:
|
|
54
|
+
|
|
55
|
+
```http
|
|
56
|
+
POST /api/v1/sites/my-site/customer-inbox/sources/SOURCE_UUID
|
|
57
|
+
Authorization: Bearer <site CLI key>
|
|
58
|
+
Idempotency-Key: source-toggle-001
|
|
59
|
+
Content-Type: application/json
|
|
60
|
+
|
|
61
|
+
{"enabled":false,"expectedVersion":2}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The response data is the same source with `enabled:false` and version `3`; its saved body, digest and check time stay unchanged. Repeat the same key and body after a lost response. A stale version returns `409 source_changed`; a foreign source returns `404`. Disabling prevents future source use and learning, but keeps existing knowledge notes. **Refresh webpage** fetches a fresh snapshot explicitly. The current packaged CLI retains its existing `sources` GET/PUT operations.
|
|
65
|
+
|
|
51
66
|
Supply `body` on a source write to save an owner-approved excerpt instead of fetching. Published sources refresh when the agent reads a source older than 24 hours. The fetcher reuses Core's DNS-pinned public HTTP infrastructure, rejects private addresses, checks redirects and bounds content. Sources over 16000 text characters require an owner-approved excerpt. No scripts run. A source version/digest fences knowledge updates against a changed source.
|
|
52
67
|
|
|
53
68
|
Knowledge search uses bounded literal keywords from natural-language queries and ranks notes by matched terms. Read the full matching note before updating it; update its current ID/version instead of creating a conflicting duplicate.
|
|
@@ -82,10 +97,16 @@ Search results contain previews. The support agent reads the complete matching n
|
|
|
82
97
|
|
|
83
98
|
Email replies route through opaque, recipient-bound Reply-To addresses linked to the site, conversation, purpose, owner and handler version. These are local addresses on one domain, not a new subdomain per thread. Subjects and message text never select the customer thread. The service checks the exact verified sender, current owner membership, route and receiving-server DMARC proof before interpreting owner mail.
|
|
84
99
|
|
|
85
|
-
Every owner email and its files enter private custody first.
|
|
100
|
+
Every owner email and its files enter private custody first. On normal guidance and owner-control routes, a Luna Decisions call reads the fresh text and bounded, labeled thread context to distinguish guidance, takeover, return, customer reply or unclear input. Use ordinary language to ask to handle the customer, or ask the agent to resume. Questions, quoted commands, negations and future conditions do not transfer control. UI/CLI `control` remains a typed, model-free action. No phrase whitelist controls ownership. A valid but uncertain control answer can use one bounded Luna tool-call fallback. It can choose only private guidance, takeover, return or unclear, with an exact fresh-text excerpt; it cannot authorize a customer reply. Both calls require current credits and distinct once-only receipts. Invalid responses, unknown paid calls and provider outages stay private rather than triggering another inference.
|
|
86
101
|
|
|
87
102
|
Guidance keeps the agent responsible. Takeover sends the owner a separate customer-visible transcript; reply through that relay address so Inbox preserves the history. A customer-facing email creates a separate public message only after a settled decision and current owner-session check. The original intake remains private for audit. Mixed or uncertain input, unavailable inference and exhausted credits stay private with an attention notice. Retry recoverable budget/receipt pauses using the existing job operation; an unknown paid attempt is never inferred again. A fresh reply to the original guidance address can also request return, while stale customer-relay sessions cannot publish.
|
|
88
103
|
|
|
104
|
+
Operational support failures and exhausted AI credits use the existing owner takeover. The owner receives a **Customer conversation** email whose body says replies go directly to the customer without AI. These server-marked reply routes relay authenticated owner messages without Decisions or support inference; normal guidance routes remain private. Use the workspace or typed CLI `control` action to return these conversations to the agent. Text sent to a direct-reply route is customer-facing, not an instruction to interpret. If automation stops while you reply through an older control-capable thread, that input stays private; Inbox offers the explicit direct-reply email instead. Send only the customer-facing message through that route. Widget chat uses the same owner relay and shows the resulting public reply in its saved conversation. Recovery never silently returns control.
|
|
105
|
+
|
|
106
|
+
An existing unretired address can continue forwarding to the configured verified owner after site deactivation or a plan downgrade. New address claims, chat and automation still require Scale/internal eligibility and activation. Forwarding uses the current site's existing mail and storage allowance and current owner checks; exhausted allowances, revoked owners, banned/deleted sites and retired addresses cannot send. Use `address` POST with `{"retire":true}` to stop forwarding, including after deactivation or downgrade. This requires a current verified admin. Other paid Inbox UI/API operations remain gated on eligible plans; the exception grants email transport and address retirement only.
|
|
107
|
+
|
|
108
|
+
This fallback depends on working Inbox transport, its database, Core and Resend. A complete service/database outage delays mail until existing webhook retries and reconciliation recover it. There is no independent forwarding service, second webhook or instant-outage-delivery promise. Unknown send outcomes stay held for reconciliation rather than risking another customer answer.
|
|
109
|
+
|
|
89
110
|
Private owner help, customer relay and customer email use separate threading chains. Inbox stores Resend's actual Message-ID and sends In-Reply-To/References; it never invents provider message IDs. Missing metadata uses scoped reconciliation without another send. Mail clients still control their own grouping. Owners and customers do not share a CC help thread. If the owner already addressed the customer, Inbox records the canonical public reply but does not send a second customer email.
|
|
90
111
|
|
|
91
112
|
Return checks current settings, site eligibility, unanswered work and site credits before support can resume. It cancels stale automatic work rather than replaying an old answer.
|
|
@@ -96,7 +117,7 @@ Set `guidanceToMe:true` in a versioned settings update to bind the signed curren
|
|
|
96
117
|
|
|
97
118
|
## Verify a direct email sender
|
|
98
119
|
|
|
99
|
-
|
|
120
|
+
When automation is active, fresh mail to the business address receives one generic confirmation email before support inference or People access. In human forwarding, the owner can respond to the supplied message without granting the sender history or account access. With passing receiving-service DMARC checks, a normal reply to its secret Reply-To confirms that mailbox. The customer can use **Confirm email** instead. No special reply words or AI decision are needed. Confirmation itself uses no AI credits; the email send and saved files use existing site allowances.
|
|
100
121
|
|
|
101
122
|
DMARC alone proves a sending domain, not a particular mailbox. Inbox requires the delivered secret destination, matching sender and site, active route, and live proof. It ignores sender-written authentication headers. Missing or gray checks offer the button only. A hard failure is held without an automatic reply. Temporary checks retry through the existing transport outbox and fall back to link confirmation after the third attempt.
|
|
102
123
|
|
|
@@ -139,17 +160,91 @@ The support agent has none of that owner authority. The server supplies its site
|
|
|
139
160
|
|
|
140
161
|
The developer guide lives at `https://frontpage.host/developers/customer-inbox`. Changes to that site use the Frontpage CLI pull/push/deploy/publish process.
|
|
141
162
|
|
|
163
|
+
## Public website knowledge
|
|
164
|
+
|
|
165
|
+
The new `website` resource and source-ID toggle commands require `frontpage-host` 0.2.6 or later.
|
|
166
|
+
|
|
167
|
+
Website searching is enabled by default. Knowledge shows **Search your public website**, its resolved address and availability. Turn it off to remove both support website tools. Explicit false survives unrelated settings saves. This permission is separate from internal notes and approved webpage snapshots.
|
|
168
|
+
|
|
169
|
+
```sh
|
|
170
|
+
frontpage customer-inbox get website --site my-site --json
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Example response data (inside the normal CLI response envelope):
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"enabled": true,
|
|
178
|
+
"origin": "https://example.com",
|
|
179
|
+
"revision": "PUBLISHED_REVISION",
|
|
180
|
+
"status": "available",
|
|
181
|
+
"retrieval": "on-demand",
|
|
182
|
+
"managedOrigins": [
|
|
183
|
+
{"origin":"https://my-site.frontpage.host","label":"Frontpage address","public":false},
|
|
184
|
+
{"origin":"https://example.com","label":"Connected domain","public":true}
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Read the current settings version, then save this JSON as `website-settings.json` to disable public website searching:
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{"expectedVersion":4,"value":{"websiteKnowledge":{"enabled":false}}}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
frontpage customer-inbox put settings --site my-site --file website-settings.json --request-key website_search_off_001
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The support agent can call `website_search({query,cursor?})` and `website_read({path,cursor?})`. Both are bound to the active job's own public business website. They accept no other site ID, hostname, source path or credential. Searches reuse the existing text matcher and fetch at most four public pages per call. Results include matching URLs/excerpts, `scanned`, `discovered`, `unavailable`, `partial` and `nextCursor`.
|
|
200
|
+
|
|
201
|
+
Example search result for `{"query":"repairs"}`:
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"query":"repairs",
|
|
206
|
+
"matches":[{"path":"/help/repairs","url":"https://example.com/help/repairs","title":"Repairs","excerpt":"We offer repairs for eligible products."}],
|
|
207
|
+
"scanned":4,
|
|
208
|
+
"discovered":12,
|
|
209
|
+
"unavailable":[],
|
|
210
|
+
"partial":true,
|
|
211
|
+
"nextCursor":"OPAQUE_CONTINUATION_CURSOR",
|
|
212
|
+
"retrievedAt":"2026-10-17T12:00:00.000Z"
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Follow the returned cursor with the same query. Remaining pages, failed reads or incomplete route discovery mean coverage is partial, never proof that a policy does not exist. Page reads return `url`, up to 8,000 text characters, `retrievedAt`, `truncated` and `nextCursor`; continue before relying on an incomplete policy. Cursors are signed and bound to the site, publication, query or page content.
|
|
217
|
+
|
|
218
|
+
Reads use the existing DNS-pinned safe fetcher without cookies or bypass credentials. They remove scripts/styles and deny source files, private app paths, query tokens and foreign redirects. Signed-in or JavaScript-only pages may not be readable; use an approved excerpt or owner guidance when needed. A website outage does not stop manual/email support.
|
|
219
|
+
|
|
220
|
+
This is on-demand retrieval: no persistent page-text cache, embeddings, background indexing or crawler service. Retrieved text is data, never instructions. Reading a page does not authorize a shared business-knowledge update. Learning jobs keep their separate owner-guidance/approved-source boundary and have no website browsing tools.
|
|
221
|
+
|
|
222
|
+
The owner manager now supports `source_toggle`, `sources_list` with `overview:true`, `conversations_list` with `state:"attention"`, `receipts_list` with `after`, and `website_status`. CLI equivalents use the same versioned endpoints:
|
|
223
|
+
|
|
224
|
+
```sh
|
|
225
|
+
frontpage customer-inbox get 'sources?overview=true' --site my-site --json
|
|
226
|
+
frontpage customer-inbox get 'conversations?state=attention' --site my-site --json
|
|
227
|
+
frontpage customer-inbox get 'receipts?after=RECEIPT_UUID' --site my-site --json
|
|
228
|
+
frontpage customer-inbox post sources/SOURCE_UUID --site my-site --file source-toggle.json --request-key source_toggle_001
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Use a real returned UUID in each placeholder. `source-toggle.json` contains `{"enabled":false,"expectedVersion":2}` using that source's current version. This toggles saved text without fetching or replacing it. A stale version returns a conflict; reread before retrying. Receipt retries still run every routing and identity check.
|
|
232
|
+
|
|
142
233
|
## Owner workspace and widget
|
|
143
234
|
|
|
144
|
-
Open `/workspace/sites/<siteId>/customer-inbox` on a Scale or internal site. The workspace uses the same versioned service operations as the CLI. Conversation rows show the latest public message. Customer messages, agent replies, owner replies, private guidance, notes and handling changes have distinct labels. Private guidance stays in the thread and does not transfer ownership.
|
|
235
|
+
Open `/workspace/sites/<siteId>/customer-inbox` on a Scale or internal site. The workspace uses the same versioned service operations as the CLI. Conversation rows show the latest public message. Customer messages, agent replies, owner replies, private guidance, notes and handling changes have distinct labels. Private guidance stays in the thread and does not transfer ownership. **Needs attention** is a Conversations filter for human-handled or paused support threads. Admins also see held incoming emails there. These emails remain outside customer history until routing and identity checks succeed; a retry queues the same checks, not a successful delivery or verification. The held list is bounded to 100 entries; pass its `nextCursor` as `receipts?after=<id>` to read more. A sender address or subject displayed there does not prove identity.
|
|
236
|
+
|
|
237
|
+
**Chat & settings** groups the support address, website access, required visitor details and appearance. **Enable website chat** shows chat automatically on your live Frontpage website, without an edit, rebuild or publish. Frontpage resolves its own address and verified connected domains automatically. Add other websites one address at a time; those need the external installation code. New configurations require both name and email; saved opt-outs remain unchanged. Collection does not verify ownership. The appearance preview uses the installed widget renderer without sending messages or making model calls. Site allowances remain on the normal Usage page.
|
|
238
|
+
|
|
239
|
+
Signing keys stay hidden in the workspace until an admin opens the developer options and chooses **Reveal signing key**. Ordinary setup reads use `widget?includeIdentity=false`, which returns `scriptUrl`, `apiOrigin` and `siteId` without a key. The existing human-admin `get widget` CLI response still includes the key; treat that output as a secret.
|
|
145
240
|
|
|
146
|
-
Use `frontpage customer-inbox get widget --site my-site` as a human admin to get the script URL, site ID and server-side app identity key.
|
|
241
|
+
Use `frontpage customer-inbox get widget --site my-site` as a human admin to get the script URL, site ID and server-side app identity key. For a website or app hosted outside Frontpage, install the script in its template:
|
|
147
242
|
|
|
148
243
|
```html
|
|
149
244
|
<script defer src="https://app.frontpage.host/customer-inbox/widget.js" data-site="SITE_UUID"></script>
|
|
150
245
|
```
|
|
151
246
|
|
|
152
|
-
The
|
|
247
|
+
The gateway adds the public loader through its existing HTML transform on Scale/internal public websites. It does not call Inbox while serving HTML. The browser checks availability before loading the interface; disabled chat or an Inbox outage does not stop website delivery. Existing explicit app installations keep their identity options without a duplicate launcher. Disabling chat rejects new operations and hides connected chats through the existing event stream. Idle/suspended tabs recheck when used, returned to or reloaded. Conversations and email support remain intact.
|
|
153
248
|
|
|
154
249
|
Update settings using the current `expectedVersion`:
|
|
155
250
|
|
package/README.md
CHANGED
|
@@ -68,3 +68,12 @@ Payments, invoices and recurring billing: see packaged [PAYMENTS.md](./PAYMENTS.
|
|
|
68
68
|
Offerings own every standalone Pay now payment. Use `frontpage payments buttons list|get|create|update|archive|restore`; create the saved offering before adding its returned `data-fp-pay` markup. Supports `--receipt-template-id UUID`, `--default-receipt`, `--active true|false`, combined price/details updates and JSON payloads. Archive deletes from active checkout but preserves history. The website agent uses the same service automatically for ordinary payment-button requests. Store stays cart-only; invoices stay saved customer-addressed records. Full instructions: PAYMENTS.md and https://frontpage.host/developers/payments.
|
|
69
69
|
|
|
70
70
|
Payments owns the shared currency from Stripe setup; Store reads it. Offering create/get/update JSON returns `receiptVariables` for custom confirmation templates, including eligible `answer_<customizationId>` tokens. Use existing mail template commands and attach with `--receipt-template-id`; see PAYMENTS.md.
|
|
71
|
+
|
|
72
|
+
### End a Store sale
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
frontpage store variants update camp-hat --id default --clear-discount --site my-site
|
|
76
|
+
frontpage store items get camp-hat --site my-site --json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`--price-cents` sets the regular price. `--discount-cents` sets a lower sale price. `--clear-discount` removes the sale and keeps the regular price; it sends `discountPriceCents: null`. Omit both sale flags on update to keep the current sale. Do not combine them. A sale price of `0` means free, not sale removal. Repeat for each live variant when ending a sale across the catalog. Store prices update live; a page publish or banner removal does not clear discounts.
|
|
@@ -5,7 +5,7 @@ import { takeFlag, assertNoUnknownFlags } from "../argv.js";
|
|
|
5
5
|
import { getApiKey } from "../auth/keychain.js";
|
|
6
6
|
import { apiBase, v1Get, httpErrorFromV1, CliHttpError, EXIT_AUTH, EXIT_USAGE, EXIT_OK, exitCodeForError, } from "../http/client.js";
|
|
7
7
|
import { emitOk, emitErr, isJson } from "../runtime.js";
|
|
8
|
-
const RESOURCE = /^(?:status|activation|address|widget|settings|knowledge(?:\/[0-9a-f-]+(?:\/history)?)?|sources
|
|
8
|
+
const RESOURCE = /^(?:status|activation|address|widget|website|settings|knowledge(?:\/[0-9a-f-]+(?:\/history)?)?|sources(?:\/[0-9a-f-]+)?|blocks(?:\/[0-9a-f-]+\/unblock)?|jobs(?:\/[0-9a-f-]+(?:\/resume)?)?|files(?:\/[0-9a-f-]+)?|receipts(?:\/[0-9a-f-]+)?|conversations(?:\/[0-9a-f-]+(?:\/(?:messages|routing|guidance|reply|control|state|revoke-sessions|verification))?)?)(?:\?[^#]*)?$/;
|
|
9
9
|
export function inboxCommand(args) {
|
|
10
10
|
const work = [...args], verb = work.shift(), resource = work.shift(), file = takeFlag(work, "--file"), key = takeFlag(work, "--request-key"), out = takeFlag(work, "--out");
|
|
11
11
|
assertNoUnknownFlags(work, "customer-inbox");
|
package/dist/commands/shop.js
CHANGED
|
@@ -433,6 +433,10 @@ export async function runShop(args) {
|
|
|
433
433
|
const variantId = requireVariantId(takeFlag(work, "--id") ?? takeFlag(work, "--variant"));
|
|
434
434
|
const priceCents = parseCentsFlag(takeFlag(work, "--price-cents"), "priceCents");
|
|
435
435
|
const discountCents = parseCentsFlag(takeFlag(work, "--discount-cents"), "discountPriceCents");
|
|
436
|
+
const clearDiscount = hasFlag(work, "--clear-discount");
|
|
437
|
+
if (clearDiscount && discountCents !== undefined) {
|
|
438
|
+
throw new CliHttpError("Use either --discount-cents or --clear-discount, not both.", EXIT_USAGE, 0, "bad_request");
|
|
439
|
+
}
|
|
436
440
|
const stockRaw = takeFlag(work, "--stock");
|
|
437
441
|
const options = parseOptions(takeAll(work, "--option"));
|
|
438
442
|
const active = parseBoolFlag(takeFlag(work, "--active"), "active");
|
|
@@ -440,7 +444,9 @@ export async function runShop(args) {
|
|
|
440
444
|
const body = {};
|
|
441
445
|
if (priceCents !== undefined)
|
|
442
446
|
body.priceCents = priceCents;
|
|
443
|
-
if (
|
|
447
|
+
if (clearDiscount)
|
|
448
|
+
body.discountPriceCents = null;
|
|
449
|
+
else if (discountCents !== undefined)
|
|
444
450
|
body.discountPriceCents = discountCents;
|
|
445
451
|
if (stockRaw !== undefined)
|
|
446
452
|
body.stock = stockRaw === "unlimited" ? null : parseCountFlag(stockRaw, "stock");
|
package/dist/registry.js
CHANGED
|
@@ -517,6 +517,7 @@ export const COMMANDS = [
|
|
|
517
517
|
],
|
|
518
518
|
flags: [
|
|
519
519
|
"items list|get|create|update|archive|restore|activate|images|stock; use --file for nested variants, options, customizations and images. Existing fixed/open pricing is retained. Store always uses Add to cart.",
|
|
520
|
+
"variants update <itemId> --id <variantId> --clear-discount ends a sale and preserves the regular price. --discount-cents sets a sale; omit both on update to preserve it. The flags cannot be combined. 0 means free, not removal. Verify with items get. Prices update live.",
|
|
520
521
|
"Descriptions use a small markdown subset. Bind data-fp-store-bind=description for the full product story; do not bake titles, prices or images into the page. Store is cart-only; use Payments for explicit Pay now.",
|
|
521
522
|
"items stock uses --add/--remove as a signed delta, or --set/--unlimited. Never combine these verbs. Product pages use data-fp-store-product and the platform cart templates. Store prices read the shared currency owned by Payments.",
|
|
522
523
|
"variants add|update|archive|restore; categories list|create|rename|archive. Create categories before assigning their slugs.",
|
package/llms.txt
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
- Redirects: frontpage redirects list|set|rm — HTTP 301/308, instant, not a file; revert does not undo; do not fake with Astro.redirect / meta refresh
|
|
19
19
|
- People CRM: frontpage people list|get|add|set|note|rm-note|follow-up|hide|unhide|tag|export. Site-scoped person graph (email or phone). Inbox stays the raw ledger. Hide is not forget. List export is CSV. Unknown leftover flags fail closed. Guide: https://frontpage.host/developers/people
|
|
20
20
|
- Routines: frontpage routines list|get|add|set|pause|resume|rm|run|runs. Several hours and several days are one routine. 8am,12pm,4pm and tue,thu,fri store hours [8, 12, 16] and weekdays [2, 4, 5]. Timezone is IANA. Do not guess UTC. Guide: https://frontpage.host/developers/routines
|
|
21
|
-
- Store catalog: frontpage store items|variants|categories|settings|orders|import. Integer cents only ($49.99 is 4999). --price-cents is the usual cost. Optional --discount-cents is the sale the buyer pays (must be lower). Create a category before assigning it. Photos are /__media/uploads/<this-slug>/… or an HTTPS URL already saved on this site. frontpage payments connect [--no-open] opens Frontpage then Stripe. Store is cart-only; currency comes from Stripe and cannot be set. Use frontpage payments for standalone Pay now and invoices. Service fee is settings set-checkout-fee. The cart starts hidden. Product pages are the default: unless they said they do not want product pages, write one src/pages/products/item.astro (or shop) with data-fp-store-product. If they said no, skip that file and do not bind href or url. Description is a small markdown subset; product-page bind is <div data-fp-store-bind="description">. Every store control carries data-fp-requires="store". Leave data-fp-store-variants empty. Do not bake titles or prices. Guide: https://frontpage.host/developers/store
|
|
21
|
+
- Store catalog: frontpage store items|variants|categories|settings|orders|import. Integer cents only ($49.99 is 4999). --price-cents is the usual cost. Optional --discount-cents is the sale the buyer pays (must be lower). End a sale with `frontpage store variants update <itemId> --id <variantId> --clear-discount`. This sends discountPriceCents: null and keeps the regular price. Omit both sale flags on update to preserve the current sale. Do not combine --clear-discount with --discount-cents; 0 means free, not removal. Read the item back to verify. Create a category before assigning it. Photos are /__media/uploads/<this-slug>/… or an HTTPS URL already saved on this site. frontpage payments connect [--no-open] opens Frontpage then Stripe. Store is cart-only; currency comes from Stripe and cannot be set. Use frontpage payments for standalone Pay now and invoices. Service fee is settings set-checkout-fee. The cart starts hidden. Product pages are the default: unless they said they do not want product pages, write one src/pages/products/item.astro (or shop) with data-fp-store-product. If they said no, skip that file and do not bind href or url. Description is a small markdown subset; product-page bind is <div data-fp-store-bind="description">. Every store control carries data-fp-requires="store". Leave data-fp-store-variants empty. Do not bake titles or prices. Guide: https://frontpage.host/developers/store
|
|
22
22
|
- Analytics funnel: --steps JSON array or comma paths (/, /pricing); bad JSON → Invalid JSON for --steps
|
|
23
23
|
- Modules: unknown key errors list Known: …; mailing list module key is signups (not subscribe)
|
|
24
24
|
- Errors: --json API envelopes include requestId when the server returned one; local validation omits requestId/httpStatus; runs wait failed/canceled → ok:false + run.error (exit 2); deploy wait = agent idle + tip compile ready (fail-closed / compile timeout → exit 2); push --wait and publish --wait wait for GET /deploy ready
|
|
@@ -45,3 +45,5 @@ Payments, invoices and recurring billing: see packaged [PAYMENTS.md](./PAYMENTS.
|
|
|
45
45
|
Offerings own every standalone Pay now payment. Use `frontpage payments buttons list|get|create|update|archive|restore`; create the saved offering before adding its returned `data-fp-pay` markup. Supports `--receipt-template-id UUID`, `--default-receipt`, `--active true|false`, combined price/details updates and JSON payloads. Archive deletes from active checkout but preserves history. The website agent uses the same service automatically for ordinary payment-button requests. Store stays cart-only; invoices stay saved customer-addressed records. Full instructions: PAYMENTS.md and https://frontpage.host/developers/payments.
|
|
46
46
|
|
|
47
47
|
Payments owns Stripe currency. Read Offering receiptVariables before creating a confirmation template; attach it through Payments. Forms use submitted input names. Full receipt contract: PAYMENTS.md.
|
|
48
|
+
|
|
49
|
+
Customer Inbox: Frontpage website chat uses one settings toggle, no website edit/publish. get website shows public availability/managed addresses. websiteKnowledge.enabled controls default-on support website reads; no source or private-preview access. Source-ID toggles, attention filtering and held receipt pagination are supported. See CUSTOMER-INBOX.md.
|